WebView2

Discuss Autohotkey related topics here. Not a place to share code.
Forum rules
Discuss Autohotkey related topics here. Not a place to share code.
sancarn
Posts: 224
Joined: 01 Mar 2016, 14:52

WebView2

21 Jun 2019, 11:19

Exciting times:

https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2webview

This extends IUnknown and therefore in theory it's an ActiveX control! I.E. Edge/Chromium GUI's embedded in AHK soon?!
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: WebView2

22 Jun 2019, 00:34

Cool!. I followed the guide Getting Started with WebView2 (developer preview) and I was able to compile, it seems to work well.
I have tried to use the CreateWebView2Environment function but I have no idea how to work with the environment_created_handler parameter in AHK.
Microsoft Edge WebView2 (developer preview).
Spoiler
User avatar
Taurus
Posts: 94
Joined: 20 Jan 2015, 10:31

Re: WebView2

21 Nov 2019, 06:12

Very cool. Would be a very nice feature! :)
:beard: Full Stack Developer > Dev for a better world | PHP for Web | AHK H for Local | with KISS (Keep IT Short and Simple) on Win 10 Pro (Version 2004) x64
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

21 Nov 2019, 19:44

Flipeador wrote:
22 Jun 2019, 00:34
Requirements: Microsoft Edge Chromium and WebView2Loader.dll in your System folder.[/spoiler]
Could you be a little more explicit? I'm not sure how that guide you linked ultimately compiles into a dll.

EDIT: I see now. The DLL gets downloaded when you install the package via NuGet. I am getting error 80070002 when I try to run the script.

EDIT: Installing the DEV channel of the browser removes the error. But as you stated, nothing appears.
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

22 Nov 2019, 08:01

Well, Edge is definitely starting up with the code provided by @Flipeador. I see four processes kick off in Task Manager however they disappear after a few seconds.

I don't really understand how the iUnknown interfaces work. But it seems like Release is being called immediately after the two calls to AddRef. My understanding is that Release wouldn't be called until it was destroyed or something.
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

22 Dec 2019, 13:38

Any other thoughts @Flipeador?
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

25 Jan 2020, 21:11

Some day we'll figure this out :). I updated it to use the new ComCall function. Tried inserting a navigation starting event handler to see if the navigation actually does anything but it doesn't get invoked. I also have no clue what I'm doing and largely just am basing my theories on Flipeador's work.

Code: Select all

; AHK v2.0-a103-56441b52
#Warn
#SingleInstance Force

DllCall("User32.dll\SetProcessDpiAwarenessContext", "Ptr", 0xFFFFFFFC)

Gui := GuiCreate()
Gui.OnEvent("Close", "ExitApp")
Gui.Show("w750 h600")

; IWebView2CreateWebView2EnvironmentCompletedHandler.
; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2createwebview2environmentcompletedhandler#interface_i_web_view2_create_web_view2_environment_completed_handler.
vtbl := BufferAlloc(4*A_PtrSize)  ; https://www.autohotkey.com/boards/viewtopic.php?t=37142#p170967
for Each, Method in ["QueryInterface","AddRef","Release","Invoke"]
    NumPut("UPtr", CallbackCreate(Method), vtbl, (A_Index-1)*A_PtrSize)

ptr := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 0, "Ptr", A_PtrSize+4, "UPtr")
NumPut("UPtr", vtbl.ptr, ptr)
NumPut("UInt", 1, ptr, A_PtrSize)

; IWebView2CreateWebViewCompletedHandler.
; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2createwebviewcompletedhandler#invoke.
vtbl2 := BufferAlloc(4*A_PtrSize)
for Each, Method in ["QueryInterface","AddRef","Release","Invoke_2"]
    NumPut("UPtr", CallbackCreate(Method), vtbl2, (A_Index-1)*A_PtrSize)
