我有Delphi 2006客户端应用程序。此客户端从COM服务器接收Olevariant类型数据。功能是:
procedure OnLimitsChanged(var SymbolsChanged: {??PSafeArray}OleVariant);
此函数返回一个字符串数组。我无法从delphi中读取OleVariant类型的数据。
从Excel VBA开始工作:
Private Sub g_Realtime_OnLimitsChanged(SymbolsChanged() As String)
Dim i%
Dim Salir As Boolean
If UBound(SymbolsChanged) <> -1 Then
i = 0: Salir = False
While Not Salir
If SymbolsChanged(i) = Simbolo Then
LlamarALimites
Salir = True
Else
i = i + 1
If i > UBound(SymbolsChanged) Then Salir = True
End If
Wend
End If
End Sub
我尝试将OleVariant转换为Psafearray ......
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject;
var ArrayTicks : Olevariant);
var
Data : pSafeArray;
i,iLow, iHigh : Integer;
value : wideString;
begin
Data:=PSafeArray(TVarData(ArrayTicks).VArray);
SafeArrayGetLBound(Data,1,iLow);
SafeArrayGetUBound(Data,1,iHigh);
for i:=iLow to iHigh do
begin
SafeArrayGetElement(Data,i,Value);
Showmessage(Value);
end;
但我收到的除了这一行:
SafeArrayGetLBound(Data,1,iLow);
调试器故障通知
项目...出现错误消息:'0x751de18c的访问冲突:读取地址0xabababab'。进程停止器。使用步骤或运行继续
非常感谢任何建议和意见。
答案 0 :(得分:4)
RTL具有VarArrayAsPSafeArray()
功能,可以从PSafeArray
正确提取(Ole)Variant
:
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : OleVariant);
var
Data : PVarArray; // RTL's version of PSafeArray
//...
begin
Data := VarArrayAsPSafeArray(ArrayTicks);
//...
end;
如果(Ole)Variant
不包含数组,则会引发异常。或者您可以使用VarIsArray()
手动检查它:
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : OleVariant);
var
Data : PVarArray;
//...
begin
if not VarIsArray(ArrayTicks) then Exit;
Data := VarArrayAsPSafeArray(ArrayTicks);
//...
end;
话虽如此,(Ole)Variant
内置了对访问PSafeArray
元素数据的支持,因此您不需要直接访问PSafeArray
(除非您需要额外的性能提升,在这种情况下,您需要在访问其数据之前自己验证PSafeArray
:
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : Olevariant);
var
i : Integer;
value : String;
begin
if not VarIsArray(ArrayTicks) then Exit;
for i := VarArrayLowBound(ArrayTicks, 1) to VarArrayHighBound(ArrayTicks, 1) do
begin
Value := ArrayTicks[i];
ShowMessage(Value);
end;
答案 1 :(得分:2)
RTL让function访问Varant
数组作为SAFEARRAY
:
function VarArrayAsPSafeArray(const V: Variant): PSafeArray;
我想记录如何反过来。
在Delphi中,Variant
是一个不透明的blob。但在内部它实际上是TVarData
结构(又称Windows VARIANT
结构)。变体可以包含不同类型的数据。您可以通过VType
成员指明哪种类型。 VType
成员的值告诉您如何解释结构的其余部分:
32位整数(VT_I4
)
VType: Word = VT_I4;
// 3 VInteger: Integer;
IUnknown界面(VT_UNKNOWN
)
VType: Word = VT_UNKNOWN;
// 13 VUnknown: Pointer;
//实际上是IUnknown BSTR(Delphi中的WideString)
VType: Word = VT_BSTR;
// 8 VOleStr: PWideChar;
在变量是32位整数的SAFEARRAY的情况下:
VType: Word = (VT_ARRAY or VT_I4);
VArray: PVarArray;
然后VArray
指向SAFEARRAY
结构:
VType: Word = (VT_ARRAY or VT_I4);
VArray: PVarArray;
cDims: Word;
fFeatures: Word;
cbElements: LongWord;
cLocks: LongWord;
pvData: Pointer;
rgsabound: array[0..0] of TSafeArrayBound;
有时候,特别是在与COM或.NET交互的时候:
PSafeArray
,PSafeArray
。如果使用Delphi的函数创建变量数组,则可以轻松地构造SafeArray
。 Delphi负责创建你的“变体数组”实际存在的底层SafeArray。
但我们想要走另一条路;我们得到一个PSafeArray
,我们希望将它包含在Delphi Variant 变量中,以便它处理所有的丑陋和生命周期。
assemblies: PSafeArray;
assemblies := DefaultAppDomain.GetAssemblies;
我们如何处理指向SAFEARRAY
?
function PSafeArrayToVariant(psa: PSafeArray): OleVariant;
begin
TVarData(v).VType = (VT_ARRAY or VT_xxxx);
TVarData(v).VArray := PVarArray(psa);
end;
除了我们需要知道SafeArray包含的内容之外;我们需要在上面的代码中填写 VT_xxxx 。
幸运的是,SAFEARRAY结构的其中一个成员告诉VType数组的成员是什么:
fFeatures: Word;
VT_BSTR
)VT_UNKNOWN
)数组VT_DISPATCH
)VT_VARIANT
)function SafeArrayGetVartype(psa: PSafeArray): TVarType; safecall; external 'OleAut32.dll';
function PSafeArrayToVariant(psa: PSafeArray): OleVariant;
var
features: Word;
vt: TVarType;
const
FADF_HAVEVARTYPE = $80;
begin
features := psa^.fFeatures;
if (features and FADF_UNKNOWN) = FADF_UNKNOWN then
vt := VT_UNKNOWN
else if (features and FADF_DISPATCH) = FADF_DISPATCH then
vt := VT_DISPATCH
else if (features and FADF_VARIANT) = FADF_VARIANT then
vt := VT_VARIANT
else if (features and FADF_BSTR) <> 0 then
vt := VT_BSTR
else if (features and FADF_HAVEVARTYPE) <> 0 then
vt := SafeArrayGetVartype(psa)
else
vt := VT_UI4; //assume 4 bytes of *something*
TVarData(Result).VType := VT_ARRAY or vt;
TVarData(Result).VArray := PVarArray(psa);
end;