1

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?

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • So I don't have an answer for you, but I'm about to try to do something similar and am curious exactly how you registered your native object? Did you create a VARIANT of type VT_DISPATCH containing your object's IDispatch pointer, pass it to JsVariantToValue, then register that value as a property on the global object? – Peter Baer Oct 26 '17 at 18:46
  • 1
    That is exactly what I did. It also means I am stuck using ChakraRT rather than being able to use ChakraCore, ChakraCore is the portable parts of the engine but IDispatch is not, so ... I've also written a function that takes IDispatch and ITypeInfo pointers and registers all the dispatchable members as properties of the global. This is because JavaScript runtime hosting doesn't have anything like IActiveScript::AddNamedItem s SCRIPTITEM_GLOBALMEMBERS flag. And sorry for deleting my response several times, I am blind and the edit box was behaving poorly with my screen reader. – SoronelHaetir Oct 27 '17 at 19:53

1 Answers1

0

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.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • I managed contact with the ChakraRT team and they confirmed that the IDispatch support is bare-bones and that indexed properties are not going to work. That being said so long as only one indexer is needed (as in my example) and that value can be converted to a usable string (also as in my example) the workaround I gave will function.However if you need an object to work in multiple languages (particularly if you need both JavaScript and VBScript) it would likely be better to just go the method route (GetEvent/SetEvent from my original question). – SoronelHaetir Nov 14 '17 at 23:03