Archived

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

Sir_Spritely

Why does WndProc() have to be global ??

Recommended Posts

Sir_Spritely    122
I realise there are ways to incorperate WndProc() into a class but as far as I can tell there must always be a global WndProc(). I have done a lot of reading on this and some of the explanations are mind boggling. I know it is something to do with the O.S calling the Wndproc() function and as such no THIS pointer is passed. Wondering if anyone can explain in detail yet simply about this issue.

Share this post


Link to post
Share on other sites
BitMaster    8651
The WndProc does not need to be a global function, a static member function works too.

The OS must be able to call the WndProc, therefore calling convention and parameters must exactly match. Non-static class member functions always have a hidden first parameter, the this pointer.

Share this post


Link to post
Share on other sites
Galapaegos    277
That is exactly why people choose to use a thunk in its place. When you use a thunk, you basically rename the function so it doesn''t have the this pointer in it. You should be able to find some material online about it from a google search if you want to know more.

On a side note, I believe you can make it a friend (or something like that) have the function work too, but if my memory serves me right it will act the same as if it was static.

-brad

Share this post


Link to post
Share on other sites
BitMaster    8651
quote:
Original post by Sir_Spritely
If the WndProc() is declared as static that means it can not access non-static members. Making this method ineffective though?


It''s tidier to use a static function than using a global function if you want to write a class wrapper. Also, you can access other static class members simpler than from a global function and it''s tidying up the code.

Share this post


Link to post
Share on other sites
Sir_Spritely    122
Can someone please read this and let me know if I have this right or correct where neccasary (Thanks for the help!)


There is a slight issue when using OOP and Windows with the WndProc() function which is as previously stated the event handler where all messages head to first. Various windows based applications use this global function in various ways. In our case this function is used as a message command centre and when messages are recieved via this function it delegates the messages out to the Msgproc() member function of the derived Application class. In the Windows structure WNDCLASSEX, the default window procedure which processes all of the applications (the window which is created) messages. Now this function is known as a Callback function meaning it is called by the Operating System and not another function. Anytime a message is generated and has to be dealt with the Windows Operating System will send the message to the WndProc() function specified in the WNDCLASSEX structure. Thus the WndProc() function is actually being called by the Windows Operating System and not the object or indeed any function associated with the application. So a Callback function such as the WndProc() does not operate on a particular object and is as such Global. All the neccasary parameters the Callback function needs are passed to it by the Windows Operating System. Hence we can say a Callback function which includes WndProc() is a global function because it does not operate on any particular object. On the other hand a member function actually does implicitly operate on a particular object and usually has the object on which it is to operate on passed to it implicitly. By this I mean the object on which it is to operate on is passed in the form of a hidden first parameter known as the THIS pointer. So WndProc() cannot be a member function because a member function always has the hidden THIS pointer as it''s first parameter. When the Windows Operating System calls the Callback function like WndProc() and tries to pass the various parameters the function needs it comes across a different function prototype. Thus a compile error is caused. It is entirely possible to make the WndProc() a member function and make it accessible by the Windows Operating System. This can be achieved by making the WndProc() member function static, this removes the hidden THIS pointer parameter so the prototype matches the one the Windows Operating System is looking to call. However another problem is then raised in that this function because it is declared as being static cannot access any instance variables (an object of the class).

Share this post


Link to post
Share on other sites
Ximmer    314
Heres how I used it as a static function with access to member variables for all messages after WM_CREATE

you just have to pass the window as the lpParameter in the CreateWindowEx Function


static LRESULT WINAPI XWindow::WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
XWindow * w;
int i;

w = (XWindow *)GetWindowLong(hWnd, GWL_USERDATA);

switch(Msg)
{
case WM_CREATE:
{
CREATESTRUCT * cs;
cs = (CREATESTRUCT *)lParam;
w = (XWindow *)cs->lpCreateParams;

SetWindowLong(hWnd, GWL_USERDATA, (LONG_PTR)w);
}
break;

case WM_DESTROY:
w->m_IsWindow = false;
break;
}

// Execute my own message map

if(w != Null)
{
w->m_wParam = wParam;
w->m_lParam = lParam;

for(i = 0; i < (int)w->m_MsgMap.GetSize(); i++)
{
if(w->m_MsgMap[i]->m_Msg == Msg)
{
w->m_MsgMap[i]->m_Function(w);
}
}
}

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


[edited by - Ximmer on March 27, 2004 7:39:16 AM]

Share this post


Link to post
Share on other sites
Mastaba    761
You can make the callback a friend of the class. Doing so DOES NOT have the exact same limitations as a static member function. However doing so still requires the callback getting the instance of the class like a static member function would need to do, since the only instance info the callback gets is the HWND. This "problem" is not a big issue, since you can store the class instance in the window's user data field when the window is created. Then when handling any message other than WM_NCCREATE, get the instance from the window's user data field, and pass the callback parameters to the class's own wndproc. Of course, you can still call the classes own wndproc even when you get the WM_NCCREATE message, you just need to store the instance in the user data field before doing so.


[edited by - Mastaba on March 27, 2004 12:12:19 AM]

Share this post


Link to post
Share on other sites
Oluseyi    2103
No, it''s very straightforward:
  1. Make your class provide a static MessageRouter function that will retrieve the appropriate instance and call that instance''s own window procedure.

  2. Inside the MessageRouter, handle the WM_NCCREATE message and store a pointer to the class instance - passed via the extra parameter (void *) afforded by CreateWindowEx - in the window userdata space (use either SetWindowLong or SetWindowPtr). For all other messages, retrieve the instance pointer using GetWindowLong or GetWindowPtr and call that instance''s window procedure.

  3. In the class constructor, fill the lpWndProc field of the WNDCLASS[EX] structure with the address of the (static) MessageRouter function.

Sit back and congratulate yourself for following Uncle ''Seyi''s 3-Step Program.

Share this post


Link to post
Share on other sites