These days I’m working on a custom application updater for our products and I had the need to Close the main Application process from the Updater process. My first implementation involved getting the main application process ID and then use something like:
...
processToWait = Process.GetProcessById(pid)
mProcessToWait.CloseMainWindow()
mProcessToWait.WaitForExit()
mProcessToWait.Close()
...
Which at first worked well.

Then I’ve started to play with things like Impersonation and Process spawning with different credential (to overcome some permissions problems in a production environment related to the application update process). The actual scenario is like this one: the main application runs under the user currently logged in the computer, while the Updater need to run as a different user with higher privileges. And all of a sudden the CloseMainWindow() function stopped to work...that is the application didn’t seemed to receive the close notification anymore (the usual ‘Do you really want to close?’ message box didn’t pop-up).

Doing more tests I noticed that the same things would have happened if the main application was minimized on the taskbar with both the application and the updater running under the same User.

Using Reflector/Spy++ and some other tools and investigating a bit it came out that the WM_CLOSE message wasn’t processed in these circumstances...and CloseMainWindow() is basically a wrapper function to post a WM_CLOSE message, so I had to look for an alternative way.

It came into my mind that since we are dealing with windows, I could simulate the input that the user gives using the ‘Windows/Control box menu’, I have no Framework API to do the task so I had to use some unmanaged code and post a WM_SYSCOMMAND with SC_CLOSE as parameter (the msdn reference is here WM_SYSCOMMAND).

This is how the final code looks like:
...
Const WM_SYSCOMMAND As Int32 = &H112
Const SC_CLOSE As Int32 = &HF060I

Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" ( _
  ByVal hwnd As Int32, _
  ByVal wMsg As Int32, _
  ByVal wParam As Int32, _
  ByVal lParam As Int32) As Int32
...
Dim handle As IntPtr = mProcessToWait.MainWindowHandle
PostMessage(handle.ToInt32, WM_SYSCOMMAND, SC_CLOSE, 0)
mProcessToWait.WaitForExit()
mProcessToWait.Close()
I have to admit I don’t like to use unmanaged code if I can avoid it, but this works in the scenarios in which CloseMainWindow() fails.