ptr2 := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 0, "Ptr", A_PtrSize+4, "UPtr")
NumPut("UPtr", vtbl2.ptr, ptr2)
NumPut("UInt", 1, ptr2, A_PtrSize)

; IWebView2NavigationCompletedEventHandler.
; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2navigationcompletedeventhandler
vtbl3 := BufferAlloc(4*A_PtrSize)
for Each, Method in ["QueryInterface","AddRef","Release","Invoke_3"]
    NumPut("UPtr", CallbackCreate(Method), vtbl3, (A_Index-1)*A_PtrSize)
ptr3 := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 0, "Ptr", A_PtrSize+4, "UPtr")
NumPut("UPtr", vtbl3.ptr, ptr3)
NumPut("UInt", 1, ptr3, A_PtrSize)

if R := DllCall(A_ScriptDir . "\WebView2Loader.dll\CreateWebView2Environment", "Ptr", ptr, "UInt") {
    MsgBox("ERROR " . Format("{:08X}",R))
}
return

QueryInterface(this, riid, ppvObject) {
    local IID_IUnknown                                       := BufferAlloc(16)
    local IWebView2CreateWebView2EnvironmentCompletedHandler := BufferAlloc(16)

    DllCall("Ole32.dll\CLSIDFromString", "Str", "{00000000-0000-0000-C000-000000000046}", "Ptr", IID_IUnknown)
    DllCall("Ole32.dll\CLSIDFromString", "Str", "{A8346945-51C2-4CE6-8B4C-6F3C4391828B}", "Ptr", IWebView2CreateWebView2EnvironmentCompletedHandler)

    if DllCall("Ole32.dll\IsEqualGUID", "Ptr", riid, "Ptr", IID_IUnknown)
    || DllCall("Ole32.dll\IsEqualGUID", "Ptr", riid, "Ptr", IWebView2CreateWebView2EnvironmentCompletedHandler)
    {
        NumPut("UPtr", this, ppvObject)
        AddRef(this)
        return 0 ; S_OK.
    }

    NumPut("UPtr", 0, ppvObject)
    return 0x80004002 ; E_NOINTERFACE.
} ; https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-queryinterface%28refiid_void%29

AddRef(this) {
    local RefCount := NumGet(this,A_PtrSize,"UInt") + 1
    ; msgbox("addref")
    NumPut("UInt", RefCount, this, A_PtrSize)
    return RefCount
} ; https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-addref

Release(this) {
    local RefCount := NumGet(this,A_PtrSize,"UInt")
    
    if (RefCount > 0)
    {
        NumPut("UInt", --RefCount, this, A_PtrSize)
        if (RefCount == 0)
            DllCall("Kernel32.dll\GlobalFree", "Ptr", this)
    }
    return RefCount
} ; https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-release

Invoke(this, HRESULT, IWebView2Environment) {
    global Gui, ptr2
    
    ; IWebView2Environment::CreateWebView Method.
    ; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2environment#createwebview.
    ComCall(3, IWebView2Environment, "Ptr", gui.hwnd, "Ptr", ptr2)

    return 0  ; S_OK.
} ; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2createwebview2environmentcompletedhandler#invoke

Invoke_2(this, HRESULT, IWebView2WebView) {
    global Gui, ptr3
    local
    
    ; Resize WebView to fit the bounds of the parent window.
    ; IWebView2WebView::put_Bounds Method.
    ; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2webview#put_bounds.
    DllCall("User32.dll\GetClientRect", "Ptr", Gui.hWnd, "Ptr", RECT:=BufferAlloc(16))
    ; MsgBox("x=" NumGet(RECT, 0, "Int") "`ny=" NumGet(RECT, 4, "Int") "`nw=" NumGet(RECT, 8, "Int") "`nh=" NumGet(RECT, 12, "Int"))
    
    ; NumPut(-400, RECT, 0, "INT"), NumPut(-100, RECT, 4, "INT")
    ComCall(38, IWebView2WebView, "Ptr", RECT)
    
    ; ComCall(37, IWebView2WebView, "Ptr", newRECT := BufferAlloc(16))
    ; MsgBox("x=" NumGet(newRECT, 0, "Int") "`ny=" NumGet(newRECT, 4, "Int") "`nw=" NumGet(newRECT, 8, "Int") "`nh=" NumGet(newRECT, 12, "Int"))
    
    ComCall(42, IWebView2WebView, "Int", 1)
    
    ComCall(8, IWebView2WebView, "Ptr", Ptr3)

    ; Schedule an async task to navigate to Bing.
    ; IWebView2WebView::Navigate Method.
    ; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2webview#navigate.
    ; ComCall(7, IWebView2WebView, "Str", "<h1>test</h1>")
    ComCall(5, IWebView2WebView, "Str", "https://www.bing.com/")

    return 0  ; S_OK.
} ; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2createwebviewcompletedhandler#invoke

