前言
如果使用变体类型的出参,必须指定VT_BYREF和数据类型的或
typedef struct FARSTRUCT tagVARIANT VARIANT;
typedef struct FARSTRUCT tagVARIANT VARIANTARG;
typedef struct tagVARIANT {
VARTYPE vt;
unsigned short wReserved1;
unsigned short wReserved2;
unsigned short wReserved3;
union {
Byte bVal; // VT_UI1.
Short iVal; // VT_I2.
long lVal; // VT_I4.
float fltVal; // VT_R4.
double dblVal; // VT_R8.
VARIANT_BOOL boolVal; // VT_BOOL.
SCODE scode; // VT_ERROR.
CY cyVal; // VT_CY.
DATE date; // VT_DATE.
BSTR bstrVal; // VT_BSTR.
DECIMAL FAR* pdecVal // VT_BYREF|VT_DECIMAL.
IUnknown FAR* punkVal; // VT_UNKNOWN.
IDispatch FAR* pdispVal; // VT_DISPATCH.
SAFEARRAY FAR* parray; // VT_ARRAY|*.
Byte FAR* pbVal; // VT_BYREF|VT_UI1.
short FAR* piVal; // VT_BYREF|VT_I2.
long FAR* plVal; // VT_BYREF|VT_I4.
float FAR* pfltVal; // VT_BYREF|VT_R4.
double FAR* pdblVal; // VT_BYREF|VT_R8.
VARIANT_BOOL FAR* pboolVal; // VT_BYREF|VT_BOOL.
SCODE FAR* pscode; // VT_BYREF|VT_ERROR.
CY FAR* pcyVal; // VT_BYREF|VT_CY.
DATE FAR* pdate; // VT_BYREF|VT_DATE.
BSTR FAR* pbstrVal; // VT_BYREF|VT_BSTR.
IUnknown FAR* FAR* ppunkVal; // VT_BYREF|VT_UNKNOWN.
IDispatch FAR* FAR* ppdispVal; // VT_BYREF|VT_DISPATCH.
SAFEARRAY FAR* FAR* pparray; // VT_ARRAY|*.
VARIANT FAR* pvarVal; // VT_BYREF|VT_VARIANT.
void FAR* byref; // Generic ByRef.
char cVal; // VT_I1.
unsigned short uiVal; // VT_UI2.
unsigned long ulVal; // VT_UI4.
int intVal; // VT_INT.
unsigned int uintVal; // VT_UINT.
char FAR * pcVal; // VT_BYREF|VT_I1.
unsigned short FAR * puiVal; // VT_BYREF|VT_UI2.
unsigned long FAR * pulVal; // VT_BYREF|VT_UI4.
int FAR * pintVal; // VT_BYREF|VT_INT.
unsigned int FAR * puintVal; //VT_BYREF|VT_UINT.
};
};
例子
void fnTest2() {
HRESULT hr = S_FALSE;
LONG lRc = 0;
CLSID clsid;
BSTR bstrStr = NULL;
IUnknown* pUnk = NULL;
IDispatch* pDispatch = NULL;
OLECHAR* szFunction = NULL;
DISPID dispid;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT var[10];
VARIANT varRc[10];
LONG lVal[10] = {0};
do {
hr = CLSIDFromProgID(OLESTR("MyStringComDll.MyString.1"), &clsid);
if (FAILED(hr)) {
break;
}
hr = CoCreateInstance(CLSID_MyString, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnk);
if (FAILED(hr)) {
break;
}
hr = pUnk->QueryInterface(IID_IDispatch, (void**)&pDispatch);
if (FAILED(hr)) {
break;
}
szFunction = OLESTR("test");
/// 出参 dispid 为虚表中length函数对应的索引项
hr = pDispatch->GetIDsOfNames(IID_NULL, &szFunction, 1, LOCALE_USER_DEFAULT, &dispid);
if (FAILED(hr)) {
break;
}
/// 使用出参的例子, 要使用VARIANT.pX, VARIANT.vt 必须是VT_BYREF | VT_数据类型
var[0].vt = VT_BYREF | VT_I4;
var[0].plVal = &lVal[1];
var[1].vt = VT_BYREF | VT_I4;
var[1].plVal = &lVal[0];
dispparams.rgvarg = var;
dispparams.rgdispidNamedArgs = NULL;
dispparams.cArgs = 2;
dispparams.cNamedArgs = 0;
hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dispparams, varRc, NULL,
NULL);
if (FAILED(hr)) {
break;
}
wprintf(L"all ok\n");
} while (0);
if (NULL != pDispatch) {
pDispatch->Release();
}
if (NULL != pUnk) {
pUnk->Release();
}
}
COM接口定义与实现
// MyStringComDll.idl : IDL source for MyStringComDll.dll
//
// This file will be processed by the MIDL tool to
// produce the type library (MyStringComDll.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(DEA21FB9-6309-4B7C-BA39-453685F6B081),
dual,
helpstring("IMyString Interface"),
pointer_default(unique)
]
interface IMyString : IDispatch
{
[id(1), helpstring("字符串赋值")] HRESULT assignment([in] LPOLESTR lpszSrc);
[id(2), helpstring("字符串是否相等,靠出参返回")] HRESULT isEqual([in] LPOLESTR lpszSrc, [out]LONG* lplRc);
[id(3), helpstring("字符串是否不相等")] HRESULT isNotEqual([in] LPOLESTR lpszSrc, [out]LONG* lplRc);
[id(4), helpstring("字符串是否<入参字符串")] HRESULT isLessThan([in] LPOLESTR lpszSrc, [out]LONG* lplRc);
[id(5), helpstring("字符串是否<=入参字符串")] HRESULT isLessThanOrEqual([in] LPOLESTR lpszSrc, [out]LONG* lplRc);
[id(6), helpstring("字符串是否>入参字符串")] HRESULT isGreateThan([in] LPOLESTR lpszSrc, [out]LONG* lplRc);
[id(7), helpstring("字符串是否>=入参字符串")] HRESULT isGreateThanOrEqual([in] LPOLESTR lpszSrc, [out]LONG* lplRc);
[id(8), helpstring("字符串是为空")] HRESULT isEmpty([out]LONG* lplRc);
[id(9), helpstring("附加一个字符串")] HRESULT Appends([in] LPOLESTR lpszSrc);
[id(10), helpstring("求字符串长度")] HRESULT length([out]LONG* lplRc);
[id(11), helpstring("得到字符串")] HRESULT GetString([out]BSTR* lpBstrStr);
[id(12), helpstring("method test")] HRESULT test([out] long* lRc1, [out] long* lRc2 );
};
[
uuid(3F08DFAB-AF55-45DE-93D4-8120F9C67D44),
version(1.0),
helpstring("MyStringComDll 1.0 Type Library")
]
library MYSTRINGCOMDLLLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(26EF0212-1BF7-4E01-9988-37AD60087846),
helpstring("MyString Class")
]
coclass MyString
{
[default] interface IMyString;
};
};
// MyString.h : Declaration of the CMyString
#ifndef __MYSTRING_H_
#define __MYSTRING_H_
#include "resource.h" // main symbols
#include <comdef.h> ///< for _bstr_t
/////////////////////////////////////////////////////////////////////////////
// CMyString
class ATL_NO_VTABLE CMyString :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyString, &CLSID_MyString>,
public IDispatchImpl<IMyString, &IID_IMyString, &LIBID_MYSTRINGCOMDLLLib>
{
public:
CMyString()
{
m_bstrStr = OLESTR("");
}
DECLARE_REGISTRY_RESOURCEID(IDR_MYSTRING)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyString)
COM_INTERFACE_ENTRY(IMyString)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// IMyString
public:
STDMETHOD(test)(/*[out]*/ long* lRc1, /*[out]*/ long* lRc2 );
STDMETHOD(isNotEqual)(/*[in]*/ LPOLESTR lpszSrc, /*[out]*/LONG* lplRc);
STDMETHOD(assignment)(/*[in]*/ LPOLESTR lpszSrc);
STDMETHOD(isEqual)(/*[in]*/ LPOLESTR lpszSrc, /*[out]*/ LONG* lplRc);
STDMETHOD(isLessThan)(/*[in]*/ LPOLESTR lpszSrc, /*[out]*/ LONG* lplRc);
STDMETHOD(isLessThanOrEqual)(/*[in]*/ LPOLESTR lpszSrc, /*[out]*/ LONG* lplRc);
STDMETHOD(isGreateThan)(/*[in]*/ LPOLESTR lpszSrc, /*[out]*/ LONG* lplRc);
STDMETHOD(isGreateThanOrEqual)(/*[in]*/ LPOLESTR lpszSrc, /*[out]*/ LONG* lplRc);
STDMETHOD(isEmpty)(/*[out]*/ LONG* lplRc);
STDMETHOD(Appends)(/*[in]*/ LPOLESTR lpszSrc);
STDMETHOD(length)(/*[out]*/ LONG* lplRc);
STDMETHOD(GetString)(/*[out]*/ BSTR* lpBstrStr);
/// 私有成员变量
private:
_bstr_t m_bstrStr; ///< 保存外面传来的字符串
};
#endif //__MYSTRING_H_
STDMETHODIMP CMyString::test(long *lRc1, long *lRc2)
{
if ((NULL == lRc1) || (NULL == lRc2)) {
return ERROR_INVALID_PARAMETER;
}
*lRc1 = 0x1111;
*lRc2 = 0x2222;
return S_OK; ///< invoke时,返回的hr并不是这里的返回值
}