【问题标题】:OpenGL, WinAPI | garbage values to unicode(I think, L"") stringOpenGL,WinAPI | unicode(我认为,L“”)字符串的垃圾值
【发布时间】:2021-02-22 07:00:20
【问题描述】:

我想尝试学习 OpenGL,我知道 C++,我找到了一个带有 C++/OpenGL 教程的site,这个网站还教了一些关于 WinAPI 的东西,因为“我们的”程序将是 Windows 应用程序。在this 教程中,它包含“我们的”第一个 Windows 应用程序的代码。代码(无法编译)

/*  Trim fat from windows*/
#define WIN32_LEAN_AND_MEAN 
#pragma comment(linker, "/subsystem:windows")
/*  Pre-processor directives*/
#include "stdafx.h"
#include <windows.h>
/*  Windows Procedure Event Handler*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT paintStruct;
    /*  Device Context*/
    HDC hDC; 
    /*  Text for display*/
    char string[] = "Hello, World!"; 
    /*  Switch message, condition that is met will execute*/
    switch(message)
    {
        /*  Window is being created*/
        case WM_CREATE: 
            return 0;
            break;
        /*  Window is closing*/
        case WM_CLOSE: 
            PostQuitMessage(0);
            return 0;
            break;
        /*  Window needs update*/
        case WM_PAINT: 
            hDC = BeginPaint(hwnd,&paintStruct);
            /*  Set txt color to blue*/
            SetTextColor(hDC, COLORREF(0x00FF0000));
            /*  Display text in middle of window*/
            TextOut(hDC,150,150,string,sizeof(string)-1);
            EndPaint(hwnd, &paintStruct);
            return 0;
            break;
        default:
            break;
    }
    return (DefWindowProc(hwnd,message,wParam,lParam));
}
/*  Main function*/
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    WNDCLASSEX  windowClass;        //window class
    HWND        hwnd;               //window handle
    MSG         msg;                //message
    bool        done;               //flag saying when app is complete
    /*  Fill out the window class structure*/
    windowClass.cbSize = sizeof(WNDCLASSEX);
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = WndProc;
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hInstance = hInstance;
    windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    windowClass.lpszMenuName = NULL;
    windowClass.lpszClassName = "MyClass";
    windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
    /*  Register window class*/
    if (!RegisterClassEx(&windowClass))
    {
        return 0;
    }
    /*  Class registerd, so now create window*/
    hwnd = CreateWindowEx(NULL,     //extended style
        "MyClass",          //class name
        "A Real Win App",       //app name
        WS_OVERLAPPEDWINDOW |       //window style
        WS_VISIBLE |
        WS_SYSMENU,
        100,100,            //x/y coords
        400,400,            //width,height
        NULL,               //handle to parent
        NULL,               //handle to menu
        hInstance,          //application instance
        NULL);              //no extra parameter's
    /*  Check if window creation failed*/
    if (!hwnd)
        return 0;
    done = false; //initialize loop condition variable
    /*  main message loop*/
    while(!done)
    {
        PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE);
        if (msg.message == WM_QUIT) //check for a quit message
        {
            done = true; //if found, quit app
        }
        else
        {
            /*  Translate and dispatch to event queue*/
            TranslateMessage(&msg); 
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

它没有编译,它有一些错误,所以我改变了一点

/*  Trim fat from windows*/
#define WIN32_LEAN_AND_MEAN 
#pragma comment(linker, "/subsystem:windows")
/*  Pre-processor directives*/
#include <tchar.h> //couldn't find stdafx.h
#include <windows.h>
/*  Windows Procedure Event Handler*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT paintStruct;
    /*  Device Context*/
    HDC hDC;
    /*  Text for display*/
    wchar_t string[] = L"F*CK!!!! It doesn't work, why am I getting Kanji? WTF\0"; // fixed error: char not compatible, char -> wchar_t
    /*  Switch message, condition that is met will execute*/
    switch (message)
    {
        /*  Window is being created*/
    case WM_CREATE:
        return 0;
        break;
        /*  Window is closing*/
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
        break;
        /*  Window needs update*/
    case WM_PAINT:
        hDC = BeginPaint(hwnd, &paintStruct);
        /*  Set txt color to blue*/
        SetTextColor(hDC, COLORREF(0x00FF0000));
        /*  Display text in middle of window*/
        TextOut(hDC, 150, 150, string, sizeof(string) - 1);
        EndPaint(hwnd, &paintStruct);
        return 0;
        break;
    default:
        break;
    }
    return (DefWindowProc(hwnd, message, wParam, lParam));
}
/*  Main function*/
int APIENTRY WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nCmdShow)
{
    WNDCLASSEX  windowClass;        //window class
    HWND        hwnd;               //window handle
    MSG         msg;                //message
    bool        done;               //flag saying when app is complete
    /*  Fill out the window class structure*/
    windowClass.cbSize = sizeof(WNDCLASSEX);
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc = WndProc;
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hInstance = hInstance;
    windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    windowClass.lpszMenuName = NULL;
    windowClass.lpszClassName = L"MyClass"; // fixed error: char* not compatible with LPCWSTR
    windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
    /*  Register window class*/
    if (!RegisterClassEx(&windowClass))
    {
        return 0;
    }
    /*  Class registerd, so now create window*/
    hwnd = CreateWindowEx(NULL,     //extended style
        L"MyClass",          //class name | fixed error: char* not compatible with LPCWSTR
        L"A Real Win App",       //app name | fixed error: char* not compatible with LPCWSTR
        WS_OVERLAPPEDWINDOW |       //window style
        WS_VISIBLE |
        WS_SYSMENU,
        100, 100,            //x/y coords
        400, 400,            //width,height
        NULL,               //handle to parent
        NULL,               //handle to menu
        hInstance,          //application instance
        NULL);              //no extra parameter's
    /*  Check if window creation failed*/
    if (!hwnd)
        return 0;
    done = false; //initialize loop condition variable
    /*  main message loop*/
    while (!done)
    {
        PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);
        if (msg.message == WM_QUIT) //check for a quit message
        {
            done = true; //if found, quit app
        }
        else
        {
            /*  Translate and dispatch to event queue*/
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

现在可以编译了,但是,我明白了 “F*CK!!!!它不起作用,为什么我得到汉字,WTF”是正确的(如果不是汉字,请原谅我)


感谢您聆听(实际阅读)我的问题

【问题讨论】:

    标签: c++ c string winapi


    【解决方案1】:

    你需要替换这个:

    TextOut(hDC, 150, 150, string, sizeof(string) - 1);
    

    用这个:

    TextOut(hDC, 150, 150, string, wcslen(string));
    

    sizeof (string) 以字节为单位,而不是字符。

    另外,请不要发送垃圾语言标签。只需选择相关的即可。

    【讨论】:

    • string 是一个编译时常量,因此实际上不需要在运行时计算它的长度。使用 Microsoft 的 _countof 或 C++ 的 std::size 非常好。
    • @IInspectable 我知道,但使用wcslen 更灵活。有一天,字符串会衰减为指针...
    • 当这种情况发生时,编译器将无法编译我建议的任何一个替代方案。至少在 OP 使用的 C++ 中。
    • @PaulSanders 对不起,“字符串将衰减为指针”是什么意思?据我所知,字符串变量是指向字符数组的指针,但是“衰减到指针”实际上是什么意思,“衰减”是什么意思?
    • @platinoob_ 如果将(C 风格)字符串作为参数传递给函数,则它会衰减到该函数内的指针。如果您随后使用sizeof(或_countof),您将获得wchar_t * 的大小(即64 位构建中的8),而不是字符串的长度,并且std::size 将失败编译。我不在乎 IInspectable 说什么,我会使用wcslen,因为它无处不在。此外,_countof 是一个 MSVC 扩展,所以这是避免它的另一个原因。
    【解决方案2】:

    TextOut() 的最后一个参数采用 character 计数,但您传递给它的是 byte 计数。

    在原始代码中,string 数组使用了char 字符,而sizeof(char) 是1 个字节,所以两个计数是相同的数值。但是您将代码更改为使用 wchar_t 字符,而在 Windows 上 sizeof(wchar_t) 是 2 个字节。

    因此,通过将TextOut(..., string, sizeof(string) - 1)wchar_t 字符串一起使用,您告诉TextOut()string 数组中的wchar_ts 是实际数量的两倍,因此TextOut()超出string 数组的范围,从周围的内存中打印出随机垃圾(认为自己很幸运,代码没有因为访问它不拥有的内存而直接崩溃)。

    如果您打算以这种方式使用sizeof(),那么要获得正确的数组元素计数,您需要将数组的字节大小除以其元素的字节大小,例如:

    TextOut(..., string, (sizeof(string) / sizeof(string[0])) - 1)
    

    您可以将其替换为 Visual Studio 中的 _countof() 宏(或其他编译器中的等效宏),例如:

    TextOut(..., string, _countof(string) - 1)
    

    在 C++11 及更高版本中,您应该改用std::size(),例如:

    TextOut(..., string, std::size(string) - 1)
    

    请注意,如果将来string 数组被wchar_t* 指针替换,这些解决方案将不再有效。 sizeof() 解决方案仍将编译,但不会产生正确的结果。但是_countof()std::size() 解决方案将无法编译,这是一件好事。然后你就会知道你需要用更合适的解决方案来替换它,比如lstrlenW()std::wstring::size()等。

    【讨论】:

    • @IInspectable 已修复
    【解决方案3】:

    您正在使用sizeof(string)。那是字节数,而不是字符数。由于您使用的是 C++,请使用std::wstring::size()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      相关资源
      最近更新 更多