在使用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
XYDispDriver.cpp
//#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);