【问题标题】:Invalid Variant Operation Exception Trying to Access OleVariant in Delphi - Works in C#尝试在 Delphi 中访问 OleVariant 的无效变体操作异常 - 在 C# 中工作
【发布时间】:2010-10-03 18:54:49
【问题描述】:

我正在尝试访问来自 ActiveX 库的回调中的 OleVariant。

这是事件处理程序在 TLB 中的定义:

procedure(ASender: TObject; var structQSnap: {??structVTIQSnap}OleVariant) of object;

下面是 TLB 中 structVTIQSnap 的定义:

structVTIQSnap = packed record
  bstrSymbol: WideString;
  bstrListingExch: WideString;
  bstrLastExch: WideString;
  fLastPrice: Double;
  nLastSize: Integer;
  bstrBbo: WideString;
  bstrBidExch: WideString;
  fBidPrice: Double;
  nBidSize: Integer;
  bstrAskExch: WideString;
  fAskPrice: Double;
  nAskSize: Integer;
  fHighPrice: Double;
  fLowPrice: Double;
  fOpenPrice: Double;
  fClosePrice: Double;
  nCumVolume: Integer;
  bstrTradeCondition: WideString;
  nQuoteCondition: Integer;
  bstrCompanyName: WideString;
  f52WeekHigh: Double;
  f52WeekLow: Double;
  fEps: Double;
  nSharesOutstanding: Integer;
  nSpCode: Integer;
  fBeta: Double;
  bstrExDivDate: WideString;
  nDivFreq: Integer;
  fDivAmt: Double;
  nAvgVolume: Integer;
  bstrCusip: WideString;
  fVwap: Double;
  bstrUpdateTime: WideString;
  bstrExch: WideString;
  nSharesPerContract: Integer;
end;

它编译得很好,但是每次我尝试访问 bstrSymbol 时,我都会得到一个“无效的变体操作”:

 procedure TForm1.HandleVTIQuoteSnap(ASender: TObject; var structQSnap: OleVariant);
 var
    symbol: WideString;
 begin
    symbol := structQSnap.bstrSymbol; // this line causes the exception
 end;

如何在 Delphi 中访问 structQSnap 及其属性?

在 C# 中,此函数适用于事件处理程序:

    void vtiQ_OnVTIQSnap(ref vtiLib.structVTIQSnap structQSnap)
    {
        MessageBox.Show("Got qsnap for " + structQuoteSnap.bstrSymbol);            
    }

有什么想法吗?

【问题讨论】:

  • 你确定 structQSnap Null 吗?

标签: c# delphi com ole


【解决方案1】:

我认为 Delphi 的 ActiveX 导入向导不知道如何正确处理 structVTIQSnap 类型(这似乎是一个记录),而只是使用默认的 OleVariant。 生成的 ..._TLB.pas 文件中是否有名为 structVTIQSnap 或类似的类型声明?尝试使用它而不是 OleVariant,例如

procedure (ASender: TObject; var structQSnap: structVTIQSnap) of object;

该类型可能会被声明为“打包记录”。

【讨论】:

  • 嗯。我可以通过这种方式访问​​ bstrSymbol。进步。我现在正在访问 bstrSymbol 旁边的其他一些变量,这是一个双精度变量 - 我得到 -1.97202464873328E111 并且我期望的数字应该在 40 左右。有什么想法吗?
  • 也许 ActiveX 控件使用了不同的记录对齐方式。尝试使用“packed”指令,或者如果有,请尝试将其注释掉并在编译器选项中尝试不同的记录字段对齐值(或使用指令 {$A2}、{$A4})。
  • 我刚刚从类型定义中删除了“packed”,它似乎可以工作。谢谢!!
  • @TOndrej:所以基本上,Delphi在导入组件时创建TLB文件时没有正确导入Type库吗?这是类型库导入器的缺陷吗?必须编辑 TLB 文件是否常见?
  • 是的,完全正确。对于一些更复杂的类型,导入器只需生成 OleVariant,您必须手动更正声明。
【解决方案2】:

您可以尝试将 structQSnap 类型转换为指向此结构的指针。类似的东西

PstructVTIQSnap = ^structVTIQSnap;
structVTIQSnap = packed record
   bstrSymbol: WideString;
   // other stuff...
end;

procedure TForm1.HandleVTIQuoteSnap(ASender: TObject;
  var structQSnap: OleVariant);
var
  ps: PstructVTIQSnap;
  symbol: WideString;
begi
  ps := PstructVTIQSnap(structQSnap.VPointer^);
  symbol := ps.bstrSymbol;
  ...
end;

但我不明白的是:我从 C# 代码中的 ref 中得知该结构应该被编组两次,一次从库到回调,第二次回到图书馆。这意味着需要在 VType 中设置 varByRef 标志($4000),但是您在评论中给出的值(3484)太小了?

【讨论】:

  • 我又运行了几次,VType 每次都显示不同的值。其他的是 32420、13772、55340,而我刚刚运行了 3 次。这一行给出: 需要的指针类型 ps := PstructVTIQSnap(structQSnap.VPointer^);
  • 这可能是因为它根本不是 Variant;看我的回答。
【解决方案3】:

尝试查看 TVarData(structQSnap).VType 中返回的内容?

也许它会起作用:

 var
   symbol: WideString;
   rec: structVTIQSnap;
 begin
    rec := structVTIQSnap(structQSnap);
    symbol := rec.bstrSymbol; 
 end;

【讨论】:

  • "VType: 3484" 是我这样做时返回的内容: ShowMessage('VType: ' + IntToStr(Integer(TVarData(structQSnap).VType)));
  • structVTIQSnap(structQSnap);说“无效的类型转换”
  • 一些奇怪的 VType 值.. 尝试查看 TVarData.VType 的 system.pas 声明,我的文件(来自 Delphi6)不包含此值.. 你也可以尝试如下代码:rec: = structQSnap;
  • rec := structQSnap;说“不兼容的类型”。我在 system.pas 中找不到任何接近该 VType 的东西。
【解决方案4】:

我不确定您为什么将“structVTIQSnap”视为“OleVariant”。对我来说似乎是一个奇怪的翻译。是不是它已经以某种形式放入了 OleVariant 中,无论是作为数组还是类似的形式?

【讨论】:

  • TLB 就是这样定义事件处理程序的过程的。我只是匹配导入类型库时自动生成的内容。
猜你喜欢
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 2010-10-02
  • 2022-11-03
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多