【问题标题】:C++ WinAPI. Wrong text display in the listboxC++ WinAPI。列表框中的文本显示错误
【发布时间】:2018-05-11 16:56:42
【问题描述】:

我的任务是创建一个程序,该程序显示系统中所有窗口的描述符列表。我得到这个输出:

可能是编码错误?

这是我的代码:

#include <windows.h>

ATOM RegMyWindowClass(HINSTANCE, LPCTSTR);
HWND hListBox;
HINSTANCE hin;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    WCHAR str[255];
    if (GetWindowTextW(hwnd, str, 255)) {
        if (IsWindowVisible(hwnd) && (!GetWindow(hwnd, GW_OWNER)))
            SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)str);
    }
    return 1;
}

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONUP:
        MessageBox(hWnd, TEXT("Вы кликнули!"), TEXT("событие"), 0);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);  
        break;
    case WM_CREATE:
        hListBox = CreateWindow("LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL,
            0, 0, 400, 400, hWnd, (HMENU)1111, hin, NULL);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
    HINSTANCE         hPrevInstance,
    LPSTR             lpCmdLine,
    int               nCmdShow)
{
    LPCTSTR lpzClass = TEXT("My Window Class!");

    if (!RegMyWindowClass(hInstance, lpzClass))
        return 1;

    RECT screen_rect;
    GetWindowRect(GetDesktopWindow(), &screen_rect); 
    int x = screen_rect.right / 2 - 200;
    int y = screen_rect.bottom / 2 - 200;

    HWND hWnd = CreateWindow(lpzClass, TEXT("Window"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, x, y, 400, 400, NULL, NULL,
        hInstance, NULL);
    ShowWindow(hWnd, SW_SHOW);
    EnumWindows(&EnumWindowsProc, 0);
    if (!hWnd) return 2;

    MSG msg = { 0 };   
    int iGetOk = 0;   
    while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (iGetOk == -1) return 3;  
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;  
}

ATOM RegMyWindowClass(HINSTANCE hInst, LPCTSTR lpzClassName)
{
    WNDCLASS wcWindowClass = { 0 };
    wcWindowClass.lpfnWndProc = (WNDPROC)WndProc;
    wcWindowClass.style = CS_HREDRAW | CS_VREDRAW;
    wcWindowClass.hInstance = hInst;
    wcWindowClass.lpszClassName = lpzClassName;
    wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    return RegisterClass(&wcWindowClass); 
}

任何想法如何解决这个问题?

【问题讨论】:

  • 尝试用TCHAR替换WCHAR,用GetWindowText替换GetWindowTextW
  • @JohnnyMopp 它有效!谢谢!
  • 您不应混合使用 TCHAR 和 WCHAR 以及 A 和 W 版本的函数。在任何地方使用 WCHARW 版本的函数,并确保在启用 UNICODE 的情况下进行编译。
  • @JohnnyMopp 这是一个糟糕的建议。现代应用程序应始终使用宽字符串(和相应的函数)而不是 ANSI 兼容性包装器。
  • @VTT 如果您明确使用WCHARW 函数,则根本无需担心UNICODE 定义。它仅适用于基于TCHARTCHAR 的函数。

标签: c++ winapi sendmessage


【解决方案1】:

问题是您正在为 ANSI 编译项目,其中 TCHARCHAR 的别名,因此正在创建一个基于 ANSI 的列表框,但您正在向它发送 Unicode 字符串。这就是为什么您在输出中看到垃圾的原因。您需要将 ANSI 字符串发送到 ListBox,例如:

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    if (IsWindowVisible(hwnd) && (!GetWindow(hwnd, GW_OWNER)))
        CHAR str[255] = {};
        if (GetWindowTextA(hwnd, str, 255)) {
            SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)str);
        }
    }
    return TRUE;
}

或者:

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    if (IsWindowVisible(hwnd) && (!GetWindow(hwnd, GW_OWNER))) {
        CHAR str[255] = {};
        if (IsWindowUnicode(hwnd)) {
            WCHAR wstr[255] = {}; 
            int len = GetWindowTextW(hwnd, wstr, 255);
            if (len) {
                len = WideCharToMultiByte(CP_ACP, 0, wstr, len+1, str, 255, NULL, NULL);
            }
            if (!len) {
                return TRUE;
            }
        }
        else if (!GetWindowTextA(hwnd, str, 255)) {
            return TRUE;
        }
        SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)str);
    }
    return TRUE;
}

话虽如此,您正在混合使用 ANSI、Unicode 和 TCHAR API。您需要选择1 API 风格并坚持一切,不要混合它们(除非你绝对必须这样做)。

由于您显示的大部分代码已经在使用TCHAR,那么您可以对所有内容使用TCHAR(不过,您真的不应该这样做,因为TCHAR 是为了向后兼容Win9x/ME没有人再使用了,只是为了帮助人们将他们的代码迁移到 Unicode。现代代码根本不应该使用TCHAR):

#include <windows.h>

