2011-12-19 8 views
8

Tôi đang làm việc trên thư viện đối tượng COM có hàm trả về VARIANT với số SAFEARRAY của BSTR s. Làm thế nào tôi có thể hiển thị các giá trị từ ví dụ VARIANT này và lưu nó vào trong một số TStringList? Tôi đã thử tìm kiếm trên mạng mà không có câu trả lời rõ ràng.Cách hiển thị giá trị từ VARIANT bằng SAFEARRAY của BSTR

Tôi đã thử các sau đây không có thành công:

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

Trả lời

4

Bạn có thể sử dụng TWideStringDynArray và để Delphi làm việc chuyển đổi:

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; 

Khi bạn gọi này với Variant SAFEARRAY lại BSTRs nó sẽ được đã tự động chuyển đổi thành TWideStringDynArray. Biến thể không tương thích sẽ gây ra lỗi thời gian chạy EVariantInvalidArgError.

Để kiểm tra xem một biến thể nắm giữ một mảng an toàn của BSTR bạn có thể làm điều này:

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 

nếu bạn đang tạo ComFunction qua vào cuối ràng buộc (CreateOleObject), bạn nên sử dụng:

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

Làm cách nào tôi có thể hiển thị các giá trị từ cá thể VARIANT này và lưu nó vào trong TStringLi st?

COM VARIANT struct có parraypparray thành viên dữ liệu là con trỏ đến một SAFEARRAY, ví dụ:

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

Lớp VCL Variant, mặt khác, có một nhà điều hành LPSAFEARRAY chuyển đổi được xác định, do đó bạn có thể chỉ định trực tiếp (nhưng chỉ khi trường Variant.VType không có cờ hiện tại là varByRef), ví dụ:

Variant V; 
LPSAFEARRAY sa = V; 

Dù bằng cách nào, một khi bạn có con trỏ SAFEARRAY, sử dụng API SAFEARRAY để truy cập BSTR giá trị, ví dụ:

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;

Bạn không cần gì cả. Lớp VCL Variant tự khởi tạo thành trạng thái trống và không cần gán VType vì bạn đang gán giá trị mới cho toàn bộ số Variant ngay sau đó.

V = ComFunction-> GetValues ​​(); // < < < < ----- V là trống

Nếu V là trống rỗng, sau đó GetValues() được trả lại một trống Variant để bắt đầu với.

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

TVarData::VString là một AnsiString& tham khảo, không phải là một con trỏ wchar_t*. Để chuyển đổi một VCL Variant (không phải là một COM VARIANT) vào một String, chỉ cần gán nó như nó vốn có và để cho các RTL hoạt động ra các chi tiết cho bạn:

String mystr = V;