如何使用SATREARRAY为BSTR的VARIANT显示值

时间:2011-12-19 07:33:05

标签: delphi c++builder bstr safearray

我正在使用一个COM对象库,其函数返回VARIANT SAFEARRAYBSTR s。如何显示此VARIANT实例中的值并将其保存在TStringList内?我试着在网上搜索没有明确的答案。

我尝试了以下但没有成功:

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

3 个答案:

答案 0 :(得分:4)

您可以使用TWideStringDynArray让Delphi进行转换:

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;

当您使用BSTR的Variant safearray调用它时,它将自动转换为TWideStringDynArray。不兼容的Variant将导致运行时错误EVariantInvalidArgError

要检查Variant是否包含BSTR的安全数组,您可以执行以下操作:

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

答案 1 :(得分: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

如果您通过后期绑定(ComFunction)创建CreateOleObject,则应使用:

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 :(得分:2)

  

如何显示此VARIANT实例的值并将其保存在TStringList中?

COM VARIANT结构包含指向parray的{​​{1}}和pparray数据成员,例如:

SAFEARRAY

另一方面,VCL VARIANT V; LPSAFEARRAY sa = V_ISBYREF(&V) ? V_ARRAYREF(&V) : V_ARRAY(&V); 类定义了Variant转换运算符,因此您可以直接指定它(但仅限于LPSAFEARRAY字段没有{ {1}}标志存在,即),例如:

Variant.VType

无论哪种方式,只要您拥有varByRef指针,请使用SafeArray API访问Variant V; LPSAFEARRAY sa = V; 值,例如:

SAFEARRAY
  

<强> VarClear(V);   TVarData(V).VType = varOleStr;

你根本不需要那些。 VCL 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; } ,因为您之后会立即为整个Variant分配新值。

  

V = ComFunction-&gt; GetValues(); //&lt;&lt;&lt;&lt; ----- V为空

如果V为空,则VType将返回空的Variant以开始。

  

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

GetValues()Variant引用,而不是TVarData::VString指针。要将VCL AnsiString&(不是COM wchar_t*)转换为Variant,只需按原样分配它,让RTL为您解决详细信息:

VARIANT