2009-11-25 16 views

Antwort

6

Die Definition SAFEARRAY (VARIANT *) ist nicht ganz korrekt. Es wird in einer IDL als SAFEARRAY (VARIANT) deklariert, aber der beim Sperren des SAFEARRAY verfügbare Zeiger ist tatsächlich ein VARIANT *. Wenn Sie einen Moment darüber nachdenken, sollte es mehr Sinn ergeben. Der Indexzeiger eines SAFEARRAY (das pvData-Member) kann unmöglich eine gesamte VARIANT an seinem physischen Speicherort enthalten, daher sollte er zumindest einen Zeiger speichern können, der zum Indizieren in ein Array von VARIANTs verwendet werden kann.

Wenn Sie <wtypes.h> betrachten, irgendwo über Linie 1110+ sehen Sie die VT_ Aufzählung Definitionen. Dort wird auch gezeigt, dass VT_VARIANT tatsächlich VARIANT * impliziert. Ebenfalls praktisch sind die [S] Tags, die aufzeigen, welche Artikel in einem SAFEARRAY erscheinen können.

/* 
* 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) 
*/ 

Hier ist ein Link zu einer Kopie der Header-Datei.

wtypes.h at DOC.DDART.NET

Proceeding von hier, Sie würden einfach ein SAFEARRAY mit einer Variante Art von VT_VARIANT erklären, dann pvData als VARIANT * behandeln, wenn das Array zu verriegeln. Hier ist der Quellcode für eine Win32-Konsolenanwendung, die dies veranschaulicht, indem eine Funktion aufgerufen wird, die derselben Deklaration wie Ihre Funktion entspricht.

#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; 
} 

Die Komponente durch diesen Test app genannt kann durch die Schaffung eines ATL-DLL-Projekt, und das Hinzufügen eines einfachen ATL Objekt namens ‚TestReader‘ angelegt werden.

Hier ist die IDL für ITestReader.

[ 
    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); 
}; 

Das Funktionselement in der IDL Deklaration entspricht dauert nur SAFEARRAY * (oder LPSAFEARRAY) Argumente.

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

Hier ist der Körper der Methode. Ebenfalls enthalten ist eine Hilfsfunktion PrintVariant() für die Kürze.

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

Wie kann ich ein Array von Strings vom VB-Skript an die SAFEARRAY-Methode übergeben ? Kannst du bitte ein Beispiel posten? –

8

Hinzufügen zu den Antworten oben dafür durch zukünftige Leser: In IDL bedeutet SAFEARRAY(...) einen Zeiger auf ein Array-Deskriptor. In C++ bedeutet SAFEARRAY jedoch einen Array-Deskriptor. Also IDL SAFEARRAY(...) ist wirklich C++ SAFEARRAY *. Das verwirrte mich bis zum Schluss. Um die Dinge noch interessanter zu machen, übergibt VB Arrays immer als Referenz. VB's () As Long ist SAFEARRAY<int32_t> ** in C++. (Ich weiß nicht, ob es tatsächlich einen häufig verwendeten Header gibt, mit dem Sie den Typ als Vorlageparameter angeben können, aber ich habe ihn aus Gründen der Übersichtlichkeit eingefügt.)

+0

+1 für einen Kommentar zu Unterschieden zwischen SAFEARRAY im IDL-Kontext und der SAFEARRAY C/C++ - Struktur – meklarian