Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

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

Posted on 2003-03-11
10
Medium Priority
?
991 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
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
I made this because I wanted to get e-mail with a attached csv file so I'd would be able to import user input into a MS Excel template, but I also wanted to register/save all inputs from each day in a file on the server. 1st - It creates a temp C…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

564 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