You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi中如何检测ShellExecute打开的MS Word文档是否已关闭

Delphi检测ShellExecute启动的Word文档关闭状态实现方案

你当前调用MS Word打开RTF文档的代码如下:

ShellExecute(Handle, nil,
  PChar(ExtractFilePath(Application.ExeName)+'Data\Quotation-Terms-1.rtf'),
  nil, nil, SW_SHOWNORMAL);

ShellExecute本身不会返回启动的进程/对象句柄,无法直接感知文档关闭状态,可根据实际场景选以下两种实现方式:


方案1:进程句柄等待法(实现简单,适合单文档场景)

替换ShellExecute为ShellExecuteEx获取启动的Word进程句柄,等待进程退出后执行RTF加载逻辑。

注意:Word默认是单实例程序,直接启动会复用已打开的Word进程,导致拿到的句柄立刻失效,需要加/w启动参数强制Word启动独立新实例。

完整代码示例:

uses ShellAPI, System.Classes; // 引用对应单元

procedure TForm1.OpenRtfBtnClick(Sender: TObject);
var
  ExecInfo: TShellExecuteInfo;
  hProcess: THandle;
  DocFullPath: string;
begin
  DocFullPath := ExtractFilePath(Application.ExeName) + 'Data\Quotation-Terms-1.rtf';
  FillChar(ExecInfo, SizeOf(ExecInfo), 0);
  ExecInfo.cbSize := SizeOf(ExecInfo);
  ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
  ExecInfo.Wnd := Handle;
  ExecInfo.lpVerb := nil;
  ExecInfo.lpFile := PChar('WINWORD.EXE');
  ExecInfo.lpParameters := PChar('/w "' + DocFullPath + '"');
  ExecInfo.nShow := SW_SHOWNORMAL;

  if not ShellExecuteEx(@ExecInfo) then
  begin
    ShowMessage('调用Word失败,请检查是否安装MS Word');
    Exit;
  end;

  hProcess := ExecInfo.hProcess;
  // 开后台线程等待进程退出,避免卡主线程UI
  TThread.CreateAnonymousThread(
    procedure
    begin
      WaitForSingleObject(hProcess, INFINITE);
      CloseHandle(hProcess);
      // 同步到主线程加载RTF到控件
      TThread.Queue(nil,
        procedure
        begin
          if FileExists(DocFullPath) then
            RichEdit1.Lines.LoadFromFile(DocFullPath);
        end
      );
    end
  ).Start;
end;

该方案局限:强制启动的独立Word实例被完全关闭时才会触发加载,如果用户在这个实例中打开了其他文档,需要等所有文档关闭、Word进程退出才会执行后续逻辑。


方案2:COM对象轮询法(检测精准,适配多文档场景)

通过Word COM接口直接监听目标文档的打开状态,不受Word多实例、多开文档影响,只要指定的RTF文档被关闭就触发加载逻辑,是更可靠的方案。
完整代码示例:

uses ComObj, System.Classes;

type
  TMainForm = class(TForm)
    RichEdit1: TRichEdit;
    OpenRtfBtn: TButton;
    procedure OpenRtfBtnClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    FWordApp: OleVariant;
    FTargetDocPath: string;
  public
  end;

procedure TMainForm.OpenRtfBtnClick(Sender: TObject);
begin
  FTargetDocPath := ExtractFilePath(Application.ExeName) + 'Data\Quotation-Terms-1.rtf';
  try
    // 优先绑定已运行的Word实例,不存在则新建
    try
      FWordApp := GetActiveOleObject('Word.Application');
    except
      FWordApp := CreateOleObject('Word.Application');
    end;
    FWordApp.Visible := True;
    // 打开目标RTF文档
    FWordApp.Documents.Open(FileName := FTargetDocPath, Visible := True);

    // 后台线程轮询文档状态
    TThread.CreateAnonymousThread(
      procedure
      var
        I: Integer;
        DocExists: Boolean;
      begin
        while True do
        begin
          Sleep(800); // 轮询间隔可根据需要调整
          DocExists := False;
          try
            if VarIsEmpty(FWordApp) then Break;
            // 遍历所有打开的Word文档,检查目标文档是否还存在
            for I := 1 to FWordApp.Documents.Count do
            begin
              if SameText(FWordApp.Documents[I].FullName, FTargetDocPath) then
              begin
                DocExists := True;
                Break;
              end;
            end;
            if not DocExists then Break;
          except
            // Word进程被强制结束时直接退出循环
            Break;
          end;
        end;
        // 回到主线程加载RTF
        TThread.Queue(nil,
          procedure
          begin
            if FileExists(FTargetDocPath) then
              RichEdit1.Lines.LoadFromFile(FTargetDocPath);
            FWordApp := Unassigned;
          end
        );
      end
    ).Start;
  except
    on E: Exception do
      ShowMessage('启动Word失败:' + E.Message);
  end;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // 窗体关闭时释放COM对象,避免残留进程
  if not VarIsEmpty(FWordApp) then FWordApp := Unassigned;
end;

该方案优势:不需要强制新建Word实例,即使用户同时打开多个Word文档、编辑其他文件,只要目标RTF被关闭就会立刻触发加载逻辑,符合绝大多数业务场景需求。


内容的提问来源于stack exchange,提问作者Issam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 09:18:27