Invoke_3(this, IWebView2WebView, IWebView2NavigationStartingEventArgs) {
    MsgBox("test")
    ComCall(3, IWebView2NavigationStartingEventArgs, "Ptr", uri)
    
    MsgBox(uri)
}
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

13 Aug 2020, 10:58

:bump: :) Wondering if anyone has ventured into this again with the updated webview2 api. Still crashes for me when trying to call Navigate.
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

13 Aug 2020, 13:00

No idea if its correct/proper but TA-DA!!! The key was calling ObjAddRef on the interface pointer to the Controller inside of Invoke_2 because as soon as that event handler finished the ref count on the Controller interface was decrementing. And the documentation for ICoreWebView2Controller states:
The CoreWebView2Controller owns the CoreWebView2, and if all references to the CoreWebView2Controller go away, the WebView will be closed.
Something great about this is that it seems to handle accelerators just fine (copy/cut/paste, F5, navigate forward/back,etc).

Code: Select all

; #Requires AutoHotkey v2.0-a112
#Warn
#SingleInstance Force

; DllCall("User32.dll\SetProcessDpiAwarenessContext", "Ptr", 0xFFFFFFFC) ; not sure if this is needed.  Works fine without it.

main := gui.new()
main.OnEvent("Close", "ExitApp")
main.Show("w1000 h800")

; IWebView2CreateWebView2EnvironmentCompletedHandler.
; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler#interface_i_web_view2_create_web_view2_environment_completed_handler.
vtbl := BufferAlloc(4*A_PtrSize)  ; https://www.autohotkey.com/boards/viewtopic.php?t=37142#p170967
for Each, Method in ["QueryInterface", "AddRef", "Release", "Invoke"]
    NumPut("UPtr", CallbackCreate(Method), vtbl, (A_Index-1)*A_PtrSize)

ptr := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 0, "Ptr", A_PtrSize+4, "UPtr")
NumPut("UPtr", vtbl.ptr, ptr)
NumPut("UInt", 1, ptr, A_PtrSize)

; ICoreWebView2CreateCoreWebView2ControllerCompletedHandler.
; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/ICoreWebView2CreateCoreWebView2ControllerCompletedHandler#invoke.
vtbl2 := BufferAlloc(4*A_PtrSize)
for Each, Method in ["QueryInterface", "AddRef", "Release", "Invoke_2"]
    NumPut("UPtr", CallbackCreate(Method), vtbl2, (A_Index-1)*A_PtrSize)
ptr2 := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 0, "Ptr", A_PtrSize+4, "UPtr")
NumPut("UPtr", vtbl2.ptr, ptr2)
NumPut("UInt", 1, ptr2, A_PtrSize)

; IWebView2NavigationCompletedEventHandler.
; https://docs.microsoft.com/en-us/microsoft-edge/hosting/webview2/reference/iwebview2navigationcompletedeventhandler
vtbl3 := BufferAlloc(4*A_PtrSize)
for Each, Method in ["QueryInterface", "AddRef", "Release", "Invoke_3"]
    NumPut("UPtr", CallbackCreate(Method), vtbl3, (A_Index-1)*A_PtrSize)
