Sign in to follow this  
dbrink

Window class (C++/Win32 API)

Recommended Posts

Hello,

I've been trying to create a Window class, just for learning purposes (I'm quite new to both C++ and the Win32 API).

I created a StaticWndProc which uses SetWindowLongPtr and GetWindowLongPtr to store the window. The problem is that wnd->WndProc(message, wParam, lParam) never gets called, because wnd is always NULL. I'm not sure if i'm just missing something or if my code is just plain wrong.

The program compiles fine, I do receive the WM_NCCREATE message, GetLastError always returns 0 and I do see the window when the running program. The messages just don't get through to WndProc.


Window.h
[code]
#include <windows.h>
#include <iostream>

class Window {
private:
HWND hWnd;
public:
~Window();
void create();
void show();
private:
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProc(UINT message, WPARAM wParam, LPARAM lParam);
};[/code]

Window.cpp
[code]
#include "Window.h"

void Window::create() {
WNDCLASSEX wndClass;

HINSTANCE hInstance = GetModuleHandle(NULL);

wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = 0;
wndClass.lpfnWndProc = (WNDPROC) StaticWndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = "MyWindow";
wndClass.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION);

if (!::RegisterClassEx(&wndClass)) {
::MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
}

hWnd = ::CreateWindowEx(WS_EX_STATICEDGE, "MyWindow", "MyWindow", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT, 320, 240, NULL, NULL, hInstance, NULL);

if (hWnd == NULL) {
::MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
}
}

void Window::show() {
::ShowWindow(hWnd, SW_SHOW);
::UpdateWindow(hWnd);
}

LRESULT CALLBACK Window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
Window *wnd;

if(message == WM_NCCREATE) {
wnd = reinterpret_cast<Window *>(((LPCREATESTRUCT)lParam)->lpCreateParams);
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(wnd));
} else {
wnd = reinterpret_cast<Window *>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
}

if (wnd) {
return wnd->WndProc(message, wParam, lParam);
} else {
::DefWindowProc(hWnd, message, wParam, lParam);
}
}

LRESULT CALLBACK Window::WndProc(UINT message, WPARAM wParam, LPARAM lParam) {
std::cout << "WndProc" << std::endl;
return ::DefWindowProc(hWnd, message, wParam, lParam);
}

Window::~Window() {
if (hWnd != NULL) {
::DestroyWindow(hWnd);
}
}[/code]

main.cpp
[code]
#include "Window.h"

int main(int argc, char **argv) {
Window wnd;

wnd.create();
wnd.show();

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

return msg.wParam;
}[/code]

Share this post


Link to post
Share on other sites
Read MSDN
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603%28v=vs.85%29.aspx

Why do you think lParam->lpCreateParams is your object?
NO.

You need to store your Window object in a global variable and in first call of wndproc set window long ptr with the value.
That's why many GUI framework requires the window widgets should be created from main thread.

Share this post


Link to post
Share on other sites
It is absolutely not necessary to use a global for this.
Once he passes his this pointer to CreateWindowEx() it will work fine, and it is the proper way to do this.
Using a global would completely defeat the object-oriented design for which he is striving.


L. Spiro

Share this post


Link to post
Share on other sites
[quote name='YogurtEmperor' timestamp='1317468817' post='4867930']
It is absolutely not necessary to use a global for this.
Once he passes his this pointer to CreateWindowEx() it will work fine, and it is the proper way to do this.
Using a global would completely defeat the object-oriented design for which he is striving.


L. Spiro
[/quote]

But that's not guaranteed to be the Window object.

Seems for MDI it's an issue.

http://msdn.microsoft.com/en-us/library/ms632680.aspx

[i]lpParam[/i] [in, optional] Type: [b]LPVOID[/b]

Pointer to a value to be passed to the window through the [url="http://msdn.microsoft.com/en-us/library/ms632603.aspx"][b]CREATESTRUCT[/b][/url] structure ([b]lpCreateParams[/b] member) pointed to by the [i]lParam[/i] param of the [b]WM_CREATE[/b] message. This message is sent to the created window by this function before it returns.

If an application calls [url="http://msdn.microsoft.com/en-us/library/ms632679.aspx"][b]CreateWindow[/b][/url] to create a MDI client window, [i]lpParam[/i] should point to a [url="http://msdn.microsoft.com/en-us/library/ms632602.aspx"][b]CLIENTCREATESTRUCT[/b][/url] structure. If an MDI client window calls [b]CreateWindow[/b] to create an MDI child window, [i]lpParam[/i] should point to a [url="http://msdn.microsoft.com/en-us/library/ms644910.aspx"][b]MDICREATESTRUCT[/b][/url] structure. [i]lpParam[/i] may be [b]NULL[/b] if no additional data is needed.

Share this post


Link to post
Share on other sites
He isn’t creating an MDI window. He is creating a window of class type “MyWindow”.
For the code he is using, reinterpret_cast<LPCREATESTRUCT>(_lParam)->lpCreateParams will absolutely be a Window * once he starts passing his this to CreateWindowEx().


L. Spiro

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this