Cast COM Object IWebBrowser2 to IServiceProvider

Get help with using AutoHotkey and its commands and hotkeys
kkleinfelter
Posts: 21
Joined: 21 Dec 2018, 10:59

Cast COM Object IWebBrowser2 to IServiceProvider

16 Aug 2019, 14:35

I need to cast an IWebBrowser2 to an IServiceProvider, then to an IOleWindow; then call GetWindow on the IOleWindow.

I have an IWebBrowser2 object (named win) for an IE tab, but calling wind.HWND returns the handle for the main frame window and not the tab. (This was by design, per Microsoft, for 'maximum compatibility' when tabs were introduced.

According to C++ programmers, I just need to cast the IWebBrowser2 to an IServiceProvider, then to an IOleWindow; then call GetWindow on the IOleWindow.

OK. How do I cast COM Objects in Autohotkey?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Cast COM Object IWebBrowser2 to IServiceProvider

16 Aug 2019, 15:04

Great info, thanks for sharing!

For the current Internet Explorer tab:

Code: Select all

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

q:: ;internet explorer - get tab hWnd (TabWindowClass hWnd)
WinGet, hWnd, ID, A
oWB := WBGet("ahk_id " hWnd)
IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}" ;source: servprov.h
IID_IShellBrowser := "{000214E2-0000-0000-C000-000000000046}" ;source: ShObjIdl.h
SID_SShellBrowser := IID_IShellBrowser ;source: ShlGuid.h
IID_IOleWindow := "{00000114-0000-0000-C000-000000000046}" ;source: oleidl.h
pSP := ComObjQuery(oWB, IID_IServiceProvider)
pOW := ComObjQuery(pSP, SID_SShellBrowser, IID_IOleWindow)
hCtl := 0
DllCall(NumGet(NumGet(pOW+0) + 3*A_PtrSize), "Ptr",pOW, "Ptr*",hCtl) ;IOleWindow::GetWindow
WinGetClass, vCtlClass, % "ahk_id " hCtl
MsgBox, % pSP "`r`n" pOW "`r`n" hCtl "`r`n" vCtlClass
ObjRelease(pOW)
ObjRelease(pSP)
oWB := ""
return
For all tabs in all Internet Explorer processes:

Code: Select all

w:: ;internet explorer - get all tab hWnds (TabWindowClass hWnd)
for oWB in ComObjCreate("Shell.Application").Windows
{
	if !(oWB.Name = "Internet Explorer")
		continue
	IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}" ;source: servprov.h
	IID_IShellBrowser := "{000214E2-0000-0000-C000-000000000046}" ;source: ShObjIdl.h
	SID_SShellBrowser := IID_IShellBrowser ;source: ShlGuid.h
	IID_IOleWindow := "{00000114-0000-0000-C000-000000000046}" ;source: oleidl.h
	pSP := ComObjQuery(oWB, IID_IServiceProvider)
	pOW := ComObjQuery(pSP, SID_SShellBrowser, IID_IOleWindow)
	hCtl := 0
	DllCall(NumGet(NumGet(pOW+0) + 3*A_PtrSize), "Ptr",pOW, "Ptr*",hCtl) ;IOleWindow::GetWindow
	;WinGetClass, vCtlClass, % "ahk_id " hCtl
	;MsgBox, % oWB.document.title "`r`n" oWB.document.url "`r`n" pSP "`r`n" pOW "`r`n" hCtl "`r`n" vCtlClass
	ObjRelease(pOW)
	ObjRelease(pSP)
	ControlGet, hCtl, Hwnd,, Internet Explorer_Server1, % "ahk_id " hCtl
	WinGetClass, vWinClass, % "ahk_id " oWB.HWND
	WinGetClass, vCtlClass, % "ahk_id " hCtl
	hWnd := Format("0x{:x}", oWB.HWND)
	hCtl := Format("0x{:x}", hCtl)
	MsgBox, % hWnd "`r`n" vWinClass "`r`n" oWB.document.title "`r`n" oWB.document.url "`r`n`r`n" hCtl "`r`n" vCtlClass
}
oWB := ""
return
This gives us a new alternative to WBGet, to get an object for the current tab. Get the hWnd for the current TabWindowClass control, and then loop through all IE objects in ComObjCreate("Shell.Application").Windows until you find a match.

Code: Select all

e:: ;internet explorer - current tab, get object
WinGet, hWnd, ID, A
ControlGet, hCtl, Hwnd,, Internet Explorer_Server1, % "ahk_id " hWnd
Loop 2
	hCtl := DllCall("user32\GetParent", "Ptr",hCtl, "Ptr")
oWB := ""
for oWB2 in ComObjCreate("Shell.Application").Windows
{
	if !(oWB2.HWND = hWnd)
		continue
	IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}" ;source: servprov.h
	IID_IShellBrowser := "{000214E2-0000-0000-C000-000000000046}" ;source: ShObjIdl.h
	SID_SShellBrowser := IID_IShellBrowser ;source: ShlGuid.h
	IID_IOleWindow := "{00000114-0000-0000-C000-000000000046}" ;source: oleidl.h
	pSP := ComObjQuery(oWB2, IID_IServiceProvider)
	pOW := ComObjQuery(pSP, SID_SShellBrowser, IID_IOleWindow)
	hCtl2 := 0
	DllCall(NumGet(NumGet(pOW+0) + 3*A_PtrSize), "Ptr",pOW, "Ptr*",hCtl2) ;IOleWindow::GetWindow
	ObjRelease(pOW)
	ObjRelease(pSP)
	if (hCtl = hCtl2)
	{
		oWB := oWB2
		break
	}
}
oWB2 := ""
MsgBox, % oWB.document.title "`r`n" oWB.document.url
oWB := ""
return
Links:
IOleWindow::GetWindow (oleidl.h) | Microsoft Docs
https://docs.microsoft.com/en-us/windows/win32/api/oleidl/nf-oleidl-iolewindow-getwindow
HWND property (Internet Explorer)
https://msdn.microsoft.com/en-us/windows/desktop/aa752126

Btw it answers this long-standing question:
Internet Explorer: get WB hWnds via object loop (+ do win objects have unique object IDs) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=26082

Btw do you have any links? Including for 'maximum compatibility'. Thanks.
Last edited by jeeswg on 25 Aug 2019, 21:34, edited 3 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
teadrinker
Posts: 1900
Joined: 29 Mar 2015, 09:41
Contact:

Re: Cast COM Object IWebBrowser2 to IServiceProvider

16 Aug 2019, 16:03

Interesting, but one can get the current tab hwnd by this way:

Code: Select all

ControlGet, hCtrl, hwnd,, Internet Explorer_Server1, ahk_class IEFrame
MsgBox, % hCtrl
kkleinfelter
Posts: 21
Joined: 21 Dec 2018, 10:59

Re: Cast COM Object IWebBrowser2 to IServiceProvider

19 Aug 2019, 07:55

Thank you to both of you. Clearly, calling ControlGet is the right thing to do in this particular case, but knowing how to cast COM objects will definitely come in handy.

Return to “Ask For Help”

Who is online

Users browsing this forum: Bing [Bot], Dom_Christo, Franktic, Google [Bot], mcl, mikeyww, stiuna, TAC109 and 29 guests