Skip to main content
GameDev.net gamedev.net
🔒 Locked

member function as WndProc?

Started by Z01 Aug 30, 2001 at 6:26 PM 13 replies 16k views
Original Post
Z01
Z01
I would like to use a member function of a class as my WndProc for various reasons (essentially, the WndProc accesses lots of data from the class, so logically it should be a member). The reason I can''t is because I can''t make assignment like: WNDCLASSEX wc; wc.lpfnWndProc = (WNDPROC) CGLWindow::WndProc; The reason this will not work, is that member functions have a hidden this pointer parameter, so the compiler can''t figure out how to match the signatures. Making the WndProc static is not acceptable. I found a solution for the borland compiler on the web, but I haven''t been able to find anything for the VC++ compiler. Essentially, the idea is to write a small snippet of ASM to offset the function pointers so they match (if i understand it correctly), and Borland has a premade function exactly for this purpose. I don''t know ASM very well and I was wondering if anyone else has encountered and solved this problem before or you could point me towards a website that solves this. Thanks
Blaster
Blaster
The idea is that you need a way to map a HWND to a pointer to you CGLWindow.
You can put the CGLWindow pointer in the user data of the window (lookup Get/SetWindowLong, and GWL_USERDATA in the help) for example.


class CGLWindow
{
private:
static LRESULT CALLBACK StaticWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
}

LRESULT CALLBACK CGLWindow::StaticWindowProc( ... )
{
CGLWindow* pWindow = (CGLWindow*)GetWindowLong( hWnd, GWL_USERDATA );

return pWindow->WindowProc( hWnd, ... );
}


I hope I could help...
Z01
Z01
Cool. Thanks, that worked nicely

You guys rock !
python_regious
python_regious
All right! I''ve been trying to figure out how to do this for ages.
If at first you don't succeed, redefine success.
Shannon Barber
Shannon Barber
There''s one small problem with that method, which may or maynot affect you:
The problem is, Windows call''s the WndProc with several messages (e.g. WM_CREATE) _when you create the window - before you can possibly toss a pointer in the GWL_USERDATA spot.

There may be a better way, but this is the hack I worked out:
When the CreateWindow method is invoked, it takes a critical section and stuffs the context pointer (this) in a static pointer hole, if the GWL_USERDATA is null, the default WndProc calls defers to the static pointer. After the GWL_USERDATA is set, it nulls the static pointer and leaves the critical section.

Part of the class is a map from the windows message to the method that handles it (requires a method pointer).

Magmai Kai Holmlor
- Not For Rent
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
AliasNotFound
AliasNotFound
Out of curiosity, why is making the window proc a static member not acceptable?

GayleSaver
GayleSaver
In my OODialogBox class, I have an excellent solution to this problem. In the future I may expand it to cover some MFC features for interest''s sake (DDX/DDV in particular).

The solution is pretty proprietary. But it belongs to me. Do you think I should post it?
VK
GayleSaver
GayleSaver
quote:
Original post by Magmai Kai Holmlor
There''s one small problem with that method, which may or maynot affect you:
The problem is, Windows call''s the WndProc with several messages (e.g. WM_CREATE) _when you create the window - before you can possibly toss a pointer in the GWL_USERDATA spot.

There may be a better way, but this is the hack I worked out:
When the CreateWindow method is invoked, it takes a critical section and stuffs the context pointer (this) in a static pointer hole, if the GWL_USERDATA is null, the default WndProc calls defers to the static pointer. After the GWL_USERDATA is set, it nulls the static pointer and leaves the critical section.

Part of the class is a map from the windows message to the method that handles it (requires a method pointer).

Magmai Kai Holmlor
- Not For Rent

I wonder why you don''t just pass it in as the lparam and call SetWindowLong on WM_CREATE?
VK
Kaellaar
Kaellaar
Here is what I do:

  
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CWindow * pWindow = 0 ;

