Search code examples
c++stringwinapiconvertershwnd

C++ WinAPI: HWND To String Returning Hex


I am using WinAPI and im trying to make a program which allows you to change the title.

#if defined(UNICODE) && !defined(_UNICODE)

#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h>
#include <windows.h>

#include <string>
#include <sstream>

using namespace std;

string HWNDToString(HWND inputA);
void setTitle(string inputA);

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;

    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(255,128,0));

    if (!RegisterClassEx (&wincl)) return 0;

    hwnd = CreateWindowEx
    (
        0,
        szClassName,
        _T("Title Changer"),
        WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        400 + 22,
        400 + 49,
        HWND_DESKTOP,
        NULL,
        hThisInstance,
        NULL
    );

    ShowWindow (hwnd, nCmdShow);
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    return messages.wParam;
}

HWND textout, titlebutton , powerbutton, textin;
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            textout = CreateWindow("STATIC", "Enter new window title here:", WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 0, 230, 20, hwnd, NULL, NULL, NULL);
            textin = CreateWindow("EDIT", "New Title", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, 0, 20, 250, 25, hwnd, (HMENU) NULL, NULL, NULL);
            titlebutton = CreateWindow("BUTTON", "Set as New Window Title", WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 45, 210, 25, hwnd, (HMENU) /*=*/1/*=*/, NULL, NULL);
            powerbutton = CreateWindow("BUTTON", "Power Off", WS_VISIBLE | WS_CHILD | WS_BORDER, 316, 0, 100, 25, hwnd, (HMENU) 2, NULL, NULL);
        break;

        case WM_COMMAND:
            if (LOWORD(wParam) == 1)
            {
                SetWindowText(hwnd, HWNDToString(textin).c_str());
                MessageBox(hwnd, string("Title changed to: " + HWNDToString(textin)).c_str(), "Title Changed", MB_OK | MB_ICONINFORMATION);
            }

            if (LOWORD(wParam) == 2)
            {
                PostQuitMessage(0);
            }
        break;

        case WM_DESTROY:
            PostQuitMessage(0);
        break;

        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
        break;
    }

    return 0;
}

string HWNDToString(HWND inputA)
{
    stringstream stringstreamBuffer;
    stringstreamBuffer << inputA;
    return stringstreamBuffer.str();
}

But the program sets the title to a random hex-like string (for example, 0x123abc).

What is wrong with the HWNDToString function I defined? Do I need to use sprintf to convert hex to string?

OS: Windows 7 Ultimate x64
IDE: Codeblocks
Compiler: GNU GCC Compiler (MinGW32)


Solution

  • An HWND is a pointer (struct HWND__* or void*, depending on whether STRICT is enabled or disabled, respectively). Passing such a pointer to operator<< of an std::ostream-based class will invoke operator<<(const void*) which formats the pointed-to memory address as a hex string.

    Since you are trying to accept a string value from the user using an EDIT control and then set your main window's title with the value of that string, you should be using the GetWindowTextLength() and GetWindowText() functions instead:

    string HWNDToString(HWND inputA)
    {
        string s;
        int len = GetWindowTextLength(inputA);
        if (len > 0)
        {
            s.resize(len + 1);
            len = GetWindowText(inputA, &s[0], s.size());
            s.resize(len);
        }
        return s;
    }
    

    case WM_COMMAND:
        if (LOWORD(wParam) == 1)
        {
            string s = HWNDToString(textin);
            SetWindowText(hwnd, s.c_str());
            MessageBox(hwnd, string("Title changed to: " + s).c_str(), "Title Changed", MB_OK | MB_ICONINFORMATION);
        }
        ...
    

    On a side note, your "Power Off" button should be sending a WM_CLOSE message to your main window, not calling PostQuitMessage() directly:

    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)                  /* handle the messages */
        {
            ...
            case WM_COMMAND:
                ....
                if (LOWORD(wParam) == 2)
                {
                    SendMessage(hwnd, WM_CLOSE, 0, 0);
                }
                break;
    
            // By default, DefWindowProc() handles WM_CLOSE by destroying the window
            // using DestroyWindow(). WM_CLOSE is also received when the user closes
            // the window manually. This allows you to close down your app correctly
            // regardless of how the window is closed.  You can handle WM_CLOSE
            // manually if you want to prompt the user before allowing the
            // window to be destroyed...
            /*
            case WM_CLOSE:
                if (MessageBox(hwnd, "Are you sure you want to power down?", "Power Down?", MB_YESNO) == IDYES)
                    DestroyWindow(hwnd);
                break;
            */
    
            case WM_DESTROY:
                PostQuitMessage(0);
                break;
    
            default:
                return DefWindowProc(hwnd, message, wParam, lParam);
        }
    
        return 0;
    }
    

    See MSDN's documentation on Destroying a Window for more details.