2009-11-25 61 views

回答

6

定义SAFEARRAY(VARIANT *)不完全正确。它在IDL中声明为SAFEARRAY(VARIANT),但锁定SAFEARRAY的指针实际上是VARIANT *。如果你暂时考虑这个问题,它应该更有意义。 SAFEARRAY(pvData成员)的索引指针不可能适合整个VARIANT的物理位置,所以至少它应该能够存储可用于索引到VARIANT数组中的指针。

如果你看<wtypes.h>,在1110+行的某处你会看到VT_枚举定义。它也显示那里VT_VARIANT实际上暗示VARIANT *。 [S]标签也很方便标记SAFEARRAY中可能出现的项目。

/* 
* VARENUM usage key, 
* 
* * [V] - may appear in a VARIANT 
* * [T] - may appear in a TYPEDESC 
* * [P] - may appear in an OLE property set 
* * [S] - may appear in a Safe Array 
* 
* 
* VT_EMPTY   [V] [P]  nothing 
* VT_NULL    [V] [P]  SQL style Null 
* VT_I2    [V][T][P][S] 2 byte signed int 
* VT_I4    [V][T][P][S] 4 byte signed int 
* VT_R4    [V][T][P][S] 4 byte real 
* VT_R8    [V][T][P][S] 8 byte real 
* VT_CY    [V][T][P][S] currency 
* VT_DATE    [V][T][P][S] date 
* VT_BSTR    [V][T][P][S] OLE Automation string 
* VT_DISPATCH   [V][T] [S] IDispatch * 
* VT_ERROR   [V][T][P][S] SCODE 
* VT_BOOL    [V][T][P][S] True=-1, False=0 
* VT_VARIANT   [V][T][P][S] VARIANT * 
... (remaining definitions omittted) 
*/ 

这是一个指向头文件副本的链接。

wtypes.h at DOC.DDART.NET

从这里出发,您只需声明SAFEARRAY具有一个变体类型VT_VARIANT的,然后把pvData为VARIANT *锁定数组的时候。下面是一个示例win32控制台应用程序的源代码,通过调用与您的函数匹配相同声明的函数来演示此应用程序。

#include "stdafx.h" 
#include "SFAComponent.h" 
#include "SFAComponent_i.c" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ::CoInitialize(NULL); 

    SAFEARRAYBOUND nameBounds; 
    nameBounds.cElements = 2; 
    nameBounds.lLbound = 0; 
    LPSAFEARRAY psaNames = SafeArrayCreate(VT_BSTR, 1, &nameBounds); 

    BSTR bstrApple = SysAllocString(L"apple"); 
    BSTR bstrOrange = SysAllocString(L"orange"); 

    SafeArrayLock(psaNames); 
    BSTR *nameArray = (BSTR *)psaNames->pvData; 
    nameArray[0] = bstrApple; 
    nameArray[1] = bstrOrange; 
    SafeArrayUnlock(psaNames); 

    SAFEARRAYBOUND valueBounds; 
    valueBounds.cElements = 2; 
    valueBounds.lLbound = 0; 
    LPSAFEARRAY psaValues = SafeArrayCreate(VT_VARIANT, 1, &valueBounds); 

    SafeArrayLock(psaValues); 
    VARIANT *valueArray = (VARIANT *)psaValues->pvData; 
    VariantClear(&valueArray[0]); 
    VariantClear(&valueArray[1]); 
    valueArray[0].vt = VT_BSTR; 
    valueArray[0].bstrVal = SysAllocString(L"hello"); 
    valueArray[1].vt = VT_I4; 
    valueArray[1].iVal = 42; 

    { 
    CComPtr<ITestReader> p; 
    p.CoCreateInstance(CLSID_TestReader); 
    p->Run(psaNames, psaValues); 
    p.Release(); // not explicitly necessary. 
    } 

    SafeArrayDestroy(psaValues); 
    SafeArrayDestroy(psaNames); 

    ::CoUninitialize(); 

    return 0; 
} 

通过此测试应用程序调用的组件可通过创建一个ATL DLL项目,并添加称为“TestReader”简单ATL对象被创建。

以下是ITestReader的IDL。

[ 
    object, 
    uuid(832EF93A-18E8-4655-84CA-0BA847B52B77), 
    dual, 
    nonextensible, 
    helpstring("ITestReader Interface"), 
    pointer_default(unique), 
    oleautomation 
] 
interface ITestReader : IDispatch{ 
    [id(1), helpstring("method Run")] HRESULT Run([in] SAFEARRAY(BSTR) paramNames, [in] SAFEARRAY(VARIANT) paramValues); 
}; 

对应于IDL声明的成员函数只需要SAFEARRAY *(或LPSAFEARRAY)参数。

public: 
    STDMETHOD(Run)(LPSAFEARRAY paramNames, LPSAFEARRAY paramValues); 

这里是方法的主体。为简洁起见,还包括一个辅助函数PrintVariant()。

void PrintVariant(VARIANT *pV) 
{ 
    switch(pV->vt) 
    { 
    case VT_BSTR: 
    wprintf(L" BSTR: %s\r\n", pV->bstrVal); 
    break; 
    case VT_I4: 
    wprintf(L" Integer: %d\r\n", pV->iVal); 
    break; 
    default: 
    wprintf(L" Unrecognized Type: vt=%d\r\n", pV->vt); 
    break; 
    } 
} 

STDMETHODIMP CTestReader::Run(LPSAFEARRAY paramNames, LPSAFEARRAY paramValues) 
{ 
    SafeArrayLock(paramNames); 
    SafeArrayLock(paramValues); 
    BSTR *nameArray = (BSTR *)paramNames->pvData; 
    VARIANT *valueArray = (VARIANT *)paramValues->pvData; 

    wprintf(L"Item 0 is %s, variant type %d\r\n", nameArray[0], valueArray[0].vt); 
    PrintVariant(&valueArray[0]); 
    wprintf(L"Item 1 is %s, variant type %d\r\n", nameArray[1], valueArray[1].vt); 
    PrintVariant(&valueArray[1]); 

    SafeArrayUnlock(paramNames); 
    SafeArrayUnlock(paramValues); 

    return S_OK; 
} 
+0

如何将字符串数组从VB脚本传递到SAFEARRAY方法?你能举个例子吗? – 2018-03-09 10:29:44

8
添加

上述用于由未来的读者参考答案: 在IDL,SAFEARRAY(...)指一个指针数组描述符。 但是在C++中,SAFEARRAY意味着一个数组描述符。因此,IDL的SAFEARRAY(...)真的是C++的SAFEARRAY *。这让我困惑不已。为了让事情更有趣,VB总是通过引用传递数组。所以VB的() As Long是在C++中的SAFEARRAY<int32_t> **。 (我不知道是否实际上有一个常用的标题,允许您指定类型作为模板参数,但为了清晰起见,我插入了它。)

+0

对IDL上下文中的SAFEARRAY与SAFEARRAY C/C++结构之间的差异发表评论+1 – meklarian 2011-06-07 18:29:07

相关问题