表单关闭时 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 访问冲突的主要内容,如果未能解决你的问题,请参考以下文章

Adobe Reader自动更新成Adobe Acrobat Reader DC下载的安装文件存放在哪里的?

Adobe acrobat reader 的最新版本是啥 win7 64位的

centos 安装 acrobat Reader之后

Adobe Reader来填写的表单无法保存,我怎么做pdf表单才能使别人可以用Adobe Reader来填写的表单能保存

最好用的PDF阅读器—Acrobat Reader DC 2021 for mac支持m1

acrobat reader哪个版本好用