String Delphi OleVariant到COM库中的字符串数组

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

我有Delphi2006客户端应用程序。此客户端从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
但我收到一封信,除了这一行:

 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;