3

I'm hosting an IWebBrowser2 control in my C++ program using nothing but plain Win32 (no mfc, atl, wtl etc). On DISPID_NAVIGATECOMPLETE2 I add a custom object to be accessed from javascript running on the displayed webpage.

To add the custom object I call InvokeEx with DISPATCH_PROPERTYPUT and a DISPPARAMS structure with a pointer to my custom object.

During the call to InvokeEx the AddRef function of my custom object is called and I increment its reference counter. But the object never gets a call to its Release function, so the reference counter never decreases down to zero again.

Who is responsible for calling Release() after AddRef() has been called in InvokeEx?

EDIT: (Adding some code)

This is the code that adds my custom object to the IHTMLWindow2. custObj points to my custom object

IHTMLWindow2 *win = NULL;
GetDoc()->get_parentWindow(&win);
IDispatchEx *winEx = NULL;
win->QueryInterface(&winEx);

DISPID dispid;
HRESULT hr = winEx->GetDispID(objName, fdexNameEnsure, &dispid); //objName is "JSObject"

DISPID namedArgs[] = {DISPID_PROPERTYPUT};
DISPPARAMS params;
params.rgvarg = new VARIANT[1];
params.rgvarg[0].pdispVal = custObj;
params.rgvarg[0].vt = VT_DISPATCH;
params.rgdispidNamedArgs = namedArgs;
params.cArgs = 1;
params.cNamedArgs = 1;

hr = winEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &params, NULL, NULL, NULL); 

This is the object that I'm adding (some private members have been left out for brevity)

class JSObject : public IDispatch {
private:
    long ref;
public:
    JSObject();

    // IUnknown
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
    virtual ULONG STDMETHODCALLTYPE AddRef();
    virtual ULONG STDMETHODCALLTYPE Release();

    // IDispatch
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
        ITypeInfo **ppTInfo);
    virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
        LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
    virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
        LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
        EXCEPINFO *pExcepInfo, UINT *puArgErr);
};

EDIT 2:

Now that it seems to be working like it should I decided to put it on github.

https://github.com/Tobbe/CppIEEmbed. Please fork and improve if you can :)

Tobbe
  • 3,282
  • 6
  • 41
  • 53
  • Document exactly what property you assign. It should be DISPATCH_PROPERTYPUTREF btw since you are assigning an object. – Hans Passant Aug 18 '11 at 14:18
  • If I use DISPATCH_PROPERTYPUTREF InvokeEx fails with DISP_E_MEMBERNOTFOUND – Tobbe Aug 18 '11 at 15:12
  • @Hans Passant: I'm not entirely sure what you're asking for when you say "Document exactly what property you assign". Does the code I added to my question give you what you asked for? – Tobbe Aug 18 '11 at 15:21
  • what is the value of *dispid*? – Hans Passant Aug 18 '11 at 15:28
  • I added a few more lines of code, hopefully that answers your question – Tobbe Aug 18 '11 at 17:06
  • 1
    Does the real code contain any error checking? I find it very hard to believe that this could work. Which of course explains the problem. – Hans Passant Aug 18 '11 at 17:13
  • Yes it does. I've pasted the full code here: http://paste2.org/p/1593965 – Tobbe Aug 18 '11 at 17:22
  • Thanks for making me take another look at this function. As you can see it doesn't properly call Release on the doc, the win or the winex. After releasing those my custom object got properly released too! – Tobbe Aug 18 '11 at 19:48

1 Answers1

2

Well, you are assigning a property, aren't you? As long as this property exists and refers to your object, it will have a reference added.

If you want the remote object to release your reference you should assign NULL to the property, or some other object.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • I should have stated this in my question, but the thing is that my reference isn't released even when the "remote object" is destroyed. Shouldn't it release all its assigned properties before dying? – Tobbe Aug 18 '11 at 15:26
  • I should. But are you sure that the remote object is really destroyed, and that there are not other references dangling around? – rodrigo Aug 18 '11 at 15:49
  • I wasn't properly releasing the remote object, so it never got destroyed. And since it was never destroyed it kept its reference to my custom object (my JSObject instance). – Tobbe Aug 18 '11 at 19:46