platinoob_
platinoob_

Reputation: 161

OpenGL, WinAPI | garbage values to unicode(I think, L"") string

I want to try and learn OpenGL, I know C++ and I found a site with C++/OpenGL tutorials, this site also teaches a few things about WinAPI,bcs "our" programms are going to be Windows applications. In this tutorial it has the code of "our" first Windows application. The code (it doesn't compile):

/*  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;
}

It didn't compile, it had a few errors so I changed it a bit:

/*  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;
}

Now it compiles, but, I get this:The "F*CK!!!! it doesn't work, why am I getting Kanji, WTF" is correct The "F*CK!!!! it doesn't work, why am I getting Kanji, WTF" is correct(Forgive me if it is not Kanji)


Thank you for listening(reading actually) to my problems

Upvotes: 0

Views: 123

Answers (3)

Remy Lebeau
Remy Lebeau

Reputation: 597016

The last parameter of TextOut() takes a character count, but you are passing it a byte count instead.

In the original code, the string array used char characters, and sizeof(char) is 1 byte, so the two counts were the same numeric value. But you changed the code to use wchar_t characters instead, and on Windows sizeof(wchar_t) is 2 bytes.

So, by using TextOut(..., string, sizeof(string) - 1) with a wchar_t string, you are telling TextOut() that there are 2 times as many wchar_ts in the string array as there really are, and thus TextOut() goes out of bounds of the string array printing out random garbage from surrounding memory (consider yourself lucky the code didn't just crash outright from accessing memory it didn't own).

If you are going to use sizeof() in this manner, then to get the correct array element count, you need to divide the array's byte size by its element's byte size, eg:

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

You can replace that with the _countof() macro in Visual Studio (or equivalent in other compilers), eg:

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

In C++11 and later, you should use std::size() instead, eg:

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

Note that if the string array is ever replaced with a wchar_t* pointer in the future, these solutions will not work anymore. The sizeof() solution will still compile but will not produce the correct result. But the _countof() and std::size() solutions will fail to compile, which is a good thing. Then you will know that you need to replace it with a more appropriate solution, like lstrlenW(), std::wstring::size(), etc.

Upvotes: 1

catnip
catnip

Reputation: 25388

You need to replace this:

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

with this:

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

sizeof (string) is in bytes, not characters.

Also, please don't spam language tags. Just pick the one(s) that are relevant.

Upvotes: 2

MSalters
MSalters

Reputation: 179981

You're using sizeof(string). That's the number of bytes, not the number of characters. Since you're using C++, use std::wstring::size().

Upvotes: 0

Related Questions