我制作了高度实验性且不稳定的 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 呢?
最佳答案
我的猜测是
BorlandIDEServices
本身不为零,但也不再有效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/