if (msg == WM_NCCREATE)
{
pWindow = (CWindow *) ((LPCREATESTRUCT) lParam)->lpCreateParams ;

SetWindowLong (hwnd, GWL_USERDATA, (long) pWindow) ;

//If you process any messages that are sent before CreateWindowEx returns

//the HWND, you need something in the place of your HWND member.

pWindow->SetHwnd (hwnd) ;
}
else
pWindow = (CWindow *) GetWindowLong (hwnd, GWL_USERDATA) ;

if (pWindow)
return (pWindow ->WndProc (msg, wParam, lParam)) ;
else
return (DefWindowProc (hwnd, msg, wParam, lParam)) ;
}


Pass the this pointer to CreateWindowEx as the lParam.

Hope that helps.
mitchw
mitchw
quote:
Original post by GayleSaver
I wonder why you don''t just pass it in as the lparam and call SetWindowLong on WM_CREATE?



Exactly what you do.
Homer Simpson
Homer Simpson
One thing I do not understand, how I can use a cast "from" a
long to myclass ????
CGLWindow* pWindow = (CGLWindow*)GetWindowLong( hWnd, GWL_USERDATA );
______::Homer Simpson::
Sneftel
Sneftel
quote:
Original post by Homer Simpson
One thing I do not understand, how I can use a cast "from" a
long to myclass ????
CGLWindow* pWindow = (CGLWindow*)GetWindowLong( hWnd, GWL_USERDATA );


They''re just bits; 32 of them, to be exact. And on an x86, win32 pointers are also 32 bits. Windows doesn''t care what value you store in that long, so you can easily tell it that a memory addresss is actually a long, and it will faithfully remember those bits for you. Later, you can take them back, and use them for their intended purpose.
LessBread
LessBread
quote:
Original post by Magmai Kai Holmlor
There's one small problem with that method, which may or maynot affect you:
The problem is, Windows call's the WndProc with several messages (e.g. WM_CREATE) _when you create the window - before you can possibly toss a pointer in the GWL_USERDATA spot.

There may be a better way, but this is the hack I worked out:
When the CreateWindow method is invoked, it takes a critical section and stuffs the context pointer (this) in a static pointer hole, if the GWL_USERDATA is null, the default WndProc calls defers to the static pointer. After the GWL_USERDATA is set, it nulls the static pointer and leaves the critical section.

Part of the class is a map from the windows message to the method that handles it (requires a method pointer).


IndirectX worked out a way to stash the this pointer prior to WM_CREATE message by setting a hook before calling CreateWindowEx. I don't have the url for the thread (June 15, 2002) but here is his demo source:

    
// cbtdemo.cpp : Defines the entry point for the application.

//


#include "stdafx.h"

// this pointer in a real application

const long TEST_THIS_VALUE = 0x847FF3B9;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
long lThis = GetWindowLong(hwnd, GWL_USERDATA);
if (lThis != TEST_THIS_VALUE)
{
MessageBox(hwnd, _T("This sample doesn't work"), _T("Error"), MB_OK);
}

if (msg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// This hook is for our thread only, so don't check if the window being created

// is the one we want to hook -- it is.


if (nCode == HCBT_CREATEWND)
{
SetWindowLong(HWND(wParam), GWL_USERDATA, TEST_THIS_VALUE);
}

return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.


WNDCLASS wc = { 0, WndProc, 0, 4, hInstance, LoadIcon(0, IDI_APPLICATION), LoadCursor(0, IDC_ARROW), HBRUSH(COLOR_WINDOW), 0, _T("cbtdemo") };
if (!RegisterClass(&wc))
DebugBreak();

HHOOK hHook = SetWindowsHookEx(WH_CBT, CBTProc, 0, GetCurrentThreadId());
HWND hwnd = CreateWindow(_T("cbtdemo"), _T("Testing CBT hooks"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, 0);
UnhookWindowsHookEx(hHook);

return 0;
}



[edited by - lessbread on July 15, 2002 11:16:52 PM]
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Homer Simpson
Homer Simpson
Thanx Guy thanx a lot i hate pointers heheheheh Bt i´ll study them heheheheh
______::Homer Simpson::

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.