Sign in to follow this  
ShadowPhoenix

WndProc Woes

Recommended Posts

ShadowPhoenix    109
So, here is the idea. I want to have a nice class to make a window. Yet I want to have an alone WndProc callback function. "No problemo", thought I, and decided to make it such. Main File has main + wndProc. WindowCreator receives the pointer for WndProc, and uses the pointer. However, I get an access violation for this.... Main File...
LRESULT (*myWND)(HWND, UINT, WPARAM, LPARAM) = NULL;  

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int Main(){
myWND=(LRESULT (__cdecl *)(HWND,UINT,WPARAM,LPARAM))&WndProc;
 myDisplay=new Display(800,600,myWND);
...}


MyDisplay File.
...
wc.lpfnWndProc		= (WNDPROC) myWND;	
RegisterClass(&wc);
...

Why does it crash :(?

Share this post


Link to post
Share on other sites
MJP    19754
Methods for wrapping a Win32 Window in a C++ class have been explored many times. The common way is to store a pointer to an instance of the (C++) class in the Window's user data by using SetWindowLongPtr and then using a static method as a proxy, a la Raymond Chen's old scratch program. The other two methods, used my Microsoft's MFC and ATL frameworks respectively, is to store a pointer to the (C++) class in the thread-local storage or to use a thunk to make Win32 call the (C++) class's message pump method.

Also before you get too far into making a Win32 wrapper class, you may want to look into WTL if you want something that's lightweight, versatile, and already implemented.

Share this post


Link to post
Share on other sites
harmless    139
take a look at this simple Wnd class that i wrote long ago.
You can inherit from this class or modify/override the WindowProc function.
The heart of the code is in stWindowProc function.

CWindow.h

#ifndef __CWINDOWS__
#define __CWINDOWS__
//------------------------------------------------------------------------------------------------------------------
// include files
//------------------------------------------------------------------------------------------------------------------
#include <windows.h>


//------------------------------------------------------------------------------------------------------------------
// constants
//------------------------------------------------------------------------------------------------------------------
class CWindow;


//------------------------------------------------------------------------------------------------------------------
// class declaration
//------------------------------------------------------------------------------------------------------------------
class CWindow
{
private:
HWND m_hWnd;
HWND m_hWndParent;
HINSTANCE m_hInstance;

// the actual window procedure which is encapsulated by this class. a public overridable window procedure
// is called inside this procedure to be used by derived class to perform operations related to windows procedure
static LRESULT CALLBACK stWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

protected:
// protected overridable function called in message loop when window is idle
// this is where real-time applications call processes such as render/logic updates
virtual bool Idle();

// protected overridable window procedure called in the actual window procedure of this class.
// this is where derived class can perform operations related to window procedure
virtual LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

public:
// constructor/destructor
CWindow();
virtual ~CWindow();

// window is registered and created here
bool Create( int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT,
const WCHAR* pWindowTitle = L"CWindow Application",
int x = CW_USEDEFAULT, int y = CW_USEDEFAULT,
unsigned long dwStyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE,
unsigned long dwExStyle = WS_EX_LEFT );

// this is the message loop of the application
bool Run();

// windows is unregistered and destroyed here
bool Release();

// function to show or hide window
void Show();
void Hide();

// access functions
HWND GetWnd();
};

#endif



CWindow.cpp

//------------------------------------------------------------------------------------------------------------------
// include files
//------------------------------------------------------------------------------------------------------------------
#include "CWindow.h"


//------------------------------------------------------------------------------------------------------------------
// default constructor
//------------------------------------------------------------------------------------------------------------------
CWindow::CWindow()
{
// set default values for window
m_hInstance = GetModuleHandle( NULL );
m_hWndParent = NULL;
}

//------------------------------------------------------------------------------------------------------------------
// default destructor
//------------------------------------------------------------------------------------------------------------------
CWindow::~CWindow()
{
}

//------------------------------------------------------------------------------------------------------------------
// default constructor
//------------------------------------------------------------------------------------------------------------------
bool CWindow::Create( int nWidth, int nHeight, const WCHAR* pWindowTitle, int x, int y, unsigned long dwStyle, unsigned long dwExStyle )
{
// make sure to clear window before creating
Release();

// Create the application window
WNDCLASSEX WndCls;
WndCls.cbSize = sizeof( WNDCLASSEX );
WndCls.style = 0;
WndCls.lpfnWndProc = stWindowProc;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hIcon = LoadIcon( NULL, IDI_APPLICATION );
WndCls.hCursor = LoadCursor( NULL, IDC_ARROW );
WndCls.hbrBackground = (HBRUSH)GetStockObject( COLOR_WINDOW + 1 );
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = TEXT("WindowClass");
WndCls.hInstance = m_hInstance;
WndCls.hIconSm = LoadIcon( NULL, IDI_APPLICATION );

// Register the application
RegisterClassEx( &WndCls );

// adjust the given extent to make it the client area rather than window size
RECT rect = { 0, 0, nWidth, nHeight };
AdjustWindowRectEx( &rect, dwStyle, false, dwExStyle );

// send the this pointer as the window creation parameter
m_hWnd = CreateWindowEx( dwExStyle,
TEXT("WindowClass"),
pWindowTitle,
dwStyle,
x, y,
rect.right - rect.left, rect.bottom - rect.top,
m_hWndParent, NULL,
m_hInstance,
(void *)this );

// show window by default
Show();

return ( m_hWnd != NULL );
}

//------------------------------------------------------------------------------------------------------------------
// window specific message handler
//------------------------------------------------------------------------------------------------------------------
bool CWindow::Run()
{
MSG msg;
ZeroMemory( &msg, sizeof( MSG ) );
while( msg.message != WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
// perform other process when window is idle
else
{
Idle();
}
}
return true;
}

//------------------------------------------------------------------------------------------------------------------
// release
//------------------------------------------------------------------------------------------------------------------
bool CWindow::Release()
{
UnregisterClass( TEXT("WindowClass"), GetModuleHandle(NULL) );
return true;
}

//------------------------------------------------------------------------------------------------------------------
// this is where real-time applications call processes such as render/logic updates
//------------------------------------------------------------------------------------------------------------------
bool CWindow::Idle()
{
return true;
}

//------------------------------------------------------------------------------------------------------------------
// method to show window
//------------------------------------------------------------------------------------------------------------------
void CWindow::Show()
{
ShowWindow( m_hWnd, SW_SHOW );
UpdateWindow( m_hWnd );
}

//------------------------------------------------------------------------------------------------------------------
// method to hide window
//------------------------------------------------------------------------------------------------------------------
void CWindow::Hide()
{
ShowWindow( m_hWnd, SW_HIDE );
UpdateWindow( m_hWnd );
}



//------------------------------------------------------------------------------------------------------------------
// static window procedure
//------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK CWindow::stWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
CWindow* pWnd;

// if the window calling this procedure is about to be created, then set this window's long
// to pointer to itself
if ( uMsg == WM_NCCREATE )
{
// Set the pointer
SetWindowLong( hWnd, GWL_USERDATA, (long)( ( LPCREATESTRUCT( lParam ) )->lpCreateParams ) );
}

// Get the pointer to the window that call this procedure
pWnd = (CWindow*)GetWindowLong( hWnd, GWL_USERDATA );

// if the window exists, call this window's specific message handler
if ( pWnd )
{
LRESULT bMessage = 0;
bMessage = pWnd->WindowProc( hWnd, uMsg, wParam, lParam );
if ( !bMessage ) return 0;
else return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
// otherwise, default it
else return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

//------------------------------------------------------------------------------------------------------------------
// window specific message handler
//------------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK CWindow::WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_DESTROY:
{
PostQuitMessage( WM_QUIT );
break;
}
default: return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

// If something was not done, let it go
return 0;
}

//------------------------------------------------------------------------------------------------------------------
// access/setup functions
//------------------------------------------------------------------------------------------------------------------
HWND CWindow::GetWnd() { return m_hWnd; }




main.cpp

//------------------------------------------------------------------------------------------------------------------
// include
//------------------------------------------------------------------------------------------------------------------
#include "CWindow.h"

//------------------------------------------------------------------------------------------------------------------
// WinMain application entry point
//------------------------------------------------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{
// instantiate CGraphics object
// -----------------------------------------------------------------------
CWindow* pApp = new CWindow;

// Create() functions invokes the window
// -----------------------------------------------------------------------
pApp->Create( true, 800, 600, L"Demo Compilation" );

// run the real-time/message loop of the application
// -----------------------------------------------------------------------
pApp->Run();

// destroy the application
// -----------------------------------------------------------------------
pApp->Release();
delete pApp;

return 0;
}



