2011-12-19 10 views
8

Estoy trabajando en una biblioteca de objetos COM con la función que devuelve VARIANT con SAFEARRAY de BSTR s. ¿Cómo puedo mostrar los valores de esta instancia de VARIANT y guardarla dentro de un TStringList? Intenté buscar en la red sin una respuesta clara.Cómo mostrar valores de un VARIANT con un SAFEARRAY de BSTRs

He intentado lo siguiente sin éxito:

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

Respuesta

4

Puede utilizar TWideStringDynArray y dejar Delphi hacer la conversión:

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; 

Cuando se llama a esto con su safearray Variante de BSTR que será convertido a TWideStringDynArray automáticamente. Una variante incompatible causará el error de tiempo de ejecución EVariantInvalidArgError.

para comprobar si una variante tiene una matriz segura de BSTR se puede hacer esto:

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 

si está creando ComFunction a través de enlace en tiempo (CreateOleObject) se debe utilizar:

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

¿Cómo puedo mostrar los valores de esta instancia VARIANT y guardarlos dentro de una TStringLi? ¿S t?

El COM VARIANT estructura tiene parray y pparray miembros de datos que son punteros a un SAFEARRAY, por ejemplo:

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

La clase VCL Variant, por el contrario, tiene un operador LPSAFEARRAY conversión definido, por lo que puede asignarlo directamente (pero solo si el campo Variant.VType que no tiene el indicador varByRef presente, es decir), por ejemplo:

Variant V; 
LPSAFEARRAY sa = V; 

De cualquier manera, una vez que tenga el puntero SAFEARRAY, utilice la API SafeArray acceder a los valores de BSTR, por ejemplo:

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;

No es necesario en absoluto. La clase VCL Variant se inicializa en un estado en blanco, y no hay necesidad de asignar VType ya que está asignando un nuevo valor a Variant inmediatamente después.

V = ComFunction-> GetValues ​​(); // < < < < V ----- está vacía

Si V está vacío, entonces GetValues() devuelve un vacío Variant para empezar.

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

TVarData::VString es una referencia AnsiString&, no un puntero wchar_t*. Para convertir un VCL Variant (no es un COM VARIANT) a un String, simplemente asignarla como está y dejar que el RTL funciona el detalle para usted:

String mystr = V; 
Cuestiones relacionadas