c# - SendMessage 使用 RegisterWindowMessage API 失败

标签 c# c++ sendmessage

我正在从 C# 应用程序向 C++ Win32 应用程序发送窗口消息。我正在通过 RegisterWindowMessage() API 使用消息。

字符串值从 C# 传输到 C++,但在 C++ 端我无法将它转换回字符串。

C#

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

_sendMessageID = RegisterWindowMessage("WM_MSG_TEST");

public void SendMessage()
{
    IntPtr buffer = Marshal.StringToBSTR("Hello");
    SendMessage((IntPtr)0xffff, (int)_sendMessageID, IntPtr.Zero, buffer);
}

C++

UINT WM_MSG_AA = RegisterWindowMessage("WM_MSG_TEST");

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_MSG_TEST)
    {
        BSTR* pcds = (BSTR*)lParam;
    }
}

请让我知道如何解决这个问题?

我也引用了下面的链接来解决问题,但它无济于事。

C# SendMessage to C++ WinProc

Send message to a hwnd in C#

// WindowCreationCode

BOOL ProcessNextMessage()
{   
    MSG msg;
    GetMessage(&(msg), _hWnd, 0, 0);
    TranslateMessage(&(msg));
    DispatchMessage(&(msg));
    return TRUE;
}
int Create(){
    CoInitialize(NULL);
    _hInst = GetModuleHandle(NULL);

    WNDCLASS wcex = { 0 };
    wcex.lpfnWndProc = WndProc;
    wcex.hInstance = _hInst;
    wcex.lpszClassName = c_szClassName;

    if (!GetClassInfo(wcex.hInstance, wcex.lpszClassName, &wcex))
    {
        if (!RegisterClass(&wcex))
        {
            return HRESULT_FROM_WIN32(GetLastError());
        }
        else
        {
            return S_OK;
        }
    }
    else
    {
        return S_OK;
    }

    _hWnd = CreateWindowEx(
        WS_EX_TOPMOST,
        c_szClassName,
        "ACTXAUTODRIVER",
        WS_DLGFRAME ,
        1, 1, 1, 1,
        NULL,
        NULL, _hInst, NULL);

        ShowWindow(_hWnd, SW_HIDE);

        while (ProcessNextMessage())
        {
        }
    CoUninitialize();
}

最佳答案

您不能像您尝试的那样跨进程边界发送原始内存指针。即使您将 C# 字符串数据转换为操作系统分配的 BSTR,分配的内存仍然只在分配它的进程的地址空间中有效。

您的字符串数据必须从一个进程的地址空间编码到另一个进程的地址空间。当 COM 通过进程边界传递 BSTR 值时,它会自动为您处理。但是对于窗口消息,只有某些消息会被操作系统自动编码,而使用 RegisterWindowMessage() 创建的消息不会被编码。

对于您正在尝试的内容,请使用 WM_COPYDATA相反,这是编码的。但是,您永远不应该广播(使用 (IntPtr)0xffff 又名 HWND_BROADCAST 作为目标窗口)WM_COPYDATA 消息!如果毫无戒心的应用收到它们未准备好正确处理的 WM_COPYDATA 消息,就会发生坏事。

让您的 C# 代码为您的 C++ 应用找到它实际感兴趣的特定窗口(来自 FindWindow/Ex() 等),然后发送 WM_COPYDATA 只有那个窗口,没有其他人。您可以使用 RegisterWindowMessage() 创建一个用于 COPYDATASTRUCT::dwData 字段的唯一值,以区分您对 WM_COPYDATA 的使用与其他人的使用 WM_COPYDATA。让您的 C++ 代码忽略任何 WM_COPYDATA 消息,其 dwData 值无法识别。

尝试更像这样的东西:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
    public IntPtr dwData;
    public int cbData;
    public IntPtr lpData;
}

const int WM_COPYDATA = 0x004A;

_cdsDataID = RegisterWindowMessage("WM_MSG_TEST");

public void SendMessage() {
    if (_cdsDataID == IntPtr.Zero) return;
    IntPtr TargetWnd = ...; // FindWindow(), etc
    if (TargetWnd == IntPtr.Zero) return;
    string s = "Hello";
    COPYDATASTRUCT copyData = new COPYDATASTRUCT();
    copyData.lpData = Marshal.StringToHGlobalUni(s);
    if (copyData.lpData != IntPtr.Zero)
    {
        copyData.dwData = _cdsDataID;
        copyData.cbData = (s.Length + 1) * 2;
        IntPtr copyDataBuff = Marshal.AllocHGlobal(Marshal.SizeOf(copyData));
        if (copyDataBuff != IntPtr.Zero)
        {
            Marshal.StructureToPtr(copyData, copyDataBuff, false);
            SendMessage(TargetWnd, WM_COPYDATA, IntPtr.Zero, copyDataBuff);
            Marshal.FreeHGlobal(copyDataBuff);
        }
        Marshal.FreeHGlobal(copyData.lpData);
    }
}
const UINT uiDataID = RegisterWindowMessage("WM_MSG_TEST");

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_COPYDATA) 
    {
        LPCOPYDATASTRUCT pcds = (LPCOPYDATASTRUCT) lParam;
        if ((pcds->dwData == WM_MSG_TEST) && (WM_MSG_TEST != 0))
        {
            WCHAR* pstr = (WCHAR*) pcds->lpData;
            ...
            return 0;
        }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

关于c# - SendMessage 使用 RegisterWindowMessage API 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52380172/

相关文章:

c# - 如何在散列文件时监视状态?

c# - WebActivator PreApplicationStartMethod 不工作

c# - 从 Web 服务返回域对象

c++ - 类 draw() 方法在直接调用时有效,但在被另一个对象调用时崩溃

c# - Twilio TwilioRestClient 'SendMessage'方法未检测到C#中的编译器错误

c# - 将右键单击发送到窗口

c++ - GetProcessId 失败,错误 6 : The handle is invalid

c# - Windows 8 手机 C# 请求桌面网站无法正常工作

c++ - 两个进程之间如何通信

c++ - 如何将 C 生成文件移植到 C++ 生成文件?