You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C++的WindowProc函数无法接收C#发送的SendMessage消息?

解决C#向MFC程序发送WM_COPYDATA无响应的问题

我来帮你排查一下这个问题,主要是两个核心原因导致MFC端的WM_COPYDATA分支没反应,咱们一步步来修复:

问题根源

  1. WM_COPYDATA参数传递完全错误:这个消息要求lParam必须指向一个标准的COPYDATASTRUCT结构体,你现在传的是普通int变量,MFC根本认不出这是WM_COPYDATA的有效数据,自然不会进入分支。
  2. 窗口句柄可能没拿到正确的对话框句柄:Process.MainWindowHandle有时候会因为程序启动顺序的问题,拿到的不是MFC对话框的实际句柄,而是程序的其他窗口(比如启动闪屏)。

第一步:修正C#端的消息发送逻辑

首先得在C#里正确定义COPYDATASTRUCT,然后修改SendMessage的调用方式,确保传递的是符合要求的结构体:

public partial class MainWindow : Window
{
    public const string strFilePath = "C:/Users/gandis/Desktop/Project/ExeC/Release/ExeC.exe";
    public const Int32 WM_COPYDATA = 0x004A;

    // 和C++端完全匹配的COPYDATASTRUCT结构体
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct COPYDATASTRUCT
    {
        public IntPtr dwData; // 自定义标识,用来区分不同消息类型
        public int cbData;    // 数据的字节数
        [MarshalAs(UnmanagedType.LPWStr)]
        public string lpData; // 要传递的字符串数据(如果传数值可以改成对应类型)
    }

    // 修正SendMessage的签名,lParam必须是COPYDATASTRUCT的引用
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 message, IntPtr wParam, ref COPYDATASTRUCT lParam);

    public MainWindow()
    {
        InitializeComponent();
    }

    private void btn_Start_Click(object sender, RoutedEventArgs e)
    {
        IntPtr hWnd = GetHandle(strFilePath);
        if (hWnd != IntPtr.Zero)
        {
            // 构造要发送的数据结构体
            COPYDATASTRUCT cds = new COPYDATASTRUCT();
            cds.dwData = (IntPtr)1; // 自定义标识,和C++端对应
            string sendContent = "来自C#的测试消息";
            // Unicode字符串的字节数要算上终止符,所以是(长度+1)*2
            cds.cbData = (sendContent.Length + 1) * 2;
            cds.lpData = sendContent;

            // 发送WM_COPYDATA消息
            SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
        }
    }

    private IntPtr GetHandle(string strFilePath)
    {
        Process proc = GetProcess(strFilePath);
        // 给程序一点时间完成窗口初始化,避免拿到空句柄
        System.Threading.Thread.Sleep(500);
        IntPtr hWnd = proc.MainWindowHandle;
        
        // 如果MainWindowHandle为空,尝试通过窗口标题查找(替换成你的MFC对话框标题)
        if (hWnd == IntPtr.Zero)
        {
            hWnd = FindWindow(null, "ExeC");
        }
        return hWnd;
    }

    private Process GetProcess(string strFilePath)
    {
        Process proc = new Process();
        proc.StartInfo.FileName = strFilePath;
        proc.Start();
        // 设置等待超时,防止无限卡住
        proc.WaitForInputIdle(1000);
        return proc;
    }

    // 补充FindWindow的DllImport,用来根据标题找窗口
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}

第二步:修正MFC端的消息处理逻辑

你的MFC代码已经有WM_COPYDATA的分支,但需要正确解析结构体,并且必须返回TRUE表示消息已处理,否则系统会认为消息没被接收:

LRESULT CExeCDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COPYDATA:
        {
            // 把lParam转换成COPYDATASTRUCT指针
            COPYDATASTRUCT* pCDS = reinterpret_cast<COPYDATASTRUCT*>(lParam);
            if (pCDS != nullptr)
            {
                // 匹配C#端的自定义标识(这里是1)
                if (pCDS->dwData == reinterpret_cast<DWORD_PTR>(1))
                {
                    // 解析字符串数据
                    CString recvMsg(reinterpret_cast<LPCTSTR>(pCDS->lpData));
                    AfxMessageBox(_T("收到C#消息:") + recvMsg);
                }
                // 如果是传递数值,比如int,可以这样解析:
                // int recvValue = *reinterpret_cast<int*>(pCDS->lpData);
                // AfxMessageBox(_T("收到数值:") + CString::Format(_T("%d"), recvValue));
            }
            // 必须返回TRUE,告诉系统消息已处理
            return TRUE;
        }
        break;
    default:
        break;
    }
    return CDialog::WindowProc(message, wParam, lParam);
}

额外注意事项

  • 字符集统一:确保MFC项目设置为使用Unicode字符集(项目属性 -> 常规 -> 字符集),和C#端保持一致,否则字符串会乱码或者解析失败。
  • 窗口句柄准确性:如果MainWindowHandle还是拿不到正确的句柄,可以用EnumWindows枚举所有窗口,通过进程ID匹配找到对应的对话框句柄。
  • 权限一致:两个程序要么都以普通用户身份运行,要么都以管理员身份运行,UAC权限隔离会导致跨权限的消息发送失败。

内容的提问来源于stack exchange,提问作者gandis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:53:15