Как отобразить значения из VARIANT с SAFEARRAY BSTR
Я работаю над библиотекой COM-объектов с функцией, которая возвращает VARIANT
с SAFEARRAY
из BSTR
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 ответа
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;
Ты можешь использовать 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;
Когда вы называете это своим Variant Safearray BSTR, он будет преобразован в TWideStringDynArray
автоматически. Несовместимый вариант вызовет ошибку времени выполнения EVariantInvalidArgError
,
Чтобы проверить, содержит ли Variant безопасный массив BSTR, вы можете сделать это:
IsOK := VarIsArray(V) and (VarArrayDimCount(V) = 1) and (VarType(V) and varTypeMask = varOleStr);
Как я могу отобразить значения из этого экземпляра VARIANT и сохранить его внутри TStringList?
COM VARIANT
структура имеет parray
а также pparray
члены данных, которые являются указателями на 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 SafeArray для доступа к 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);
TVarData::VString
является AnsiString&
ссылка, а не wchar_t*
указатель. Чтобы преобразовать VCL Variant
(не COM VARIANT
) к String
просто назначьте его как есть, и пусть RTL проработает детали для вас:
String mystr = V;