1

Ok, so i made a class which creates a HWND.

However, the window created shows some strange properties: it is not like other windows - it's non-transparent, the close-minimize-maximize buttons are located differently from normal windows.

But the style specified is default (WM_OVERLAPPEDWINDOW).

What's more, it can't be closed unless i move it a bit (seems like it is not generating WM_DESTROY or WM_CLOSE messages before moving).

This might be a problem with the implementation of main WinProc calling another message processer using pointers. However, i have no idea why the window is unusually looking.

My code:

//mywind.h
class Window
{
private:
    HWND mHwnd;
    const char* className="Window";
    static LRESULT CALLBACK StartWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); //main WindowProc function
    LRESULT ThisWindowProc(UINT msg, WPARAM wParam, LPARAM lParam); //Another, object-specific message processing function
    bool isClassRegistered(HINSTANCE hinst);

public:
    Window() : mHwnd( 0 ) { }
    ~Window();

    int create(std::string title, int width, int height);
};

//mywind.cpp
Window::~Window()
{
    if( mHwnd ) DestroyWindow( mHwnd );
}

int Window::create(std::string title, int width, int height)
{
    WNDCLASS wincl;
    HINSTANCE hInst = NULL;
    hInst = GetModuleHandle(NULL);

    if(hInst==NULL)
    {
        printf("Failed to load hInstance\n");
        return -1;
    }

    if(!GetClassInfo(hInst, className, &wincl))
    {
        printf("Getting class info.\n");

        wincl.style = 0;
        wincl.hInstance = hInst;
        wincl.lpszClassName = className;
        wincl.lpfnWndProc = StartWindowProc;
        wincl.cbClsExtra = 0;
        wincl.cbWndExtra = 0;
        wincl.hIcon = NULL;
        wincl.hCursor = NULL;
        wincl.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
        wincl.lpszMenuName = NULL;

        if(!isClassRegistered(hInst))
        {
            if (RegisterClass(&wincl) == 0)
            {
                printf("The class failed to register.\n");
                return 0;
            }
        }
    }

    mHwnd = CreateWindow(className, title.c_str(), WS_VISIBLE | WS_OVERLAPPEDWINDOW,
                     CW_USEDEFAULT, CW_USEDEFAULT, width, height,
                     NULL, NULL, hInst, this);
    if(mHwnd==NULL)
    {
        printf("Failed to create HWND.\n");
        return -1;
    }

    MSG msg;
    while(GetMessage(&msg, mHwnd, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    printf("Destroying window.\n");

    if(mHwnd) DestroyWindow(mHwnd);
    mHwnd=NULL;

    printf("Returning.\n");

    return msg.wParam;
}

bool Window::isClassRegistered(HINSTANCE hinst)
{
    WNDCLASSEX clinf;
    if(!GetClassInfoEx(hinst, className, &clinf)) return false;
    return true;
}

LRESULT CALLBACK Window::StartWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    Window* winp = NULL;

    if(msg == WM_CREATE)
    {
        CREATESTRUCT* cs = (CREATESTRUCT*) lParam;
        winp = (Window*) cs->lpCreateParams;

        SetLastError(0);
        if(SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) winp) == 0)
        {
            if(GetLastError()!=0) return -1;
        }
    }
    else
    {
        winp = (Window*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
    }

    if(winp) return winp->ThisWindowProc(msg, wParam, lParam);

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

LRESULT Window::ThisWindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_PAINT:
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;

    default:
        return DefWindowProc(mHwnd, msg, wParam, lParam);
    }

    return 0;
}

//main.cpp

#include "mywind.h"

int main(int argc, char* argv[])
{
    Window mwnd;
    mwnd.create("Test", 200, 200);

    return 0;
}
Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
hakeris1010
  • 285
  • 1
  • 5
  • 12
  • Good stuff at learning to wrap an HWND inside a C++ class with GetWindowLong/SetWindowLong. There's a lightweigh class in Windows (ATL) that comes with Visual Studio that does all the heavy lifting for you: http://stackoverflow.com/questions/3122695/what-is-an-efficient-way-to-wrap-hwnds-in-objects-in-c/3122743#3122743 – selbie Nov 14 '15 at 19:42
  • Please don't edit the question after it has been answered, because the answer doesn't make sense any more. (You fixed the problem in your question, so now it looks like you asked a question about code that works fine.) – Raymond Chen Apr 25 '19 at 04:22

2 Answers2

5

Notice that you don't set mHwnd until CreateWindowEx returns. This means that all the messages sent during window creation pass 0 to DefWindowProc instead of the actual window handle. This causes the window manager to think you are bypassing default handling and doing custom captions, which is why everything looks wrong.

TL;DR: Set mHwnd inside your WM_NCCREATE handler.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
0

I am 90% sure that your problem is the missing manifest which enables WinXP/7 look. Now you are in compatibility mode and the window frame is for Windows 98/2000 style. For more details read this link (or many others for the same problem): http://www.mctainsh.com/Articles/Csharp/XpControlsInCS.aspx

i486
  • 6,491
  • 4
  • 24
  • 41