Archived

This topic is now archived and is closed to further replies.

Subotron

Making WindowProc part of a window wrapper class without using static

Recommended Posts

I''m making a window wrapper class and it all works fine, except that I have make the windowproc function either extern or static inside the class. I want it to be non-static, but part of the class (it''ll be virtual later on) is there a(n) (easy) way to archieve this? I''ve seen a few articles on window wrappers, but they either use the way described above or they have some weird code I really don''t understand. Someone told me to declare the windowproc like this inside the class: class CWindow { public: WNDPROC WindowProc; }; is this the way to do it? But like this, it seems like a variable to me. How do I use it? How do I set it up make it virtual etc. please help me on this it''s been bugging me for (too) long now... Thanks in advance | Panorama 3D Engine | Contact me | | MSDN | Google | SourceForge |

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
if you make it static and call a virtual method from that you need a mechanism for the static method to get hold of the instance of your window class - eg a global var or something similar.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I looked into this a bit a while ago. I''m no Windows GUI developer - so it''s not something I know much about. However you are basically trying to wrap a C API (or subset of one) in a C++ OO framework. Win32 defines the function as C linkage - so you can''t get round the fact that it has to be a static function. You also can''t get round the fact that a static function, by its nature, will have no ''this'' pointer - so you have to work around it - by either making the class a singleton or having a global var. You can use macros to tidy it up a little tho.

I''d be interested in any other (nicer) solutions to this too.

Share this post


Link to post
Share on other sites
I ran into the same problem. What I did was leave the WindowProc function static. I created a structure to hold the windows message parameters

struct MESSAGE
{HWND hWnd;UINT uiMsg;WPARAM wParam;LPARAM lParam;}

I fill out an instance of this variable in the Base Class WindowProc function. I then handled the last message stored in a derived class WindowProc function, every frame.

Maybe not quite what you are looking for but it works all right.

I should probably be working now...

Share this post


Link to post
Share on other sites
Use a static std::map in the CWindow class to map from window handles to CWindow pointers. Create the mappings during window creation, and when you receive a message in WndProc use that map to translate from HWND to CWindow*.


  
class CWindow {
public:
CWindow();
private:
void init();
HWND mHandle;

static std::map<HWND, CWindow*> msThisMap;
static long FAR PASCAL staticWndProc(...);
long instanceWndProc(...);
};

// during some

CWindow::CWindow() {
init();
}

void CWindow::init() {
// pass the static WndProc callback

WNDCLASS wc;
wc.lpfnWndProc = &staticWndProc;
RegisterClass(wc);

// associate the HWND with a this pointer

HWND mHandle = CreateWindowEx(...);
if (!mHandle) {
throw "ahhhhhhhhhhhhh!";
}
msThisMap[mHandle] = this;
}

long CWindow::staticWndProc(HWND hwnd, UINT msg, UINT wParam, UINT lParam) {
// retrieve the CWindow* pointer that was stored in init()

CWindow* thisPointer = msThisMap[mHandle];
// dispatch the call to the correct instance

return thisPointer->instanceWndProc(msg, wParam, lParam);
}



That code sample is far from complete, and is probably incorrect in a few places since I pretty much did it from memory, but it should give you an idea of how to accomplish your goal. It's a hack, but hacks are all you have.


edit: code /code tags don't handle templates

[edited by - Dobbs on March 18, 2003 10:21:12 AM]

Share this post


Link to post
Share on other sites
Another way is to create a global(or static) map containing pointers to instances of the window wrapper class. The HWND is used as a key to the map.

Every time a window object is created, add it to the map with HWND as key. In the static WndProc, use the map to find what window object is associated with the HWND and pass the message handling to the object. AFAIK MFC uses this method.

Share this post


Link to post
Share on other sites
Here''s what I do. Store the class attached to a window in the window''s user data area.
i.e. (NOTE: casts omitted)

WM_CREATE:
SetWindowLong (the_window, GWL_USERDATA, this);

The ''this'' pointer would be passed as the lpParam parameter to the CreateWindow(Ex) function. Note that WM_CREATE is not the first message to be sent to a window, so you''ll need to check for NULL pointers (the user data area is initialised to 0). So, to create a window:
window = new WindowClass ();
window->Create (creation_args); // CreateWindow(Ex) (..., this);
window->Show ();


EVERYTHING_ELSE:
this_ptr = GetWindowLong (the_window, GWL_USERDATA);
this_ptr->do_a_function (some_args);

Pros: No nasty globals.
Cons: If you''re already using the GWL_USERDATA for something, then you''ll need to either add extra bytes in the WNDCLASS(EX) or have the GWL_USERDATA point to a structure/class.

Skizz

Share this post


Link to post
Share on other sites
Well, if you want less complexity, and don't mind a bit of a 'hack' in this area, I can suggest this:

Make your WinProc outside any class, and give it a static variable as a pointer to your class. Like this:

int __stdcall WinProc(...)
{
static EntireGame* me = NULL;
}

Then, *before* you actually make the window, but *after* you construct your class, call this function manually.

//...
EntireGame* game = new EntireGame(...);
WinProc(0, OBJECT_INIT, 0, (LPARAM)game);
//...

So, now you just have to look for this in your WinProc function and set the static variable to the LPARAM of the function, and from then on, have it simply relay all messages to your object. Like this:


int __stdcall WinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
static EntireGame* me = 0;
if(msg == OBJECT_INIT)
{
me = (EntireGame*) lp;
return 0;
}
if(me == NULL)
return DefWindowProc(hwnd,msg,wp,lp);
else
return me->WindowProc(hwnd,msg,wp,lp);
}


And from then on, your class' own, personal WindowProc will be responsible for messages.

NOTE: This is basically the same method as setting the Window's User Data, but a little more straight-forward if you aren't used to that sort of thing.

[edited by - Rick Scott on March 18, 2003 11:54:53 AM]

Share this post


Link to post
Share on other sites