Dexterslab
Dexterslab

Reputation: 25

CComVariant passing as VARIANT

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, &param1, &param2);

Upvotes: 1

Views: 3932

Answers (1)

sharptooth
sharptooth

Reputation: 170489

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.

Upvotes: 2

Related Questions