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::GetExte rnal(IDisp atch** ppDispatch)
{
AFX_MANAGE_STATE(AfxGetApp ModuleStat e());
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
STDMETHODIMP CBrowserUIHandler::GetExte
{
AFX_MANAGE_STATE(AfxGetApp
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()
Thanks,
Eric Penner
I believe smartpointers addRef and Release for you.
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.
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(ID ispatch** disp)
{
smartPointer.Attach(*disp) ;//no need to call AddRef
}
You can find this info in the MSDN library under _com_ptr_t::Attach
HRESULT MyInterface::SomeMethod(ID
{
smartPointer.Attach(*disp)
}
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!!
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(rein terpret_ca st<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 :)
IUnknown* pUnk = NULL;
pDisp->QueryInterface(rein
//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
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 :)
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.
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
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
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 :)
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.