请教COM, IDispatch相关问题!
我得到一个COM的组件, 其中有:
/* interface IDZCommABS */
/* [unique][helpstring][nonextensible][oleautomation][uuid][object] */
MIDL_INTERFACE("59313063-9D27-4F30-ACB6-4E662FFFA9EF")
IDZCommABS : public IUnknown
{
public:
.....
....
/* dispinterface _IDZCommABSEvents */
/* [helpstring][uuid] */
EXTERN_C const IID DIID__IDZCommABSEvents;#if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B031A9E6-858C-48A7-B7B9-0FEB0B6DA398")
_IDZCommABSEvents : public IDispatch
{
};
当我在VC6中用:
hr = CoCreateInstance( IID_IDZCommABS, NULL, CLSCTX_INPROC,
IID_IUnknown, ( LPVOID* )&lpUnknown );
成功,但是:
hr = lpUnknown->QueryInterface( IID_IDispatch, (LPVOID*)&m_pDisp );
时,就失败了.提示不支持该接口, 为什么呢?
我得到一个COM的组件, 其中有:
/* interface IDZCommABS */
/* [unique][helpstring][nonextensible][oleautomation][uuid][object] */
MIDL_INTERFACE("59313063-9D27-4F30-ACB6-4E662FFFA9EF")
IDZCommABS : public IUnknown
{
public:
.....
....
/* dispinterface _IDZCommABSEvents */
/* [helpstring][uuid] */
EXTERN_C const IID DIID__IDZCommABSEvents;#if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("B031A9E6-858C-48A7-B7B9-0FEB0B6DA398")
_IDZCommABSEvents : public IDispatch
{
};
当我在VC6中用:
hr = CoCreateInstance( IID_IDZCommABS, NULL, CLSCTX_INPROC,
IID_IUnknown, ( LPVOID* )&lpUnknown );
成功,但是:
hr = lpUnknown->QueryInterface( IID_IDispatch, (LPVOID*)&m_pDisp );
时,就失败了.提示不支持该接口, 为什么呢?
倒是连接点事件_IDZCommABSEvents继承自IDispatch。
IDZCommABS *p = NULL;
CoCreateInstance( CLSID_DZCommABS, NULL, CLSCTX_INPROC, IID_IDZCommABS, (LPVOID *)&p );
p->SomeMethod();
p->Release();
p = NULL;当然,以上的CLSID和IID是我杜撰的。
HRESULT InvokeByName( IDZCommABS *p, LPCTSTR lpszMethod )
{
if ( lstrcmp( lpszMethod, _T("SomeMethod") ) == 0 )
return p->SomeMethod();
else if ( lstrcmp( lpszMethod, _T("AnotherMethod") ) == 0 )
return p->AnotherMethod();
// ...
}
然后通过CreateStdDispatch取得IDispatch接口。
自己写一个包装类
提供一个方法
比如:bool CallFunction(CString funname,...){
if(funname="fun1"){
//调用fun1方法
}elseif(funname="fun2"){
//调用fun2方法
}}
-------------------------
为什么可以这样,这样可行马?1 其他的路绝对走不通.
2 com你了解.而且你可以得到一个确切的实例.
invoke用在你对你要用的那个对象不大了解的时候
3 那个com的函数种类有限,你不许花费多大的精力,可行!
你可以用Ole View看一下,是不是有TLB。也可以用VB试一下(VB也支持非IDispatch接口,只要有TLB)。如果没有TLB,那除非你有它的interface定义头文件,否则肯定是没办法的了。你可以查一下关于TypeLib的文档,如果搞不懂,可以再问。
如果是dim obj as Object
set obj =createobject("progid")
obj.method他是调用了 Invoke如果是
dim obj as IDog
set obj=createobject("progid")
obj.method他就不是调用了invoke,这种情况没有继承IDispath也是可以的.上次关于插件的讨论,我最后就是用第二种方法实现的.
我写了一个idl,定义了插件接口,没有继承IDispatch,
用midl编译得到tlb后,在activedll工程里引用他.
添加了一个类实现了tlb中定义的tlb.
在;另一个工程中使用createojbect创建了他的对象.
但是这样并使用了IDispatch.你用vc试一下把.怎么样才能得到一个
指向
没有实现IDispatch接口的对象
的IDispatch指针.得不到这个IDisatch指针,你又如何调用Invoke呢?建议看
<Com+ 与 Visual Basic6> 讲vb中实现com的原理和背后做的工作
<com 本质论> 讲 com 原理.
你推荐的书我一定会找来看看。
不过,碰巧,不久前我刚刚做过类似的事情,并不是很难的。建议你也试试看。
COM有如下定义:
IDZCommABS : public IUnknown
{
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetNewID(
/* [out] */ LONG *lplReturnCode,
/* [in] */ ULONGLONG lProjectID,
/* [out] */ ULONGLONG *lpullConnectID) = 0;
....
};
我利用如下语句调用:
LONG *lpOut = new LONG();
ULONGLONG *lpOut2 = new ULONGLONG(); vArgs[0].vt = VT_PTR;
vArgs[0].plVal = lpOut;
vArgs[1].vt = VT_I8;
vArgs[1].ullVal = 1;
vArgs[2].vt = VT_PTR;
vArgs[2].pullVal = lpOut2; dispparams.cArgs = 3;
dispparams.cNamedArgs = 0;
dispparams.rgvarg = vArgs;
hr = m_lpTInfo->Invoke( (PVOID *)lpIUnk, pFuncDesc->memid, DISPATCH_METHOD, &dispparams,
NULL, NULL, NULL );为何总提示参数不正确?应如何调用?
hr = LoadTypeLib( L"e:\\DZCommABS.dll", &m_lpITypeLib );
hr = m_lpITypeLib->GetTypeInfo( i, &m_lpTInfo );
否则Invoke会失败。2. m_lpTInfo->Invoke( (PVOID *)lpIUnk, ... 中的lpIUnk应该是对应Interface的指针,不能是单纯的IUnknown*。可以通过QueryInterface取得正确的Interface指针。3. 确保Invoke中的其它参数是正确的,这和IDispatch::Invoke是一样的。下面代码给你参考:这是我写的测试用代码,完全可以运行的。const GUID g_LibID = ...; // LIB ID
const OLECHAR * const g_pClassName = OLESTR("..."); // COM Class Name
const OLECHAR * const g_pFuncName = OLESTR("..."); // Function Name// TypeAttrWrap wraps the TYPEATTR pointer, release the structure after uesd.
class TypeAttrWrap
{
private:
ITypeInfoPtr m_pTypeInfo;
TYPEATTR * m_pTypeAttr;public:
TypeAttrWrap(ITypeInfo * pTypeInfo) : m_pTypeAttr(NULL), m_pTypeInfo(pTypeInfo)
{
} ~TypeAttrWrap()
{
if (m_pTypeAttr)
{
m_pTypeInfo->ReleaseTypeAttr(m_pTypeAttr);
}
} HRESULT GetInfo()
{
return m_pTypeInfo->GetTypeAttr(& m_pTypeAttr);
} operator BOOL () const
{
return (m_pTypeAttr != NULL);
} const TYPEATTR * operator -> () const
{
return m_pTypeAttr;
} TYPEATTR * operator -> ()
{
return m_pTypeAttr;
}
};int main(int argc, char* argv[])
{
if (FAILED(CoInitialize(NULL)))
{
cout << "Error" << endl;
return 1;
} try
{
HRESULT hr; // 1. Load Type Library
ITypeLibPtr pTypeLib;
hr = LoadRegTypeLib(
g_LibID, // Type Library's GUID
1, 0, // Version
GetThreadLocale(), // LCID
&pTypeLib); // Result
if (FAILED(hr))
{
_com_issue_error(hr);
} // 2. Get coclass's Type Infomation
ITypeInfoPtr pTypeInfo;
MEMBERID memId;
USHORT uFound = 1;
CComBSTR bstrTypeName(g_pClassName);
hr = pTypeLib->FindName(
bstrTypeName, // coclass Name
0, // Hash Value, use 0 as the default value.
&pTypeInfo, // Returned ITypeInfo * Array.
&memId, // Returned Member ID Array.
&uFound); // in/out The Array Size.
if (FAILED(hr))
{
_com_issue_error(hr);
}
if (uFound != 1)
{
_com_issue_error(E_INVALIDARG);
} // 3. Get coclass's Main Interface's TypeInfo
TypeAttrWrap pTypeAttr(pTypeInfo);
hr = pTypeAttr.GetInfo();
if (FAILED(hr))
{
_com_issue_error(hr);
} // 3.1. Get Implemented Type Number
USHORT nImplTypes = pTypeAttr->cImplTypes; // 3.2. Find The Default Interface From The Implemented Types
USHORT nImplTypeIndex;
for (nImplTypeIndex = 0; nImplTypeIndex < nImplTypes; ++ nImplTypeIndex)
{
// 3.2.1. Get Implemented Type's Flag
int TypeFlags;
hr = pTypeInfo->GetImplTypeFlags(nImplTypeIndex, &TypeFlags);
if (FAILED(hr))
{
_com_issue_error(hr);
} // 3.2.2. End The Loop While We Find The Default Interface
if (TypeFlags == IMPLTYPEFLAG_FDEFAULT)
{
break;
}
} // 3.3. If It Is Not Found, ...
if (nImplTypeIndex >= nImplTypes)
{
_com_issue_error(E_INVALIDARG);
} // 3.4. Get The RefType's Handle
HREFTYPE hRefType;
hr = pTypeInfo->GetRefTypeOfImplType(nImplTypeIndex, &hRefType);
if (FAILED(hr))
{
_com_issue_error(hr);
} // 3.5. Get The ITypeInfo
ITypeInfoPtr pInterfaceInfo;
hr = pTypeInfo->GetRefTypeInfo(hRefType, &pInterfaceInfo);
if (FAILED(hr))
{
_com_issue_error(hr);
} // 4. Get Default Interface's GUID
TypeAttrWrap pInterfaceAttr(pInterfaceInfo);
hr = pInterfaceAttr.GetInfo();
if (FAILED(hr))
{
_com_issue_error(hr);
} GUID guidInterface = pInterfaceAttr->guid; // 5. Create Instance And Get The Default Interface
IUnknownPtr pObj;
hr = pTypeInfo->CreateInstance(NULL, guidInterface, (void **) &pObj);
if (FAILED(hr))
{
_com_issue_error(hr);
} // 6. Get Function's DISPID By The Name
MEMBERID FuncId;
CComBSTR bstrFuncName(g_pFuncName);
hr = pInterfaceInfo->GetIDsOfNames(&bstrFuncName, 1, &FuncId);
if (FAILED(hr))
{
_com_issue_error(hr);
} // 7. Call The Function
CComVariant Params[2];
Params[0] = 10L;
Params[1] = 20L;
DISPPARAMS dispParams;
dispParams.rgvarg = Params;
dispParams.rgdispidNamedArgs = NULL;
dispParams.cArgs = 2;
dispParams.cNamedArgs = 0;
CComVariant Result;
EXCEPINFO ExceptionInfo;
UINT ArgErr;
hr = pInterfaceInfo->Invoke(pObj, FuncId, DISPATCH_METHOD, &dispParams, &Result, &ExceptionInfo, &ArgErr);
if (FAILED(hr))
{
_com_issue_error(hr);
} // 8. Write The Result
cout << Result.lVal << endl;
}
catch (_com_error& e)
{
CHAR * pMsg = e.Description();
if (pMsg)
{
cout << "Error : " << pMsg << endl;
}
else
{
cout << "Error : 0x" << hex << e.Error() << endl;
}
} CoUninitialize(); return 0;
}