Jump to content
  • Advertisement
Sign in to follow this  
assainator

win32 OO programming problem

This topic is 2997 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Heey all,

I want try build some win32 apps but I thing win32 itself is ugly and not productive.
Therefor i'm trying to make a OO system for creating windows and controlls.
But i'm having a problem with the WNDCLASSEX registration.

I keep getting problems with setting the lpfnWndProc field in WNDCLASSEX
I get the following errors
Quote:

window.cpp(14) : error C3867: 'Window::WndProc': function call missing argument list; use '&Window::WndProc' to create a pointer to member

window.cpp(14) : error C2440: '=' : cannot convert from 'LRESULT (__stdcall Window::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'

I have tried changing 'wc.lpfnWndProc = WndProc;' to 'wc.lpfnWndProc = (WNDPROC)WndProc;' but then I get the error:
Quote:

window.cpp(12) : error C2440: 'type cast' : cannot convert from 'overloaded-function' to 'WNDPROC'


my code:
Window.hpp

#pragma once

#define WIN32_LEAN_AND_MEAN
#include "EasX_Api.hpp"
#include <windows.h>

class Window
{
private:
WNDCLASSEX wc;
HWND Hwnd;
int CmdShow;

public:
EASX_API Window(HINSTANCE hInstance, int showCMD);
EASX_API ~Window(void);

EASX_API void Show();


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};




Window.cpp

#include "Window.hpp"
#include <stdlib.h>


Window::Window(HINSTANCE hInstance, int showCMD)
{
this->CmdShow = showCMD;

//Register the WNDCLASSED
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc; //This causes the problem
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"App";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
exit(0);
}

//Create the Window
Hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
wc.lpszClassName,
L"TestApp",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 200, 100, NULL, NULL, hInstance, NULL);

if(Hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
exit(0);
}

}

Window::~Window(void)
{
}

void Window::Show()
{
ShowWindow(Hwnd, CmdShow);
UpdateWindow(Hwnd);
}

LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}


Share this post


Link to post
Share on other sites
Advertisement
You can't use a member-function as the call-back, as the window won't know about the this object needed when calling WndProc. To solve this, you must store a pointer to the object, and use a static function that calls the correct function on the object.
Each window has user-data, that you can set with SetWindowLongPtr(hWnd, GWLP_USERDATA, pointer), and retrieve with GetWindowLongPtr.

Example:

class Window {
Window();
LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

static LRESULT StaticWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};


Window::Window() {
hWnd = CreateWindow(...);

SetWindowLongPtr(hWnd, GWLP_USERDATA, this);
}

LRESULT WndProc(...) {
...
}

LRESULT StaticWndProc(...) {
Window *window = (Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(window)
return window->WndProc(...);
else
return DefWindowProc(...);
}



Remember that you get some messages to the window proc even before CreateWindow returns. You could also pass the this object in the lpParam to CreateWindow, and set the user-data in the WM_CREATE message for example.

Share this post


Link to post
Share on other sites
@Erik Rufelt: Thanks for the advice, it solved my problem
@nobodynews: Thanks for pointing me to that article, it is really helpfull

assainator

Share this post


Link to post
Share on other sites
I've come a lot further not but i'm encountering another problem.

I've made a simple base class for all windows 'WinClass', and 2 divered classes. 1: 'Window' and 2: 'Button'

Now I want to have a stl vector with the pointers to all the children in my WinClass. (see source below 'WinBase.hpp')
I also have a functions called 'SetParent(WinBase *parent)' and a function called 'AddChild(WinBase *Child)'

lets say I create a window and a button.
1. I create the window
2. I create the button and set the window as parent using SetParent(window)
2.1 In this function there is a call the the parents 'AddChild' functions that will add the a pointer to the button, to the vector of children.

But whenever the call to AddChild is made, I get a access violation error.
If i remove the call to _Children.push_back(Child) in the AddChild function the program runs fine.

Can anyone see what i'm doing wrong?

thanks in advance,
assainator


#pragma once

#include <Windows.h>
#include "EasX_Api.hpp"
#include <vector>

class WinBase
{
public:
EASX_API WinBase(HINSTANCE hInst, WinBase* Parent);
EASX_API ~WinBase(void);

EASX_API HWND Hwnd();
EASX_API void SetSize(int x, int y);
EASX_API void SetPos(int x, int y);
EASX_API void SetText(LPCWSTR text);
EASX_API void SetClsName(LPCWSTR clsname);

EASX_API virtual void Create();
EASX_API virtual void Show();
EASX_API void Update();

EASX_API void SetParent(WinBase *Parent);
EASX_API void AddChild(WinBase *Child); //A function to add a child to the vector

protected:
HWND _hWnd;
HINSTANCE _hInst;
WinBase *_Parent;
std::vector<WinBase *> _Children; // The vector with poiters to the children

unsigned int Style;

LPCWSTR _clsname, _text;

int _x, _y, _sizex, _sizey;
};





#include "WinBase.hpp"


WinBase::WinBase(HINSTANCE hInst, WinBase *Parent)
{
this->_hInst = hInst;
this->_Parent = Parent;
this->_sizex = CW_USEDEFAULT;
this->_sizey = CW_USEDEFAULT;
this->_x = CW_USEDEFAULT;
this->_y = CW_USEDEFAULT;

this->_text = L"WinBase";
this->_clsname = L"";
this->_hWnd = NULL;

Parent->AddChild(this);
}


WinBase::~WinBase(void)
{
DestroyWindow(_hWnd);
}

void WinBase::SetClsName(LPCWSTR clsname)
{
this->_clsname = clsname;
}

void WinBase::SetPos(int x, int y)
{
_x = x;
_y = y;
}

void WinBase::SetSize(int x, int y)
{
_sizex = x;
_sizey = y;
}

HWND WinBase::Hwnd()
{
return _hWnd;
}

void WinBase::SetText(LPCWSTR text)
{
_text = text;
}

void WinBase::Create()
{
//Do nothing since the WinBase shouldn't show up, so there's no need to create it.
}

void WinBase::Show()
{
//Do nothing since the WinBase shouldn't show up.
}

void WinBase::Update()
{
UpdateWindow(_hWnd);
}

void WinBase::SetParent(WinBase *Parent)
{
this->_Parent = Parent;
Parent->AddChild(this);
}

void WinBase::AddChild(WinBase *Child)
{
_Children.push_back(Child);
}

Share this post


Link to post
Share on other sites
What does your debugger say? What bad address is being accessed? Which of the variables contains that address?

Share this post


Link to post
Share on other sites
Quote:

What bad address is being accessed? Which of the variables contains that address?


Thanks for asking, I should have asked myself these questions right away. I found the issue. It appears that if I create a WinBase with a parent of NULL, that it would still try to access this and add a child to it.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!