How to activate a window of an external application - c#

I've used FindWindow to get a handle to a window of an external application. How can I use this handle to activate the window of the external application, if it is minimized or behind other applications on the windows desktop?

To prevent focus-stealing (or at least make accidental focus-stealing harder), Windows puts up some roadblocks to one process bringing another process's window to the top.
Check MSDN for SetForegroundWindow (especially in the Remarks section) and AllowSetForegroundWindow.
You should either send a message to the process to tell it to restore its own window, or that process has to explicitly allow your process to do this.

FindWindow() followed by ShowWindow().

Related

How do I manage an external Windows application in C#?

What is the best way to manage an external windows application in C# (or .NET)?
So far my I've been able to launch a process using System.Diagnostics.Process, however this simply allows me to launch/kill a process. (from what I've gathered)
I noticed System.Diagnostics.Process has a CloseMainWindow() routine which will send a request to a process' window. Can I use this Process class to send different messages? (if so, can anyone point me in direction of where I can learn about these windows messages)
I need to be able to manage an external program and manipulate it the following ways:
1) Launch
2) Kill Process
3) Show Application (Fullscreen and in taskbar)
4) Hide Application (Fullscreen and in taskbar)
Further details:
Windows 7, Restricted to .Net 3.5 Framework
You might be able to use interop and use SendMessage to do all of your functionality. See this: http://pinvoke.net/default.aspx/user32.SendMessage
Try sending a message to that window. Take a look at SendMessage . The messages you need are SW_MINIMIZE,SW_RESTORE and SW_SHOWMAXIMIZED.
You're going to need to use some Win32 P/Invoke stuff to send window messages in order to do what you want.
See this code sample on ShowWindow or SendMessage which tells an external window to show or hide itself. You'll first need to get the window handle you want with FindWindowEx.
you can do all you want in different ways, once you start the process yourself or you find it in the list of running processes, using classes or methods of System.Diagnostics.Process, then you can follow different options...
for example consider that once you have this handle: Process.MainWindowHandle you can send messages to that handle, with SendMessage and PostMessage and this allows you to do very very much; or you can use PInvoke APIs like SetWindowPos or ShowWindow or SetWindowLong and do basically really everything...
see this for example:
How to use the ShowWindow API to hide and show a form
I can send you more links but won't like to refer to the whole MSDN ;-)

how to close a window from a different process

I have a c# application which I want to instruct to shutdown nicely, from a different process.
I also want to be able to ask it to open its main window.
I have a reference to its main window handle.
I know I can do it using elaborate schemes such as remoting or WCF.
the question is can I do it using simpler mechanisms such as window messages, or the OnClose event handlers of the window in the c# application
Pinvoke SendMessage() to send the WM_CLOSE message to the app's main window. Asking it to open its main window is probably going to be quite difficult, you cannot obtain the window handle until the window is created. Process.Start() would be the normal way.
A low cost alternative to WCF and superior to pinvoke is a named pipe or a socket to interface with the app. This requires being able to modify the source code of the app.
Process.CloseMainWindow
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.closemainwindow.aspx
I think that you could probably use FindWindow to find the correct child window and then SendMessage or PostMessage to send a WM_CLOSE.
Here's another StackOverflow question that deals with doing this in C#.
Edit: Though as the other answer says in that question, you might be able to use Process.CloseMainWindow instead.
I would first make my target application "aware" of the fact that some other process might like to trigger its closing or opening of a window or doing any action. This should be implemented similar to calling any method on another process through the target app's api or public methods. ..unless you are trying to do something with 3rd party applications, I think you shouldn't attempt to directly send them messages to close or shutdown.

What is an alternative to Sendkeys for closing a legacy application?

