为什么`as`运算符可能会抛出讨厌的EAccessViolation而不是普通的EIntfCastError?

时间:2014-04-21 23:33:46

标签: delphi debugging ide toolsapi

我已经制作了高度实验性且不稳定的IDE插件,这会在IDE关闭时导致非常讨厌的A / V(打破最近的项目功能,grr!)。我最终将其缩小到特定的析构函数:

destructor TMyAddIn.Destroy;
begin
  {$IFDEF DEBUG}
  { BUG is here, causes A/V at shutdown }
  (BorlandIDEServices as IOTAMessageServices).AddTitleMessage('Goodbye');
  {$ENDIF}

  { ... }
  { finalizing stuff }
  { ... }

   inherited;
end;

read of address 0x00000008上发生了A / V异常。

我在问题陈述中添加了更多防御措施:

  if Assigned(BorlandIDEServices) then    { passes }
    if Supports(BorlandIDEServices, IOTAMessageServices) then   { fails }
     (BorlandIDEServices as IOTAMessageServices).AddTitleMessage('Goodbye');

...并弄清楚什么(1)指针仍然不是nil(2)QueryInterface仍然有效(3)所需的界面不再存在。鉴于一切看起来都很正常,我希望友好EIntfCastError。但为什么我有A / V呢?

1 个答案:

答案 0 :(得分:4)

我的猜测是

  1. BorlandIDEServices本身不是零,但也不再有效

  2. BorlandIDEServices有效,但其内部IOTAMessageServices实施不是。

  3. 这些可能导致read of address 0x00000008错误。

    您应该做的是在插件生命周期的早期获取IOTAMessageServices接口并保持它,这样由于引用计数它在析构函数中仍然有效,例如:

    {$IFDEF DEBUG}
    private
      MsgSvc: IOTAMessageServices;
    {$ENDIF}
    
    constructor TMyAddIn.Create;
    begin
      inherited;
    
      { ... }
      { initializing stuff }
      { ... }
    
      {$IFDEF DEBUG}
      MsgSvc := BorlandIDEServices as IOTAMessageServices;
      MsgSvc.AddTitleMessage('Hello');
      {$ENDIF}
    end;
    
    destructor TMyAddIn.Destroy;
    begin
      {$IFDEF DEBUG}
      MsgSvc.AddTitleMessage('Goodbye');
      {$ENDIF}
    
      { ... }
      { finalizing stuff }
      { ... }
    
       inherited;
    end;