Send byte[] from c# via Win32 SendMessage
I'm working on porting some code from c++ to c#, and I'm having some trouble getting PostMessage to work in the c# app. I'm not very good (yet) at MFC stuff, and I think I'm making a few basic mistakes. What happens in the c++ code is that a byte array is posted to a window:
unsigned long result[5] = {0};
//Put some data in t开发者_如何学运维he array
unsigned int res = result[0];
Text winName = "window name";
HWND hWnd = FindWindow(winName.getConstPtr(), NULL);
BOOL result = PostMessage(hWnd, WM_COMMAND, 10, res);
I'm using the following c# code (based on code here) in an attempt to do the same thing:
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.SafeArray)]
public byte[] lpData;
}
public static int sendWindowsByteMessage(int hWnd, int wParam, byte[] data)
{
int result = 0;
if (hWnd > 0)
{
int len = data.Length;
COPYDATASTRUCT cds;
cds.dwData = (IntPtr)100;
cds.lpData = data;
cds.cbData = len + 1;
result = PostMessage(hWnd, WM_COPYDATA, wParam, ref cds);
}
return result;
}
byte[] result = getResults();
int hWnd = MessageHelper.FindWindow(null, "window name");
int status = MessageHelper.sendWindowsByteMessage(hWnd, 10, result);
The value of status is always 0, which according to the docs on PostMessage means failure. Any pointers on the (probably simple) mistakes I'm making?
WM_ COPYDATA
must be sent rather than posted.
I'm not sure that your byte[] marshaling is right either.
Here is a version of the same logic that I have used successfully:
[StructLayout(LayoutKind.Sequential)]
internal class COPYDATASTRUCT
{
internal uint dwData;
internal uint cbData;
internal IntPtr lpData;
}
// send DATA packet
internal static void SendData(IntPtr hWnd, uint dwData, DATA infos)
{
// get pointer to DATA block
IntPtr infoMem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DATA)));
Marshal.StructureToPtr(infos, infoMem, false);
// construct COPYDATASTRUCT to point to DATA block
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.dwData = dwData;
cds.lpData = infoMem;
cds.cbData = (uint)Marshal.SizeOf(typeof(DATA));
// get pointer to COPYDATASTRUCT block
IntPtr cdsMem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(COPYDATASTRUCT)));
Marshal.StructureToPtr(cds, cdsMem, false);
// send message with block pointer to other process
SendMessage(hWnd, WM_COPYDATA, 0, (uint)cdsMem.ToInt32());
// Free allocated memory
Marshal.FreeHGlobal(cdsMem);
Marshal.FreeHGlobal(infoMem);
}
If the target window is in another process you need to use HGlobal memory. I am not sure if the UnmanagedType.SafeArray does that for you.
PostMessage probably fails because the window handle is invalid. Call GetLastError to find out what the reason for the failure was. You'll actually want to use SendMessage here - the buffer is only guaranteed to be allocated for the duration of the call, and PostMessage is asynchronous - it returns after posting the message and your cds structure might get freed before the target window proc is invoked. If you need to use PostMessage, you'll have to explicitly allocated an unmanaged buffer, copy your data to it, and use that for the call.
精彩评论