Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

24 Dec 2016, 15:44

If one does a for loop.

Code: Select all

for oWB in ComObjCreate("Shell.Application").Windows
Can one retrieve the hWnds for the 'Internet Explorer_Server' controls?
Thank you.

[EDIT:] This issue is resolved here:
Cast COM Object IWebBrowser2 to IServiceProvider - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=67163
Last edited by jeeswg on 24 Aug 2019, 06:37, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
lexikos
Posts: 9621
Joined: 30 Sep 2013, 04:07
Contact:

Re: Internet Explorer: get WB hWnds via object loop

24 Dec 2016, 16:34

No.

You need to send a message directly to the control. There are examples in other threads.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop

24 Dec 2016, 17:17

When I want to retrieve the urls and titles for websites I do 2 loops.

I loop through the 'Internet Explorer_Server' controls, and grab LocationName, LocationURL and the text from the 'Frame Tab' controls (as a check to confirm LocationName is correct).
These are in the order last accessed, with the most recently accessed (active tab), first (I believe).
[EDIT: document.title/document.url are preferable to LocationName/LocationURL. They are not lost when you clear the IE cache/cookies etc.]

I do the object loop described above, to the get LocationName and LocationURL, in the order the tabs were opened (I believe).

Then I try to combine the two lists (I want them in object loop order).
Is there any identifier that could be retrieved on both loops to tie up the two lists.
Currently I use the url, but you can have the same url more than once with different titles.
Last edited by jeeswg on 24 Aug 2019, 06:40, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
phaleth
Posts: 38
Joined: 13 Apr 2015, 03:49

Re: Internet Explorer: get WB hWnds via object loop

29 Dec 2016, 07:24

You could check for the combination of both the URL and Website's title (tab's name).
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

29 Dec 2016, 16:26

- Thank you. The script basically does everything that it can to ensure the matching is as good as is possible.
- It's just that if there were unique window object IDs to tie the two lists together, I could do a much simpler rewrite, gain an important universal technique, and would have something easier for people to understand, use, and learn from.
- I've always been curious as to whether there are unique IDs retrievable during both the control loop and object loop that would allow information from both loops to be tied together.
Last edited by jeeswg on 24 Aug 2019, 06:43, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
phaleth
Posts: 38
Joined: 13 Apr 2015, 03:49

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

30 Dec 2016, 14:24

For more uniqueness you can always query the webpage for example on how many <a>, <p> and <script> tags does it have and add that to the composite string.

If you want it to look like non-sense you can always feed the resulting string into some sort of converter that generates for example a MD5 or SHA1 hash. There are some scripts that can do this on these boards.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

31 Dec 2016, 06:01

@phaleth Thank you, that's the curious thing, there's so much information you can get from a document object, you wonder if there is some actual object ID available that would give certainty, that would tie together the items in the two separate loops, furthermore you don't know if the number of tags will change between loops.
Also for example you could have the same url, but say a timestamp in the title that changed between the two loops, so here a common ID would be very useful.

I've provided a basic version of each loop to demonstrate how the initial data is retrieved. Getting the title via the frame tab is security against object Internet titles that have 'gone wrong' e.g. by clearing IE's history, which usually makes the 'title' the same as the url.
Also the frame tab control might say 'hello - Google Search' where as the document object says less usefully: 'Google'.
It should be noted that the frame tab text is usually truncated at 95 characters.
If there is some clash, between the title texts, a prefix such as '[ERROR]' can be added to the front of the retrieved title, for the user to then double-check the title themselves, or perhaps even use a function to download the url to a variable and retrieve the title.

Code: Select all

WinGet, hWnd, ID, ahk_class IEFrame
vOutput := "[ORDER 1: CONTROL ORDER]`r`n"

;get url + title, control order
Loop
{
	ControlGet, hCtl, Hwnd,, % "Internet Explorer_Server" A_Index, % "ahk_id " hWnd
	if (hCtl = "")
		break

	;Frame Tab\TabWindowClass\Shell DocObject View\Internet Explorer_Server
	ControlGet, hCtl, Hwnd,, % "Internet Explorer_Server" A_Index, % "ahk_id " hWnd
	hCtl2 := DllCall("user32\GetParent", "Ptr",hCtl, "Ptr")
	, hCtl3 := DllCall("user32\GetParent", "Ptr",hCtl2, "Ptr")
	ControlGetText, vTitle,, % "ahk_id " hCtl3
	vIsV1 := !!SubStr(1, 0)
	if (SubStr(vTitle, vIsV1-20) = " - Internet Explorer")
		vTitle := SubStr(vTitle, 1, -20)
	vOutput .= vTitle "`r`n"

	;WBGet: https://autohotkey.com/board/topic/47052-basic-webpage-controls-with-javascript-com-tutorial/
	oWB := WBGet("ahk_id " hWnd, A_Index)
	;vOutput .= oWB.LocationName "`r`n"
	;vOutput .= oWB.LocationUrl "`r`n"
	vOutput .= oWB.document.title "`r`n"
	vOutput .= oWB.document.url "`r`n"
	oWB := ""
	vOutput .= "`r`n"
}

