delphi - 为什么 `as` 运算符可能会抛出令人讨厌的 EAccessViolation 而不是正常的 EIntfCastError ?

标签 delphi debugging ide toolsapi

我制作了高度实验性且不稳定的 IDE 插件,这会在 IDE 关闭时导致极其令人讨厌的 A/V(破坏了最近的项目功能,糟糕!)。我最终将范围缩小到特定的析构函数:

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

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

   inherited;
end;

读取地址 0x00000008 时发生 A/V 异常。

我为有问题的陈述添加了更多防御措施:

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

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

最佳答案

我的猜测是

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

  2. BorlandIDEServices 有效,但其内部 IOTAMessageServices 实现无效。

这些可能会导致读取地址 0x00000008 错误。

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

{$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;

关于delphi - 为什么 `as` 运算符可能会抛出令人讨厌的 EAccessViolation 而不是正常的 EIntfCastError ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23207796/

相关文章:

Delphi子类继承

delphi - Delphi 曾经有过 foreach 循环吗?

每个项目特定的 Eclipse 断点?

java - 网格世界中的变形小动物?

ide - 如何在IntelliJ 9中包装面板输出?

delphi - 有什么方法可以改变Delphi2007 IDE中Code Insight红色 'underline'的颜色吗?

python - 如何在 IntelliJ 中打开 .ipynb 文件?

delphi - 是否有与 TIniFiles 相同的函数或单元不会保存到文件?

linux - GDB远程调试: can't stop the thread

delphi - 是否可以将语句转换为表达式?