Sign in to follow this  
templewulf

Accessing a window wrapper object

Recommended Posts

I hope one of you fine ladies or gentlemen can help me with this! I'm building a framework for a Square/Enix style 2d RPG and I'm having trouble working through the encapsulation of a Window class. I've read the article on a Win32 wrapper class by Oluseyi, but I keep getting access exceptions whenever I try to use the object I'm pointing to. What I want is to get a pointer to the object that called the WndProc method so I can tell it to call its parent and set the bGameActive member to false when it receives the wparam WA_INACTIVE. From what I can tell, GetWindowLong returns a pointer to the window, but how does that refer back to the wrapper object? THEEEEEEN, I'd like to know how to get a pointer to the parent object without resorting to just making a pointer to it a member of my CWulfWin wrapper class. Is there a more elegant solution? See code here in CWulfWin.cpp or
//TempleWulf
//08/07/05
//CWulfWin.h
//Class Wulf Window Manager

#ifndef CWULFWIN_H
#define CWULFWIN_H

//define flags
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN

//includes
#include <windows.h>
#include <string>

//namespace
using namespace std;

//linker inputs

//globals

///////////////////////////////////////////
//CWulfWin
//manages window activity & win32 messages
class CWulfWin
{
private:
protected:
	WNDCLASSEX wndclass;	//wndclass contains hinstance
	HWND hwnd;	

	string strClassName;
	string strWindowName;

	signed long	nXsize, nYsize,
				nXpos, nYpos;	

public:
	//constructors
	CWulfWin();
	CWulfWin(const CWulfWin & wndNew);
	~CWulfWin();

	//static stdcall function
	static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
	
	HWND SetHWND(const HWND & hwnd);
	HWND GetHWND()
	{return hwnd;}	

	bool InitWindow(const HINSTANCE & hinstance);
	void CloseWindow();
};

///////////////////////////////////////////
//constructor
CWulfWin::CWulfWin()
{
	//class defaults	
	nXsize = 640;
	nYsize = 480;
	nXpos = nYpos = 0;	
	strClassName = "CWulfWin WNDCLASSEX";
	strWindowName = "Wulf System: designed by TempleWulf";
}

///////////////////////////////////////////
//copy constructor
CWulfWin::CWulfWin(const CWulfWin & wndNew)
{
}


///////////////////////////////////////////
//destructor
CWulfWin::~CWulfWin()
{
}

///////////////////////////////////////////
//Window Procedure
LRESULT CALLBACK CWulfWin::WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	CWulfWin* pwwThis = NULL;

	//if not the create message, retrieve the window for this msg
	if(message != WM_NCCREATE)
	{		
		pwwThis = reinterpret_cast<CWulfWin *>(GetWindowLong(hwnd, GWL_USERDATA));
	}

	//otherwise, continue with the switch as normal:	

	switch(message)
	{
		case WM_NCCREATE:
		{
			//retrieve window handle from NCCREATE lparam
			pwwThis = reinterpret_cast<CWulfWin *>( ((LPCREATESTRUCT)lparam)->lpCreateParams);
			SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(pwwThis));			
			
			return DefWindowProc(hwnd, message, wparam, lparam);
		}
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}
		case WM_ACTIVATE:
		{
			if(	LOWORD(wparam) == WA_ACTIVE	)
			{
				//pwsGame->SetActive(true);
			}
			else
			{
				//pwsGame->SetActive(false);
			}
		}

	}

	//default message case:
	return DefWindowProc(hwnd, message, wparam, lparam);
}

///////////////////////////////////////////
//InitWindow
//performs functions to start window
bool CWulfWin::InitWindow(const HINSTANCE & hinstance)
{
	//initialize WNDCLASSEX struct
	this->wndclass.cbSize = sizeof(WNDCLASSEX);	
	this->wndclass.style =	CS_DBLCLKS | 
							CS_OWNDC | 
							CS_HREDRAW | 
							CS_VREDRAW;
	this->wndclass.lpfnWndProc = WndProc;
	this->wndclass.cbClsExtra = NULL;	//unnecessary for a popup window
	this->wndclass.cbWndExtra = NULL;	//same here
	this->wndclass.hInstance = hinstance;	//handle to the application instance
	this->wndclass.hIcon = LoadIcon(	NULL, //hinstance of app whose resource you load
										IDI_WINLOGO	);
	this->wndclass.hIconSm = this->wndclass.hIcon;
	this->wndclass.hCursor = LoadCursor(	NULL, //use null instead of hinstance for windows resources
											IDC_ARROW	);
	this->wndclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);	//brush used to erase
	this->wndclass.lpszMenuName = NULL;	//won't use a menu
	this->wndclass.lpszClassName = this->strClassName.c_str();	//class name?

	//register WNDCLASSEX struct
	RegisterClassEx(&this->wndclass);

	//create window
	//setHWND
	if(!(
	this->SetHWND(  CreateWindowEx(	NULL,	//dwExStyle unused
									wndclass.lpszClassName,	//class name
									this->strWindowName.c_str(),	//title bar text										
									WS_OVERLAPPEDWINDOW |	//specifies windowed application									
									WS_VISIBLE,	//dwStyle
									nXpos, nYpos,	//x, y where window should appear
									nXsize, nYsize,	//width, height of window
									NULL,	//handle of parent window, NULL = desktop
                                    NULL,	//handle to menu resource
									hinstance,	//handle to app that owns this window
									NULL	)	)))	//lpParam, used for MDI
	{		
		return false;
	}

	//return success
	return true;
}

