Page 1 of 1

Webview2 iDispatch

Posted: 18 Aug 2020, 07:55
by kczx3
The WebView2 control allows you to add host objects to the script. The information on what types it allows is described here - AddHostObjectToScript.

It states that it supports IDispatch and I thought that AHK's objects supported that since we can pass them to IE. I seem to be able to pass an object by first calling ObjPtrAddRef on the object and then passing the returned address. I can see that the browser can see the object however it just shows that its an empty array (which its not). My test object was just { stuff: "things" }. Do I maybe need to manually implement Invoke for the object?
webview2-idispatch.png (5.79 KiB) Viewed 440 times

Re: Webview2 iDispatch

Posted: 18 Aug 2020, 07:58
by kczx3
Guessing I shouldn't implement it directly...
IDispatch wrote:Generally, you should not implement Invoke directly

Re: Webview2 iDispatch

Posted: 18 Aug 2020, 09:55
by kczx3
I'm able to get this to work by passing vref to the browser.

Code: Select all

vbuf := BufferAlloc(24, 0)
vref := ComObject(0x400C, vbuf.ptr)  ; 0x400C is a combination of VT_BYREF and VT_VARIANT.

vref[] := (*) => MsgBox("From AHK", "Hello!", "YN")
Setting vref to an AHK Array sort of works however I can't figure out how to properly access the values.[0] just seems to return the JavaScript proxy object.

Setting vref to a SAFEARRAY works nicely.
webview2-safearray.png (4.2 KiB) Viewed 422 times
Setting vref to an AHK object sort of works too. You can directly access the members however trying to call the object itself in the JavaScript console similarly returns a proxy object promise.
webview2-ahk-object.png (35.64 KiB) Viewed 422 times
Passing a SAFEARRAY directly didn't seem to work either. It seems the VT_BYREF | VT_VARIANT is required or at least circumvents some issue that I'm unfamiliar with.

Passing values from JS to AHK via functions works pretty well. AHK receives a ComObjArray if JS passes an array. If JS passes an object then AHK receives a ComObj but I'm unable to figure out how to reference the properties as dot notation isn't working. Let's say I pass the object {hay: "horses"} from JS to AHK. Trying to access the "hay" property returns this in the JavaScript console: Error: (0x80070005) Access is denied. Value is not modifiable

Re: Webview2 iDispatch

Posted: 26 Aug 2020, 08:24
by kczx3
I feel like the issue with JS objects is somehow related to this note:
Microsoft wrote:Remote JavaScript objects like callback functions are represented as an VT_DISPATCH VARIANT with the object implementing IDispatch. The JavaScript callback method may be invoked using DISPID_VALUE for the DISPID.

Re: Webview2 iDispatch

Posted: 26 Aug 2020, 19:03
by lexikos
All AutoHotkey objects implement IDispatch. There is no need to implement it unless you want to change the behaviour.

In JavaScript, there is no distinction between array elements and properties. The JScript engine (which isn't in use here) invokes x['y'] the same way as x.y: it first calls IDispatch::GetIDsOfNames, and then IDispatch::Invoke. AutoHotkey objects assign an ID to each unique name, then map the ID back to a name when invoked. The flags for Invoke specify to invoke a property; there is no flag for array indexing.

Functions are invoked via IDispatch with DISPID_VALUE instead of mapping a name to an ID. DISPID_VALUE maps to either Call or __Item depending on the type of invocation. Since COM supports parameterised properties, clients such as JScript, VBScript and C# will specify the flags for "either property or method". In such cases, AutoHotkey tries one and then the other. So in other words, the JScript call v = arr(n) can result in a call to arr.__Item[n]. However, the statement arr(n) (where the return value is discarded) is only ever a method call.

That's probably your answer for reading arrays: use arr(n), not arr[n].

For writing to arrays, I was surprised to find that arr(n) = value is accepted by JScript and works. I doubt it would work in any other JavaScript engine.
I feel like the issue with JS objects is somehow related to this note:
Which objects are like callback functions? It's too vague. It tells you how to invoke a callback, but nothing about any other type of object or operation.

%obj%() translates to a method call with DISPID_VALUE if obj is a COM object (IDispatch).
You can directly access the members however trying to call the object itself in the JavaScript console similarly returns a proxy object promise.
How did you try to call the object itself? I see no such attempt in your screenshot; you only evaluate the object (.AHK), retrieve its property (.stuff), and invoke two methods (.invoke() and .things()). I'd guess that .invoke() was supposed to do something special, since it seems you've defined things but not invoke.

If you want to call the object itself, you just call the object itself: .AHK(). In JScript this would result in a call to IDispatch::Invoke with DISPID_VALUE, which would translate to Call (I think the flags would only specify a method call in this context).

Re: Webview2 iDispatch

Posted: 31 Aug 2020, 08:12
by kczx3
I'm trying to find the time to gather my thoughts and questions a bit better. And to provide a working example for reference. Please excuse my delay in a formulated response and thank you for your reply.