I want my C# program to shut down a certain legacy application before proceeding. The legacy app may be shut down immediately using ctrl+x. I could do this using Sendkeys, but I've been told that sendkeys can be a little flaky. Is there an alternative way for me to send this key combination and shut the legacy app down?
If you know what the window's title is on the caption bar, such as 'Foo', then you can use p/invoke to find the window and get the handle from it 'FindWindow'. Once you get the handle, then you can use 'SendMessage' to that handle sending a 'WM_KEYUP' that denotes Ctrl+X together.
Hope this helps,
Best regards,
Tom.
If this is a GUI application. It may also respond to Alt+F4 via SendKeys.
Unlike ctrl+x, Alt+F4 will not depend on which window has focus. This is a standard accelerator for windows applications and most older GUI applications will support it. The main reason SendKey is considered flakey is because keystrokes get delivered to the focus window, which may or may not understand them. But Alt+F4 is an accelerator, so it should work regardless of which window has focus.
If you can get the handle to the main window. (use FindWindow if you don't have it already). You can
PostMessage(hwndApp, WM_SYSCOMMAND, SC_CLOSE, 0);
This is equivalent to choosing the close option from the system menu on the window. SendMessage should work as well, but PostMessage is safer since your application doesn't wait for the message to be delivered.
WM_SYSCOMMAND
Other options include:
System.Diagnostics.Process.Kill
System.Diagnostics.Process.CloseMainWindow
If the latter works, use it. If not, and you lose nothing by killing the process directly, then Kill().

Find which MDI child just got focus Win32 API

I have a program that has a MDI host and I would like to be able to get which of it children just got focus, bassiclly I would like to make a window focus changed event for this application.
The application is a 3rd party and I don't have the source, I have the window handle to the main program and the MDI host part.
I know I'll have to use Win32 API just not sure which ones.
I am writing my application in C#
Thanks.
I guess what you're looking for is intercepting WM_SETFOCUS and WM_KILLFOCUS messages
The real problem is how are you going to do this. I guess the easiet way is to install a hook which is a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure. You're doing it by using SetWindowsHookEx winapi function with WH_CALLWNDPROC or WH_CALLWNDPROCRET types of hooks. There some are examples posted on codeproject; also there is one on msdn: How to set a Windows hook in Visual C# .NET
What is not really clear in your post is where your code running: in the same process with the MDI windows or is it a separate application\service? In case it is you would also need to inject your code into the remote process. Check this link for details on how you can do it: Three Ways to Inject Your Code into Another Process
hope this helps, regards

Prevent Process 'A' from spawning Process 'B' which then shows up on top of what should be the "TopMost" Process 'C'

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.
Setting the TopMost property (or adding the WS_EX_TOPMOST style to a window) does not make it unique in the system. Any number of topmost windows may be created by any number of applications; the only guarantee is that all topmost windows will be drawn 'above' all non-topmost windows. If there are two or more topmost windows, the Z-order still applies. From your description, I suspect that flash.exe is also creating a topmost window.
Aside from periodically forcing your window to the top of the Z-order, I think there is little you can do. Be warned, however, that this approach is dangerous: if two or more windows are simultaneously trying to force themselves to the top of the Z-order, the result will be a flickering mess that the user will likely have to use the task manager to escape.
I recommend that your program not attempt to meddle with other processes on the computer (unless that is its explicit purpose, e.g. a task manager clone). The computer belongs to the user, and he may not value your program more highly than all others.
Addendum:
For the emergency situation described in the comments, I would look at possible solutions along these lines:
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.
If I can't close it nicely, am I permitted to kill it? If so, TerminateProcess() should work.
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.)
You can use the Process class to start flash.exe directly - and use an appropriate ProcessStartInfo settings to show the window in a hidden state - or with a WindowStyle of hidden or minimized.
You could also consider using the SetWindowsHookEx API to intercept the process start API calls, and when the process is flash.exe run some code to restore you window to top-most status.
Matthew's answer is excellent, but I suspect you may be asking the wrong question. Why does your application need to be topmost? If you're trying to create a kiosk or some such, then topmost is not the way to go.
Edit: After reading your response to Matthew's comment, I'd suggest creating a new desktop and switching to it before displaying your alert. (See CreateDesktop and SwitchDesktop in MSDN.)

Categories

Resources