ATOM RegMyWindowClass(HINSTANCE, LPCTSTR);
HWND hListBox;
HINSTANCE hin;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    if (IsWindowVisible(hwnd) && (!GetWindow(hwnd, GW_OWNER))) {
        TCHAR str[255];
        if (GetWindowText(hwnd, str, 255)) {
            SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)str);
        }
    }
    return TRUE;
}

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONUP:
        // this is one case where it doesn't make sense to use TCHAR
        MessageBoxW(hWnd, L"Вы кликнули!", L"событие", 0);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);  
        break;
    case WM_CREATE:
        hListBox = CreateWindow(TEXT("LISTBOX"), TEXT(""), WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL,
            0, 0, 400, 400, hWnd, (HMENU)1111, hin, NULL);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
    HINSTANCE         hPrevInstance,
    LPSTR             lpCmdLine,
    int               nCmdShow)
{
    LPCTSTR lpzClass = TEXT("My Window Class!");

    if (!RegMyWindowClass(hInstance, lpzClass))
        return 1;

    RECT screen_rect;
    GetWindowRect(GetDesktopWindow(), &screen_rect); 
    int x = screen_rect.right / 2 - 200;
    int y = screen_rect.bottom / 2 - 200;

    HWND hWnd = CreateWindow(lpzClass, TEXT("Window"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, x, y, 400, 400, NULL, NULL,
        hInstance, NULL);
    ShowWindow(hWnd, SW_SHOW);
    EnumWindows(&EnumWindowsProc, 0);
    if (!hWnd) return 2;

    MSG msg = { 0 };   
    int iGetOk = 0;   
    while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (iGetOk == -1) return 3;  
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;  
}

ATOM RegMyWindowClass(HINSTANCE hInst, LPCTSTR lpzClassName)
{
    WNDCLASS wcWindowClass = { 0 };
    wcWindowClass.lpfnWndProc = &WndProc;
    wcWindowClass.style = CS_HREDRAW | CS_VREDRAW;
    wcWindowClass.hInstance = hInst;
    wcWindowClass.lpszClassName = lpzClassName;
    wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    return RegisterClass(&wcWindowClass); 
}

除此之外,一切都使用 Unicode:

#include <windows.h>

ATOM RegMyWindowClass(HINSTANCE, LPCWSTR);
HWND hListBox;
HINSTANCE hin;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    if (IsWindowVisible(hwnd) && (!GetWindow(hwnd, GW_OWNER))) {
        WCHAR str[255];
        if (GetWindowTextW(hwnd, str, 255)) {
            SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)str);
        }
    }
    return TRUE;
}

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONUP:
        MessageBoxW(hWnd, L"Вы кликнули!", L"событие", 0);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);  
        break;
    case WM_CREATE:
        hListBox = CreateWindowW(L"LISTBOX", L"", WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL,
            0, 0, 400, 400, hWnd, (HMENU)1111, hin, NULL);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
    HINSTANCE         hPrevInstance,
    LPSTR             lpCmdLine,
    int               nCmdShow)
{
    LPCWSTR lpzClass = L"My Window Class!";

    if (!RegMyWindowClass(hInstance, lpzClass))
        return 1;

    RECT screen_rect;
    GetWindowRect(GetDesktopWindow(), &screen_rect); 
    int x = screen_rect.right / 2 - 200;
    int y = screen_rect.bottom / 2 - 200;

    HWND hWnd = CreateWindowW(lpzClass, L"Window",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, x, y, 400, 400, NULL, NULL,
        hInstance, NULL);
    ShowWindow(hWnd, SW_SHOW);
    EnumWindows(&EnumWindowsProc, 0);
    if (!hWnd) return 2;

    MSG msg = { 0 };   
    int iGetOk = 0;   
    while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (iGetOk == -1) return 3;  
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;  
}

ATOM RegMyWindowClass(HINSTANCE hInst, LPCWSTR lpzClassName)
{
    WNDCLASSW wcWindowClass = { 0 };
    wcWindowClass.lpfnWndProc = &WndProc;
    wcWindowClass.style = CS_HREDRAW | CS_VREDRAW;
    wcWindowClass.hInstance = hInst;
    wcWindowClass.lpszClassName = lpzClassName;
    wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    return RegisterClassW(&wcWindowClass); 
}

或者,如果您需要保持与项目中其他地方的现有代码逻辑的兼容性,则对所有内容都坚持使用 ANSI:

#include <windows.h>

ATOM RegMyWindowClass(HINSTANCE, LPCSTR);
HWND hListBox;
HINSTANCE hin;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    if (IsWindowVisible(hwnd) && (!GetWindow(hwnd, GW_OWNER))) {
        CHAR str[255];
        if (GetWindowTextA(hwnd, str, 255)) {
            SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)str);
        }
    }
    return TRUE;
}

LRESULT CALLBACK WndProc(
    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONUP:
        // this is one case where it doesn't make sense to use ANSI
        MessageBoxW(hWnd, L"Вы кликнули!", L"событие", 0);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);  
        break;
    case WM_CREATE:
        hListBox = CreateWindowA("LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL,
            0, 0, 400, 400, hWnd, (HMENU)1111, hin, NULL);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
    HINSTANCE         hPrevInstance,
    LPSTR             lpCmdLine,
    int               nCmdShow)
{
    LPCSTR lpzClass = "My Window Class!";

    if (!RegMyWindowClass(hInstance, lpzClass))
        return 1;

    RECT screen_rect;
    GetWindowRect(GetDesktopWindow(), &screen_rect); 
    int x = screen_rect.right / 2 - 200;
    int y = screen_rect.bottom / 2 - 200;

    HWND hWnd = CreateWindowA(lpzClass, "Window",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, x, y, 400, 400, NULL, NULL,
        hInstance, NULL);
    ShowWindow(hWnd, SW_SHOW);
    EnumWindows(&EnumWindowsProc, 0);
    if (!hWnd) return 2;

    MSG msg = { 0 };   
    int iGetOk = 0;   
    while ((iGetOk = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (iGetOk == -1) return 3;  
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;  
}

ATOM RegMyWindowClass(HINSTANCE hInst, LPCSTR lpzClassName)
{
    WNDCLASSA wcWindowClass = { 0 };
    wcWindowClass.lpfnWndProc = &WndProc;
    wcWindowClass.style = CS_HREDRAW | CS_VREDRAW;
    wcWindowClass.hInstance = hInst;
    wcWindowClass.lpszClassName = lpzClassName;
    wcWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcWindowClass.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    return RegisterClassA(&wcWindowClass); 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多