我有一个需要成为TopMost的Windows窗体应用程序。我将我的表单设置为TopMost,我的应用程序按照我的喜好工作,除了一个案例。
第三方应用程序(称为 player.exe )在我的应用程序顶部弹出的部分屏幕上显示SWF电影文件。
使用进程监视器我确定 player.exe 应用程序调用
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
在我的情况下:
flash.exe 901 96 379 261 somemovie.swf
由于我的表单设置为TopMost后,在新进程中生成了flash.exe,因此它出现在我的应用程序之上。
我做的第一件事是让我的应用程序最小化 player.exe 主应用程序窗口,希望这也会阻止Flash出现。但是,不幸的是它不会......即使闪光灯电影开始时窗口最小化,它也会显示在像素位置(901,96)。然后我尝试创建一个计时器,以便每隔10ms将form.TopMost属性设置为true。这种方法很有效,但你仍然可以看到swf文件非常快速。
是否存在某种类型的Windows API调用,可用于暂时阻止 player.exe 生成可见的子进程?我承认这听起来有点牵强。但是,好奇是否有其他人遇到过类似的问题。
本附录旨在回复以下Mathew帖子中提出的一些建议。
对于评论中描述的紧急情况,我将按照这些方针查看可能的解决方案:
1)第三方应用程序通常如何开始 停止?我被允许关闭它 一样的方法?如果是服务,那么 服务控制管理器可以阻止它。 如果是常规应用, 发送逃生击键(用 也许是SendInput()或WM_CLOSE 消息到它的主窗口可能会有效。
关闭应用程序的最简单方法是CTRL-ALT-DEL,然后杀死进程。 -要么- 正确的方法是在点击鼠标左键时按住ESC ...然后输入您的用户名和密码,导航一些菜单以停止播放器。
没有PAUSE命令......信不信由你。
我不认为使用WM_CLOSE会有所帮助,因为最小化应用程序不会。这会杀死这个过程吗?如果没有,你怎么重新打开它。
2)如果我不能很好地关闭它,我可以杀死它吗?如果是这样, TerminateProcess()应该可以工作。
我无法杀死这个过程有两个原因。 1)重新启动后,您需要提供用户名/密码凭据...可能有办法解决这个问题,因为它不会在机器重新启动时提示但是... 2)每当我在任务管理器中终止进程时< strong>它没有优雅地消失并询问您是否要发送错误报告。
3)如果我绝对不得不让其他进程运行,我会尝试 看看我是否可以编程 调用快速用户切换带我 到另一个会话(在那里 将不会竞争最顶层的窗户)。 我不知道API在哪里开始 用这个。 (彼得罗德曼 为此建议SwitchDesktop() 他回答的目的。)
我对这个想法感到非常兴奋......我在CodeProject上找到了this article,它提供了很多API Wrapper方法。我停止实现它因为我认为为了让桌面工作,你必须运行explorer.exe(我没有)。
EDIT2 :第二个想法......也许不需要explorer.exe。我会试一试并报告。
Edit3 :无法获取该文章中的代码。将不得不搁置一下。
正如人们所预料的那样,这个问题没有简单的答案。最好的解决方案是在需要保证不会出现任何内容时,有问题地切换到不同的桌面。我无法找到一个简单的C#桌面切换实现工作,我有一个迫在眉睫的疑问,我只会在实施后打开一组全新的蠕虫。因此,我决定不实施桌面切换。我找到了C++ Implementation that works well.请为其他人发布C#虚拟桌面实现。
答案 0 :(得分:3)
设置TopMost属性(或将WS_EX_TOPMOST样式添加到窗口)不会使其在系统中唯一。任何数量的应用程序都可以创建任意数量的最顶层窗口;唯一的保证是所有最顶层的窗口都将被绘制在所有非最顶层窗口的“上方”。如果有两个或更多最顶层的窗口,Z顺序仍然适用。根据您的描述,我怀疑flash.exe也在创建一个最顶层的窗口。
除了定期强迫你的窗户到Z顺序的顶部,我认为你几乎无能为力。但请注意,这种方法很危险:如果两个或多个窗口同时试图强迫自己到Z顺序的顶部,结果将是一个闪烁的混乱,用户可能不得不使用任务管理器逸出。
我建议您的程序不要试图干扰计算机上的其他进程(除非这是其明确目的,例如任务管理器克隆)。计算机属于用户,他可能不会比其他计算机更重视您的程序。
<强>附录:强>
对于评论中描述的紧急情况,我将按照这些方针查看可能的解决方案:
第三方应用程序通常如何启动和停止?我允许以同样的方式关闭它吗?如果是服务,Service Control Manager可以阻止它。如果它是常规应用程序,则可以在其主窗口中发送转义键击(可能带有SendInput()或WM_CLOSE消息。
如果我不能很好地关闭它,我可以杀死吗?如果是这样,TerminateProcess()应该有效。
如果我绝对不得不让其他进程继续运行,我会尝试看看我是否可以通过编程方式调用快速用户切换来将我带到另一个会话(其中没有竞争的最顶层窗口)。我不知道API在哪里开始这个。 (Peter Ruderman在答案中为此目的建议SwitchDesktop()。)
答案 1 :(得分:0)
您可以使用Process class直接启动flash.exe - 并使用适当的ProcessStartInfo设置将窗口显示为隐藏状态 - 或者使用隐藏或最小化的WindowStyle。
您还可以考虑使用SetWindowsHookEx API拦截进程启动API调用,当进程为flash.exe时,运行一些代码以将窗口恢复到最顶级状态。
答案 2 :(得分:0)
马修的回答非常好,但我怀疑你可能会提出错误的问题。为什么您的应用程序需要是最顶层的?如果您正在尝试创建一个自助服务终端或其他类型的服务器,那么最重要的不是最佳选择。
编辑:在阅读了对Matthew评论的回复后,我建议您在显示提醒之前创建一个新桌面并切换到该桌面。 (请参阅MSDN中的CreateDesktop和SwitchDesktop。)