发送自定义Windows消息...自定义数据编组

时间:2013-04-30 19:15:37

标签: c# .net winapi marshalling sendmessage

我有一个需要与另一个应用程序连接的WPF应用程序。

此应用程序有大约20个自定义Windows消息(WM_USER + 50 ... WM_USER + 70)。

我想要完成的总结:

WPF应用程序 - > SendMessage - > ThirdParty应用程序

我遇到的问题是所有消息都是CUSTOM消息。因此,我必须实现自己的数据编组。

请参阅http://msdn.microsoft.com/en-us/library/windows/desktop/ms644950(v=vs.85).aspx

我需要经历的过程似乎是:

  1. 抓住进程并打开它以进行所有访问。   User32.GetWindowThreadProcessId(windowHandle,out pId);

    //使用所有访问权限打开流程   someprocess = OpenProcess((0x1F0FFF),false,(int)pId);

  2. 在此过程中分配缓冲区: IntPtr buffer = VirtualAllocEx(hProcess,IntPtr.Zero,1024,0x1000,0x04);

  3. 填写一些将写入#2中创建的缓冲区的结构?

  4. 将#3复制到远程缓冲区是#2? WriteProcessMemory的??

  5. 发送自定义消息(SendMessage(windowhandle,customMsg,0,来自#2的缓冲区?)

  6. 将结构从远程进程缓冲区读回到本地缓冲区

  7. 将此数据编组为托管类型。 (这是一个C#.Net应用程序)

  8. 我真的可以使用一些洞察力。到目前为止,我没有太多运气。我认为我最关注的部分是要发送到WriteProcessMemory的结构类型?

2 个答案:

答案 0 :(得分:1)

WM_COPYDATA绝对是最简单的方法。 WM_COPYDATA允许您将两个不同的数据项发送到另一个进程 - DWORD值和任意大小的数据块。因此,对于您的实现,您可能会执行以下操作:

COPYDATASTRUCT cds;
cds.dwData = WM_USER + 50; // the "message" you want to send
cds.cbData = sizeof(MyDataForMessage50); // the size of the chunk of data
cds.lpData = lpMessage50Data; // a pointer to the chunk of data
SendMessage(hwndTarget, WM_COPYDATA, reinterpret_cast<WPARAM>(hwndSender),
            reinterpret_cast<LPARAM>(&cds));

请注意,hwndTarget是其他流程中的目标窗口,hwndSender发送流程中的窗口。目标窗口接收相同的参数,因此可以使用wParam来了解发送邮件的人,因此可以在需要时发送回复。

在接收端的WndProc中:

if (uMsg == WM_COPYDATA)
{
    HWND hwndSender = reinterpret_cast<HWND>(wParam);
    LPCOPYDATASTRUCT pcds = reinterpret_cast<LPCOPYDATASTRUCT>(lParam);
    DWORD dwCustomMsg = pcds->dwData;
    LPVOID pCustomData = pcds->lpData;
    DWORD dwCustomDataSize = pcds->cbData;

    // do something with the custom message

    // return TRUE to indicate message received
    return TRUE;
}

另请注意WM_COPYDATA文档中的重要说明:

  

接收应用程序应将数据视为只读。该   lParam参数仅在处理消息期间有效。   接收应用程序不应释放引用的内存   lParam的。如果接收应用程序必须在之后访问数据   SendMessage返回,它必须将数据复制到本地缓冲区

答案 1 :(得分:0)

发送消息的示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
    class Program
    {
        public const int WM_COPYDATA = 0x4A;
        public const UInt32 WM_COMMAND = 0x0111;
        public const UInt32 IDM_MENU_SECUREDISCONNECT = 305;
        public const UInt32 PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
        [StructLayout(LayoutKind.Sequential)]
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int cbData;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string lpData;
        }
        [DllImport("User32.dll", EntryPoint = "SendMessage", SetLastError = true)]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
        private const string MARKER = "MARKER\n";
        static void Main(string[] args)
        {
            IntPtr destWnd = (IntPtr)int.Parse(args[0]);
          string packedargs = DAZZLE_MARKER + String.Join("\n", args[1]);
            /
            byte[] sarr = System.Text.Encoding.Unicode.GetBytes(packedargs);
            int len = sarr.Length;
            COPYDATASTRUCT CopyDataStruct;
            CopyDataStruct.dwData = (IntPtr)100;
            CopyDataStruct.cbData = (len + 1) * 2;
            CopyDataStruct.lpData = packedargs;
            int result = SendMessage(destWnd, WM_COPYDATA, 0, ref CopyDataStruct);
        }
    }
}