C++ 如何从对象的ATL集合中检索对象指针?
我有一个对象集合,定义为:C++ 如何从对象的ATL集合中检索对象指针?,c++,com,atl,C++,Com,Atl,我有一个对象集合,定义为: typedef IField ItemInterface; typedef CComObject<CField>* ItemClassPtr; typedef CAdapt< CComPtr<ItemInterface> > ItemType; typedef std::vector< ItemType > ContainerType; 现在我试图检索一个指向对象的指针,以便调
typedef IField ItemInterface;
typedef CComObject<CField>* ItemClassPtr;
typedef CAdapt< CComPtr<ItemInterface> > ItemType;
typedef std::vector< ItemType > ContainerType;
现在我试图检索一个指向对象的指针,以便调用它的一个方法:
ItemClassPtr pField;
short type1;
m_coll[index].m_T->QueryInterface( __uuidof(ItemInterface), (void **)&pField ) );
pField->get_Type(&type1);
在get_类型调用中,如果访问冲突,它就会崩溃。
根据回复者的帖子,此内容更改为:
short type1;
IField * ppField = m_coll[index].m_T;
CComQIPtr<CField, &__uuidof(IField)> pField = ppField;
pField->get_Type(&type1);
shorttype1;
i字段*ppField=m\u coll[index].m\u T;
CComQIPtr pField=ppField;
pField->get_Type(&type1);
但当我尝试在get_类型调用中跟踪时,它仍然崩溃
以下是CField类定义的前言:
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()
class ATL\u NO\u VTABLE字段:
公共CComObjectRootEx,
公共课程,
公共ISupportErrorInfo,
公共访问,
公共场所
{
友人班;
朋友级录音机;
公众:
CField();
~CField();
声明\u注册表\u资源ID(IDR\u字段)
声明\u保护\u最终\u构造()
开始地图(CField)
COM_接口_条目(IField)
COM_接口_条目(IDispatch)
COM_接口_条目(ISupportErrorInfo)
COM_接口_条目_IID(uuuuIdof(IField),CField)
END_COM_MAP()
请帮忙
请注意,此问题是先前ATL问题的一个分支
这更全面地描述了集合类。我用typedefs替换了#defines
Vance您不能使用
查询接口()
要获取类指针,请仅获取接口指针。您也不能将接口指针类型转换为类指针。访问实现类的唯一安全方法是定义该类实现的单独私有接口,并让该接口公开一个返回t的方法类对象的此指针。例如:
class CField;
interface DECLSPEC_UUID("...") IFieldAccess : public IUnknown
{
public:
virtual CField* get_ClassPtr() = 0;
};
class ATL_NO_VTABLE CField :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CField, &CLSID_Field>,
public IDispatchImpl<IField, &IID_IField, &LIBID_SQLite02>,
public ISupportErrorInfo,
public IFieldAccess,
{
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(IDispatch)
COM_INTERFACE_ENTRY(IField)
COM_INTERFACE_ENTRY(IFieldAccess)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()
};
CField* CField::get_ClassPtr()
{
return this;
}
类字段;
接口DECLSPEC_UUID(“…”)IFieldAccess:公共IUnknown
{
公众:
虚拟CField*get_ClassPtr()=0;
};
类别ATL_NO_VTABLE字段:
公共CComObjectRootEx,
公共课程,
公共场所,
公共ISupportErrorInfo,
公共访问,
{
友人班;
朋友级录音机;
公众:
CField();
~CField();
声明\u注册表\u资源ID(IDR\u字段)
声明\u保护\u最终\u构造()
开始地图(CField)
COM_接口_条目(IDispatch)
COM_接口_条目(IField)
COM_接口_条目(IFieldAccess)
COM_接口_条目(ISupportErrorInfo)
END_COM_MAP()
};
CField*CField::get_ClassPtr()
{
归还这个;
}
CComPtr pFieldAccess;
CField*pField;
短型1;
m_coll[index].m_T->QueryInterface(__uuidof(IFieldAccess),(void**)和pFieldAccess));
pField=pFieldAccess->get_ClassPtr();
pField->get_Type(&type1);
您使用QueryInterface
查询ItemInterface
/IField
,因此您获得的指针属于这种类型(假设COM对象本身正确实现了该方法)
因此,您接下来要做的是从IField
到ItemClassPtr
/cMobject*
的无效重新解释。这不起作用:在pField
的行中,您的异常在那里有无效的非空指针
这里的另一个问题是引用计数过多:您的原始指针ppField
接收到一个计数器递增的指针,我看不出您在这里释放它,我想您可能在其他地方管理引用时也出错了。如果代码中存在其他引用计数问题,您最终可能会遇到很多问题如果您的对象已经被销毁,并且您有一个指向已销毁对象的指针的调用,则代码上也会出现类似的访问冲突
此时有助于解决问题的是异常位置的调用堆栈。根据当前描述,不清楚您在get\u Type
调用中的深度
BTW,如果您试图从接口指针恢复C++类指针,那么如果没有封送处理,很容易出现问题,否则,从<代码> iFiel**/COD>获得<代码> cFiel*>代码>,在不存在MHHSHILAN的情况下,您可以这样做:
IField* pField = ...
CField* pNativeField = static_cast<CField*>(pField);
<>这是简单的,引用计数器友好。上面的<代码> COMION接口FAX >代码创建一个伪造的接口条目,它通过“代码> QueryInterface < /CODE >一个原始C++指针公开。这将返回<代码> EyNoCuffe<代码>错误,而不崩溃。l、 我在创建例程中添加了一个ppField->Release(),这样引用计数器就正确了.m_T;CComQIPtr pField=ppField;-pField仍然指向错误的位置。我将在原始问题中添加CField类前言以及您建议的更改。我查看了您的CField
代码,并分别更新了我的答案(最后一个代码片段),您需要将更新复制到您的代码中。指定CLSID_字段似乎可以做到这一点。我遇到了另一个问题,但至少我在get_类型例程中。谢谢!Remy的解决方案的问题是它也是一个黑客。IFieldAccess
使用不可封送的COM类型(原始指针),所以它只在这个解决方案有效的地方工作-没有任何情况下它能以任何方式更安全地工作。更多无用的代码专用于黑客本身(你必须声明一个单独的无用类!),速度较慢,没有真正的优势。我不需要实现IFieldAccess::get_ClassPtr()CField
类实现了IFieldAccess
接口。CField::get\u ClassPtr()
方法是IFieldAccess::get\u ClassPtr()
实现。这是我的想法,但我得到了IFieldAccess::get\u ClassPtr(void)未找到链接错误。请注意,我将_接口更改为接口,并假设IFieldAccessPtr为“IFieldAccess*”。它需要在接口中声明为纯虚拟。我更新了我的answe
CComPtr<IFieldAccess> pFieldAccess;
CField* pField;
short type1;
m_coll[index].m_T->QueryInterface( __uuidof(IFieldAccess), (void **)&pFieldAccess) );
pField = pFieldAccess->get_ClassPtr();
pField->get_Type(&type1);
IField* pField = ...
CField* pNativeField = static_cast<CField*>(pField);
CComPtr<IField> pField = ...
CField* pNativeField = static_cast<CField*>((IField*) pField);
// NOTE: pNativeField is valid until at least pField is released
class ATL_NO_VTABLE CField :
// ...
BEGIN_COM_MAP(CField)
//...
COM_INTERFACE_ENTRY_IID(CLSID_Field, CField)
END_COM_MAP( )
//...
IField* pField = ...
CComQIPtr<CField, &CLSID_Field> pNativeField = pField;