C ++ WinAPI.Неверное отображение текста в списке - PullRequest
0 голосов
/ 11 мая 2018

У меня есть задача создать программу, которая отображает список дескрипторов всех окон в системе. Я получаю этот вывод:

image

Может быть, это неправильная кодировка?

Вот мой код:

#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); 
}

Есть идеи как это исправить?

1 Ответ

0 голосов
/ 11 мая 2018

Проблема в том, что вы компилируете свой проект для ANSI, где TCHAR является псевдонимом для CHAR, и, таким образом, создаете ListBox на основе 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;
}

Как говорится, вы смешиваете API ANSI, Unicode и TCHAR. Вам нужно выбрать стиль 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); 
}

Иначе, используйте Юникод для всего:

#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); 
}
...