Reputation: 25
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);
Upvotes: 1
Views: 3932
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