10

我设法提炼出根植于我的问题的潜在问题之一:如何在下面的单元中跟踪 OLE 自动化对象的 _AddRef / _Release 调用。

我也会回答这个答案,以防万一其他人碰到这个。

问题:使用下面的代码,为什么 WINWORD.EXE 不总是退出(有时它确实退出)。

该单位可能会进一步削减。

unit Unit2;

interface

uses
  Winapi.Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls,
  WordXP;

type
  TForm2 = class(TForm)
    WordXPFailsToQuitButton: TButton;
    procedure WordXPFailsToQuitButtonClick(Sender: TObject);
  private
    FWordApplication: TWordApplication;
  strict protected
    function GetWordApplication: TWordApplication; virtual;
    function GetWordApplication_Documents: Documents; virtual;
    procedure WordApplication_DocumentBeforeClose(ASender: TObject; const Doc: _Document; var Cancel: WordBool); virtual;
    procedure WordApplication_Quit(Sender: TObject); virtual;
    property WordApplication: TWordApplication read GetWordApplication;
    property WordApplication_Documents: Documents read GetWordApplication_Documents;
  end;

var
  Form2: TForm2;

implementation

uses
  Vcl.OleServer;

{$R *.dfm}

function TForm2.GetWordApplication: TWordApplication;
begin
  if not Assigned(FWordApplication) then
  begin
    FWordApplication := TWordApplication.Create(nil);

    FWordApplication.AutoConnect := False;
    FWordApplication.AutoQuit := False;
    FWordApplication.ConnectKind := ckNewInstance;
    FWordApplication.OnDocumentBeforeClose := WordApplication_DocumentBeforeClose;
    FWordApplication.OnQuit := WordApplication_Quit;
    FWordApplication.Connect;
  end;
  Result := FWordApplication;
end;

function TForm2.GetWordApplication_Documents: Documents;
begin
  Result := WordApplication.Documents;
  if not Assigned(Result) then
    raise EAccessViolation.Create('WordApplication.Documents');
end;

procedure TForm2.WordXPFailsToQuitButtonClick(Sender: TObject);
begin
  try
    WordApplication_Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
    WordApplication.Visible := True;
    WordApplication.ActiveDocument.Close(False, EmptyParam, EmptyParam);
  finally
    WordApplication.OnQuit := nil;
    WordApplication.OnDocumentBeforeClose := nil;
    WordApplication.AutoQuit := True;
    WordApplication.Disconnect;
    WordApplication.Free;
    FWordApplication := nil;
  end;
end;

procedure TForm2.WordApplication_DocumentBeforeClose(ASender: TObject; const Doc: _Document; var Cancel: WordBool);
begin
  FWordApplication.Disconnect;
end;

procedure TForm2.WordApplication_Quit(Sender: TObject);
begin
  FWordApplication.Disconnect;
end;

end.
4

1 回答 1

8

回答第 1 部分:

在以下事件中注释掉断开连接:

procedure TForm2.WordApplication_DocumentBeforeClose(ASender: TObject; const Doc: _Document; var Cancel: WordBool);
begin
//  FWordApplication.Disconnect;
end;

该事件将在 DocumentClose(...) 方法期间调用,然后从 FWordApplication 实例断开并删除 OLE 接口。

我还没有弄清楚哪个引用是悬空的,但这有效地使 WINWORD.EXE 在大多数情况下保持活动状态。

回答第 2 部分:

有时 WINWORD.EXE 确实退出,因为没有调用 toe WordApplication_DocumentBeforeClose 事件。原因是代码运行速度如此之快,以至于 Word 尚未完全初始化以执行事件。

于 2013-05-25T19:49:53.933 回答