我有一个应用程序调用其他实用程序应用程序来为特定设备设置一些设置。 该实用程序应用程序使用ShellExecuteEx进行调用。
为了不使用户混淆,最好将实用程序模式窗口设置为我的主窗口。 如何做到这一点?
我试过的东西:
你有两件事要模拟:所有权和形式。
要模拟所有权:您需要将新的子进程窗口的所有者设置到您的窗口。 这应该减轻任何z订购问题。 虽然我不知道这是否从另一个过程。 如果没有,那么你可能不得不附加你的线程输入队列,然后调用它。 或者使用其他一些代码注入技术。
SetWindowLong <target window handle>, GWL_HWNDPARENT, <new owner handle>
为了模拟模态,我认为你使用EnableWindow和WaitForSingleObjectEx是正确的。
简单的答案是,即使线程处于相同的进程中,也无法在线程A中的窗口中无缝地创建线程B模式的窗口。 如果你拥有这两个窗口的代码,你可能会接近,但在这种情况下,通过将所有的UI放在一个线程中,你将获得更好的结果。
如果您尝试向用户建议线程B的窗口对于线程A是模态的,那么您必须获得许多微妙的Z顺序和激活行为(正如您已经注意到的),以免您遭受到不可思议的谷歌效应对用户来说很清楚,线程B的窗口正试图成为它不是的东西,因此似乎被破坏了。
为了避免这一点,我会采取这种做法:
这样,如果一切正常快速地进行,交互可能是无缝的,但是如果子进程出了问题或者Z顺序改变了,等等,这将清楚为什么父进程正在等待以及用户需要做或取消或继续他开始的任务。
EnableWindow是正确的,这通常是如何消息框和其他“模态”窗口。 至于zorder更改,您可以拦截WM_WINDOWPOSCHANGING消息并设置SWP_NOZORDER标志以防止zorder更改。 确保在设置EnableWindow时只做这个(false)。
只是合乎逻辑的建议,
也许你可以创建无形的模态形式 ,并从他使用方法#1。
让我们来看看你的方法#3,这是非常接近你想要的。 我怀疑问题是,当第二个应用程序关闭时,Windows决定不想将焦点还原到禁用的窗口。 在这种情况发生之前,你可以尝试重新启用你的窗口,但这很可能是棘手的(而且不值得付出)。
不要直接禁用窗口,只要忽略用户输入就可以禁用它。 因此,而不是调用EnableWindow,更改您的消息循环以筛选出输入消息。 特别是,如果
msg >= WM_KEYFIRST || msg <= WM_KEYLAST || msg >= WM_MOUSEFIRST || msg <= WM_MOUSELAST
然后丢弃该消息; 否则,将它传递给正常的调度循环。 你正在做的是创建自己的禁用窗口,但Windows不知道这一点。