Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending a message to an application running on a secondary logged in user account

Tags:

winapi

delphi

I'm trying to send a message to an application running under a different user account (a user that is also logged in with a different account on the computer, using quick user switch on XP and later, and executed the application).

The background is that my application can update itself, but in order to do that all running instances must be closed first.
The instances need to be shut down (instead of just killing the process), so the updater does that by sending a custom message to them (with SendMessage). In order to send a message I need a handle to the main window of the process.

This works fine using EnumWindows - as long as the instances are running under the same user account, because EnumWindows does not list windows belonging to a different user.

So I tried a different approach. I used CreateToolhelp32Snapshot to first list all running processes on the system, and then iterating through the threads calling CreateToolhelp32Snapshot again. With those thread ids I could then list their windows using EnumThreadWindows.

Once again this works fine, but.. once again only for the current logged in user. The problem here is that even though CreateToolhelp32Snapshot lists process ids belonging to a different user it does not list thread ids belonging to them. The code for this is a little lengthy, but if it's required I can edit it in - please leave a comment for that.

So, how could I get the main window handle of my application running on a different logged in user account?

like image 664
Chris Avatar asked Feb 26 '12 16:02

Chris


2 Answers

Use something that's known to work across sessions; This kind of stuff is often used for desktop-service communications, so look for that if you want to google. Here's my suggestion:

  1. Create an event that will only be used to trigger the "need to shut down" state. Use the CreateEvent function make sure you start your name with Global\ so it's valid across sessions.
  2. On application startup create a thread that opens the named event (uses the same CreateEvent function, pay close attention to the ERROR_ALREADY_EXISTS non-error). That thread should simply wait for the event. When the event is triggered, send the required message to your main window. That thread can easily and safely do that because it's running inside your process. The thread will mostly be idle, waiting for the event to be triggered, so don't worry about CPU penalty.
  3. Your application updateer should simply trigger the named event.

This is just one idea, I'm sure there are others.

like image 87
Cosmin Prund Avatar answered Oct 16 '22 18:10

Cosmin Prund


Pipes are overkill. A global manual-reset event (e.g. "Global\MyApplicationShutdownEvent") which causes application instances to kill themselves should be enough.

like image 20
arx Avatar answered Oct 16 '22 18:10

arx