ptr3 := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 0, "Ptr", A_PtrSize+4, "UPtr")
NumPut("UPtr", vtbl3.ptr, ptr3)
NumPut("UInt", 1, ptr3, A_PtrSize)

if R := DllCall(A_ScriptDir . "\WebView2Loader.dll\CreateCoreWebView2Environment", "Ptr", ptr, "UInt") {
    MsgBox("ERROR " . Format("{:08X}",R))
}
return

QueryInterface(this, riid, ppvObject) {
    local IID_IUnknown := BufferAlloc(16)
    local ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler := BufferAlloc(16)

    DllCall("Ole32.dll\CLSIDFromString", "Str", "{00000000-0000-0000-C000-000000000046}", "Ptr", IID_IUnknown)
    DllCall("Ole32.dll\CLSIDFromString", "Str", "{86EF6808-3C3F-4C6F-975E-8CE0B98F70BA}", "Ptr", ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler)

    if DllCall("Ole32.dll\IsEqualGUID", "Ptr", riid, "Ptr", IID_IUnknown)
    || DllCall("Ole32.dll\IsEqualGUID", "Ptr", riid, "Ptr", ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler)
    {
        NumPut("UPtr", this, ppvObject)
        AddRef(this)
        return 0 ; S_OK.
    }

    NumPut("UPtr", 0, ppvObject)
    return 0x80004002 ; E_NOINTERFACE.
} ; https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-queryinterface%28refiid_void%29

AddRef(this) {
    local RefCount := NumGet(this,A_PtrSize,"UInt") + 1
    ; ToolTip("add count = " . RefCount)
    NumPut("UInt", RefCount, this, A_PtrSize)
    return RefCount
} ; https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-addref

Release(this) {
    local RefCount := NumGet(this,A_PtrSize,"UInt")
    
    if (RefCount > 0)
    {
        NumPut("UInt", --RefCount, this, A_PtrSize)
        ; ToolTip("released count = " . RefCount)
        if (RefCount == 0)
            DllCall("Kernel32.dll\GlobalFree", "Ptr", this)
    }
    return RefCount
} ; https://docs.microsoft.com/en-us/windows/desktop/api/unknwn/nf-unknwn-iunknown-release

; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2createcorewebview2environmentcompletedhandler#invoke
Invoke(this, HRESULT, ICoreWebView2Environment) {
    global main, ptr2
    
    ; ICoreWebView2Environment::CreateCoreWebView2Controller Method.
    ; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2environment#createcorewebview2controller
    ComCall(3, ICoreWebView2Environment, "Ptr", main.hwnd, "Ptr", ptr2)

    return 0  ; S_OK.
}

; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2createcorewebview2controllercompletedhandler#invoke
Invoke_2(this, HRESULT, IWebView2WebViewController) {
    global main, webview, ptr3
    
    ObjAddRef(IWebView2WebViewController) ; This was key to retain a reference to the Controller
    
    ; Resize WebView to fit the bounds of the parent window.
    ; IWebView2WebViewController::put_Bounds Method.
    ; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2controller#put_bounds
    DllCall("User32.dll\GetClientRect", "Ptr", main.hWnd, "Ptr", RECT := BufferAlloc(16))
    ComCall(6, IWebView2WebViewController, "Ptr", RECT)

    ; IWebView2WebViewController::get_CoreWebView2
    ; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2controller#get_corewebview2
    ComCall(25, IWebView2WebViewController, "Ptr", webView := BufferAlloc(8))
    webview := NumGet(webView, "Ptr")
    
    ; ICoreWebView2::add_navigationstarting
    ; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2#add_navigationstarting
    ComCall(7, webview, "Ptr", ptr3, "Ptr", token := BufferAlloc(8))
    
    ; ICoreWebView2::Navigate
    ; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2#navigate
    ComCall(5, webview, "Str", "https://www.google.com/")

    return 0  ; S_OK.
}

