我正在使用的应用程序中有一个非常令人沮丧的错误。 该例程应该在一个窗口中执行某些操作,然后在方法结束时将焦点返回给另一个窗口,但是当前一天我开始使用大型数据集时,焦点在最后停止返回。 我一次一行地通过代码,并且错误停止了。 所以,我认为它是某种时机问题。 我追溯到我发现我怀疑是罪魁祸首。 调用ShellExecute(…),终止我使用的图像编辑器。 ( http://msdn.microsoft.com/en-us/library/bb762153(VS.85).aspx )
现在,如果我经过这个调用,然后继续运行程序,一切正常,但如果我刚刚跑过这条线,就会发生错误。 怎么会这样? 我在这个方法的最后调用SetFocus()。 不pipe这个程序怎么打到这个?
这是非常令人沮丧的
首先应该清楚的是与Windows /消息/焦点等相关的Win32 API调用不依赖于时序。 每个线程都有自己的窗口/消息子系统,这里没有竞争条件。
你所描述的是别的东西。 您实际上启动另一个进程(应用程序),与您的并发运行。 请注意, ShellExecute
是一个异步功能。 它在创建流程后立即返回,从现在开始,您的应用程序和您创建的流程同时运行。
现在,由于系统中只有一个窗口可能会一直关注,所以您创建的流程很可能只是偷走了您的焦点。 为了避免这种情况,您应该先等待该过程完成工作,然后才能将焦点恢复到您的窗口并继续工作。
为此,您必须获取创建的进程的句柄,并在其上调用Win32等待函数。 ShellExecute
不会返回您创建的进程的句柄。 但是ShellExecuteEx
– 呢。 顺便说一句,它也允许你启动一个进程,指令它不显示用户界面,如果这是你想要的。
你应该这样写:
SHELLEXECUTEINFO sei; memset(&sei, 0, sizeof(sei)); sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_NOCLOSEPROCESS; sei.lpFile = L"notepad.exe"; sei.nShow = SW_SHOWNORMAL; // or SW_HIDE if you don't want to show it if (ShellExecuteEx(&sei)) { // wait for completion WaitForSingleObject(sei.hProcess, INFINITE); CloseHandle(sei.hProcess); }
这应该是有帮助的
PS当然,你应该关闭创建过程的句柄。 也就是说,必须在WaitForSingleObject
之后调用CloseHandle
。
正如你所说,这个问题听起来像是一个时机。
我不熟悉ShellExecute函数,但从您链接的页面:
“由于ShellExecute可以将执行委托给使用组件对象模型(COM)激活的Shell扩展(数据源,上下文菜单处理程序,动词实现),COM应该在调用ShellExecute之前进行初始化。一些Shell扩展需要COM单线程单元(STA)类型“。
也许这是相关的?