I want to call a 3rd party function from my code. The function's prototype is:
HRESULT foo(/*[in]*/VARIANT, /*[in]*/VARIANT*, /*[out]*/VARIANT*)
Currently I am using CComVariant wrappers around my VARIANT variables, and I want to pass them to this function. I am a little bit confused, how should I do it. In the case of the input arguments, should I just pass them directly, or detach them into a simple VARIANT and pass those variables? As I can see, both version works, but which one is the cleaner and recommended method? My current code is something like this:
CComVariant param0(CComBSTR( "Hello world"));
CComVariant param1(VARIANT_FALSE);
CComVariant param2;
HRESULT hr = foo(param0, ¶m1, ¶m2);
Yes, this code is okay and can hardly be done better given how ATL::CComVariant is designed unless you spend some time writing helper functions. A couple of thoughts on that.
Passing CComVariant as in VARIANT is okay - the base part is just member-wise copied into the function parameter and used by the called function from there. No deep copying happens and that's okay, the callee can use the copy just as well, if it wants to deep copy the parameter or AddRef() it - it still can do so.
Passing address of CComVariant as in VARIANT is okay (CComVariant* is implicitly upcast to VARIANT*, the function accesses the subobject), but not the best code in the world. Here's why. There's a lot of similar classes which own resources, the most important of them are ATL::CComBSTR, _bstr_t, ATL::CComPtr, _com_ptr_t and all of them have operator&() overloaded and also those of them which belong to ATL namespace just return the pointer to the stored pointer but _bstr_t and _com_ptr_t release the owned object before returning the pointer. Which is why this:
ATL::CComPtr<IUnknown> ptr( initialize() );
&ptr;
and this:
_com_ptr_t<IUnknown> ptr( initialize() );
&ptr;
have different effects. Neither ATL::CComVariant nor _variant_t have operator&() overloaded which complicates things a bit further. The cleaner way would be to use an "accessor extractor" method such as _variant_t::GetVARIANT() but ATL::CComVariant has not such method. So using & is the only option you have here.
Passing CComVariant address obtained using & as out VARIANT* is okay, but again not the best code in the world. It's fine when you know for sure the variant is empty but this code:
CComVariant var( obtainIUnknown() );
foo( whatever, whatever, &var );
will blindly overwrite the pointer and cause the previously referenced object to be leaked. A better way would be to use something like _variant_t::GetAddress() which clears the variant and then returns a pointer to raw VARIANT but again ATL::CComVariant has no such method.
So the bottom like is you code is okay, just be careful when modifying it. If you happen to write a lot of code like this you may be better off writing helper functions which do those "extraction" manipulations.
Related
I am writing code that utilizes COM interfaces. I am basing my code on examples that I have found online. I do not want to utilize smart pointers in this case because I want to understand the basics of COM and not just have a smart pointer class do all of the work for me.
In order to frame my questions, let's assume I have a class similar to the following:
public class TestClass
{
private:
IUnknown *m_pUnknown;
public:
TestClass();
void AssignValue();
}
TestClass::TestClass()
{
m_pUnknown = NULL;
}
void TestClass::AssignValue()
{
IUnknown *pUnknown = NULL;
//Assign value to pUnknown here - not relevant to my questions
m_pUnknown = pUnknown;
pUnknown->Release();
}
Now on to my specific questions.
1) The examples I've seen to not use AddRef() when initializing a value, such as in the class constructor. Does the AddRef() happen "automatically" behind the scenes when a COM pointer is first assigned a value?
2) Although my code example does not show it, it is my understanding that in the AssignValue() method, when you assign a second value to overwrite the value of pUnknown (originally set in the class constructor), Release() is automatically called. After assigning the new value to pUnknown its reference count stands at zero. I need to call pUnknown->AddRef() immediately after the reassignment. Is my understanding correct?
Notes: I assume we are ignoring exceptions for simplicity here. If this was for real, you would want to use smart pointers to help keep things straight in the presence of exceptions. Similarly, I am not worrying about proper copying or destruction of instances of your example class or multi-threading. (Your raw pointers cannot be used from different threads as simply as you might assume.)
First, You need to make any necessary calls to COM. The only way anything might happen "automatically" behind the scenes would be if you were using smart pointers to do them.
1) The examples you refer to have to be getting their COM interface pointers from somewhere. This would be by making COM calls, e.g., CoCreateInstance() and QueryInterface(). These calls are passed the address of your raw pointer and set that raw pointer to the appropriate value. If they weren't also implicitly AddRef'ed, the reference count might be 0 and COM could delete the associated COM object before your program could do anything about it. So such COM calls must include an implicit AddRef() on your behalf. You are responsible for a Release() to match this implicit AddRef() that you instigated with one of these other calls.
2a) Raw pointers are raw pointers. Their value is garbage until you arrange for them to be set to something valid. In particular, assigning a value to one will NOT auto-magically call a function. Assigning to a raw pointer to an interface does not call Release() - you need to do that at the appropriate time. In your post, it appears that you are "overwriting" a raw pointer that had previously been set to NULL, hence there was no existing COM interface instance in the picture. There could not have been an AddRef() on something that doesn't exist, and must not be a Release() on something that isn't there.
2b)
Some of the code you indicated by a comment in your example is very relevant, but can easily be inferred. You have a local raw pointer variable, pUnknown. In the absent code, you presumably use a COM call that obtains an interface pointer, implicitly AddRefs it, and fills in your raw pointer with the proper value to use it. This gives you the responsibility for one corresponding Release() when you are done with it.
Next, you set a member raw pointer variable (m_pUnknown) with this same value. Depending on the previous use of this member variable, you might have needed to call Release() with its former value before doing this.
You now have 2 raw pointers set to the value to work with this COM interface instance and responsibility for one Release() due to 1 implicit AddRef() call. There are two ways to deal with this, but neither is quite what you have in your sample.
The first, most straightforward, and proper approach (which others have correctly pointed out & I skipped passed in the first version of this answer) is one AddRef() and one Release() per pointer. Your code is missing this for m_pUnknown. This requires adding m_pUnknown->AddRef() immediately after the assignment to m_pUnknown and 1 corresponding call to Release() "someplace else" when you are done using the current interface pointer from m_pUnknown. One usual candidate for this "someplace else" in your code is in the class destructor.
The second approach is more efficient, but less obvious. Even if you decide not to use it, you may see it, so should at least be aware of it. Following the first approach you would have the code sequence:
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
pUnknown->Release();
Since pUnknown and m_pUnknown are set the same here, the Release() is immediately undoing the AddRef(). In this circumstance, eliding this AddRef/Release pair is reference count neutral and saves 2 round trips into COM. My mental model for this is a transfer of the interface and reference count from one pointer to the other. (With smart pointers it would look like newPtr.Attach( oldPtr.Detach() ); ) This approach leaves you with the original/not shown implicit AddRef() and needing to add the same m_pUnknown->Release() "someplace else" as in the first alternative.
In either approach, you exactly match AddRefs (implicit or explicit) with Releases for each interface and never go to a 0 reference count until you are done with the interface. Once you do hit 0, you do not attempt to use the value in the pointer.
Avi Berger already posted a great answer, but here is the same thing stated another way in case it helps with understanding.
In COM, reference counting is done within the COM object. The COM runtime will destruct and free an object whose reference count reaches 0. (This might be delayed by some time from the point of the count hitting 0).
Everything else is a convention. The usual convention amongst C++ COM programmers is that raw interface pointers should be treated as owning pointers. This concept means that any time a pointer points to a COM object, the pointer owns that object.
Using this terminology, the object may have multiple owners at any one time, and the object will be destroyed when nobody owns it.
However, raw pointers in C++ don't have ownership semantics built in. So you have to implement it yourself by making function calls:
Call AddRef on an interface pointer when that pointer takes ownership of an object. (You'll need to be aware of which Windows API functions or other library functions already do this, to avoid you doing it twice)
Call Release on an interface pointer when that pointer is about to stop owning an object.
The benefit of smart pointers is that they make it impossible for you to forget to call Release when an interface pointer stops owning an object. This includes the following cases:
Pointer goes out of scope.
Pointer is made to stop pointing to the object, by using assignment operator.
So, looking at your sample code. You have the pointer m_pUnknown. You want this pointer to take ownership of the object, so the code should be:
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
You will also need to add code to your class destructor and your class assignment operator to call m_pUnknown->Release(). I would very strongly recommend wrapping these calls in the smallest class possible (that is, write your own smart pointer and make TestClass have that smart pointer as a member variable). Assuming of course you don't want to use an existing COM smart pointer class for pedagogical reasons.
The call pUnknown->Release(); is correct because pUnknown currently owns the object, and the pointer is about to stop owning the object due to the fact that it will be destroyed when the function block ends.
You may observe that it would be possible to remove both of the lines m_pUnknown->AddRef() and pUnknown->Release(). The code will behave exactly the same. However , it is better to follow the convention outlined above. Sticking to a convention helps yourself to avoid errors and it also helps other coders to understand your code.
To put it another way, the usual convention is to think of the pointer as having a reference count of either 0 or 1, even though the reference counting is not actually implemented that way.
First, my apologies. My attempt to simplify my code for the sake of clarity turned out to be misguided. However, I believe my questions were answered. If I may, I will summarize.
1) Any COM object that is assigned a value other than NULL needs to be immediately followed by AddRef() unless the AddRef() was implicitly handled (as is the case with some Windows API calls).
2) Any reassignment of value to a COM pointer, assuming that the "before" value is not NULL must be immediately proceeded by Release(). AddRef() would then by needed as mentioned in #1.
3) Any COM variable whose value needs to be preserved beyond its current scope requires that it have a reference count of at least 1 upon exiting its said scope. This may mean that an AddRef() is required.
Would this be a fair summary? Did I miss anything?
All raw pointers need to be handled with Smartpointers in a program.
But I'm having problems with this Xaudio2 call
HRESULT XAudio2Create(_Out_ IXAudio2 **ppXAudio2, _In_ UINT32 Flags,
_In_ XAUDIO2_PROCESSOR XAudio2Processor);
My Question is how do you use smart pointers when passing it as a pointer to a pointer and is this even possible? If not how should I go about this in a smart way? I.e how do I pass a smart pointer for the parameter _Out_ IXAudio2 **ppXAudio2
Any Help will be much appreciated.
There are two wrinkles here--first is to handle the fact that the function expects a raw pointer to a (nonconst!) raw pointer, second is to work around the fact that all the built-in smart pointers call delete on the owned pointer when what you need to do here is call its Release() method. Waiting to create the smart pointer until after the factory function returns will solve problem 1, and a custom deleter can solve problem 2. Exactly how you want to do things is up to you, but something like this should work:
IXAudio2* p = nullptr;
if(!SUCCEEDED(XAudio2Create(&p, GetFlags(), GetProcessor())))
; // fail
std::shared_ptr<IXAudio2> smart(p,
[](IXAudio2* p) { p->Release(); }); // or unique_ptr with somewhat different syntax
Addendum: There have been tons of COM smart pointers written over the years that do essentially this and also call AddRef()/RemoveRef() when appropriate. e.g. ATL's CComPtr. If you have access to one of these, you could use it instead of rolling your own.
I'm going through some legacy C++ code dealing with the Windows Imaging Component library and I observed this:
void setProperties(IPropertyBag2* const pBag)
{
pBag->Write(...);
}
void other_function()
{
CComPtr<IPropertyBag2> pBag;
//Code to initialize pBag
setProperties(pBag);
}
The setProperties method simply writes a bunch of properties to the property bag.
The code compiles and runs fine because I think it calls the appropriate typecasting operator.
My question is whether such an interface is recommended or is there a better way of passing the pointer.
For example, is there any difference (in terms of safety/ performance) if the signature was changed to:
void setProperties(const CComPtr<IPropertyBag2>& pBag)
Raw interface pointers are the canonical way to work with COM objects. They are also the most flexible. Using a reference to a CComPtr will tie you into using CComPtr always.
Any COM pointer, even a dumb one, is automatically a smart pointer since the object itself implements AddRef and Release. If the function isn't keeping a copy of the pointer there's no need even to worry about that.
The CComPtr type will automatically cast itself to a raw pointer for convenience.
There aren't many advantages to using a CComPtr parameter (unless it's non-const and you're going to modify it). CComPtr is more useful for local variables and instance variables.
But it's OK to do it, if only as a matter of style/consistency.
I have a COM function that should return a SafeArray via a LPSAFEARRAY* out parameter.
The function creates the SafeArray using ATL's CComSafeArray template class.
My naive implementation uses CComSafeArray<T>::Detach() in order to move ownership from the local variable to the output parameter:
void foo(LPSAFEARRAY* psa)
{
CComSafeArray<VARIANT> ret;
ret.Add(CComVariant(42));
*psa = ret.Detach();
}
int main()
{
CComSafeArray<VARIANT> sa;
foo(sa.GetSafeArrayPtr());
std::cout << sa[0].lVal << std::endl;
}
The problem is that CComSafeArray::Detach() performs an Unlock operation so that when the new owner of the SafeArray (main's sa in this case) is destroyed the lock isn't zero and Destroy fails to unlock the SafeArray with E_UNEXPECTED (this leads to a memory leak since the SafeArray isn't deallocated).
What is the correct way to transfer ownership between to CComSafeArrays through a COM method boundary?
Edit: From the single answer so far it seems that the error is on the client side (main) and not from the server side (foo), but I find it hard to believe that CComSafeArray wasn't designed for this trivial use-case, there must be an elegant way to get a SafeArray out of a COM method into a CComSafeArray.
The problem is that you set the receiving CComSafeArray's internal pointer directly.
Use the Attach() method to attach an existing SAFEARRAY to a CComSafeArray:
LPSAFEARRAY ar;
foo(&ar);
CComSafeArray<VARIANT> sa;
sa.Attach(ar);
Just to confirm that the marked answer is the correct one. RAII wrappers cannot work across COM boundaries.
The posted method implementation is not correct, you cannot assume that the caller is going to supply a valid SAFEARRAY. Just [out] is not a valid attribute in Automation, it must be either [out,retval] or [in,out]. If it is [out,retval], which is what it looks like, then the method must create a new array from scratch. If it is [in,out] then the method must destroy the passed-in array if it doesn't match the expected array type and create a new one.
I'd guess that where was no intent to allow such a use case. Probably it was not the same developer who wrote CComVariant & CComPtr :)
I believe that CComSafeArray's author considered value semantics as major goal; Attach/Detach might simply be a "bonus" feature.
I've always used the following rule for signatures of functions that return ref-counted objects based on whether they do an AddRef or not, but want to explain it to my colleagues too... So my question is, is the rule described below a widely followed rule? I'm looking for pointers to (for example) coding rules that advocate this style.
If the function does not add a reference to the object, it should be returned as the return value of the function:
class MyClass
{
protected:
IUnknown *getObj() { return m_obj; }
private:
IUnknown *m_obj;
};
However, if the function adds a reference to the object, then a pointer-to-pointer of the object is passed as a parameter to the function:
class MyClass
{
public:
void getObj(IUnknown **outObj) { *outObj = m_obj; (*outObj)->AddRef(); }
private:
IUnknown *m_obj;
};
It's much more typical to use the reference-counting smart pointers for cases when a new object is created and the caller has to take ownership of it.
I've used this same style on projects with a lot of COM. It was taught to me by a couple of people that learned it when they worked at NuMega on a little thing called SoftICE. I think this is also the style taught in the book "Essential COM", by Don Box (here it is at Amazon). At one point in time this book was considered the Bible for COM. I think the only reason this isn't still the case is that COM has become so much more than just COM.
All that said, I prefer CComPtr and other smart pointers.
One approach is to never use the function's return value. Only use output parameters, as in your second case. This is already a rule anyway in published COM interfaces.
Here's an "official" reference but, as is typical, it doesn't even mention your first case: http://support.microsoft.com/kb/104138
But inside a component, banning return values makes for ugly code. It is much nicer to have composability - i.e. putting functions together conveniently, passing the return value of one function directly as an argument to another.
Smart pointers allow you to do that. They are banned in public COM interfaces but then so are non-HRESULT return values. Consequently, your problem goes away. If you want to use a return value to pass back an interface pointer, do it via a smart pointer. And store members in smart pointers as well.
However, suppose for some reason you didn't want to use smart pointers (you're crazy, by the way!) then I can tell you that your reasoning is correct. Your function is acting as a "property getter", and in your first example it should not AddRef.
So your rule is correct (although there's a bug in your implementation which I'll come to in a second, as you may not have spotted it.)
This function wants an object:
void Foo(IUnknown *obj);
It doesn't need to affect obj's refcount at all, unless it wants to store it in a member variable. It certainly should NOT be the responsibility of Foo to call Release on obj before it returns! Imagine the mess that would create.
Now this function returns an object:
IUnknown *Bar();
And very often we like to compose functions, passing the output of one directly to another:
Foo(Bar());
This would not work if Bar had bumped up the refcount of whatever it returned. Who's going to Release it? So Bar does not call AddRef. This means that it is returning something that it stores and manages, i.e. it's effectively a property getter.
Also if the caller is using a smart pointer, p:
p = Bar();
Any sane smart pointer is going to AddRef when it is assigned an object. If Bar had also AddRef-ed well, we have again leaked one count. This is really just a special case of the same composability problem.
Output parameters (pointer-to-pointer) are different, because they aren't affected by the composability problem in the same way:
Again, smart pointers provide the most common case, using your second example:
myClass.getObj(&p);
The smart pointer isn't going to do any ref-counting here, so getObj has to do it.
Now we come to the bug. Suppose smart pointer p already points to something when you pass it to getObj...
The corrected version is:
void getObj(IUnknown **outObj)
{
if (*outObj != 0)
(*outObj)->Release();
*outObj = m_obj;
(*outObj)->AddRef(); // might want to check for 0 here also
}
In practise, people make that mistake so often that I find it simpler to make my smart pointer assert if operator& is called when it already has an object.