///////////////////////////////////////////////
//CloseWindow
//performs end-of-use functions (release memory, close window, etc)
void CWulfWin::CloseWindow()
{	
}

///////////////////////////////////////////////
//SetHWND
HWND CWulfWin::SetHWND(const HWND & hwnd)
{
	this->hwnd = hwnd;
	return this->hwnd;
}

#endif

Any clues?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
To get a pointer to the parent, as long as it was a window that used the framework, you could call 'GetParent(hwnd)', and from that, you could call 'GetWindowLong(parentHwnd, GWL_USERDATA)', and that should return the pointer to the wrapper object of the parent.

I sometimes feel it to be more elegant to store a pointer to the parent in the child, though, and in a framework I created (http://www.codeproject.com/library/DWinLib.asp) all the framework windows have a 'parentC' pointer built into them. It is somewhat more complete than Oluseyi's example, as DWinLib takes care of automatically releasing the classes of the child windows upon cleanup. There is also some other stuff in DWinLib that makes wrapping Windows easier, including wrapping Windows Controls, and a flicker-free docking window framework.

David

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
...
Quote:
From what I can tell, GetWindowLong returns a pointer to the window, but how does that refer back to the wrapper object?


Forgot to answer this. In the case of Oluseyi's work, GetWindowLong returns a pointer back to the window wrapper class that 'corresponds' to the Windows window, if that makes sense. It is the 'this' pointer of your CWulfWin window. Your term, 'pointer to a window' is misleading if you are thinking about a Windows HWND. GetWindowLong is returning a pointer to your CWulfWin class.

I believe that you need to change to 'GetWindowPtrLong' (or something like that) in the case of 64 bit computing, so Oluseyi's and my wrapper both need to be changed in that case. I have not done any such porting to date.

David

Share this post


Link to post
Share on other sites
I've done it the way that David and Oluseyi did it... by storing a pointer in the HWND's "LONG" user data variable... but it doesn't port to 64 bit...

I'm thinking that a static function on your main "Window" class that passes the HWND could return your pointer.

Use a static std::map<HWND, Window *> to store a pointer to each window as it is created (you don't have to delete the pointers in the map, as long as the window objects are deleted elsewhere)

static Window *Window::getWindowThru(HWND);
static std::map<HWND,Window *> _windows;

...

If you do it THIS way, it will port, because the size of the Window pointer will store in the std::map template.

[EDIT]

Besides, you don't really have type safety with using the stored pointer from GetWindowLong... you have to cast it back to your Window pointer, or pointer to whichever object you are looking for.

Using "window = Window::getWindow(hwnd)" solves that problem automatically.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
It will take slightly more time to search through a map than it will to call GetWindowLong and cast it, if that is important to you. The proper 64 bit function is 'GetWindowLongPtr' (Google for it, or use MSDN). You could switch between these in code based off of a #define for 64 bit, if your compiler uses such a define.

David

Share this post


Link to post
Share on other sites
Thanks for all the quick replies. I had to go to bed early to get to work (which is where I am now...shh!!)

Anyway, I have no idea how GetWindowLong would get a pointer to my class but I won't question it. My problem is that it causes an exception when I try to access class members / methods with the pointer it gives me.

Has anyone else tried to execute this code?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
It appears that you are not passing anything in the CREATESTRUCT. The last NULL in the following should be a 'this' instead.

	//create window
//setHWND
if(!(
this->SetHWND( CreateWindowEx( NULL, //dwExStyle unused
wndclass.lpszClassName, //class name
this->strWindowName.c_str(), //title bar text
WS_OVERLAPPEDWINDOW | //specifies windowed application
WS_VISIBLE, //dwStyle
nXpos, nYpos, //x, y where window should appear
nXsize, nYsize, //width, height of window
NULL, //handle of parent window, NULL = desktop
NULL, //handle to menu resource
hinstance, //handle to app that owns this window
NULL ) ))) //lpParam, used for MDI //MAKE THIS 'NULL'
{
return false;
}



Try that, and see if it helps. There may be something else missing as well - this was just a cursory glance.

As far as your other question, SetWindowLong stores a 32 bit value into the GWL_USERDATA 'slot' that Windows reserves for your window. Your 'this' pointer is 32 bits under 32 bit operating systems and compilers, so GetWindowLong simply retrieves that value and then you use it (through casting) as your 'this' value.

David

Share this post


Link to post
Share on other sites
OHHHHHHHHHHHHH!!!

I didn't even know that was for! Well, now I just feel like a dope!

I really appreciate your quick responses, though. Do you have a regular account with GameDev so I can rate you up?

You too, Verg. I'm not as concerned with execution speed so much as readable OOP design. So, your suggestion is awfully helpful as well!

P.S. - Do you think Microsoft will create an OOP API for their OS? That would make Longhorn something worth talking about!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
It wasn't too clear from the documentation, so don't feel so bad. And I don't have a GD account, as I am a curmudgeon, and don't want to agree to a long-ass user agreement - this world is getting too lawyer-oriented, and I don't want to keep going that way. But I'll gladly accept your mental 'Thank you', and wish you the best of luck in your programming endeavors.

If you think that the GetWindowLong and SetWindowLong lead to an un-object oriented approach, I challenge you to look through the class layout and code to DWinLib and keep that belief.

From what I hear, .Net IS MS's answer OOD solution to Windows. It was created by some of the same people that created Borland's Visual Class Library, a truly kick-ass class library for Windows.

David

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