WindowProc

Started by
18 comments, last by WalterTamboer 18 years, 5 months ago
// Message Processing Functions virtual LRESULT CALLBACK AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam); bool CApplication::Create() { // Init parent window class information ZeroMemory(&m_wcx, sizeof(m_wcx)); m_wcx.cbClsExtra = 0; m_wcx.cbSize = sizeof(WNDCLASSEX); m_wcx.cbWndExtra = 0; m_wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); m_wcx.hCursor = LoadCursor(NULL, IDC_ARROW); m_wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); m_wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); m_wcx.hInstance = m_hInstance; m_wcx.lpfnWndProc = CApplication::WndProc; m_wcx.lpszClassName = m_lpClassName; m_wcx.lpszMenuName = NULL; m_wcx.style = CS_CLASSDC; if (!RegisterClassEx(&m_wcx)) return false; // Create parent window m_hWnd = CreateWindowEx( 0, m_lpClassName, m_lpWndName, m_dwstyle, m_nXPos, m_nYPos, m_nWidth, m_nHeight, m_hWnd, NULL, m_hInstance, NULL ); if (!m_hWnd) return false; // Show and update parent window ShowWindow(m_hWnd, SW_SHOW); UpdateWindow(m_hWnd); return true; } LRESULT CApplication::AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_KEYDOWN: if (wParam == VK_ESCAPE) PostQuitMessage(0); return 0; case WM_CLOSE: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd,uMsg, wParam, lParam); } ////////////////////////////////////////////////// // WndProc ////////////////////////////////////////////////// LRESULT CALLBACK CApplication::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) { CApplication *w = (CApplication *) (LONG)::GetWindowLongPtr(hWnd, GWL_USERDATA); return w->AppProc(hWnd,uMsg, wParam, lParam); } ********************************************************************** In the WndProc, when I run the program, it seems error on the first statement of the WndProc Function. Since, WndProc is the static function, but I want it can call the AppProc function, how can I do it sucess? Thx ***********************************************************************
Advertisement
Hi bud,

You can make wndproc a static member function of your class.

Like this:

Header
#pragma once#include <windows.h>#include <string>#include "..\\Kernel\\process.h"#include "..\\Kernel\\kernel.h"#include "..\\Kernel\\kbase.h"struct	win_window_props{	unsigned int		x,y;	unsigned int		w,h;	std::string			className;	std::string			windowCaption;	win_window_props() {};	win_window_props(	unsigned int	x,									unsigned int	y,									unsigned int	w,									unsigned int	h,									std::string className,									std::string windowCaption)		:	x(x), y(y), w(w), h(h), className(className), windowCaption(windowCaption)	{};};class win_window : public KERNEL::process{public:	win_window(HINSTANCE instance, const std::string& label, const win_window_props& props );	~win_window();	void Initialise( KERNEL::kernel* pKernel );	void Frame();	void Restart();	void End();	HWND& GetWindowRef()	{	return window; };	static LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );private:	HWND						window;	HINSTANCE				instance;	static win_window*		pThis;	win_window_props		windowProps;};


CPP
#include "win_window.h"win_window::win_window(HINSTANCE instance, const std::string& label, const win_window_props& props  ):process( label ){	this->instance = instance;	windowProps = props;}win_window::~win_window(){}void win_window::Initialise( KERNEL::kernel* pKernel ){	this->pKernel = pKernel;	this->pThis = this;	// Create the window handle etc	// Register the window class	WNDCLASSEX wc = {		sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,										GetModuleHandle(NULL), NULL, NULL, NULL, NULL,										&windowProps.className[0], NULL };	RegisterClassEx( &wc );	// Create the application's window	window = CreateWindow(	&windowProps.className[0], &windowProps.windowCaption[0],											WS_OVERLAPPEDWINDOW, windowProps.x, windowProps.y, windowProps.w, windowProps.h,											GetDesktopWindow(), NULL, this->instance, NULL );	// Show the window	ShowWindow( window, SW_SHOWDEFAULT );	UpdateWindow( window );}void win_window::Frame(){	MSG msg;	ZeroMemory( &msg, sizeof(msg) );	if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )	{		TranslateMessage( &msg );		DispatchMessage( &msg );	}}void win_window::Restart(){}void win_window::End(){}LRESULT WINAPI win_window::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ){	switch( msg )	{	case WM_DESTROY:		{			pThis->pKernel->SetState( KERNEL::KSC_END );			PostQuitMessage( 0 );			return 0;		}	}	return DefWindowProc( hWnd, msg, wParam, lParam );}// Give presence to the static memberwin_window* win_window::pThis;


