ShellExecuteEx 并等待文件实际打开

Posted

技术标签:

【中文标题】ShellExecuteEx 并等待文件实际打开【英文标题】:ShellExecuteEx and waiting until file has been actually opened 【发布时间】:2018-12-21 17:25:45 【问题描述】:

这是场景:

我使用ShellExecuteEx 来打开给定的.xlsx 文件。这工作正常,Excel 已启动并在 Excel 中打开 .xlsx 文件。

现在ShellExecuteEx 或多或少会在 Excel 完全启动并打开 .xlsx 文件之前立即返回。到目前为止一切顺利。

有没有办法等到 Excel 实际打开 .xlsx 文件?类似 BOOL FileIsOpenExclusively(LPCTSTR filename) 函数返回 TRUE 的东西是文件被独占打开吗?

然后我可以做这样的事情(简约、幼稚和无错误检查)伪代码:

ShellExecuteEx(... stuff for opening myfile.xlsx ...);

while (FileIsOpenExclusively("myfile.xlsx"))

   Sleep(500);


// now "myfile.xlsx" is opened execusively

已编辑

实际稍微复杂一点的场景是这样的:

ShellExecuteEx 启动 Excel 打开给定的 .xlsx 文件。 那么我需要以某种方式知道 .xlsx 文件何时关闭,要么是因为 Excel 用户关闭了该文件,要么是因为用户一起退出了 Excel。

这个伪代码说明了我现在正在做的事情:

ShellExecuteEx(... stuff for opening myfile.xlsx ...);

Sleep(5000);  // wait that Excel has hopefully has opened the file

do

   Sleep(500);
   Open("myfile.xlsx");
 while (opening file is unsuccessful)

 // file could be opened which means that Excel has closed it

 Close("myfile.xlsx");

问题是Sleep(5000);:如果 Excel 无法在 5.5 秒内打开文件,下面的测试将失败,因为它会认为 Excel 甚至在文件打开之前就已经关闭了文件。因此,我需要知道 Excel 何时打开文件,而不是等待确定的时间。

也许还有另一种方法。一些 cmets 建议使用WaitForInputIdle,这听起来很有希望,但如果事先已经有一个打开的 Excel 实例(待测试),这可能不起作用。

另一条评论建议枚举***窗口并检查窗口标题的更改,但我不确定这是否适用于现代 Excel 版本(待检查),如果它有效,它可能会停止使用下一个主要 Excel 版本。

使用机会锁听起来很有希望,我将在下周进行测试。

最后使用重启管理器也可能是一个线索。

【问题讨论】:

可能是 CreateProcess 和 WaitForInputIdle? WaitForInputIdle should really be called WaitForProcessStartupComplete 和 WaitForInputIdle waits for any thread, which might not be the thread you care about 为什么必须等待Excel打开文件?没有冒犯,但这闻起来像 XY 问题。无论如何,您可以通过 Excel 进程使用Restart Manager to check if the file has been opened。 另一个允许您在进程想要打开文件时接收通知的 API 是在文件上放置 Opportunistic Lock。当另一个进程想要打开同一个文件时,锁会被打破,你会收到一个通知。然而,缺点是,例如,打开对话框可能会在文件实际打开之前打破锁定。但至少它是值得研究的。 如果 Excel 根本不打开文件怎么办?与启动的应用程序通信没有标准;你必须做一些临时的事情。对于 Excel,您可以尝试使用 object model to open workbooks。 【参考方案1】:

正如其他人所说,没有办法知道应用程序何时打开文件,但如果它专门用于 Excel,您可以使用 COM 自动化。

Here 是 python 示例,here 是通用文档。在 C++ 中,您必须使用 CoCreateInstance 来获取 IDispatch。

【讨论】:

很遗憾,COM 不是一个选项,因为可能会使用其他程序并且可能需要使用文件格式。 在这种情况下,您可以创建一个过滤器驱动程序,用于记录文档何时被读取并预测就绪情况。 真的存在在文件打开和通过FSCTL_REQUEST_OPLOCK修改时得到通知

以上是关于ShellExecuteEx 并等待文件实际打开的主要内容,如果未能解决你的问题,请参考以下文章

为啥 ShellExecuteEx 不返回进程句柄?

WinApi ShellExecuteEx - 在文件列表上使用动词“复制”

vb代码之---打开文件或文件夹属性

如何打开指定文件的属性对话框?

等待由 IShellDispatch2.ShellExecute 启动的进程

用ShellExecuteEx函数执行一个vc写的exe,vc程序的返回函数是return(n)