?
Solved

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

Posted on 2003-03-11
10
Medium Priority
?
950 Views
Last Modified: 2013-12-14
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
0
Comment
Question by:weary
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
  • 2
10 Comments
 
LVL 1

Expert Comment

by:madface
ID: 8118736
I believe smartpointers addRef and Release for you.
0
 
LVL 1

Author Comment

by:weary
ID: 8120555
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.
0
 
LVL 1

Expert Comment

by:madface
ID: 8122023
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
}
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 1

Author Comment

by:weary
ID: 8123067
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!!
0
 

Expert Comment

by:Polymorphic
ID: 8124956
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 :)
0
 
LVL 1

Author Comment

by:weary
ID: 8130386
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.
0
 

Expert Comment

by:Polymorphic
ID: 8132673
"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

0
 

Expert Comment

by:Polymorphic
ID: 8132691
sorry about grammatical mistakes i was in a hurry :)
0
 
LVL 1

Author Comment

by:weary
ID: 8139582
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
0
 

Accepted Solution

by:
Polymorphic earned 84 total points
ID: 8142253
Weary,
yes casting is dangerous but it is extremely helpful when you have a hierarchy objects i.e. MFC.  Yes take caution but dont be afraid to cast.

anyway as far as i know there is no  behavior in CComQIPtr that will allow you to increment the ref count with out it decrementing it when the object goes out of scope.
hope i have been helpful


0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

741 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question