2009-11-25 14 views

cevap

6

SAFEARRAY (VARIANT *) tanımı çok doğru değil. Bir IDL'de SAFEARRAY (VARIANT) olarak bildirilir, ancak SAFEARRAY'ın kilitlenmesinden elde edilen işaretçi aslında bir VARIANT * 'tır. Bunu bir an düşünürseniz, biraz daha mantıklı olmalı. Bir SAFEARRAY'ın (pvData üyesi) indeks işaretçisi, fiziksel konumdaki bir VARYANT'ın tamamını sığdıramaz, bu yüzden en azından, bir VARYANT dizisine dizmek için kullanılabilecek bir işaretçiyi saklayabilmelidir.

< wtypes.h adresine bakarsanız >, satır 1110+ hakkında bir yere VT_ numaralandırma tanımlarını görürsünüz. Ayrıca VT_VARIANT'ın VARIANT * olduğunu ima ettiği de gösterilmiştir. Ayrıca, SAFEARRAY'da hangi öğelerin görünebileceğini belirten [S] etiketleri de kullanışlıdır.

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

Aşağıda başlık dosyasının bir kopyasını bir bağlantı.

wtypes.h at DOC.DDART.NET

buradan Bildiri, sadece, VT_VARIANT bir varyant türü ile SAFEARRAY'ini beyan dizi kilitleme zaman sonra * VARIANT olarak pvData tedavi edecektir. İşte, örnek olarak aynı deklarasyonla eşleşen bir işlevi çağırarak örnek bir win32 konsol uygulaması için kaynak kodu.

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

bu test uygulaması tarafından adlandırılan parça

ATL DLL proje oluşturma ve 'TestReader' olarak adlandırılan, basit bir ATL nesnesi eklenerek oluşturulabilir.

İşte ITestReader için 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 beyan karşılık gelen elemanı işlevi sadece SAFEARRAY * (ya da LPSAFEARRAY) argüman alır.

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

İşte yöntemin gövdesi. Ayrıca dahil kısırlık için bir yardımcı işlevi 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 komut dizisinden dizi dizisini SAFEARRAY yöntemine nasıl geçirebilirim ? bir örnek gönderir misiniz IDL bağlamında SAFEARRAY ve SAFEARRAY C/C++ struct arasındaki farklar hakkında yorum için –

8

gelecek okuyucular tarafından referans olarak yukarıdaki yanıtlar ekleme: IDL , SAFEARRAY(...) bir dizi tanımlayıcısı için bir işaretçi anlamına gelir. Ancak C++ 'da, SAFEARRAY bir dizi tanıtıcısı anlamına gelir. Yani IDL'nin SAFEARRAY(...) gerçekten C++ 's SAFEARRAY * olduğunu. Bu beni hiç sona erdirmedi. İşleri daha da ilginç hale getirmek için, VB her zaman dizileri referans olarak geçirir. Dolayısıyla VB'nin () As Long C++ 'da SAFEARRAY<int32_t> ** olduğunu. (Aslında, bir şablon parametresi olarak türünü belirtmenize izin veren bir yaygın kullanılan başlık olup olmadığını bilmiyorum, ancak açıklık için ekledim.)

+0

+1 – meklarian

İlgili konular