2

I'm attempting to pass messages between two applications - one of them is a plugin, and the other is a standalone configuration utility. When my plugin detects an event, I want to send a message to my utility and prompt the user to reconfigure.

The code I'm using is as follows:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
private const int MESSAGE_UNAUTH = 0x401;

[... misc logic here, function def, etc]

Process[] processes = Process.GetProcessesByName("MyConfigurationApplication");

if (processes.Length > 0)
{
    foreach (Process p in processes)
    {
        SendMessage(p.MainWindowHandle, MESSAGE_UNAUTH, IntPtr.Zero, IntPtr.Zero);
    }
}

And then in my receiving process, I have the following code (I also defined MESSAGE_UNAUTH in this class):

protected override void WndProc(ref Message message)
{
    if (message.Msg == MESSAGE_UNAUTH)
    {
        MessageBox.Show("Message received");
    }
    base.WndProc(ref message);
}

Things I have already verified with the debugger:

  1. The message is getting sent. All the code in the Sender, including the SendMessage call, is executing.
  2. The message is not getting received (obviously).
  3. The WndProc() function is not getting called at all when the message is sent. It is, however, getting called a whole bunch of times when the configuration utility is launched (I'm assuming this is Windows' behavior).

I've gone through enough online tutorials to need eyedrops, and as far as I know, everything here is syntax-correct and "proper," but for some reason, between when I send the message and when the receiver's WndProc() should be called, black magic is happening.

Any ideas would be greatly appreciated.


Update: Using Marshal.GetLastWin32Error(), I am getting an error #1400, which appears to correspond to an invalid window handle. However, I don't see why that would be the case, since the process was found and we entered the for each loop successfully. The one caveat I can think of is that my configuration utility is presented as a taskbar icon, and doesn't necessarily have a visible window at all times - would this prevent p.MainWindowHandle from being valid? If so, how can I work around this to pass a message to the process instead of the window?


Update: Process.MainWindowHandle is 0, so it looks like that is indeed the problem - when the form in my configuration utility is not visible, no valid window handler is returned, even though my utility icon is visible in the notification bar. Is there any way I can send a message to the process, or even to the taskbar icon?

sichinumi
  • 1,835
  • 3
  • 21
  • 40
  • What is the value of MainWindowhandle? – Jacob Seleznev Jun 27 '12 at 22:04
  • 0, so it looks like that is indeed the problem. (See update) – sichinumi Jun 27 '12 at 22:05
  • 1
    If you can't send Windows message did you consider other means of IPC communications e.g [named pipes](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365590(v=vs.85).aspx)? – Jacob Seleznev Jun 27 '12 at 22:20
  • I have considered this, but it was decided by executive decision that a quick and easy solution was desired, and that named pipes/TCP were too much of a time investment for the time span of this project. If this method proves too difficult, our last resort is some kludgy file IO/change listener code. – sichinumi Jun 28 '12 at 14:04

5 Answers5

1

You can try to enumerate all windows associated with the process. See How to enumerate all windows belonging to a particular process using .NET?

Community
  • 1
  • 1
Jacob Seleznev
  • 8,013
  • 3
  • 24
  • 34
1

Depending on the .NET framework you are using, this will help resolve your issues. There was a bug in the old .NET frameworks (2.0 I think) where calling to Process.MainWindowHandle when the process starts up returns 0. Any subsequent call will also result in a 0. This is due to caching the main window handle, which should have been fixed in .NET 3.0 and later.

You might also try giving full trust to your WndProc which might help. Something like:

[System.Security.Permissions.PermissionSet( System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
protected override void WndProc(ref Message m) 
{
    //...
}

On a side note, if you can change your implementation then I strongly suggest you go for better inter process communication means such as sockets, TCPChannel (which I think is replaced by WCF), named pipes...

GETah
  • 20,922
  • 7
  • 61
  • 103
  • Also note that there is no concept of a "main window handle" to a Win32 process. There are just 0 or more "top level window". – Deanna Jun 28 '12 at 10:52
0

The message might not be sent, it might be blocked. See here: When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).

zmbq
  • 38,013
  • 14
  • 101
  • 171
  • Aha! Using Marshal.GetLastWin32Error() returns error #1400, which appears to reflect an invalid window handle. Why would it be invalid, though, if the process is being found and we are entering the loop? – sichinumi Jun 27 '12 at 21:52
0

Use Windows Registermessage in bothe sender and receiver end will resolve the problem

0

Problem was that the process I was sending the message to only existed as a tooltip icon and not as an active, open window. Turns out the windows message functionality is designed for window-to-window messages, not process-to-process messages.

Solution was aforementioned kludgy system of file IO handlers.

sichinumi
  • 1,835
  • 3
  • 21
  • 40