Re: usage help for _com_ptr_t smart pointers created with #import
STDMETHODIMP CFoo::set_Bar(VARIANT v)
{
try {
_variant_t vt;
vt.ChangeType(VT_UNKNOWN, &v);
pBar = V_UNKNOWN(&vt);
} catch (_com_error&) {
return E_INVALIDARG;
}
return S_OK;
}
I believe VariantChangeType (invoked under the hood) already
coerces VT_EMPTY/VT_NULL into a NULL VT_UNKNOWN VARIANT,
but you should test. If not, it's easy to prepend the checks for
these values to the code...
--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnickolov@mvps.org
MVP VC FAQ: http://www.mvps.org/vcfaq
=====================================
"Jason S" <jmsachs@gmail.com> wrote in message
news:1156353530.922898.187540@i3g2000cwc.googlegroups.com...
I've been using #import a little bit, with smart pointers that I assign
only once with CreateInstance, e.g.
IFooPtr pfoo;
try
{
HRESULT hr = pfoo.CreateInstance (CLSID_foo, NULL, CLSCTX_ALL);
if (hr != S_OK)
// handle accordingly
// do stuff
}
catch (_com_error& e)
{
// handle accordingly
}
It seems to work well.
But now I have a case where I need to assign smart pointers upon a
method call and can't quite figure out the right way to do this.
Say I have an object CFoo which has a member IBarPtr pBar, where
IBarPtr is an #import-generated smart pointer. pBar may or may not be
NULL. pBar may be assigned internally with IBarPtr::CreateInstance (via
some other action initiated by one of CFoo's methods), or it may be set
from a method call through CFoo's methods set_Bar(VARIANT v) and
get_Bar(VARIANT *pv).
get_Bar seems easy to implement, something like this:
STDMETHODIMP CFoo::get_Bar(VARIANT *pv)
{
// should handle E_POINTER here
VariantInit(pv);
if (pBar == NULL)
return S_FALSE;
// if pBar is empty, we leave the variant empty and return S_FALSE
V_VT(pv) = VT_DISPATCH;
hr = pBar->QueryInterface(V_DISPATCH(pv));
return hr;
}
But I'm having trouble thinking what I need to do for set_Bar. I want
to make sure the following:
1) if the Variant contains VT_EMPTY, I want to release pBar and set it
to NULL, and return S_OK.
2) if the Variant contains something besides VT_EMPTY or VT_UNKNOWN or
VT_DISPATCH, I return an error and pBar is left alone. This is easy.
3) if the Variant does contain a VT_UNKNOWN or VT_DISPATCH, I want to
make sure it supports the IBar interface.
3a) if the Variant does support IBar, then pBar gets assigned a new
value from the variant, and the old value of pBar should be released
properly, and I return S_OK.
3b) if the Variant does not support IBar, then I want to return an
error and leave pBar alone.
Here's my attempt but I'm not sure it does the right thing. See my
questions marked with "???"
STDMETHODIMP CFoo::set_Bar(VARIANT v)
{
switch(V_VT(&v))
{
case VT_EMPTY:
// ??? is this the right way to free pBar?
pBar = NULL;
return S_OK;
case VT_UNKNOWN:
case VT_DISPATCH:
try {
pBar = V_UNKNOWN(&v);
// ??? will this release the old value of pBar?
}
catch (_com_error& e)
{
// ??? if I get here, is pBar left alone or is it corrupted?
// if it's corrupted, how do I test the incoming variant
// before I assign it to pBar?
return E_INVALIDARG;
}
return S_OK;
default:
return E_INVALIDARG;
}
}