2011-12-19 10 views
8

Sto lavorando su una libreria di oggetti COM con una funzione che restituisce un VARIANT con un SAFEARRAY di BSTR s. Come posso visualizzare i valori da questa istanza VARIANT e salvarlo in uno TStringList? Ho provato a cercare in rete senza una risposta chiara.Come visualizzare valori da un VARIANT con SAFEARRAY di BSTR

ho provato la seguente senza successo:

Variant V; 
String mystr; 

VarClear(V); 
TVarData(V).VType = varOleStr; 
V = ComFunction->GetValues(); //<<<<----- V is empty 
mystr = (wchar_t *)(TVarData(V).VString); 
Memo1->Lines->Add(mystr); 
VarClear(V); 

risposta

4

È possibile utilizzare TWideStringDynArray e lasciare che Delphi fare la conversione:

procedure LoadStringsFromVariant(const Values: TWideStringDynArray; Strings: TStrings); 
var 
    I: Integer; 
begin 
    Strings.BeginUpdate; 
    try 
    for I := Low(Values) to High(Values) do 
     Strings.Add(Values[I]); 
    finally 
    Strings.EndUpdate; 
    end; 
end; 

Quando si chiama questo con il vostro Variant matrice protetta di BSTR sarà convertito in TWideStringDynArray automaticamente. Una variante incompatibile causerà l'errore di runtime EVariantInvalidArgError.

Per verificare se una Variante detiene una matrice sicura di BSTR si può fare questo:

IsOK := VarIsArray(V) and (VarArrayDimCount(V) = 1) and (VarType(V) and varTypeMask = varOleStr); 
4
uses ActiveX; 

var 
    VSafeArray: PSafeArray; 
    LBound, UBound, I: LongInt; 
    W: WideString; 
begin 
    VSafeArray := ComFunction.GetValues(); 
    SafeArrayGetLBound(VSafeArray, 1, LBound); 
    SafeArrayGetUBound(VSafeArray, 1, UBound); 
    for I := LBound to UBound do 
    begin 
    SafeArrayGetElement(VSafeArray, I, W); 
    Memo1.Lines.Add(W); 
    end; 
    SafeArrayDestroy(VSafeArray); // cleanup PSafeArray 

se si sta creando ComFunction via vincolante tardi (CreateOleObject) si dovrebbe usare:

var 
    v: Variant; 
v := ComFunction.GetValues; 
for i := VarArrayLowBound(v, 1) to VarArrayHighBound(v, 1) do 
begin 
    W := VarArrayGet(v, [i]); 
    Memo1.Lines.Add (W); 
end; 
2

Come visualizzare i valori da questa istanza VARIANT e salvarlo in un TStringLi st?

Il COM VARIANT struttura ha parray e pparray membri dati che sono puntatori a un SAFEARRAY, per esempio:

VARIANT V; 
LPSAFEARRAY sa = V_ISBYREF(&V) ? V_ARRAYREF(&V) : V_ARRAY(&V); 

La classe VCL Variant, d'altra parte, ha un operatore LPSAFEARRAY conversione definito, in modo da poterlo assegnare direttamente (ma solo se il campo Variant.VType non ha il flag varByRef presente), ad esempio:

Variant V; 
LPSAFEARRAY sa = V; 

In entrambi i casi, una volta che si ha il puntatore SAFEARRAY, utilizzare l'API SafeArray per accedere ai valori BSTR, ad esempio:

bool __fastcall VariantToStrings(const Variant &V, TStrings *List) 
{ 
    // make sure the Variant is holding an array 
    if (!V_ISARRAY(&V)) return false; 

    // get the array pointer 
    LPSAFEARRAY sa = V_ISBYREF(&V) ? V_ARRAYREF(&V) : V_ARRAY(&V); 

    // make sure the array is holding BSTR values 
    VARTYPE vt; 
    if (FAILED(SafeArrayGetVartype(sa, &vt))) return false; 
    if (vt != VT_BSTR) return false; 

    // make sure the array has only 1 dimension 
    if (SafeArrayGetDim(sa) != 1) return false; 

    // get the bounds of the array's sole dimension 
    LONG lBound = -1, uBound = -1; 
    if (FAILED(SafeArrayGetLBound(sa, 0, &lBound))) return false; 
    if (FAILED(SafeArrayGetUBound(sa, 0, &uBound))) return false; 

    if ((lBound > -1) && (uBound > -1)) 
    { 
     // access the raw data of the array 
     BSTR *values = NULL; 
     if (FAILED(SafeArrayAccessData(sa, (void**)&values))) return false; 
     try 
     { 
      List->BeginUpdate(); 
      try 
      { 
       // loop through the array adding the elements to the list 
       for (LONG idx = lBound; l <= uBound; ++idx) 
       { 
        String s; 
        if (values[idx] != NULL) 
         s = String(values[idx], SysStringLen(values[idx])); 
        List->Add(s); 
       } 
      } 
      __finally 
      { 
       List->EndUpdate(); 
      } 
     } 
     __finally 
     { 
      // unaccess the raw data of the array 
      SafeArrayUnaccessData(sa); 
     } 
    } 

    return true; 
} 

VarClear (V); TVarData (V) .VType = varOleStr;

Non hai bisogno di quelli a tutti. La classe VCL Variant si inizializza in uno stato vuoto e non è necessario assegnare lo VType poiché si assegna immediatamente un nuovo valore all'intero Variant.

V = ComFunction-> GetValues ​​(); // < < < < ----- V è vuoto

Se V è vuota, allora GetValues() restituisce un vuoto Variant per cominciare.

mystr = (wchar_t *) (TVarData (V) .VString);

TVarData::VString è un riferimento AnsiString&, non un puntatore wchar_t*. Per convertire un VCL Variant (non un COM VARIANT) per un String, basta assegnarlo così com'è e lasciare che il RTL funziona dettaglio per voi:

String mystr = V; 
Problemi correlati