;===============

vOutput .= "[ORDER 2: OBJECT ORDER]`r`n"

;get url + title, object order
for oWB in ComObjCreate("Shell.Application").Windows
{
	if !(hWnd = oWB.Hwnd)
		continue
	;vOutput .= oWB.LocationName "`r`n"
	;vOutput .= oWB.LocationUrl "`r`n"
	vOutput .= oWB.document.title "`r`n"
	vOutput .= oWB.document.url "`r`n"
	vOutput .= "`r`n"
}
oWB := ""

vIsV1 := !!SubStr(1, 0)
if (SubStr(vOutput, vIsV1-4) = "`r`n`r`n")
	vOutput := SubStr(vOutput, 1, -2)

Clipboard := vOutput
MsgBox, % "done"
return
Last edited by jeeswg on 24 Aug 2019, 06:49, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
phaleth
Posts: 38
Joined: 13 Apr 2015, 03:49

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

01 Jan 2017, 11:14

The following code will say "they match" only when a single IE window with single IE tab is opened. On the comparison it only deals with the last out entries from each loop and so this code needs more work. Right now it's just good enough to give you the idea of what to compare to get pretty decent uniqueness.

Code: Select all

WinGet, Hwnd, ID, ahk_class IEFrame
vOutput := "[ORDER 1: CONTROL ORDER]`r`n"

;get url + title, control order
Loop
{
	ControlGet, hCtl, Hwnd, , Internet Explorer_Server%A_Index%, ahk_id %Hwnd%
	if (hCtl = "")
		break

	;Frame Tab\TabWindowClass\Shell DocObject View\Internet Explorer_Server
	ControlGet, hCtl, Hwnd, , Internet Explorer_Server%A_Index%, ahk_id %Hwnd%
	hCtl2 := DllCall("GetParent", UInt, hCtl), hCtl3 := DllCall("GetParent", UInt, hCtl2)
	ControlGetText, vTitle, , ahk_id %hCtl3%
	
	if (SubStr(vTitle, 1-20) = " - Internet Explorer")
		StringTrimRight, vTitle, vTitle, 20
	
	if (oWB.LocationUrl ~= "blank")
		continue
	
	vOutput .= vTitle "`r`n"

	;WBGet: https://autohotkey.com/board/topic/47052-basic-webpage-controls-with-javascript-com-tutorial/
	oWB := WBGet("ahk_id " Hwnd, A_Index)
	vOutput .= oWB.LocationName "`r`n"
	vOutput .= oWB.LocationUrl "`r`n"
	vOutput .= "`r`n"
	controlOuterHTML := oWB.document.documentElement.outerHTML
	oWB := ""
}

;===============

vOutput .= "[ORDER 2: OBJECT ORDER]`r`n"

;get url + title, object order
for oWB in ComObjCreate("Shell.Application").Windows
{
	objectHwnd := ""
	try {
		objectHwnd := oWB.Hwnd
	}
	
	if (Hwnd != objectHwnd)
		continue
	
	vOutput .= oWB.LocationName "`r`n"
	vOutput .= oWB.LocationUrl "`r`n"
	vOutput .= "`r`n"
	objectOuterHTML := oWB.document.documentElement.outerHTML
}
oWB := ""

if (SubStr(vOutput, 1-4) = "`r`n`r`n")
	StringTrimRight, vOutput, vOutput, 2

match := % (controlOuterHTML = objectOuterHTML) ? "they match" : "they don't match"

MsgBox,
(LTrim
	%vOutput%
	
	--------------------
	
	%match%
)
Return

WBGet(WinTitle="ahk_class IEFrame", Svr#=1) {               ;// based on ComObjQuery docs
   static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
        , IID := "{0002DF05-0000-0000-C000-000000000046}"   ;// IID_IWebBrowserApp
;//     , IID := "{332C4427-26CB-11D0-B483-00C04FD90119}"   ;// IID_IHTMLWindow2
   SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
   if (ErrorLevel != "FAIL") {
      lResult:=ErrorLevel, VarSetCapacity(GUID,16,0)
      if DllCall("ole32\CLSIDFromString", "wstr","{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr",&GUID) >= 0 {
         DllCall("oleacc\ObjectFromLresult", "ptr",lResult, "ptr",&GUID, "ptr",0, "ptr*",pdoc)
         return ComObj(9,ComObjQuery(pdoc,IID,IID),1), ObjRelease(pdoc)
      }
   }
} ; by jethrow
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

