Link to home
Start Free TrialLog in
Avatar of weary
weary

asked on

How to AddRef an out parameter (IDispatch**) when using smart pointers

Hey, I'm using smart pointers and I need to provide the following method:

STDMETHODIMP CBrowserUIHandler::GetExternal(IDispatch** ppDispatch)
{
     AFX_MANAGE_STATE(AfxGetAppModuleState());

     if(m_bAllowDispatchAccess)
     {
          CComQIPtr<IDispatch> spThisDispatch(this);

          if(spThisDispatch)
          {
               spThisDispatch.p->AddRef();
               *ppDispatch = spThisDispatch;
               return S_OK;
          }
     }

     *ppDispatch = NULL;
     return E_NOINTERFACE;
}

Before adding spThisDispatch.p->AddRef(); the app would crash.  I think this makes sense, as I am making a copy of the interface, so I should call AddRef (right??).  I'm wondering how this should be done using smart pointers, rather than accessing the pointer itself. This is a pretty common scenario, so I figure there must be a way to "do it right" without calling AddRef directly.

Thanks,

Eric Penner
Avatar of madface
madface

I believe smartpointers addRef and Release for you.
Avatar of weary

ASKER

They do in most cases, but in this case I'm required to use a normal interface pointer (IDispatch** ppDispatch). So just using smart pointers doesn't solve this problem.

The rules of COM dictate that when I copy my Smart Pointer into *ppDispatch, AddRef has to be called. My Smart Pointer spThisDispatch doesn't call AddRef in this case though.

I'm wondering, is there is a standard way to do this using Smart Pointers, such that AddRef is called somewhere.

This is what makes me mad about using smart pointers in general, as you can't really just forget about AddRef and Release, due to cases like this.
call attach from the smartpointer. if the fAddRef is false Attach will call AddRef and clam ownership of the interface.

You can find this info in the MSDN library under _com_ptr_t::Attach

HRESULT MyInterface::SomeMethod(IDispatch** disp)
{
   smartPointer.Attach(*disp);//no need to call AddRef
}
Avatar of weary

ASKER

madface,

I don't think that will accomplish anything here.  There are two problems with the code you have written:

First, the purpose of this method is pass an interface out of this method via ppDispatch.  This means *ppDispatch is likely NULL. We are suppose to write something into it. Creating a smart pointer around *ppDispatch will just copy NULL into the Smart Pointer's internal pointer.

Second, assuming you create "smartPointer" within the method (you have ommited this), then once that pointer goes out of scope, it will Release() the reference that it added in when you called attach. So even if it were a valid interface this wouldn't add an extra reference to anything.

I'm beggining to think that once you are faced with any non-smart pointers, you have to start keeping track of referenfces again. I still hate using that ugly addref call though. I'm Still looking for ideas!!
FYI anytime a method returns a interface pointer it is assumed that AddRef was called on that pointer.
IUnknown* pUnk = NULL;
pDisp->QueryInterface(reinterpret_cast<void**>(&pUnk));
//no need to call AddRef since QueryInterface did it for us
//this is true with all methods that return interface pointers
//but we must call release when we are done

Also you do not need the smart pointer.  It is a waste of memory for this solution.
try this instead

//inside your method above
IDispatch* retVal = reinterpret_cast<IDispatch*>(this);
retVal->AddRef();
*pVal = retVal;

//return S_OK or do whatever here

Smart pointers are not ideal here since you are not using the smart pointer for any purpose other then to preform AddRef

Hope this helps :)
Avatar of weary

ASKER

Hey Polymorphic,

Yeah, I actually had a bug before, since I didn't do that AddRef.  Luckly I remembered the rules about passing interfaces via "out" paremeters, so it was easy to find.

Regarding the Smart Pointer, I don't think it's a complete waste. Using a cast (as you have above) assumes that the IDispatch interface is implemented using inheritance (not always the case - I know this is pulling hairs). The Smart pointer (CComQIPtr) here is simply a quick means of calling QueryInterface to get IDispatch (regardless of how it's implemented).

Anyway, I guess what I'm looking for is confirmation that Smart Pointers aren't the global way of dealing with AddRef and Release.  In some cases you just have to call them manually, so you still have to always be thinking about reference counting to aviod bugs.

What would be great is a solution in which smart pointers could deal with this AddRef somehow, and live up to their claims that they care of reference counting completely.

Anyway, I'll accept your comment, if you confirm that you think there is NO WAY to do this smart pointers.  Otherwise I'm still looking for a way.
"assumes that the IDispatch interface is implemented using inheritance (not always the case"

I've been programming with COM for over 2 years now, so i'm no pro but im not push over ether.  
Could you please tell where an interface is not implemented though inheritance.
As far as I know all interface must be inherited from to implement them.

As for your problem, you should know if your object is derived from IDispatch or not. If your not sure peek in the idl and look for MyInterfaceName : IDispatch.  With atl objects with duel interface support IDispatch is the default base interface.
Another way to check is to look for the Invoke method in your object. Type this->Invoke. if it comes up in the inteli-sence menu, you are deriving from IDispatch else your not.
If you are a deriving from IDispatch, IDispatch* retVal = reinterpret_cast<IDispatch*>(this);
is assumed safe.  

You can also call QueryInterface but most COM developers just cast when dealing with there own objects.

"if you confirm that you think there is NO WAY to do this smart pointers."
I'm not saying there is no way to do it with smart pointers im just saying it might not be the best solution.  Your code above should work just fine

sorry about grammatical mistakes i was in a hurry :)
Avatar of weary

ASKER

Hey Polymorphic,

I think MFC implements some OLE COM interfaces through nested objects rather than multiple inheritance (not sure). I agree with you that since this is my own class, I can know that this cast is safe.

The reason I never use casting is simply to make all my code the same. Since casting is not safe in a lot of circumstances (pretty much every case except in your own objects), I just never do it.

I don't like how I use smart pointers here either, which is why I posted this question. I want to know if there is a way to do it without accessing the internal pointer
ASKER CERTIFIED SOLUTION
Avatar of Polymorphic
Polymorphic

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial