将ansi消息发送到unicode窗口

时间:2016-12-17 20:48:56

标签: c winapi

如果我用RegisterClassExW注册一个窗口类,我创建一个该类的窗口(让我们调用该窗口hwndA),如果我发送SendMessageA(hwndA, WM_SETTEXT, 0, (LPARAM)"Hello"),当hwndA收到WM_SETTEXT时, lParam始终指向unicode字符串,即使我使用了SendMessageA()

4 个答案:

答案 0 :(得分:4)

如果您使用RegisterClassExW注册Window类,那么是。 Windows具有SendMessage的特殊情况逻辑和使用字符串的众所周知的消息。这包括WM_SETTEXT

如果使用ANSI样式函数RegisterClassARegisterClassExA注册了Window的类,则后续带字符串的窗口消息的所有字符串参数都将为ascii。如果窗口的类已使用宽版本(RegisterClassWRegisterClassExW)注册,则所有带字符串的后续窗口消息都将是unicode。

因此,在一般情况下,假设您的代码使用Unicode API(这些天是默认值),您总是在WM_SETTEXT中获得Unicode字符串。 Windows会将通过SendMessageA传入的ansi字符串转换为宽字符串。

这是我做的确认:

以下面的WndProc为例 - 从默认的Visual Studio Win32应用程序模板修改。

void LogPointer(const wchar_t* name, void* value, bool isUnicode)
{
    std::wostringstream ss;
    ss << L"Name=" << name << L"   value=" << std::hex << value << std::dec;
    if (isUnicode)
    {
        ss << L"    printed: " << (const wchar_t*)value;
    }
    else
    {
        ss << L"    printed: " << (const char*)value;
    }
    ss <<  L"\r\n";

    std::wstring str = ss.str();
    OutputDebugStringW(str.c_str());
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    char* psz = "Hello world";
    wchar_t* wpsz = L"Bye Bye";

    switch (message)
    {

        case WM_SETTEXT:
        {
            LogPointer(L"psz", psz, false);
            LogPointer(L"wpsz", wpsz, true);
            LogPointer(L"lParam", (void*)lParam, true);


            return DefWindowProc(hWnd, message, wParam, lParam);
        }

        case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
                case IDM_ABOUT:
                {
                    OutputDebugStringW(L"Invoking SendMessageA with ansi string\r\n");
                    SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)psz);

                    OutputDebugStringW(L"\r\nInvoking SendMessageW with wide string\r\n");
                    SendMessageW(hWnd, WM_SETTEXT, 0, (LPARAM)wpsz);
                    break;
                }

输出如下:

Invoking SendMessageA with ansi string
Name=psz   value=0096338C    printed: Hello world
Name=wpsz   value=0096339C    printed: Bye Bye
Name=lParam   value=005ADE78    printed: Hello world

Invoking SendMessageW with wide string
Name=psz   value=0096338C    printed: Hello world
Name=wpsz   value=0096339C    printed: Bye Bye
Name=lParam   value=0096339C    printed: Bye Bye

现在在两组输出日志行中观察lParam的值。

如果是SendMessageAlParam的指针值既不匹配psz也不匹配wpsz。引擎盖下的Windows识别出它需要将ansi字符串转换为宽字符。因此它为您进行转换,并实际发送它管理的不同分配字符串。

对于SendMessageW,lParam==wpsz。没有转换。 Windows只是将lParam值直接传递给WndProc来电。

答案 1 :(得分:1)

你可以使用

SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Hello");

SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)L"Hello");

在两种情况下lParam(在windowproc中)总是指向一个unicode字符串。在第一种情况下SendMessageA - 系统从堆或堆栈分配内存,并将ansi "Hello"转换为unicode,并且您获得了指向此内存的指针。 在第二种情况SendMessageW中 - 您在窗口过程中直接指向L"Hello"

答案 2 :(得分:0)

注意,如果使用SetWindowLongPtrA,回调函数lParam(WM_SETTEXT)会指向一个ANSI字符串,所以如果回调函数中需要wchar_t,请提前使用SetWindowLongPtrW

答案 3 :(得分:-3)

CreateWindow A或W进行更改而非regstyle.W窗口可能会将其解释为宽字符。