javascriptwinapichakra

Chakra and IDispatch based indexed properties


I am creating a scriptable application using the native windows API and the chakrart JavaScript engine. I have interfaces like the following in my IDL:

[oleautomation, dual, nonextensible,
uuid(...)]
interface IMyInterface : IDispatch
{
[id(MYDISPID_EVENT), propget] HRESULT Event(BSTR strEventName, [out, retval] IDispatch ** ppHandler);
[id(MYDISPID_EVENT), propput] HRESULT Event(BSTR strEventName, IDispatch * pHandler);
};

I have been able to add the native objects to the chakrart engine without trouble (by using JsVariantToValue and then setting a property on the global object of the current context). However when I attempt to set an event handler I get the exception message 'Object doesn't support this property or method'.

I have tried the following syntax variations:

object.Event["foo"] = handler;
object.Event("foo", handler);
object.put_Event("foo", handler);
object.Event("foo") = handler;

That last is close to how this would be done using vbscript:

object.Event("foo") = GetRef("handler)

If I use method syntax in the IDL like the following it works, I would simply prefer to use property assignment if possible.

[id(MYDISPID_GETEVENT)] HRESULT GetEvent(BSTR strEventName, [out, retval] IDispatch ** ppHandler);
[id(MYDISPID_SETEVENT)] HRESULT SetEvent(BSTR strEventName, IDispatch * pHandler);

And also note that simple property assignments do work, it is only when I try indexed properties that it breaks. I do understand that JavaScript does something very different with object[prop] syntax, at least for native JavaScript objects. Is this perhaps simply an incompatibility in the chakrart interop layer?


Solution

  • I have confirmed a way to perform this with the desired syntax (App.Event['foo'] = someHandler;). As mentioned I already knew JavaScript treats name['foo'] as a member lookup on name

    Have the App object implement a propget for Event that returns an object with a custom (non-dual interface) IDispatch implementation. That object keeps a map of names to DISPIDs and whenever an unknown name is requested via GetIDsOfNames a previously unassigned DISPID is returned.

    Note that in order to comply with the rules for IDispatch the object needs to keep track of names even if a null handler is later assigned to a given name, so that the same DISPID will always be returned for a particular name.