I had a real pain recently where I wanted to control one windows app from another. I found some useful stuff on the net, but nothing that gave an end to end solution. So here’s what I came up with.
Firstly I’ll explain why this is useful. SendMessage is part of the Win32 API, and is used to send messages from one application to another. There are a set of predefined properties that the message can relate to, and these can be used to send messages to existing applications to perform all sorts of useful functions such as changing the font in notepad, or bringing a window to the fore. For more information of the wider use of the SendMessage function, have a look at:
http://www.autohotkey.com/docs/commands/PostMessage.htm
http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx
The main use that I’m interested in is passing a specific instruction (via a string) from one app that I’ve written, to another one that I’ve written. This way I can effectively remote control one app from another (particularly useful if you want your main application to open a pop-up, and you don’t want to worry about the pop-up’s performance affecting the main application). Let’s now have a quick look at the SendMessage function:
SendMessage(int hWnd, int Msg, int wParam, int lParam)
hWnd – This is the window instance id of the application you want to send a message to. This id is retrieved using the FindWindow function
Msg – This is the type of message you want to send
wParam – Message specific data you pass in
wParam – Message specific data you pass in
Also used is the FindWindow function. This is to get the relevant window id:
FindWindow(String lpClassName, String lpWindowName)
lpClassName -The name of the class you want
lpWindowName – The name of the window that you want
To send a message that is a string, you need to use the WM_DATACOPY message property. The hard part is that you cannot just send the string as a parameter across. You need to send a pointer to the memory address of the string. If you just want to send an integer as a message you can use the WM_USER message property and send it as a value without a problem.
Below now is a brief listing of my MessageHelper.cs class, for the whole class file see:
http://craigcook.co.uk/samples/MessageHelper.cs.txt
02 | using System.Collections.Generic; |
05 | using System.Runtime.Serialization.Formatters.Binary; |
06 | using System.Runtime.InteropServices; |
07 | using System.Diagnostics; |
09 | public class MessageHelper |
11 | [DllImport( "User32.dll" )] |
12 | private static extern int RegisterWindowMessage( string lpString); |
14 | [DllImport( "User32.dll" , EntryPoint = "FindWindow" )] |
15 | public static extern Int32 FindWindow(String lpClassName, String lpWindowName); |
18 | [DllImport( "User32.dll" , EntryPoint = "SendMessage" )] |
19 | public static extern int SendMessage( int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam); |
22 | [DllImport( "User32.dll" , EntryPoint = "PostMessage" )] |
23 | public static extern int PostMessage( int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam); |
25 | [DllImport( "User32.dll" , EntryPoint = "SendMessage" )] |
26 | public static extern int SendMessage( int hWnd, int Msg, int wParam, int lParam); |
28 | [DllImport( "User32.dll" , EntryPoint = "PostMessage" )] |
29 | public static extern int PostMessage( int hWnd, int Msg, int wParam, int lParam); |
31 | [DllImport( "User32.dll" , EntryPoint = "SetForegroundWindow" )] |
32 | public static extern bool SetForegroundWindow( int hWnd); |
34 | public const int WM_USER = 0x400; |
35 | public const int WM_COPYDATA = 0x4A; |
38 | public struct COPYDATASTRUCT |
42 | [MarshalAs(UnmanagedType.LPStr)] |
46 | public bool bringAppToFront( int hWnd) |
48 | return SetForegroundWindow(hWnd); |
51 | public int sendWindowsStringMessage( int hWnd, int wParam, string msg) |
57 |
byte [] sarr = System.Text.Encoding.Default.GetBytes(msg); |
58 |
int len = sarr.Length; |
60 |
cds.dwData = (IntPtr)100; |
63 |
result = SendMessage(hWnd, WM_COPYDATA, wParam, ref cds); |
69 | public int sendWindowsMessage( int hWnd, int Msg, int wParam, int lParam) |
75 |
result = SendMessage(hWnd, Msg, wParam, lParam); |
81 | public int getWindowId( string className, string windowName) |
84 | return FindWindow(className, windowName); |
So now you can call the code to send a message like so:
MessageHelper msg = new MessageHelper();
int result = 0;
//First param can be null
int hWnd = msg.getWindowId(null, “My App Name”);
result = msg.sendWindowsStringMessage(hWnd, 0, “Some_String_Message”);
//Or for an integer message
result = msg.sendWindowsMessage(hWnd, MessageHelper.WM_USER, 123, 456);
Now all you need to do on the app that you want to receive the message is override the following function in the form class (obviously you can change what the responses are, and you’ll need to create constants for the parameters):
01 | protected override void WndProc( ref Message m) |
06 |
MessageBox.Show( "Message recieved: " + m.WParam + " - " + m.LParam); |
09 |
COPYDATASTRUCT mystr = new COPYDATASTRUCT(); |
10 |
Type mytype = mystr.GetType(); |
11 |
mystr = (COPYDATASTRUCT)m.GetLParam(mytype); |
12 |
this .doSomethingWithMessage(mystr.lpData); |
출처 : http://boycook.wordpress.com/2008/07/29/c-win32-messaging-with-sendmessage-and-wm_copydata/