Hope that helps mate,

ace
It seems quick complex.

I saw some forum or sample, that can use getwindowlong function

Here is my sample:
(.cpp)
LRESULT CALLBACK CApplication::AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
PostQuitMessage(0);
return 0;

case WM_CLOSE:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd,uMsg, wParam, lParam);
}

//////////////////////////////////////////////////
// WndProc
//////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CApplication *app = (CApplication*)GetWindowLong(hWnd, GWL_USERDATA);

return app->AppProc(hWnd,uMsg, wParam, lParam);
}


(.h)
public:
void Init(HINSTANCE hInstance);
bool Create();
void Run();

// Message Processing Functions
virtual LRESULT CALLBACK AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);

// Get Method
HINSTANCE GetHInstance();
HWND GetHWnd();

protected:
// Main Data
HINSTANCE m_hInstance; // Handle to application instance
HWND m_hWnd; // Handle to parent window
WNDCLASSEX m_wcx; // Structure contains parent window class information
MSG m_msg;
char* m_lpClassName; // Class name of parent window
char* m_lpWndName; // Name of parent window
DWORD m_dwstyle; // Parent window style
int m_nXPos; // Horizontal position of parent window
int m_nYPos; // Vertical position of parent window
int m_nWidth; // Parent window width
int m_nHeight; // Parent window height
};

static LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);




*******************************************
there has the warning, why?
warning C4312: 'type cast' : conversion from 'LONG' to 'CApplication *' of greater size
*******************************************

Would you mind to answer me some questions?
Why I need to use static function for the wndclassex.lpfnwndproc?
Why I cannot use the class member directly?
Quote:Original post by GDMichael
...there has the warning, why?
warning C4312: 'type cast' : conversion from 'LONG' to 'CApplication *' of greater size

Because your compiler is set to check for 64 bit compatibility issues. Uncheck that option in the project options, and this warning will disappear. Or use Get / SetWindowLongPtr (I believe) in place of Get / SetWindowLong.

Quote:Would you mind to answer me some questions?
Why I need to use static function for the wndclassex.lpfnwndproc?
Why I cannot use the class member directly?


Both of these are because Windows does not know how to call back into a class. Windows only knows how to call back to C'ish functions, as that's what Windows was primarily written in back in the days.

Another issue is that every compiler vendor is free to implement class functions in a variety of ways, and there is no 'standard' way for a class function to be called. The 'this' pointer can be placed on the stack or in a register - it is up to the implementation.

For a little more on this, see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_core_thiscall.asp. Note the statement 'The thiscall calling convention cannot be explicitly specified in a program, because thiscall is not a keyword.' 'thiscall' is specific to MS, and other compiler vendors can do it differently.
(.cpp)

//////////////////////////////////////////////////
// Include
//////////////////////////////////////////////////
#include "Core_Global.h"


//////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////
CApplication::CApplication()
{
m_hInstance = NULL;
m_hWnd = NULL;
m_lpClassName = "CoreAppWnd";
m_lpWndName = "Core Game";
m_dwstyle = WS_OVERLAPPEDWINDOW;
m_nXPos = 0;
m_nYPos = 0;
m_nWidth = 800;
m_nHeight = 600;
}

//////////////////////////////////////////////////
// Destructor
//////////////////////////////////////////////////
CApplication::~CApplication()
{

}

