在使用COM组件时,在编译时就获得接口类型定义等信息,为早期绑定。又称VTABLE绑定,所有com组件都支持。
后期绑定要求组件接口为自动化接口,即后期绑定接口必须继承自IDispatch.
(MATLAB编译的组件都有双接口,也支持后期绑定)
后期绑定可以借助XYDispDriver,原作者发布的C++类 http://www.codeproject.com/com/comdispatchdriver.asp 已经不能访问了。
在网络上找到代码,测试了下可以用。
XYDispDriver.h
#ifndef XYDISPDRIVER_H #define XYDISPDRIVER_H // uncomment the following line if you are exporting the XYDispDriver class // #define XYDISPDRIVER_BUILDDLL // uncomment the following line if you are importing the XYDispDriver class // #define XYDISPDRIVER_USEDLL // uncomment the following line if you want to output debug messages // #define XYDISPDRIVER_DEBUG #ifdef XYDISPDRIVER_BUILDDLL #define XYDISPDRIVER_EXPORT __declspec(dllexport) #else # ifdef XYDISPDRIVER_USEDLL #define XYDISPDRIVER_EXPORT __declspec(dllimport) #else #define XYDISPDRIVER_EXPORT #endif #endif //#include <windows.h> #include <atlbase.h> #include <tchar.h> #include <stdio.h> #include <oaidl.h> #include <ocidl.h> #define XYDISPDRIVER_OLENAMELEN 120 // XYDispInfo: private helper class to store type info of a method or a property class XYDispInfo { friend class XYDispDriver; XYDispInfo(); ~XYDispInfo(); // dispatch id DISPID m_dispID; // method or property name BSTR m_bstrName; // invoke flag WORD m_wFlag; // offset of virtual function short m_oVft; // calling convention CALLCONV m_callconv; // output type VARTYPE m_vtOutputType; // output data VARIANT* m_pOutput; // number of parameters int m_nParamCount; // parameter type array WORD* m_pParamTypes; // assignment operator XYDispInfo& operator=(const XYDispInfo& src); }; // helper class to initialize/uninitialize com // declare one such object in each thread is enough // but it doesn't hurt to have multiples class XYDISPDRIVER_EXPORT CoInit { public: CoInit() { CoInitialize(NULL); } ~CoInit() { CoUninitialize(); } }; // XYDispDriver: the main class class XYDISPDRIVER_EXPORT XYDispDriver { // initialize/uninitialize com CoInit m_coInit; // pointer to the IDispatch interface IDispatch* m_pDisp; // pointer to the IConnectionPoint interface IConnectionPoint* m_pCP; // used by IConnectionPoint::Advise/Unadvise DWORD m_dwCookie; // number of methods and properties int m_nDispInfoCount; // array of type info XYDispInfo* m_pDispInfo; // error return code HRESULT m_hRet; // exception info EXCEPINFO* m_pExceptInfo; // private helper functions/members int m_nVarCount; int m_nMethodCount; int FindDispInfo(LPCTSTR strName, const WORD wFlag = DISPATCH_METHOD); HRESULT InvokeMethodV(const int nIndex, va_list argList); static HRESULT InvokeVariantMethodV(IDispatch* pDisp, const DISPID dispidMethod, WORD wInvokeFlag, VARIANT* pVarRet, EXCEPINFO* pExcepInfo, const nParamCount, va_list argList); bool LoadTypeInfo(); public: XYDispDriver(); ~XYDispDriver(); // clean up void Clear(); // copy contructor XYDispDriver(const XYDispDriver& src); // assignment operator XYDispDriver& operator=(const XYDispDriver& src); // create a com object with given prog id bool CreateObject(LPCTSTR strProgID, DWORD dwClsContext = CLSCTX_ALL); // create a com object with given class id bool CreateObject(CLSID clsid, DWORD dwClsContext = CLSCTX_ALL); // attach a IDispatch pointer to the obejct bool Attach(IDispatch* pDisp); // return the IDispatch pointer IDispatch* GetDispatch() { return m_pDisp; } // return the pointer to ith XYDispInfo XYDispInfo* GetDispInfo(const int i) { return (i>=0&&i<m_nDispInfoCount)?(m_pDispInfo+i):NULL; } // return the index of a property in the internal storage int FindProperty(LPCTSTR strPropertyName); // return the index of a method in the internal storage int FindMethod(LPCTSTR strMethodName); // get the type of a property by name WORD GetPropertyType(LPCTSTR strPropertyName); // get the type of a property by index WORD GetPropertyType(int nPropertyIndex); // get a property value by name VARIANT* GetProperty(LPCTSTR strPropertyName); // get a property value by index VARIANT* GetProperty(int nPropertyIndex); // set a property value by name bool SetProperty(LPCTSTR strPropertyName, ...); // set a property value by index bool SetProperty(int nPropertyIndex, ...); // set a property value (ref) by name bool SetPropertyRef(LPCTSTR strPropertyName, ...); // set a property value (ref) by index bool SetPropertyRef(int nPropertyIndex, ...); // get return type of a method by name WORD GetReturnType(LPCTSTR strMethodName); // get return type of a method by index WORD GetReturnType(int nMethodIndex); // get number of parameters in a method by name int GetParamCount(LPCTSTR strMethodName); // get number of parameters in a method by index int GetParamCount(int nMethodIndex); // get the type of a parameter in a method by name WORD GetParamType(LPCTSTR strMethodName, const int nParamIndex); // get the type of a parameter in a method by index WORD GetParamType(int nMethodIndex, const int nParamIndex); // invoke a method by name VARIANT* InvokeMethod(LPCTSTR strMethodName, ...); // invoke a method by index VARIANT* InvokeMethod(int nMethodIndex, ...); // invoke a method without type info static HRESULT InvokeVariantMethod(IDispatch* pDisp, LPCTSTR strMethodName, WORD wInvokeFlag, VARIANT* pVarRet, EXCEPINFO* pExcepInfo, const nParamCount, ...); static HRESULT InvokeVariantMethod(IDispatch* pDisp, const DISPID dispidMethod, WORD wInvokeFlag, VARIANT* pVarRet, EXCEPINFO* pExcepInfo, const nParamCount, ...); // add event handler bool Advise(IUnknown *pUnkSink, REFIID riid); // remove event handler void Unadvise(); // get the last error code as HRESULT HRESULT GetLastError() { return m_hRet; } // get exception info EXCEPINFO* GetExceptionInfo() { return m_pExceptInfo; } }; #endif
//#include "stdAfx.h" #include "XYDispDriver.h" void CharToWChar(unsigned short* pTarget, const char* pSource) { while(*pSource) { *pTarget = *pSource; pSource++; pTarget++; } *pTarget = 0; } XYDispInfo::XYDispInfo() { m_dispID = 0; m_bstrName = NULL; m_wFlag = 0; m_oVft = -1; m_callconv = CC_STDCALL; m_vtOutputType = VT_NULL; m_pOutput = NULL; m_nParamCount = 0; m_pParamTypes = NULL; } XYDispInfo::~XYDispInfo() { if(m_bstrName!=NULL) { ::SysFreeString(m_bstrName); } if(m_pOutput!=NULL) { ::VariantClear(m_pOutput); } delete m_pOutput; delete []m_pParamTypes; } XYDispInfo& XYDispInfo::operator=(const XYDispInfo& src) { m_dispID = src.m_dispID; if(m_bstrName) ::SysFreeString(m_bstrName); if(src.m_bstrName) m_bstrName = ::SysAllocString(src.m_bstrName); else m_bstrName = NULL; m_wFlag = src.m_wFlag; m_oVft = src.m_oVft; m_callconv = src.m_callconv; m_vtOutputType = src.m_vtOutputType; if(m_pOutput) delete m_pOutput; m_pOutput = new VARIANT; ::VariantInit(m_pOutput); m_nParamCount = src.m_nParamCount; if(m_pParamTypes) delete []m_pParamTypes; if(m_nParamCount>0) { m_pParamTypes = new WORD[m_nParamCount+1]; memcpy(m_pParamTypes,src.m_pParamTypes,(m_nParamCount+1)*sizeof(WORD)); } else m_pParamTypes = NULL; return *this; } XYDispDriver::XYDispDriver() { m_pCP = NULL; m_dwCookie = 0; m_pDisp = NULL; m_nVarCount = 0; m_nMethodCount = 0; m_nDispInfoCount = 0; m_pDispInfo = NULL; m_hRet = S_OK; m_pExceptInfo = NULL; } XYDispDriver::~XYDispDriver() { Clear(); } XYDispDriver::XYDispDriver(const XYDispDriver& src) { m_pCP = NULL; m_dwCookie = 0; m_pDisp = NULL; m_nVarCount = 0; m_nMethodCount = 0; m_nDispInfoCount = 0; m_pDispInfo = NULL; m_hRet = S_OK; m_pExceptInfo = NULL; *this = src; } XYDispDriver& XYDispDriver::operator=(const XYDispDriver& src) { Clear(); m_pDisp = src.m_pDisp; if(m_pDisp) { m_pDisp->AddRef(); if(src.m_nDispInfoCount>0) { m_nDispInfoCount = src.m_nDispInfoCount; m_pDispInfo = new XYDispInfo[m_nDispInfoCount]; for(int i=0;i<m_nDispInfoCount;i++) m_pDispInfo[i] = src.m_pDispInfo[i]; } } return *this; } void XYDispDriver::Clear() { m_hRet = S_OK; Unadvise(); if(m_pExceptInfo!=NULL) { ::SysFreeString(m_pExceptInfo->bstrSource); ::SysFreeString(m_pExceptInfo->bstrDescription); ::SysFreeString(m_pExceptInfo->bstrHelpFile); delete m_pExceptInfo; m_pExceptInfo = NULL; } if(m_pDisp!=NULL) { m_pDisp->Release(); m_pDisp = NULL; } if(m_pDispInfo) { delete []m_pDispInfo; m_pDispInfo = NULL; } m_nVarCount = 0; m_nMethodCount = 0; m_nDispInfoCount = 0; } bool XYDispDriver::CreateObject(LPCTSTR strProgID, DWORD dwClsContext) { Clear(); CLSID clsid; #ifdef _UNICODE WCHAR* pProgID = (WCHAR*)strProgID; #else WCHAR pProgID[XYDISPDRIVER_OLENAMELEN+1]; CharToWChar(pProgID,strProgID); #endif m_hRet = ::CLSIDFromProgID(pProgID, &clsid); if(m_hRet==S_OK) return CreateObject(clsid, dwClsContext); else { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("CLSIDFromProgID failed: %x\n"),m_hRet); #endif return false; } } bool XYDispDriver::CreateObject(CLSID clsid, DWORD dwClsContext) { Clear(); m_hRet = ::CoCreateInstance(clsid,NULL,dwClsContext,IID_IDispatch,(void**)(&m_pDisp)); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("CoCreateInstance failed: %x\n"),m_hRet); #endif return false; } return LoadTypeInfo(); } bool XYDispDriver::LoadTypeInfo() { /*UINT nTypeInfoCount; m_hRet = m_pDisp->GetTypeInfoCount(&nTypeInfoCount); if(m_hRet!=S_OK||nTypeInfoCount==0) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetTypeInfoCount failed or no type info: %x\n"),m_hRet); #endif }*/ ITypeInfo* pTypeInfo; m_hRet = m_pDisp->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&pTypeInfo); if(m_hRet!=S_OK||pTypeInfo==NULL) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetTypeInfo failed: %x\n"),m_hRet); #endif return false; } TYPEATTR* pTypeAttr; m_hRet = pTypeInfo->GetTypeAttr(&pTypeAttr); if(m_hRet!=S_OK) { pTypeInfo->Release(); #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetTypeAttr failed: %x\n"),m_hRet); #endif return false; } if(pTypeAttr->typekind!=TKIND_DISPATCH&&pTypeAttr->typekind!=TKIND_COCLASS) { pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Cannot get type info\n")); #endif m_hRet = S_FALSE; return false; } if(pTypeAttr->typekind==TKIND_COCLASS) { int nFlags; HREFTYPE hRefType; ITypeInfo* pTempInfo; TYPEATTR* pTempAttr = NULL; for (int i=0;i < pTypeAttr->cImplTypes;i++) { if(pTypeInfo->GetImplTypeFlags(i,&nFlags)==S_OK&&(nFlags&IMPLTYPEFLAG_FDEFAULT)) { m_hRet = pTypeInfo->GetRefTypeOfImplType(i,&hRefType); if(m_hRet==S_OK) m_hRet = pTypeInfo->GetRefTypeInfo(hRefType,&pTempInfo); if(m_hRet==S_OK) { m_hRet = pTempInfo->GetTypeAttr(&pTempAttr); if(m_hRet!=S_OK) { pTempInfo->Release(); pTempInfo = NULL; break; } } else break; } } pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); if(pTempAttr==NULL) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Failed to get reference type info: %x\n"),m_hRet); #endif if(m_hRet==S_OK) m_hRet = S_FALSE; return false; } else { pTypeInfo = pTempInfo; pTypeAttr = pTempAttr; } } m_nMethodCount = pTypeAttr->cFuncs; m_nVarCount = pTypeAttr->cVars; m_nDispInfoCount = m_nMethodCount+2*m_nVarCount; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Method and variable count = %d\n"), m_nMethodCount+m_nVarCount); #endif m_pDispInfo = new XYDispInfo[m_nDispInfoCount]; for(int i=0;i < m_nMethodCount;i++) { FUNCDESC* pFuncDesc; m_hRet = pTypeInfo->GetFuncDesc(i, &pFuncDesc); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetFuncDesc failed: %x\n"),m_hRet); #endif pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); m_nMethodCount = m_nVarCount = m_nDispInfoCount = 0; return false; } m_pDispInfo[i].m_dispID = pFuncDesc->memid; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("%d: DispID = %d\n"),i, m_pDispInfo[i].m_dispID); #endif unsigned int nCount; m_hRet = pTypeInfo->GetNames(m_pDispInfo[i].m_dispID ,&m_pDispInfo[i].m_bstrName,1,&nCount); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetNames failed: %x\n"),m_hRet); #endif pTypeInfo->ReleaseFuncDesc(pFuncDesc); pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); m_nMethodCount = m_nVarCount = m_nDispInfoCount = 0; return false; } #ifdef XYDISPDRIVER_DEBUG wprintf(L"MethodName = %s\n", m_pDispInfo[i].m_bstrName); #endif switch(pFuncDesc->invkind) { case INVOKE_PROPERTYGET: m_pDispInfo[i].m_wFlag = DISPATCH_PROPERTYGET; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("PropertyGet\n")); #endif break; case INVOKE_PROPERTYPUT: m_pDispInfo[i].m_wFlag = DISPATCH_PROPERTYPUT; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("PropertyPut\n")); #endif break; case INVOKE_PROPERTYPUTREF: m_pDispInfo[i].m_wFlag = DISPATCH_PROPERTYPUTREF; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("PropertyPutRef\n")); #endif break; case INVOKE_FUNC: #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("DispatchMethod\n")); #endif m_pDispInfo[i].m_wFlag = DISPATCH_METHOD; break; default: break; } m_pDispInfo[i].m_oVft = pFuncDesc->oVft; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("VTable offset: %d\n"),m_pDispInfo[i].m_oVft); #endif m_pDispInfo[i].m_callconv = pFuncDesc->callconv; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Calling convention: %d\n"),m_pDispInfo[i].m_callconv); #endif m_pDispInfo[i].m_pOutput = new VARIANT; ::VariantInit(m_pDispInfo[i].m_pOutput); m_pDispInfo[i].m_vtOutputType = pFuncDesc->elemdescFunc.tdesc.vt; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Return type = %d\n"), m_pDispInfo[i].m_vtOutputType); #endif if(m_pDispInfo[i].m_vtOutputType==VT_VOID||m_pDispInfo[i].m_vtOutputType==VT_NULL) { m_pDispInfo[i].m_vtOutputType = VT_EMPTY; } m_pDispInfo[i].m_nParamCount = pFuncDesc->cParams; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("ParamCount = %d\n"), m_pDispInfo[i].m_nParamCount); #endif m_pDispInfo[i].m_pParamTypes = new WORD[m_pDispInfo[i].m_nParamCount+1]; for(int j=0;j<m_pDispInfo[i].m_nParamCount;j++) { if(pFuncDesc->lprgelemdescParam[j].tdesc.vt==VT_PTR||pFuncDesc->lprgelemdescParam[j].tdesc.vt==VT_SAFEARRAY) { m_pDispInfo[i].m_pParamTypes[j] = (pFuncDesc->lprgelemdescParam[j].tdesc.lptdesc->vt)|VT_BYREF; } else { m_pDispInfo[i].m_pParamTypes[j] = pFuncDesc->lprgelemdescParam[j].tdesc.vt; } #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Param(%d) type = %d\n"),j,m_pDispInfo[i].m_pParamTypes[j]); #endif } m_pDispInfo[i].m_pParamTypes[m_pDispInfo[i].m_nParamCount] = 0; pTypeInfo->ReleaseFuncDesc(pFuncDesc); } for(i=m_nMethodCount;i<m_nMethodCount+m_nVarCount;i++) { VARDESC* pVarDesc; m_hRet = pTypeInfo->GetVarDesc(i-m_nMethodCount, &pVarDesc); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetVarDesc failed: %x\n"),m_hRet); #endif pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); m_nMethodCount = m_nVarCount = m_nDispInfoCount = 0; return false; } m_pDispInfo[i].m_dispID = pVarDesc->memid; m_pDispInfo[i+m_nVarCount].m_dispID = m_pDispInfo[i].m_dispID; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("%d: DispID = %d\n"),i, m_pDispInfo[i].m_dispID); #endif unsigned int nCount; m_hRet = pTypeInfo->GetNames(m_pDispInfo[i].m_dispID ,&m_pDispInfo[i].m_bstrName,1,&nCount); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetNames failed: %x\n"),m_hRet); #endif pTypeInfo->ReleaseVarDesc(pVarDesc); pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); m_nMethodCount = m_nVarCount = m_nDispInfoCount = 0; return false; } m_pDispInfo[i+m_nVarCount].m_bstrName = ::SysAllocString(m_pDispInfo[i].m_bstrName); #ifdef XYDISPDRIVER_DEBUG wprintf(L"VarName = %s\n", m_pDispInfo[i].m_bstrName); #endif switch(pVarDesc->varkind) { case VAR_DISPATCH: m_pDispInfo[i].m_wFlag = DISPATCH_PROPERTYGET; m_pDispInfo[i+m_nVarCount].m_wFlag = DISPATCH_PROPERTYPUT; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("VarKind = VAR_DISPATCH\n")); #endif m_pDispInfo[i].m_vtOutputType = pVarDesc->elemdescVar.tdesc.vt; m_pDispInfo[i+m_nVarCount].m_vtOutputType = VT_EMPTY; #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("VarType = %d\n"), m_pDispInfo[i].m_vtOutputType); #endif m_pDispInfo[i+m_nVarCount].m_nParamCount = 1; m_pDispInfo[i+m_nVarCount].m_pParamTypes = new WORD[2]; m_pDispInfo[i+m_nVarCount].m_pParamTypes[0] = m_pDispInfo[i].m_vtOutputType; m_pDispInfo[i+m_nVarCount].m_pParamTypes[1] = 0; break; default: #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("VarKind = %d\n"),pVarDesc->varkind); #endif m_pDispInfo[i].m_wFlag = 0; m_pDispInfo[i+m_nVarCount].m_wFlag = 0; break; } m_pDispInfo[i].m_pOutput = new VARIANT; ::VariantInit(m_pDispInfo[i].m_pOutput); m_pDispInfo[i+m_nVarCount].m_pOutput = new VARIANT; ::VariantInit(m_pDispInfo[i+m_nVarCount].m_pOutput); pTypeInfo->ReleaseVarDesc(pVarDesc); } pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); return true; } bool XYDispDriver::Attach(IDispatch* pDisp) { Clear(); if(pDisp==NULL) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Invalid dipatch pointer"),m_hRet); #endif return false; } m_pDisp = pDisp; m_pDisp->AddRef(); return LoadTypeInfo(); } int XYDispDriver::FindProperty(LPCTSTR strPropertyName) { return FindDispInfo(strPropertyName,DISPATCH_PROPERTYGET); } int XYDispDriver::FindMethod(LPCTSTR strMethodName) { return FindDispInfo(strMethodName); } WORD XYDispDriver::GetPropertyType(LPCTSTR strPropertyName) { int nPropertyIndex = FindProperty(strPropertyName); return GetPropertyType(nPropertyIndex); } WORD XYDispDriver::GetPropertyType(int nPropertyIndex) { if(nPropertyIndex>=0) return m_pDispInfo[nPropertyIndex].m_vtOutputType; else return VT_EMPTY; } VARIANT* XYDispDriver::GetProperty(LPCTSTR strPropertyName) { int nPropertyIndex = FindProperty(strPropertyName); if(nPropertyIndex>=0) { return GetProperty(nPropertyIndex); } return NULL; } VARIANT* XYDispDriver::GetProperty(int nPropertyIndex) { if(m_pDispInfo[nPropertyIndex].m_wFlag==DISPATCH_PROPERTYGET) { va_list argList; va_start(argList,nPropertyIndex); m_hRet = InvokeMethodV(nPropertyIndex, argList); va_end(argList); return m_hRet==S_OK?m_pDispInfo[nPropertyIndex].m_pOutput:NULL; } return NULL; } bool XYDispDriver::SetProperty(LPCTSTR strPropertyName, ...) { int nPropertyIndex = FindDispInfo(strPropertyName,DISPATCH_PROPERTYPUT); if(nPropertyIndex>=0) { va_list argList; va_start(argList,strPropertyName); m_hRet = InvokeMethodV(nPropertyIndex, argList); va_end(argList); return m_hRet==S_OK; } return false; } bool XYDispDriver::SetProperty(int nPropertyIndex, ...) { if(m_pDispInfo[nPropertyIndex].m_wFlag==DISPATCH_PROPERTYPUT) { va_list argList; va_start(argList,nPropertyIndex); m_hRet = InvokeMethodV(nPropertyIndex, argList); va_end(argList); return m_hRet==S_OK; } return false; } bool XYDispDriver::SetPropertyRef(LPCTSTR strPropertyName, ...) { int nPropertyIndex = FindDispInfo(strPropertyName,DISPATCH_PROPERTYPUTREF); if(nPropertyIndex>=0) { va_list argList; va_start(argList,strPropertyName); m_hRet = InvokeMethodV(nPropertyIndex, argList); va_end(argList); return m_hRet==S_OK; } return false; } bool XYDispDriver::SetPropertyRef(int nPropertyIndex, ...) { if(m_pDispInfo[nPropertyIndex].m_wFlag==DISPATCH_PROPERTYPUTREF) { va_list argList; va_start(argList,nPropertyIndex); m_hRet = InvokeMethodV(nPropertyIndex, argList); va_end(argList); return m_hRet==S_OK; } return false; } WORD XYDispDriver::GetReturnType(LPCTSTR strMethodName) { int nMethodIndex = FindMethod(strMethodName); return GetReturnType(nMethodIndex); } WORD XYDispDriver::GetReturnType(int nMethodIndex) { if(nMethodIndex>=0) return m_pDispInfo[nMethodIndex].m_vtOutputType; else return VT_EMPTY; } int XYDispDriver::GetParamCount(LPCTSTR strMethodName) { int nMethodIndex = FindMethod(strMethodName); return GetParamCount(nMethodIndex); } int XYDispDriver::GetParamCount(int nMethodIndex) { if(nMethodIndex>=0) return m_pDispInfo[nMethodIndex].m_nParamCount; else return -1; } WORD XYDispDriver::GetParamType(LPCTSTR strMethodName, const int nParamIndex) { int nMethodIndex = FindMethod(strMethodName); return GetParamType(nMethodIndex, nParamIndex); } WORD XYDispDriver::GetParamType(int nMethodIndex, const int nParamIndex) { if(nMethodIndex>=0&&nParamIndex>=0&&nParamIndex<m_pDispInfo[nMethodIndex].m_nParamCount) { return m_pDispInfo[nMethodIndex].m_pParamTypes[nParamIndex]; } else return VT_EMPTY; } VARIANT* XYDispDriver::InvokeMethod(LPCTSTR strMethodName, ...) { int nMethodIndex = FindMethod(strMethodName); if(nMethodIndex>=0) { va_list argList; va_start(argList,strMethodName); m_hRet = InvokeMethodV(nMethodIndex, argList); va_end(argList); return m_hRet==S_OK?m_pDispInfo[nMethodIndex].m_pOutput:NULL; } return NULL; } VARIANT* XYDispDriver::InvokeMethod(int nMethodIndex, ...) { if(m_pDispInfo[nMethodIndex].m_wFlag==DISPATCH_METHOD) { va_list argList; va_start(argList,nMethodIndex); m_hRet = InvokeMethodV(nMethodIndex, argList); va_end(argList); return m_hRet==S_OK?m_pDispInfo[nMethodIndex].m_pOutput:NULL; } return NULL; } int XYDispDriver::FindDispInfo(LPCTSTR strName, const WORD wFlag) { #ifdef _UNICODE WCHAR* pName = (WCHAR*)strName; #else WCHAR pName[XYDISPDRIVER_OLENAMELEN+1]; CharToWChar(pName,strName); #endif int nRet = -1; for(int i=0;i<m_nDispInfoCount;i++) { if(wcscmp(pName,m_pDispInfo[i].m_bstrName)==0&&m_pDispInfo[i].m_wFlag==wFlag) { nRet = i; break; } } return nRet; } HRESULT XYDispDriver::InvokeMethodV(int nIndex, va_list argList) { m_hRet = S_OK; if(m_pDispInfo[nIndex].m_wFlag==0) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Invalid invokation flag\n")); #endif m_hRet = S_FALSE; return m_hRet; } DISPPARAMS dispparams; memset(&dispparams, 0, sizeof dispparams); dispparams.cArgs = m_pDispInfo[nIndex].m_nParamCount; DISPID dispidNamed = DISPID_PROPERTYPUT; if(m_pDispInfo[nIndex].m_wFlag&(DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) { dispparams.cNamedArgs = 1; dispparams.rgdispidNamedArgs = &dispidNamed; } if(dispparams.cArgs!=0) { // allocate memory for all VARIANT parameters VARIANT* pArg = new VARIANT[dispparams.cArgs]; dispparams.rgvarg = pArg; memset(pArg, 0, sizeof(VARIANT) * dispparams.cArgs); // get ready to walk vararg list const WORD* pb = m_pDispInfo[nIndex].m_pParamTypes; pArg += dispparams.cArgs - 1; // params go in opposite order while(*pb!=0) { pArg->vt = *pb; // set the variant type switch (pArg->vt) { case VT_UI1: pArg->bVal = va_arg(argList, BYTE); break; case VT_I2: pArg->iVal = va_arg(argList, short); break; case VT_I4: pArg->lVal = va_arg(argList, long); break; case VT_R4: pArg->vt = VT_R4; pArg->fltVal = va_arg(argList, float); break; case VT_R8: pArg->dblVal = va_arg(argList, double); break; case VT_BOOL: pArg->boolVal = (VARIANT_BOOL)(va_arg(argList, BOOL) ? -1 : 0); break; case VT_ERROR: pArg->scode = va_arg(argList, SCODE); break; case VT_DATE: pArg->date = va_arg(argList, DATE); break; case VT_CY: pArg->cyVal = va_arg(argList, CY); break; case VT_BSTR: { #ifdef _UNICODE LPCOLESTR lpsz = va_arg(argList, LPOLESTR); pArg->bstrVal = ::SysAllocString(lpsz); #else LPCSTR lpsz = va_arg(argList, LPSTR); WCHAR* pData = new WCHAR[strlen(lpsz)+1]; CharToWChar(pData,lpsz); pArg->bstrVal = ::SysAllocString(pData); delete []pData; #endif } break; case VT_UNKNOWN: pArg->punkVal = va_arg(argList, LPUNKNOWN); break; case VT_DISPATCH: pArg->pdispVal = va_arg(argList, LPDISPATCH); break; case VT_ARRAY: pArg->parray = va_arg(argList, SAFEARRAY*); break; case VT_VARIANT: *pArg = va_arg(argList, VARIANT); break; case VT_UI1|VT_BYREF: pArg->pbVal = va_arg(argList,unsigned char*); break; case VT_I2|VT_BYREF: pArg->piVal = va_arg(argList, short*); break; case VT_I4|VT_BYREF: pArg->plVal = va_arg(argList, long*); break; case VT_R4|VT_BYREF: pArg->pfltVal = va_arg(argList, float*); break; case VT_R8|VT_BYREF: pArg->pdblVal = va_arg(argList, double*); break; case VT_BOOL|VT_BYREF: { // coerce BOOL into VARIANT_BOOL BOOL* pboolVal = va_arg(argList, BOOL*); *pboolVal = (*pboolVal)?MAKELONG(0,-1):0; pArg->pboolVal = (VARIANT_BOOL*)pboolVal; } break; case VT_ERROR|VT_BYREF: pArg->pscode = va_arg(argList, SCODE*); break; case VT_DATE|VT_BYREF: pArg->pdate = va_arg(argList, DATE*); break; case VT_CY|VT_BYREF: pArg->pcyVal = va_arg(argList, CY*); break; case VT_BSTR|VT_BYREF: pArg->pbstrVal = va_arg(argList, BSTR*); break; case VT_UNKNOWN|VT_BYREF: pArg->ppunkVal = va_arg(argList, LPUNKNOWN*); break; case VT_DISPATCH|VT_BYREF: pArg->ppdispVal = va_arg(argList, LPDISPATCH*); break; case VT_ARRAY|VT_BYREF: pArg->pparray = va_arg(argList, SAFEARRAY**); break; case VT_VARIANT|VT_BYREF: pArg->pvarVal = va_arg(argList, VARIANT*); break; default: break; } --pArg; // get ready to fill next argument ++pb; } } // initialize return value VARIANT* pvarResult = m_pDispInfo[nIndex].m_pOutput; ::VariantClear(pvarResult); // initialize EXCEPINFO struct if(m_pExceptInfo!=NULL) { ::SysFreeString(m_pExceptInfo->bstrSource); ::SysFreeString(m_pExceptInfo->bstrDescription); ::SysFreeString(m_pExceptInfo->bstrHelpFile); delete m_pExceptInfo; } m_pExceptInfo = new EXCEPINFO; memset(m_pExceptInfo, 0, sizeof(*m_pExceptInfo)); UINT nArgErr = (UINT)-1; // initialize to invalid arg // make the call m_hRet = m_pDisp->Invoke(m_pDispInfo[nIndex].m_dispID,IID_NULL,LOCALE_SYSTEM_DEFAULT,m_pDispInfo[nIndex].m_wFlag,&dispparams,pvarResult,m_pExceptInfo,&nArgErr); // cleanup any arguments that need cleanup if (dispparams.cArgs != 0) { VARIANT* pArg = dispparams.rgvarg + dispparams.cArgs - 1; const WORD* pb = m_pDispInfo[nIndex].m_pParamTypes; while (*pb != 0) { switch (*pb) { case VT_BSTR: ::SysFreeString(pArg->bstrVal); break; } --pArg; ++pb; } } delete[] dispparams.rgvarg; // throw exception on failure if(m_hRet<0) { ::VariantClear(m_pDispInfo[nIndex].m_pOutput); if(m_hRet!=DISP_E_EXCEPTION) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Invoke failed, no exception: %x\n"),m_hRet); #endif delete m_pExceptInfo; m_pExceptInfo = NULL; return m_hRet; } // make sure excepInfo is filled in if(m_pExceptInfo->pfnDeferredFillIn != NULL) m_pExceptInfo->pfnDeferredFillIn(m_pExceptInfo); #ifdef XYDISPDRIVER_DEBUG wprintf(L"Exception source: %s\n",m_pExceptInfo->bstrSource); wprintf(L"Exception description: %s\n",m_pExceptInfo->bstrDescription); wprintf(L"Exception help file: %s\n",m_pExceptInfo->bstrHelpFile); #endif return m_hRet; } if(m_pDispInfo[nIndex].m_vtOutputType!=VT_EMPTY) { m_pDispInfo[nIndex].m_pOutput->vt = m_pDispInfo[nIndex].m_vtOutputType; } delete m_pExceptInfo; m_pExceptInfo = NULL; return m_hRet; } bool XYDispDriver::Advise(IUnknown __RPC_FAR *pUnkSink, REFIID riid) { if(m_pDisp==NULL) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Null dipatch pointer\n")); #endif m_hRet = S_FALSE; return false; } Unadvise(); IConnectionPointContainer* pCPContainer = NULL; m_hRet = m_pDisp->QueryInterface(IID_IConnectionPointContainer,(void**)&pCPContainer); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Failed to call QueryInterface to get the IConnectionPointContainer interface: %x\n"),m_hRet); #endif return false; } m_hRet = pCPContainer->FindConnectionPoint(riid,&m_pCP); pCPContainer->Release(); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Failed to call FindConnectionPoint to get the IConnectionPoint interface: %x\n"),m_hRet); #endif return false; } m_hRet = m_pCP->Advise(pUnkSink,&m_dwCookie); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Failed to call Advise: %x\n"),m_hRet); #endif m_pCP->Release(); m_pCP = NULL; return false; } return true; } void XYDispDriver::Unadvise() { if(m_pCP!=NULL) { m_hRet = m_pCP->Unadvise(m_dwCookie); if(m_hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Failed to call Unadvise: %x\n"),m_hRet); #endif } m_pCP->Release(); m_pCP = NULL; m_dwCookie = 0; } } HRESULT XYDispDriver::InvokeVariantMethod(IDispatch* pDisp, LPCTSTR strMethodName, WORD wInvokeFlag, VARIANT* pVarRet, EXCEPINFO* pExcepInfo, const nParamCount, ...) { if(pDisp==NULL||strMethodName==NULL||nParamCount<0) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Invalid parameters to InvokeVariantMethod")); #endif return S_FALSE; } #ifdef _UNICODE WCHAR* pName = (WCHAR*)strMethodName; #else WCHAR* pName = new WCHAR[XYDISPDRIVER_OLENAMELEN+1]; CharToWChar(pName,strMethodName); #endif DISPID dispid; HRESULT hRet = pDisp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&dispid); #ifndef _UNICODE delete []pName; #endif if(hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("GetIDsOfNames failed: %x\n"),hRet); #endif return hRet; } else { va_list argList; va_start(argList,nParamCount); hRet = InvokeVariantMethodV(pDisp, dispid, wInvokeFlag, pVarRet, pExcepInfo, nParamCount, argList); va_end(argList); } return hRet; } HRESULT XYDispDriver::InvokeVariantMethod(IDispatch* pDisp, const DISPID dispidMethod, WORD wInvokeFlag, VARIANT* pVarRet, EXCEPINFO* pExcepInfo, const nParamCount, ...) { if(pDisp==NULL||nParamCount<0) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Invalid parameters to InvokeVariantMethod")); #endif return S_FALSE; } va_list argList; va_start(argList,nParamCount); HRESULT hRet = InvokeVariantMethodV(pDisp, dispidMethod, wInvokeFlag, pVarRet, pExcepInfo, nParamCount, argList); va_end(argList); return hRet; } HRESULT XYDispDriver::InvokeVariantMethodV(IDispatch* pDisp, const DISPID dispidMethod, WORD wInvokeFlag, VARIANT* pVarRet, EXCEPINFO* pExcepInfo, const nParamCount, va_list argList) { DISPPARAMS dispparams; memset(&dispparams, 0, sizeof dispparams); dispparams.cArgs = nParamCount; if(nParamCount>0) { dispparams.rgvarg = new VARIANT[nParamCount]; memset(dispparams.rgvarg, 0, sizeof(VARIANT)*nParamCount); VARIANT* pArg; for(int i=nParamCount-1;i>=0;i--) { pArg = dispparams.rgvarg+i; *pArg = va_arg(argList, VARIANT); } } else dispparams.rgvarg = NULL; if(pVarRet) ::VariantInit(pVarRet); UINT nArgErr = (UINT)-1; HRESULT hRet = pDisp->Invoke(dispidMethod,IID_NULL,LOCALE_SYSTEM_DEFAULT,wInvokeFlag,&dispparams,pVarRet,pExcepInfo,&nArgErr); if(nParamCount>0) delete[] dispparams.rgvarg; if(hRet!=S_OK) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Invoke failed: %x\n"),hRet); #endif if(pVarRet) ::VariantClear(pVarRet); if(hRet==DISP_E_EXCEPTION) { #ifdef XYDISPDRIVER_DEBUG _tprintf(_T("Exception occurred\n")); #endif if(pExcepInfo) { if(pExcepInfo->pfnDeferredFillIn != NULL) pExcepInfo->pfnDeferredFillIn(pExcepInfo); #ifdef XYDISPDRIVER_DEBUG wprintf(L"Exception source: %s\n",pExcepInfo->bstrSource); wprintf(L"Exception description: %s\n",pExcepInfo->bstrDescription); wprintf(L"Exception help file: %s\n",pExcepInfo->bstrHelpFile); #endif } } } return hRet; }
//初始化COM库
HRESULT hr = CoInitialize(NULL);
//创建接口实例指针
XYDispDriver disp;
bool res = disp.CreateObject("XXXXX.YYYYYY"); //progid
....
//调用 方法
disp.InvokeMethod("somefunction", 1 , &out, in1, in2);