【问题标题】:Determine when an Excel workbook has closed with Delphi使用 Delphi 确定 Excel 工作簿何时关闭
【发布时间】:2010-11-21 00:45:22
【问题描述】:

以下代码打开由 'app' 参数指定的文档,然后等待特定文档关闭。这适用于所有文档类型,除非您打开 Excel 工作簿并打开另一个 Excel 工作簿。代码认为文档实际上仍处于打开状态时已关闭。我将如何解决这个问题?

procedure RunAppAndWAit( a: TApplication; app, par, verb: string);
var
  seinfo: tshellexecuteinfo;
  exitcode: dword;
begin
  fillchar( seinfo, sizeof( seinfo), 0);
  seinfo.cbsize := sizeof( tshellexecuteinfo);

  with seinfo do
  begin
    fmask := see_mask_nocloseprocess;
    wnd := a.Handle;
    lpfile := pchar( app);
    lpDirectory := pchar( ExtractFileDir( app));
    lpParameters := pchar( par);
    lpVerb := pchar( verb);

    nshow := sw_shownormal;
  end;

  if ShellExecuteEx( @seinfo) then
  begin
    repeat
      a.ProcessMessages;
      GetExitCodeProcess( seinfo.hprocess, exitcode);
    until ( exitcode <> still_active) or a.terminated;
  end
  else
    sshowmessage( 'Unable to open ' + app);
end;

【问题讨论】:

    标签: delphi excel


    【解决方案1】:

    您的尝试仅适用于在启动文档的同一进程中打开文档的应用程序。

    许多应用程序不再以这种方式工作:启动文档的进程会将文档传递给显示/编辑它的另一个进程,然后启动进程终止。

    您将需要找到一个支持事件回调的 API(在本例中为 Excel,很可能是 Excel 公开的 COM API),以便您更仔细地观察 Excel 对您的文档所做的实际操作。

    使用此 API 打开您的文档,注册一个在文档关闭时调用的事件,等待该事件,然后关闭。

    【讨论】:

    • 我最终决定的是定期尝试打开文件。如果发生异常,那么它还没有关闭。它有效,但我现在觉得有点脏......
    【解决方案2】:

    这并不漂亮,并且可能不像您希望的那样可靠,但是您可以循环(或者更好的是,使用计时器事件?)调用 Windows EnumWindows 函数来查找与您期望 Excel 匹配的标题栏显示此文件。 (显然,这是一个特定于 Excel 的解决方案。)

    例如,查找包含单词“Excel”和您的文件名的标题栏,这就是 Excel 在标题栏中显示的内容。

    这种方法可能存在漏洞,使其变得脆弱。事实上,我有点犹豫要不要发布这个,因为我认为这个解决方案不是特别健壮。但是,如果您没有其他方法可以解决您的问题,这可能会起作用...

    谷歌“EnumWindows Delphi”获取示例代码。

    ...进一步思考,下面是另一种方式。正如 Jeroen 所说,您可以使用 Excel 的 API。如果您正在执行大量此类调用,则将 CreateOLEObject 和 unAssigned 赋值放在函数之外可能会减轻它的负担。 (而且你需要一些尝试...除了块,以防 Excel 不再运行等。)这个解决方案也是 Excel 特定的和笨拙的,IMO。我不知道是否有可能导致返回错误结果的情况(如文件、在 Excel 中打开的对话框?)。

    所以,基本上,我是说,这里有两种相对较弱的方法,它们是 Excel 特有的,可能并不总是有效。 (当我这样说时,我几乎宁愿删除整个帖子......但是,也许它会给你一些关于你想如何继续的想法。)

    此代码未经测试,但类似的代码过去曾为我工作过:

      uses ComObj;
    
      function FindWorkbook( Workbookname: String):boolean;
      var
        ExcelOLE: Variant;
        WorkbookNumber: Integer;
      begin
        Result := FALSE;
        ExcelOLE := CreateOLEObject('Excel.Application');
        try
          for WorkbookNumber := 1 to ExcelOLE.Workbooks.Count do
            if UpperCase(WorkbookName) = UpperCase(ExcelOLE.Workbooks[WorkbookNumber].Name) then
              Result := TRUE;
        finally
          ExcelOLE := unAssigned;
        end;
      end; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多