I have a collection of objects that is defined as:
typedef IField ItemInterface;
typedef CComObject<CField>* ItemClassPtr;
typedef CAdapt< CComPtr<ItemInterface> > ItemType;
typedef std::vector< ItemType > ContainerType;
and I have created several of the CField objects via a series of calls (ignoring hresult):
IField* ppField = 0;
hresult = CField::CreateInstance(&ppField);
ItemType spField = ppField;
m_coll.push_back(spField);
ppField->Release();
and now I'm trying to retrieve a pointer to an object so that I can call one of it's methods:
ItemClassPtr pField;
short type1;
m_coll[index].m_T->QueryInterface( __uuidof(ItemInterface), (void **)&pField ) );
pField->get_Type(&type1);
and it crashes on access violation at the get_Type call. this was changed in response to a responder's post to:
short type1;
IField * ppField = m_coll[index].m_T;
CComQIPtr<CField, &__uuidof(IField)> pField = ppField;
pField->get_Type(&type1);
but it still crashes when I attempt to trace in the get_Type call.
Here is the preamble to the CField class definition:
class ATL_NO_VTABLE CField :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CField, &CLSID_Field>,
public ISupportErrorInfo,
public IFieldAccess,
public IDispatchImpl<IField, &IID_IField, &LIBID_SQLite02>
{
friend class CFields;
friend class CrecordSet;
public:
CField();
~CField();
DECLARE_REGISTRY_RESOURCEID(IDR_FIELD)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CField)
COM_INTERFACE_ENTRY(IField)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY_IID(__uuidof(IField), CField)
END_COM_MAP()
Please help!
Note that this question is an offshoot from a previous ATL question In ICollectionOnSTLImpl implementation, can't access m_T or item object's members That more fully describes the collection class. I have replaced the #defines with typedefs.
Vance
You query with
QueryInterface
forItemInterface
/IField
, so the pointer you obtain is of this type (supposedly, provided that COM object itself implement the method correctly).So what you are doing next is an invalid reinterpret_cast from
IField
toItemClassPtr
/CComObject<CField>*
. This does not work: by the line you have exception at yourpField
has invalid non-NULL pointer there.Another problem you have here is a bloated reference counting: your raw pointer
ppField
receives a pointer with incremented counter, I don't see you are releasing it here, I suppose you might be managing reference wrong somewhere else as well. Having other reference counting issues on your code, you might eventually have a very much similar access violation on your code, if your object is already destroyed and you have a call on the pointer to destroyed object.What is helpful to troubleshoot problems at this point is the call stack at exception position. From current description it is not clear how deep you are inside the
get_Type
call.BTW, if you are trying to restore C++ class pointer from interface pointer, it is easy if no marshaling is involved and is likely to be a problem otherwise. To get
CField*
fromIField*
in absence marhshaling here you can do this:Note that lifetime of class pointer is dependendent on life time of COM object itself, so it's much safer to do this:
This is easy, but assumes that
IField
you have on your hands is implemented byCField
and nothing else. Otherwise,static_cast
would succeed and get you a pointer, but it is going to be invalid. Another safer option similar to Remy's but easier to do is the following:This is simple and reference counter friendly. The
COM_INTERFACE_ENTRY
above creates a fake interface entry which exposes throughQueryInterface
a raw C++ pointer. This will return aE_NOINTERFACE
error gracefully without crashing in caseIField
is implemented by something else.You can't use
QueryInterface()
to get a class pointer, only an interface pointer. And you can't type-cast an interface pointer to a class pointer, either. The only safe way to get access to the implementation class is to define a separate private interface that the class implements, and have that interface expose a method that returns the class object'sthis
pointer. For example:.