Search code examples
javascriptcomevent-handlingdom-eventsactivex

Invoke marshalled COM interface multiple times


I am writing a COM object for JavaScript consumption. JavaScript code is turn runs in an hosted WebBrowserControl. I need to fire some events from COM object to JavaScript, the excellent guide to which at Dr. Dobbs

e.g. I have following in my *.idl

IJSCallback
{
    void Listen(IDispatch* pJSMethod);
}

JavaScript methods are received as IDispatch* in C++ code, which is to be stored for calling it later, from another thread. No matter what method for marshaling is used (CoMarshalInterThreadInterfaceInStream or IGlobalInterfaceTable) the event firing thread is able to call JavaScript function only once. After that IDispatch::Invoke() returns E_ACCESSDENIED!

sample JavaScript code

var server = new ActiveXObject("prog_id")
var.Listen(function(ip_add) {
    // ip_add from COM object
});

the C++ thread is pretty straight forward.

// called from JavaScript
CMyObject::Listen(IDispatch* pJSMethod)
{
    // IStream* m_pStream;
    CoMarshalInterThreadInterfaceInStream(pJSMethod, IID_IDispatch, &m_pStream);
}

// called from internal C++ thread.
CMyObject::FireEvent()
{
    // IStream* m_pStream;
    // IDispatch* m_pJSMethod;
    CoGetInterfaceAndReleaseStream(m_pStream, IID_IDispatch, (LPVOID*)&m_pJSMethod);

    HSREULT hr = m_pJSMethod->Invoke(...); // hr = S_OK, call is received in JavaScript
    hr = m_pJSMethod->Invoke(...); // hr = E_ACCESSDENIED, call is not received in JavaScript
}

is this expected behavior? or something wrong in code?


Solution

  • Fixed. As mentioned in comments alert() works but document.writeln() doesn't. That is because document.writeln() resets the current document including scripts elements, use document.createElement(), document.createTextNode() and friends to modify current loaded elements.

    This could be common knowledge for those familiar with HTML/JavaScript, for rest of us it can be a real deal.