String Delphi OleVariant到COM库中的字符串数组
我有Delphi2006客户端应用程序。此客户端从COM服务器接收Olevariant类型的数据。功能是:String Delphi OleVariant到COM库中的字符串数组,string,delphi,com,variant,safearray,String,Delphi,Com,Variant,Safearray,我有Delphi2006客户端应用程序。此客户端从COM服务器接收Olevariant类型的数据。功能是: procedure OnLimitsChanged(var SymbolsChanged: {??PSafeArray}OleVariant); 此函数返回一个字符串数组。我无法从delphi中读取OleVariant类型数据 在Excel VBA中,它正在工作: Private Sub g_Realtime_OnLimitsChanged(SymbolsChanged() As Str
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
但我收到一封信,除了这一行:
SafeArrayGetLBound(Data,1,iLow);
调试器错误通知项目错误消息:“0x751de18c处的访问冲突:读取地址0xabababab”。过程塞。使用步骤或运行继续
任何建议都将不胜感激。RTL有一个
vararrayaspasafearray()
函数,用于从(Ole)变体中正确提取PSafeArray
:
procedure TfmConfiguracion.RecibirNuevosTicks(ASender: TObject; var ArrayTicks : OleVariant);
var
Data : PVarArray; // RTL's version of PSafeArray
//...
begin
Data := VarArrayAsPSafeArray(ArrayTicks);
//...
end;
如果(Ole)变量
不包含数组,将引发异常。或者您可以使用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
):
RTL具有访问Varant
数组作为SAFEARRAY
的权限:
function VarArrayAsPSafeArray(const V: Variant): PSafeArray;
我想记录下如何做相反的事情
变体是一种结构
在Delphi中,变量是一个不透明的blob。但在内部,它实际上是TVarData
结构(又称Windows结构)。变量可以保存不同类型的数据。您可以通过VType
成员指示哪种类型。VType
成员的值告诉您如何解释结构的其余部分:
32位整数(VT_I4
)
- 变体
VType:Word=VT_I4代码>//3
VInteger:整数代码>
一个IUnknown接口(VT\u UNKNOWN
)
- 变体
VType:Word=VT\u未知代码>//13
VUnknown:指针代码>//实际上我不知道
一个BSTR(德尔福中又称宽字符串)
- 变体
VType:Word=VT\u BSTR代码>//8
VOleStr:PWideChar代码>
如果变量是32位整数的安全数组:
- 变体
VType:Word=(VT_数组或VT_I4)代码>
VArray:PVarArray代码>
然后VArray
指向一个SAFEARRAY
结构:
- 变体
VType:Word=(VT_数组或VT_I4)代码>
VArray:PVarArray代码>
cDims:Word代码>
f特性:Word代码>
cbElements:LongWord代码>
时钟:长单词代码>
pvData:指针代码>
rgsabound:TSafeArrayBound的数组[0..0]代码>
如果我们从安全阵列开始呢
有时,特别是与COM或.NET交互时,您会:
- 必须提供一个
psaarray
- 或者被给予一个
psaarray
如果使用Delphi函数创建变量数组,则可以非常轻松地构造安全数组。Delphi在创建“变体数组”实际所在的底层SafeArray方面做了大量工作
但我们想走另一条路;我们得到了一个PSafeArray
,我们想把它封装在一个DelphiVariant变量中,这样它就可以处理所有的丑陋和一生
assemblies: PSafeArray;
assemblies := DefaultAppDomain.GetAssemblies;
我们如何处理指向安全阵列的指针
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是什么:
f特性:Word代码>
- FADF\u BSTR:它是一个BSTR数组(
VT\u BSTR
)
- FADF\u UNKNOWN:它是IUnknown的数组(
VT\u UNKNOWN
)
- FADF_调度:它是IDispatch的数组(
VT_调度
)
- FADF_变体:它是一个变体数组(
VT_变体
)
- FADF_HAVEVARTYPE:您可以使用
最终功能
函数SafeArrayGetVartype(psa:PSafeArray):TVarType;安全呼叫;外部“OleAut32.dll”;
功能PSafeArray变异(psa:PSafeArray):油酸变异;
变量
特点:字;
vt:TVarType;
常数
FADF_HAVEVARTYPE=80美元;
开始
特点:=psa^.F特性;
如果(特征和FADF_未知)=FADF_未知,则
vt:=vt_未知
否则,如果(功能和FADF_分派)=FADF_分派,则
vt:=vt\U调度
否则,如果(特征和FADF_变体)=FADF_变体,则
vt:=vt_变量
否则,如果(功能和FADF_BSTR)为0,则
vt:=vt\u BSTR
否则如果(功能和FADF_HAVEVARTYPE)为0,则
vt:=SafeArrayGetVartype(psa)
其他的
vt:=vt_UI4//假设有4个字节的*某物*
TVarData(结果).VType:=VT_数组或VT;
TVarData(结果).VArray:=PVarArray(psa);
结束;
您假设ArrayTicks
是一个数组,但可能不是。为什么ArrayTicks
被var
传递?感谢您的快速响应。此函数是第三方com库。他们告诉我函数返回一个字符串数组(CStringArray到Safearray)。如果不是VarIsArray(ArrayTicks),则退出;数据:=vararrayaspasafarray(ArrayTicks)代码>不兼容类型:此行中的“PsafeArray”和“PVarArray”异常<
assemblies: PSafeArray;
assemblies := DefaultAppDomain.GetAssemblies;
function PSafeArrayToVariant(psa: PSafeArray): OleVariant;
begin
TVarData(v).VType = (VT_ARRAY or VT_xxxx);
TVarData(v).VArray := PVarArray(psa);
end;
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;