1、用向导生成一个MFC ActiveX工程(MyTest)。2、给接口_DMyTest添加一个函数MyFunc,并编译生成ocx。3、用向导创建一个Dialog Base工程(Client),在ClientDlg.cpp中
#import "..\MyTest\Debug\MyTest.ocx" no_namespace
并
void CClientDlg::OnButton3()
{
// TODO: Add your control notification handler code here
::CoInitialize(NULL);
{
_DMyTestPtr pCtl;
pCtl.CreateInstance(__uuidof(MyTest));
pCtl->MyFunc();
}
::CoUninitialize();
}4、编译发现在MyTest.tlh中
_COM_SMARTPTR_TYPEDEF(_DMyTest, __uuidof(IDispatch));5、运行程序
报错:“abnormal program termination”。6、调试,发现接口指针已经获取成功;只是在最后调用MyFunc的时候出错;而MyFunc是个空函数。
#import "..\MyTest\Debug\MyTest.ocx" no_namespace
并
void CClientDlg::OnButton3()
{
// TODO: Add your control notification handler code here
::CoInitialize(NULL);
{
_DMyTestPtr pCtl;
pCtl.CreateInstance(__uuidof(MyTest));
pCtl->MyFunc();
}
::CoUninitialize();
}4、编译发现在MyTest.tlh中
_COM_SMARTPTR_TYPEDEF(_DMyTest, __uuidof(IDispatch));5、运行程序
报错:“abnormal program termination”。6、调试,发现接口指针已经获取成功;只是在最后调用MyFunc的时候出错;而MyFunc是个空函数。
check its return value is E_OK?
AfxEnableControlContainer();
试试!
问题好像出在
_COM_SMARTPTR_TYPEDEF(_DMyTest, __uuidof(IDispatch));
而ATL控件是:
_COM_SMARTPTR_TYPEDEF(IMyTest, __uuidof(IMyTest));各位不妨一试!to dawndu(东南飞) :
——确信,因为F10每步,pCtl发生变化,并且非空。to kingzai(stevenzhu):
——是E_OK,也就是0,之前我写了判断语句,后来又改回来;并且调用AddRef是可以的!to hushuangyan74() :
——向导生成的Dialog Base程序,肯定是调用了的。
_COM_SMARTPTR_TYPEDEF(_DMyTest, __uuidof(IDispatch));
中的__uuidof(IDispatch),也就是IID_IDispatch,那么
pCtl.CreateInstance(__uuidof(MyTest));
后pCtl中的接口指针实际就是个IDispatch*,只不过在
_COM_SMARTPTR_TYPEDEF(_DMyTest, __uuidof(IDispatch));
被模板参数要求用_DMyTest来看待。那么这应该在编译时期产生类型不匹配的错误,不过在_com_ptr_t的源码中是使用下面的代码获得那个接口指针的
hr = CoCreateInstance(rclsid, pOuter, dwClsContext, GetIID(), reinterpret_cast<void**>(&m_pInterface));
即由于void**的屏蔽,编译器无法发现,进而在执行
pCtl->MyFunc();
时,pCtl.m_pInterface实际是IDispatch而不是_DMyTest,它的虚函数只有7个,而不是_DMyTest的8个(如果只增加了一个方法),所以当pCtl->MyFunc();时,它获得虚函数表中第8个项目的数值作为函数地址进行调用,那是无效的进而失败,也就是为什么调用AddRef是好的,因为它是虚函数表中的第一个项目。至于为什么会生成
_COM_SMARTPTR_TYPEDEF(_DMyTest, __uuidof(IDispatch));
而不是
_COM_SMARTPTR_TYPEDEF(_DMyTest, _DMyTest);
抱歉,没兴致去试,也不清楚为什么这样,也许是VC的一个小BUG(可能是用双接口实现的导致的)。
参考
OleSetContainedObject