01 Jan 2017, 12:35

Thank you phaleth, using the outerHTML is an interesting idea, out of interest does it slow down the script much, or use much CPU?

I have various methods for matching up the window lists, and I'm quite happy with what I have. My main concern is, if anybody happens to know if there is some sort of unique ID that can be retrieved on both loops (or happens to know that there isn't), and possibly any other details to retrieve from the objects that may help establish uniqueness/semi-uniqueness, possibly a date created/opened.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
phaleth
Posts: 38
Joined: 13 Apr 2015, 03:49

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

01 Jan 2017, 16:13

By milliseconds maybe. Use A_TickCount variable to find out the difference in runtime.

I don't think digging any deeper into this is worth the while, but maybe you will hit onto something else if you try.
https://msdn.microsoft.com/cs-cz/librar ... 85%29.aspx
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

01 Jan 2017, 16:39

Great link. By milliseconds? Retrieve milliseconds from where? Is it possible to retrieve the times of events in that list?

I've found a few times, sneaky useful things on IE documents, from things not easily findable in MSDN, like the % zoom.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
phaleth
Posts: 38
Joined: 13 Apr 2015, 03:49

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

02 Jan 2017, 11:13

Yeah, it's possible to retrieve the run time.

Code: Select all

startTime := A_TickCount
Sleep, 1000
MsgBox, 0, Run time, % endTime := A_TickCount - startTime
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

02 Jan 2017, 12:05

I meant if there were some method like GetProcessTimes (which retrieves when a process was opened), for the document objects, the object loop seems to retrieve them in such an order.

[EDIT: I misread the link, it appears it tells you when events happen, at the time they happen, I don't know if you can subsequently retrieve when they happened.]
Last edited by jeeswg on 24 Aug 2019, 06:51, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

09 Jan 2017, 00:20

It appears that oWB.document.title gives the same text as the Frame Tab control, and what's more, it's not truncated.
Thus everything can be achieved via the object loop, with no reference to controls needed.

Thus I can achieve what I want very simply, retrieving webpage titles and urls, as below:

Code: Select all

^q::
WinGet, hWnd, ID, ahk_class IEFrame
vOutput := ""
for oWB in ComObjCreate("Shell.Application").Windows
{
	if (hWnd = oWB.HWND)
		vOutput .= oWB.document.title "`r`n" oWB.LocationUrl "`r`n`r`n"
}
oWB := ""
vOutput := SubStr(vOutput, 1, -2) ;trim right
Clipboard := vOutput
MsgBox, % "done"
return
Note: oWB.document.title is preferable to oWB.LocationName, because it always gives the proper title, e.g. 'Google' v. 'google hello - Google Search', and is not susceptible, to clearing IE's history (in which case LocationName becomes the same as LocationURL).

Note: this code retrieves information for the tabs on one specific IE window.
To get all tabs, either perform the loop for all IEFrame windows, or use the condition: if (oWB.Name = "Internet Explorer").
(The latter would give you information from all the tabs whenever they were created, regardless of which IEFrame window they are in.)

I would still be interested if either the win objects or the document objects have some kind of unique ID number, or retrievable creation date. Clearly the object loop is accessing a list that is in date-created order.

It seems very odd for items not to have some kind of ID, when processes/windows/controls clearly do.
Last edited by jeeswg on 24 Aug 2019, 06:54, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs)

04 Oct 2017, 19:54

It looks like there is a way to do this, if you add a custom property to a tab.

Code: Select all

;WBGet function - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=39869

vCount := 0

q:: ;internet explorer tab - set property
vCount++
WinGet, hWnd, ID, A
oWB := WBGet("ahk_id " hWnd)
oWB.PutProperty("MyProperty", vCount)
oWB := ""
return

w:: ;internet explorer tab - get property
WinGet, hWnd, ID, A
oWB := WBGet("ahk_id " hWnd)
MsgBox, % oWB.GetProperty("MyProperty")
oWB := ""
return

e:: ;internet explorer tab - set property
DetectHiddenWindows, On
WinGet, vWinList, List, ahk_class IEFrame
Loop % vWinList
{
	hWnd := vWinList%A_Index%
	WinGet, vCtlList, ControlList, % "ahk_id " hWnd
	Loop Parse, vCtlList, % "`n"
	{
		ControlGet, hCtl, Hwnd,, % "Internet Explorer_Server" A_Index, % "ahk_id " hWnd
		if !hCtl
			break
		oWB := WBGet("ahk_id " hWnd, A_Index)
		oWB.PutProperty("MyProperty", hCtl)
		oWB := ""
	}
}
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot] and 124 guests