2009-11-25 18 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