2009-11-25 22 views

答えて

6

SAFEARRAY(VARIANT *)の定義は正しくありません。 SAFEARRAY(VARIANT)としてIDLで宣言されていますが、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

ここから出発し、あなたは単純に配列をロックするとき* VARIANTとしてpvDataを扱い、その後、VT_VARIANTのバリアント型とSAFEARRAYを宣言します。あなたの関数と同じ宣言に一致する関数を呼び出すことによってこれを実証する、サンプルの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メソッド?あなたは例を投稿できますか? –

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

関連する問題