Share this post


Link to post
Share on other sites
Evil Steve    2017
Never ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever cast a function pointer. If it doesn't compile without the cast, then there's a reason for that. Forcing the cast will just cause a runtime failure instead of a compile time one.

Share this post


Link to post
Share on other sites
MJP    19754
Quote:
Original post by Evil Steve
Never ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever cast a function pointer. If it doesn't compile without the cast, then there's a reason for that. Forcing the cast will just cause a runtime failure instead of a compile time one.


As an addendum to this, don't use C-style casts in C++. Get to know reinterpret_cast and friends, they do a better job of keeping you from doing something stupid.

Share this post


Link to post
Share on other sites
ShadowPhoenix    109
Thank you, harmless!
I decided to implement your version of it (rebuilding it to get it to work) instead of playing around with function pointers.

Quote:
Original post by Evil Steve
Never ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever ever cast a function pointer. If it doesn't compile without the cast, then there's a reason for that. Forcing the cast will just cause a runtime failure instead of a compile time one.

Sorry, this is my first time ever trying to work with a function pointer. I didn't even know you could do this kind of a stuff!

Quote:
As an addendum to this, don't use C-style casts in C++. Get to know reinterpret_cast and friends, they do a better job of keeping you from doing something stupid.


Oh, I thought reinterpret_cast was just Microsoft's way of casting....

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