0

I have a windows form application which needs to be the TopMost. I've set my form to be the TopMost and my application works as I'd like it to except for in one case.

There is a 3rd party application (referred to as player.exe) that displays SWF movie files on a portion of the screen that popup on top of my application.

Using Process Monitor I determined that player.exe application calls
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
in my case:
flash.exe 901 96 379 261 somemovie.swf

Since flash.exe is being spawned in a new process after my form has been set to the TopMost it is appearing on top of my application.

First thing I did was make my application minimize the player.exe main application window hoping that this would prevent the Flash from appearing also. But, unfortunately it doesn't... even with the window minimized whenever the flash movie starts it shows up at the pixel location (901,96). I then tried creating a timer to keep setting the form.TopMost property to true every 10ms. This sort of works but you still see a very quick blip of the swf file.

Is there some type of Windows API call which can be used to temporarily prevent player.exe from spawning child processes which are visible? I admit it sounds a little far fetched. But, curious if anyone else has had a similar problem.


Addendum:

This addendum is to provide a reply to some of the suggestions layed out in Mathew's post below.

For the emergency situation described in the comments, I would look at possible solutions along these lines:

1) How does the third party application normally get started and stopped? Am I permitted to close it the same way? If it is a service, the Service Control Manager can stop it. If it is a regular application, sending an escape keystroke (with SendInput() perhaps) or WM_CLOSE message to its main window may work.

Easiest way to close the app is to CTRL-ALT-DEL, then kill process. -OR- The proper way is to Hold ESC while clicking the left mouse button... then input your username and password, navigate some menu's to stop the player.

There is no PAUSE command... believe it or not.

I don't think using WM_CLOSE will help since minimizing the application doesn't. Would that kill the process also? If not, how do you reopen it.

2) If I can't close it nicely, am I permitted to kill it? If so, TerminateProcess() should work.

I can't kill the process for two reasons. 1) Upon relaunch you need to supply username/password credentials... There may be a way to get around this since it doesn't prompt when the machine is rebooted but... 2) Whenever I kill the process in task manager it doesn't die gracefully and asks if you want to send an error report.

3) If I absolutely have to leave the other process running, I would try to see if I can programmatically invoke fast user switching to take me to a different session (in which there will be no competing topmost windows). I don't know where in the API to start with this one. (Peter Ruderman suggests SwitchDesktop() for this purpose in his answer.)

I got really excited by this idea... I found this article on CodeProject which provides a lot of the API Wrapper methods. I stopped implementing it because I think that in order for desktop's to work you must have explorer.exe running (which I do not).

EDIT2: On second thought... maybe explorer.exe isn't needed. I'll give it a try and report back.

Edit3: Was unable to get the code in that article working. Will have to put this on hold for a moment.


Answer Summary

As one might have expected, there is no simple answer to this problem. The best solution would be to problematically switch to a different desktop when you need to guarantee nothing will appear over it. I was unable to find a simple C# implementation of desktop switching that worked and I had a looming doubt that I would just be opening a whole new set of worms once it was implemented. Therefore, I decided not to implement the desktop switching. I did find a C++ Implementation that works well. Please post working C# virtual desktop implementations for others.

4

3 回答 3

3

设置 TopMost 属性(或将 WS_EX_TOPMOST 样式添加到窗口)不会使其在系统中唯一。任意数量的应用程序可以创建任意数量的最顶层窗口;唯一的保证是所有最顶层的窗口都将绘制在所有非最顶层窗口的“上方”。如果有两个或多个最上面的窗口,Z 顺序仍然适用。根据您的描述,我怀疑 flash.exe 也在创建一个最顶层的窗口。

除了定期将您的窗口强制到 Z 顺序的顶部之外,我认为您无能为力。但是请注意,这种方法是危险的:如果两个或多个窗口同时试图将自己强制到 Z 顺序的顶部,结果将是一个闪烁的混乱,用户可能不得不使用任务管理器来逃脱。

我建议您的程序不要试图干预计算机上的其他进程(除非这是它的明确目的,例如任务管理器克隆)。计算机属于用户,他可能不会比其他人更重视您的程序。

附录:

对于评论中描述的紧急情况,我会考虑以下可能的解决方案:

  1. 第三方应用程序通常如何启动和停止?我可以以同样的方式关闭它吗?如果是服务,服务控制管理器可以停止它。如果它是一个常规应用程序,则向其主窗口发送一个转义键击(可能使用SendInput())或WM_CLOSE消息可能会起作用。

  2. 如果我不能很好地关闭它,我可以杀死它吗?如果是这样,TerminateProcess()应该可以工作。

  3. 如果我绝对必须让另一个进程运行,我会尝试查看是否可以以编程方式调用快速用户切换以将我带到不同的会话(其中不会有竞争的最顶层窗口)。我不知道在 API 中从哪里开始。(Peter Ruderman在他的回答中为此建议SwitchDesktop() 。)

于 2009-07-15T19:07:44.023 回答
0

您可以使用Process 类直接启动 flash.exe - 并使用适当的ProcessStartInfo设置以隐藏状态显示窗口 - 或使用隐藏或最小化的 WindowStyle。

您还可以考虑使用SetWindowsHookEx API 来拦截进程启动 API 调用,并在进程为 flash.exe 时运行一些代码将您的窗口恢复到最顶层状态。

于 2009-07-15T17:47:54.107 回答
0

马修的回答很好,但我怀疑你可能问错了问题。为什么您的应用程序需要位于最顶层?如果您正在尝试创建一个信息亭或类似的东西,那么 topmost 不是要走的路。

编辑:阅读您对 Matthew 评论的回复后,我建议您创建一个新桌面并切换到它,然后再显示您的警报。(请参阅 MSDN 中的 CreateDesktop 和 SwitchDesktop。)

于 2009-07-15T19:39:09.610 回答