表单关闭时 Acrobat Reader ActiveX 访问冲突

Posted

技术标签:

【中文标题】表单关闭时 Acrobat Reader ActiveX 访问冲突【英文标题】:Acrobat Reader ActiveX Access Violation on form close 【发布时间】:2016-06-17 16:00:57 【问题描述】:

我的 Delphi 应用程序有一个使用 Acrobat Reader ActiveX 控件查看 pdf 的表单。当我使用控件的功能(LoadFile、gotoNextPage、gotoPreviousPage、gotoFirstPage、gotoLastPage),然后关闭表单时,我收到以下错误:“地址 6AF5703C 的访问冲突。读取地址 6AF5703C”。当我运行应用程序,但不使用控件的功能,然后关闭窗体,应用程序将退出而没有错误。

有人知道此问题的修复或解决方法吗?

我的应用是使用 Delphi 5(旧版应用)编写的。我已安装 Adob​​e Acrobat Reader DC v15.016.20045。

【问题讨论】:

自从我使用 TPDF 对象(PDFLib_Tlb.Pas 的导入)以来已经有好几年了,我无法让它在 Win10 下运行,但是您之前是否尝试过将 TPDF 实例的 FIntf 成员设置为 Nil你关闭你的表格?那将是我要尝试的第一件事。顺便说一句,尽管有“F”前缀,但 FIntf 是公共成员。 与现代版 Delphi(包括 DX10)类似。我花了几个小时试图找到解决方案,但没有成功。重建和修改 Adob​​eTlb 文件没有帮助。我还没有尝试来自@MartynA 的解决方案 :) 到目前为止,我在 try except 块中发布 Adob​​e 控件的代码 @Zam,我安装了当前版本的 Reader DC 并且遇到了同样的问题,到目前为止没有解决方案。 Active X 不再有公开的 FIntf 成员,所以不要理会我的建议。 【参考方案1】:

正如我在对 Zam 的评论中所说,使用今天下载的 Acrobat Reader DC 的当前版本,我遇到了与您完全相同的错误。

请尝试此代码并让我们知道它是否可以为您避免错误,因为它确实对我有用,并且在 FormClose 或之后没有 AV。

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  Ref : Integer;
begin
  Ref := AcroPdf1.ControlInterface._AddRef;
  AcroPdf1.Src := '';
  AcroPdf1.Free;
  AcroPdf1 := Nil;
end;

这是我的 FormCreate,其中包含我唯一的其他代码。

procedure TForm1.FormCreate(Sender: TObject);
begin
  AFileName := 'd:\aaad7\pdf\printed.pdf';
  AcroPdf1.src := AFileName;
  AcroPdf1.setZoom(200);  // <- this line is to exercise the
    // ControlInterface to provoke the AV on shutdown
end;

我完全不知道为什么我的FormClose 避免了 AV 问题,而且在其他人这么说之前,是的,我也觉得它很生气!几乎没有什么值得称为“解决方案”的东西,但也许它会为比我更了解 COM 和 Ole 控件的人提供一个合适的解决方案。

我最初包含Ref := AcroPdf1._AddRef 只是作为一个实验。我注意到在它之后,Ref 的值是 9。在 AcroPdf1.Src := '' 之后,在调试器评估器中调用 AcroPdf1._Release 返回值 4。我正要查看是否通过强制 RefCount 向下来避免 AV反复调用_Release,然后是Presto!,在我第一次跟踪FormClose 退出后,没有AV。

更新:我没有对以下内容进行详尽的测试,但这个简化的FormClose 无论如何也避免了我系统上的 AV:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  Ref : Integer;
begin
  Ref := AcroPdf1.ControlInterface._AddRef;
end;

显然,省略对Ref 的分配应该没有任何区别。

顺便说一句,我在 64 位 Win10 上使用 Delphi 10 Seattle。

【讨论】:

这会导致 TAcroPdf 实例的内存泄漏吗?释放对象引用时,可能会忽略接口的递增引用计数 (_AddRef)。在释放对象引用之前不要调用 _Release。当我这样做时,我再次遇到访问冲突。 这在我的 Delphi 6 旧版应用程序上完美运行。就我而言,只有一个 TAcroPDF 对象,在应用启动时创建并在关闭时销毁。 很好,+1。 _AddRef() 调用以 Acrobat Reader 进程停留(并消耗内存和一些 CPU 周期)直到父进程终止为代价来修复访问冲突。然后操作系统将清理所有内容。 谢谢,完美运行 你拯救了我的一天。谢谢!【参考方案2】:

更好的解决方案是在“AcroPDFLib_Tlb.pas”中编辑 TPDF 对象

只需在代码中添加适当的析构函数即可释放 OLE 对象:

声明

Type
  TAcroPDF = class(TOleControl)
  ...
  public
    destructor Destroy; override; // <- New Line
  ...
  end;

实施

destructor TAcroPDF.Destroy;
begin
 FIntf := NIL;
 inherited;
end;

【讨论】:

以上是关于表单关闭时 Acrobat Reader ActiveX 访问冲突的主要内容,如果未能解决你的问题,请参考以下文章