将ansi消息发送到unicode窗口

将ansi消息发送到unicode窗口,c,winapi,C,Winapi,如果我用注册表类注册了一个窗口类,并创建了该类的窗口(我们称之为窗口hwndA),如果我发送了SendMessageA(hwndA,WM_SETTEXT,0,(LPARAM)“Hello”),当hwndA接收到WM_SETTEXT时,LPARAM将始终指向unicode字符串,即使我使用了SendMessageA()?创建窗口A或W进行更改而不是regstyle。W窗口可能会将其解释为宽字符。您可以使用 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Hel

如果我用注册表类注册了一个窗口类,并创建了该类的窗口(我们称之为窗口hwndA),如果我发送了SendMessageA(hwndA,WM_SETTEXT,0,(LPARAM)“Hello”),当hwndA接收到WM_SETTEXT时,
LPARAM
将始终指向unicode字符串,即使我使用了
SendMessageA()

创建窗口A或W进行更改而不是regstyle。W窗口可能会将其解释为宽字符。

您可以使用

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

在这两种情况下,
lParam
(在windowproc中)始终指向unicode字符串。在第一种情况下,系统从堆或堆栈中分配内存,并将ansi
“Hello”
转换为unicode,就得到了指向该内存的指针。
在第二种情况下,
sendmaessew
-如果使用
registerclassesxw
注册窗口类,则在windowproc

中直接指向
L“Hello”
,然后是。Windows对
SendMessage
和使用字符串的已知消息具有特殊的大小写逻辑。这包括
WM\u SETTEXT

如果窗口的类是用ANSI样式的函数注册的,
RegisterClassA
registerClassxa
,则后续带有字符串的窗口消息的所有字符串参数都将是ascii。如果窗口的类是用宽版本(
RegisterClassW
RegisterClassXW
)注册的,则所有后续带有字符串的窗口消息都将是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;
                }
现在观察两组输出日志行中的
lParam

sendmagesa
的情况下,
lParam
的指针值与
psz
wpsz
的指针值都不匹配。在引擎盖下面的Windows可以识别出它需要将ansi字符串转换为宽字符。因此,它为您进行转换,并实际发送一个它管理的不同的分配字符串


在SendMessageW的情况下,
lParam==wpsz
。没有进行任何转换。Windows刚刚将
lParam
值直接传递给
WndProc
调用。

请注意,如果使用SetWindowLongPtrA,回调函数lParam(WM_SETTEXT)将指向ANSI字符串,因此如果回调函数中需要wchar\t,预先使用SetWindowLongPtrW

通过调用来确定窗口是Unicode窗口还是ANSI窗口。
CreateWindowA
CreateWindowW
都可以用于任何窗口类,但都不能更改已注册窗口类的字符集。@IInspectable,因此您有Curaçao类,并希望在CreateWindowA中使用它。这有点像垃圾。您是否准备在惩罚框中使用下个月?无论如何,字符
ç
可以在几个ANSI代码页中使用,因此是的,
CreateWindowA
可以创建类
Curaçao
的窗口。不建议这样做,但可能。不管怎样,如果你停止评论那些你一点也不知道的东西,那将大有帮助。你的答案是错的。我的评论是正确的。你没有什么要补充的。说真的。
CreateWindowA可以创建一个类为L“Curaçao”的窗口。
这是我在本文前面写的线索
CreateWindowA
不需要很宽的字符串文字。但是,如果当前的ANSI代码页可以表示所有符号,那么传递
“Curaçao”
没有什么错。无论如何,我想说的一点很简单:你提出的答案是错误的。请参阅示例:“窗口的字符集由RegisterClass函数的使用决定。”
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