; https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/0-9-538/icorewebview2navigationstartingeventhandler#invoke
Invoke_3(this, IWebView2WebView, IWebView2NavigationStartingEventArgs) {
    ComCall(4, IWebView2NavigationStartingEventArgs, "Ptr", isUserInitiated := BufferAlloc(4))
    
    if (NumGet(isUserInitiated, "Int")) {
        uri := BufferAlloc(8)
        ComCall(3, IWebView2NavigationStartingEventArgs, "Ptr", uri)
        url := StrGet(NumGet(uri, "Ptr"))
        
        if (MsgBox("You are about to navigate to: " . url . "`n`nDo you want to continue?", "Navigation warning", "YN Icon!") = "No") {
            
            ; IWebView2NavigationStartingEventArgs::put_Cancel
            ComCall(8, IWebView2NavigationStartingEventArgs, "Int", true)
            
            ; ICoreWebView2::NavigateToString
            ComCall(6, IWebView2WebView, "Str", "<h1>Navigation Canceled</h1><p>You chose to cancel navigation to the following URL: " . url . "</p>")
        }
    }
    
    return 0 ; S_OK
}
User avatar
Taurus
Posts: 94
Joined: 20 Jan 2015, 10:31

Re: WebView2

17 Aug 2020, 06:52

Thanks for keeping this up to date!!! :thumbup: ;)
:beard: Full Stack Developer > Dev for a better world | PHP for Web | AHK H for Local | with KISS (Keep IT Short and Simple) on Win 10 Pro (Version 2004) x64
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

17 Aug 2020, 07:27

Taurus wrote:
17 Aug 2020, 06:52
Thanks for keeping this up to date!!! :thumbup: ;)
Up to date might be a stretch! This has just always intrigued me, mostly due to my disdain for Internet Explorer. I did some more work to wrap some of this functionality in a few utility classes and then a very basic class called WebView. Eventually, I can see adding to it to wrap most of the functionality of the ICoreWebView2 and ICoreWebView2Controller interfaces.
User avatar
Taurus
Posts: 94
Joined: 20 Jan 2015, 10:31

Re: WebView2

13 Oct 2020, 03:15

Hi, do you have any update / working example on this?

I tried it, but i get Error 80070002. :(

By the way, Teamviewer is using WebView2Loader.dll too. 8-)
:beard: Full Stack Developer > Dev for a better world | PHP for Web | AHK H for Local | with KISS (Keep IT Short and Simple) on Win 10 Pro (Version 2004) x64
User avatar
Taurus
Posts: 94
Joined: 20 Jan 2015, 10:31

Re: WebView2

13 Oct 2020, 04:07

Hm... found this, but i don't understand it... :think:

https://github.com/webview/webview
:beard: Full Stack Developer > Dev for a better world | PHP for Web | AHK H for Local | with KISS (Keep IT Short and Simple) on Win 10 Pro (Version 2004) x64
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

13 Oct 2020, 06:35

Taurus wrote:
13 Oct 2020, 03:15
Hi, do you have any update / working example on this?

I tried it, but i get Error 80070002. :(

By the way, Teamviewer is using WebView2Loader.dll too. 8-)
Do you have at least the Beta channel installed for the new Chromium-based Edge?
User avatar
Taurus
Posts: 94
Joined: 20 Jan 2015, 10:31

Re: WebView2

14 Oct 2020, 09:41

I am using 86.0.622.38 (Offizielles Build) (64-Bit)

Do i have to use anything else?
:beard: Full Stack Developer > Dev for a better world | PHP for Web | AHK H for Local | with KISS (Keep IT Short and Simple) on Win 10 Pro (Version 2004) x64
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: WebView2

14 Oct 2020, 10:25

You have to have the Beta Channel installed or you can install the Webview2 Runtime.

Are you using the class from the v2 Scripts forum?

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 13 guests