//////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////
void CApplication::Init(HINSTANCE hInstance)
{
m_hInstance = hInstance;
}

//////////////////////////////////////////////////
// Create
//////////////////////////////////////////////////
bool CApplication::Create()
{
// Init parent window class information
ZeroMemory(&m_wcx, sizeof(m_wcx));
m_wcx.cbClsExtra = 0;
m_wcx.cbSize = sizeof(WNDCLASSEX);
m_wcx.cbWndExtra = 0;
m_wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
m_wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
m_wcx.hInstance = m_hInstance;
m_wcx.lpfnWndProc = WndProc;
m_wcx.lpszClassName = m_lpClassName;
m_wcx.lpszMenuName = NULL;
m_wcx.style = CS_CLASSDC;

if (!RegisterClassEx(&m_wcx))
return false;

// Create parent window
m_hWnd = CreateWindowEx(
0,
m_lpClassName,
m_lpWndName,
m_dwstyle,
m_nXPos,
m_nYPos,
m_nWidth,
m_nHeight,
m_hWnd,
NULL,
m_hInstance,
NULL
);
if (!m_hWnd)
return false;

// Show and update parent window
ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);

return true;
}

//////////////////////////////////////////////////
// Run
//////////////////////////////////////////////////
void CApplication::Run()
{
ZeroMemory(&m_msg, sizeof(MSG));
while (m_msg.message != WM_QUIT)
{
if (PeekMessage(&m_msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&m_msg);
DispatchMessage(&m_msg);
}
else {
if (!Render())
break;
}
}

UnregisterClass(m_lpClassName, m_hInstance);
}

//////////////////////////////////////////////////
// Render
//////////////////////////////////////////////////
bool CApplication::Render()
{
return true;
}

//////////////////////////////////////////////////
// AppProc
//////////////////////////////////////////////////
LRESULT CALLBACK CApplication::AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
PostQuitMessage(0);
return 0;

case WM_CLOSE:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd,uMsg, wParam, lParam);
}

//////////////////////////////////////////////////
// WndProc
//////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CApplication *app = (CApplication *) (LONG_PTR)::GetWindowLongPtr(hWnd, GWLP_USERDATA);

return app->AppProc(hWnd,uMsg, wParam, lParam);
/*switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
PostQuitMessage(0);
return 0;

case WM_CLOSE:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd,uMsg, wParam, lParam);*/
}

//////////////////////////////////////////////////
// GetHInstance
//////////////////////////////////////////////////
HINSTANCE CApplication::GetHInstance()
{
return m_hInstance;
}

//////////////////////////////////////////////////
// GetHWnd
//////////////////////////////////////////////////
HWND CApplication::GetHWnd()
{
return m_hWnd;
}



(.h)

#ifndef CORE_APPLICATION_H
#define CORE_APPLICATION_H

class CApplication
{
public:
CApplication(); // Constructor
virtual ~CApplication(); // Destructor

public:
void Init(HINSTANCE hInstance);
bool Create();
void Run();
virtual bool Render();

// Message Processing Functions
virtual LRESULT CALLBACK AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);

// Get Method
HINSTANCE GetHInstance();
HWND GetHWnd();

protected:
// Main Data
HINSTANCE m_hInstance; // Handle to application instance
HWND m_hWnd; // Handle to parent window
WNDCLASSEX m_wcx; // Structure contains parent window class information
MSG m_msg;
char* m_lpClassName; // Class name of parent window
char* m_lpWndName; // Name of parent window
DWORD m_dwstyle; // Parent window style
int m_nXPos; // Horizontal position of parent window
int m_nYPos; // Vertical position of parent window
int m_nWidth; // Parent window width
int m_nHeight; // Parent window height
};

static LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);

#endif





**************************************************************
I have several questions to ask?
1. For your suggestion, I try to use GetWindowLongPtr, but when run-time, it still error occur, am I anything incorrect?
2. I don't know what is the meaning of 64 bit compliant code? What's that?
3. "thiscall" does mean this->abc();, right?

