2011-12-19 60 views
8

我正在使用具有返回VARIANTSAFEARRAYBSTR s的函數的COM對象庫。我如何顯示這個VARIANT實例的值並將其保存在TStringList?我試圖找到沒有明確答案的網絡。如何顯示來自VARIANT的具有SAFEARRAY的BSTR的值

我嘗試沒有成功如下:

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

回答

4

您可以使用TWideStringDynArray,讓德爾福做轉換:

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; 

當你調用此方法BSTRs你變SAFEARRAY這將是自動轉換爲TWideStringDynArray。不兼容的變體將導致運行時錯誤EVariantInvalidArgError

要檢查的Variant擁有BSTR的安全數組,你可以這樣做:

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 

,如果你是通過後期綁定(CreateOleObject)創建ComFunction你應該使用:

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

如何顯示來自此VARIANT實例的值並將其保存在TStringLi中ST?

的COM VARIANT結構有parraypparray數據成員是指向一個SAFEARRAY,例如:

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

的VCL Variant類,在另一方面,有一個LPSAFEARRAY轉換運算符定義,所以你可以直接分配它(但只有在Variant.VType字段沒有varByRef標誌存在的情況下),例如:

Variant V; 
LPSAFEARRAY sa = V; 

無論哪種方式,一旦你有SAFEARRAY指針,使用安全數組API來訪問BSTR值,例如:

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;

你根本不需要這些。 VCL Variant類將自身初始化爲空白狀態,並且不需要分配VType,因爲您之後立即爲整個Variant分配新值。

V = ComFunction-> GetValues(); // < < < < ----- V爲空

如果V是空的,則是GetValues()返回空Variant開始。

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

​​是AnsiString&引用,而不是wchar_t*指針。到VCL Variant(不是一個COM VARIANT)轉換爲String,只是將其指定爲-是,讓RTL工作了詳細爲您:

String mystr = V; 
相關問題