Thx your help
and I am really sorry that make all of you trouble
**************************************************************
First, when posting code, surround it in '[_source_]' '[_\source_]' tags (without the underscores), as per the faq (http://www.gamedev.net/community/forums/faq.asp). It is much more considerate to those of us who read your posts, versus just pasting it as you have done.

Second, I'm not going to delve into the GetWindowLongPtr issue, and solve your bug, because you haven't told us what the error is. I would guess that you need to call SetWindowLongPtr at the correct time. Looking a little closer, I see that is indeed the case. Where are you setting the pointer at? You must do this before trying to access the pointer at GWLP_USERDATA.

Third, 64 bit compliant code is code that is ready to run on the new and upcoming 64 bit operating systems. If you don't need the 64 bit capabilities in your programs, you are more than welcome to keep your code as 32 bit, as those operating systems will be capable of running 32 bit executables.

Fourth, 'thiscall' means how the machine processes 'this->abc()'. It doesn't mean 'this->abc()', but rather how the stack and registers are used 'under-the-hood', when your program executes that statement. Google 'thiscall', 'stdcall', and 'cdecl' to start your learning process.

Have fun!
(.h)
#ifndef CORE_APPLICATION_H#define CORE_APPLICATION_Hclass CApplication{public:	CApplication();						// Constructor	virtual ~CApplication();			// Destructorpublic:	void Init(HINSTANCE hInstance);	bool Create();	void Run();	virtual bool Render();	// Message Processing Functions	virtual LRESULT CALLBACK AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);	// Get Method	HINSTANCE	GetHInstance();	HWND		GetHWnd();protected:	// Main Data	HINSTANCE	m_hInstance;			// Handle to application instance	HWND		m_hWnd;					// Handle to parent window	WNDCLASSEX	m_wcx;					// Structure contains parent window class information	MSG			m_msg;	char*		m_lpClassName;			// Class name of parent window	char*		m_lpWndName;			// Name of parent window	DWORD		m_dwStyle;				// Parent window style	int			m_nXPos;				// Horizontal position of parent window	int			m_nYPos;				// Vertical position of parent window	int			m_nWidth;				// Parent window width	int			m_nHeight;				// Parent window height};static LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam);#endif


(*.cpp)
[sourcelang="cpp"]//////////////////////////////////////////////////// Include//////////////////////////////////////////////////#include "CApplication.h"//////////////////////////////////////////////////// Constructor//////////////////////////////////////////////////CApplication::CApplication(){	m_hInstance		= NULL;	m_hWnd			= NULL;	m_lpClassName	= "CoreAppWnd";	m_lpWndName		= "Core Game";	m_dwStyle		= WS_OVERLAPPEDWINDOW;	m_nXPos			= 0;	m_nYPos			= 0;	m_nWidth		= 800;	m_nHeight		= 600;}//////////////////////////////////////////////////// Destructor//////////////////////////////////////////////////CApplication::~CApplication(){}//////////////////////////////////////////////////// Init//////////////////////////////////////////////////void CApplication::Init(HINSTANCE hInstance){	m_hInstance = hInstance;}//////////////////////////////////////////////////// Create//////////////////////////////////////////////////bool CApplication::Create(){	// Init parent window class information	ZeroMemory(&m_wcx, sizeof(m_wcx));	m_wcx.cbClsExtra	= 0;	m_wcx.cbSize		= sizeof(WNDCLASSEX);	m_wcx.cbWndExtra	= 0;	m_wcx.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);	m_wcx.hCursor		= LoadCursor(NULL, IDC_ARROW);	m_wcx.hIcon			= LoadIcon(NULL, IDI_APPLICATION);	m_wcx.hIconSm		= LoadIcon(NULL, IDI_APPLICATION);	m_wcx.hInstance		= m_hInstance;	m_wcx.lpfnWndProc	= WndProc;	m_wcx.lpszClassName	= m_lpClassName;	m_wcx.lpszMenuName	= NULL;	m_wcx.style			= CS_CLASSDC;	if (!RegisterClassEx(&m_wcx))		return false;		// Create parent window	m_hWnd = CreateWindowEx(							0,							m_lpClassName,							m_lpWndName,							m_dwStyle,							m_nXPos,							m_nYPos,							m_nWidth,							m_nHeight,							m_hWnd,							NULL,							m_hInstance,							NULL						   );	if (!m_hWnd)		return false;	// Show and update parent window	ShowWindow(m_hWnd, SW_SHOW);	UpdateWindow(m_hWnd);	return true;}//////////////////////////////////////////////////// Run//////////////////////////////////////////////////void CApplication::Run(){	ZeroMemory(&m_msg, sizeof(MSG));	while (m_msg.message != WM_QUIT)	{		if (PeekMessage(&m_msg, NULL, 0, 0, PM_REMOVE))		{			TranslateMessage(&m_msg);			DispatchMessage(&m_msg);		}		else {			if (!Render())				break;		}	}	UnregisterClass(m_lpClassName, m_hInstance);}//////////////////////////////////////////////////// Render//////////////////////////////////////////////////bool CApplication::Render(){	return true;}//////////////////////////////////////////////////// AppProc//////////////////////////////////////////////////LRESULT CALLBACK CApplication::AppProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam){    switch (uMsg)    {		case WM_KEYDOWN:			if (wParam == VK_ESCAPE)				PostQuitMessage(0);				return 0;		case WM_CLOSE:			PostQuitMessage(0);			return 0;	}		return DefWindowProc(hWnd,uMsg, wParam, lParam);}//////////////////////////////////////////////////// WndProc//////////////////////////////////////////////////LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam){	CApplication *app = (CApplication *) (LONG_PTR)::GetWindowLongPtr(hWnd, GWLP_USERDATA);	return app->AppProc(hWnd,uMsg, wParam, lParam);/*    switch (uMsg)    {		case WM_KEYDOWN:			if (wParam == VK_ESCAPE)				PostQuitMessage(0);				return 0;		case WM_CLOSE:			PostQuitMessage(0);			return 0;	}		return DefWindowProc(hWnd,uMsg, wParam, lParam);*/}//////////////////////////////////////////////////// GetHInstance//////////////////////////////////////////////////HINSTANCE CApplication::GetHInstance(){	return m_hInstance;}//////////////////////////////////////////////////// GetHWnd//////////////////////////////////////////////////HWND CApplication::GetHWnd(){	return m_hWnd;}


*********************************************
1. What is the usage of WIndowLongPtr?
2. The Error is on run-time:
"Unhandled exception at 0x0042307b in 3DPRGApp.exe: 0xC000000005: Access violation reading location 0X00000000.
And the error is point to "return app->App(hwnd, uMsg, wParam, lParam);
***********************************************

I am really sorry make all of you trouble becuase my english is not really good, may be I don't fully understand the MSDN.. Hope you can help me ...and many many thanks.
You have to call 'SetWindowLongPtr' somewhere, and that somewhere must be before you try to use the pointer set there. According to Oluseyi (http://www.gamedev.net/reference/articles/article1810.asp), the first Window message a window receives is WM_NCCREATE, therefore, this message is the logical one to call SetWindowLongPtr from. (I have heard that WM_NCCREATE is not the actual first message from other places, though, so you will have to debug if this is not the case.)

Your call to SetWindowLongPtr would look like:

if(message == WM_NCCREATE) {    // retrieve Window instance from window creation data and associate    wnd = reinterpret_cast<Window *>((LPCREATESTRUCT)lparam)->lpCreateParams;    SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<long>(wnd));    // save window handle    wnd->SetHWND(hwnd);  }


Or something of that nature.

Good luck.
This article here on Gamedev, and this one at Code Project are useful for learning how to do this. The second one is written for Windows CE, but there are notes for applying it to desktop versions of Windows.
There is also http://www.codeproject.com/library/DWinLib.asp.

This topic is closed to new replies.

Advertisement