Wrapping up a window class or two [Resolved]
I am making an app, with two different windows. And I want to wrap the windows up in two classes.
But I have a few questions about what I should do with the message pump and the message handler (if that is what they are called).
Is the message handler (the one that takes cares of what to do with the different messages) supposed to be a member function in the two classes. But the message pump (is that what it is called? The one with TranslateMessage() and DispatchMessage()) supposed to be just a global function in the app, and not be wrapped up at all? If so, am I supposed to send a function pointer (to the message pump) as a parameter to each of the classes, when making new objects?
PS: Please correct the names of the two functions if they are a bit (or totaly) off.
Thanks in advance.
ØØ
Re: Wrapping up a window class or two
You should go for the message main loop (that's the GetMessage(), TranslateMessage() & DispatchMessage() thingee) into the WinMain. And the window procedure must be a static member of your class, because the calling convention __thiscall is not compatible with standard C calling conventions that are used to implement a window procedure (__stdcall). Just search the forum and you will find a ton of people who have tried this before you.
Re: Wrapping up a window class or two
You may want to look at some posts by Bond. I remember Bond working on something similar to this..
Re: Wrapping up a window class or two
Thanks, been seraching since I posted the thread. And searched for Bonds thread too. But couldn't find anything about the message pump in his thread. I found some other interesting threads about the topic.
It looks like the Mesage handler should be ok to have as a member function, but the message pump the (WNDPROC) has to be a static global function. But if the function that creates and registers the window is member functions, then I guess I have to pass a function pointer to the class when I am making it. How else should I set the wndClass.lpfnWndProc?
Code:
void Device::DefineWndCls(HINSTANCE hInstance){
wndClass.hInstance = hInstance; // Handle to this instance
wndClass.lpszClassName = szWinName; // The window class name
wndClass.lpfnWndProc = WndProc; // Window function
wndClass.style = 0; // Default style
wndClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_ICON1); // Load an icon.
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Load a cursour.
wndClass.lpszMenuName = NULL; // We are not using a menu
wndClass.cbClsExtra = 0; // No extra info needed
wndClass.cbWndExtra = 0; // No extra info needed
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW); // Set a normal background color
}
Re: Wrapping up a window class or two
Sorry, didn't read fully before I sent that info...
here goes...
Quote:
Is the message handler (the one that takes cares of what to do with the different messages) supposed to be a member function in the two classes.
yes . That makes sense.. because different window classes would want to handle the messages differently, so as the name suggests, message handler, could be put as a class specific thing.
Quote:
But the message pump (is that what it is called? The one with TranslateMessage() and DispatchMessage()) supposed to be just a global function in the app, and not be wrapped up at all? If so, am I supposed to send a function pointer (to the message pump) as a parameter to each of the classes, when making new objects?
You are right. Message pump is supposed to be running all the time in a thread which creates windows. So, it is something you want to put either in the main thread ( in which case it would go into WinMain as suggested ) or in case of seperate thread, it would be a part of the thread procedure.
Re: Wrapping up a window class or two
Thanks, that was a good answer. But just to wrap this up. Passing in a functioni pointer to the class is the only way to tell the class about the Message pump right. It sounds like a ok idea. but if there is a better way. Please tell me before I mark this thread as resolved and hand out points.
Thanks
ØØ
Re: Wrapping up a window class or two
Quote:
Originally Posted by NoteMe
Thanks, that was a good answer. But just to wrap this up. Passing in a functioni pointer to the class is the only way to tell the class about the Message pump right. It sounds like a ok idea. but if there is a better way. Please tell me before I mark this thread as resolved and hand out points.
Thanks
ØØ
Why would you want the class to know about the message pump ? The class doesn't need to know . If the message pump has been implemented in the thread, then it's gonna dispatch message to the appropriate window and that window's wndproc should take care of doing the necessary ?
PS: Message pump is the
GetMessage/TranslateMessage/DispatchMessage thing..
Are you confusing message pump with message handler.
Re: Wrapping up a window class or two
Sorry, fell asleep on my coatch with my laptop on my lap last night..:D..
And I belive you are totaly right. After readin my post again, I can't even understand that you bothered to answer me. I made no sense. I did get confused again about what was the message pump and what was the message handler.
Well I got it now. Thanks for all your help. I really appreciate it. And totaly got it now.
ØØ
Re: Wrapping up a window class or two
Regarding to your highlighted source code:
Code:
wndClass.lpfnWndProc = WndProc;
It should be something like:
Code:
// Device.h
class Device
{
protected:
static LRESULT WndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
public:
void DefineWndCls(HINSTANCE hInstance);
};
Code:
// Device.cpp
#include "device.h"
void Device::DefineWndCls(HINSTANCE hInstance)
{
wndClass.hInstance = hInstance; // Handle to this instance
wndClass.lpszClassName = szWinName; // The window class name
wndClass.lpfnWndProc = (WNDPROC)Device::WndProc; // Window function
wndClass.style = 0; // Default style
wndClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_ICON1); // Load an icon.
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Load a cursour.
wndClass.lpszMenuName = NULL; // We are not using a menu
wndClass.cbClsExtra = 0; // No extra info needed
wndClass.cbWndExtra = 0; // No extra info needed
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW); // Set a normal background color
}
DWORD Device::WndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
// handlers go here
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Re: Wrapping up a window class or two
Yeah, thats what I ended up doing. Thanks.
Øyvind Østlund
Re: Wrapping up a window class or two
WNDPROC doesn't necessarilly have to be static. You could create machine code thunk (similar to ATL/WTL thunk) that strips most of class information from pointer to member function and points to class member directly. That way you could have a window class with only one WNDPROC function that ISN'T static.
The only problem with this method is that it is processor dependant and compiler dependant.
Here's an example of a thunk that works with msvc 6.0 on intel compatible and does not support multiple and virtual inheritance:
namespace WCL
{
#if defined(_M_IX86) && defined(_MSC_VER)
#pragma pack (push,1)
template <typename TFnStatic, typename TFnMember, typename TObject>
class CCallbackThunkT
{
protected:
BYTE m_byMov;
DWORD m_dwObject;
BYTE m_byJmp;
DWORD m_dwRelProc;
public:
CCallbackThunkT (VOID) : m_byMov (0), m_dwObject (0), m_byJmp (0), m_dwRelProc (0) {};
~CCallbackThunkT (VOID) {}
VOID Init (TObject* pObject, TFnMember fnMember)
{
m_byMov = 0xB9; // mov ECX, m_dwObject
m_dwObject = reinterpret_cast<DWORD> (pObject);
m_byJmp = 0xE9; // jmp m_dwRelProc
m_dwRelProc = *(reinterpret_cast<LPDWORD> (&fnMember)) - (reinterpret_cast<DWORD> (this) + sizeof (CCallbackThunkT)); // relative jmp
::FlushInstructionCache (::GetCurrentProcess(), this, sizeof (CCallbackThunkT));
}
__forceinline TFnStatic GetStaticProc (VOID) const
{
return (reinterpret_cast<TFnStatic> (this));
}
__forceinline operator TFnStatic (VOID) const
{
return (reinterpret_cast<TFnStatic> (this));
}
};
#pragma pack (pop)
#endif // defined(_M_IX86) && defined(_MSC_VER)
}
namespace WCL
{
class CWindow
{
protected:
typedef LRESULT (CWindow::* WCL_WNDPROC) (HWND, UINT, WPARAM, LPARAM);
CCallbackThunkT<WNDPROC, WCL_WNDPROC, CWindow> m_cbThunk;
HWND m_hWnd;
public:
CWindow (HWND hWnd = NULL) : m_hWnd (hWnd)
{
m_cbThunk.Init (this, WndProc);
}
LRESULT WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
m_hWnd = hWnd;
switch (uMsg)
{
case WM_DESTROY:
::PostQuitMessage (0);
return 0L;
}
return ::DefWindowProc (hWnd, uMsg, wParam, lParam);
}
WNDPROC GetWndProc (VOID)
{
return m_cbThunk.GetStaticProc();
}
}
}
...
using namespace WCL;
...
(inside your WinMain):
CWindow Window;
WNDCLASS wc;
ZeroMemory (&wc, sizeof (WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = Window.GetWndProc();
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle (NULL);
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT ("MyWindow");
// then you'll need to call some sort of create function (not present here)...
Re: Wrapping up a window class or two
Or you could just use WTL.
Re: Wrapping up a window class or two
You are wrong... The Window procedure has to be static because, a normal class member requires this to be passed as the first parameter. And how should the GUI subsystem know which class are you currently using? So the Window procedure must be static.
WTL just uses a static function pointer table which has pointer to member functions to be called on a specific message/id. Just take a carefully look on the WTL/MFC (especially CCmdTarget class) source code and you will find out that it's member procedure is also static.
Convinced? :)
Re: Wrapping up a window class or two
Actually I'm currently using my own window classes on msvc 6.0 without any static functions.
And I never said that I'm using the same thunking technique as ATL.
Now try the code first before posting again that this is impossible.
Still not convinced??
Check out theese links:
www.hackcraft.net/cpp/windowsThunk/thiscall/
http://www.codeproject.com/atl/atlaux.asp
(see CAuxThunk)
http://www.codecomments.com/archive2...-3-407950.html
http://www.codeproject.com/cpp/SoloGenericCallBack.asp
(see 3rd comment under "Use __thiscall" comment)
http://www.codeproject.com/cpp/thunk.asp
http://www.codeproject.com/cpp/Ellipses.asp
Re: Wrapping up a window class or two
Of course you can make pointers to member which to be called on specific id's or message. This is the way how MFC handles their action on buttons etc. But the window procedure which calls those application defined handlers is static. And that's the way it has to be. Apart from making it static you can also make it a global function.
Code:
LRESULT WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
m_hWnd = hWnd;
switch (uMsg)
{
case WM_DESTROY:
::PostQuitMessage (0);
return 0L;
}
return ::DefWindowProc (hWnd, uMsg, wParam, lParam);
}
WNDPROC GetWndProc (VOID)
{
return m_cbThunk.GetStaticProc();
}
Your Window procedure here, is also a normal global function. And not the member. My point was to explain that a window procedure can (theoretically) never and absolutley never be a member of a class. Just take a look at the SoloGenericCallback example at the CodeProject:
Code:
class A{
_CallBackProcThunk thunk;
//start callback here
void Init(...){
thunk.Init((DWORD_PTR)StaticCallerProc, this);
SomeCallback(param1,..., (CALLBACK_TYPE)&thunk); //see this
}
static void StaticCallerProc(HWND hWnd, ...){
//At here, hWnd is already modified with pThis;
A* pThis = (A*)hWnd;
pThis->MemberCallbackProc(mHWnd, ...);
}
void MemBerCallbackProc(HWND hWnd, ...){
// we did
}
};
The CallerProc is static. And the CallerProc here is in the GUI handling the window procedure. And here it is static because the Idiom says that it should remain a member of the window class. I have never said that it is impossible that a static member (the Window procedure or the StaticCallerProc) can not call a non-static member function from a specified class. Even MFC does this. With help of the pointer to member Idiom.
That's the way it is.
Re: Wrapping up a window class or two
And now to the point... If it is practically possible to do it - As the forum post in your link shows us, by using assembler and bypassing the __thiscall etc - But why do want to do it?? It is just unecessary and will end up in a code that is
- Hard to read
- Hard to debug
- And a complete overhead
Since a static member procedure which has a map of the ids and member to be called, much more easily, not so fault-prone and easier to implement. Even the designers of the MFC decided not to use this technique with the assembler instructions and so on...
Keep it simple...
Re: Wrapping up a window class or two [Resolved]
Quote:
Originally Posted by NoteMe
Is the message handler (the one that takes cares of what to do with the different messages) supposed to be a member function in the two classes. But the message pump (is that what it is called? The one with TranslateMessage() and DispatchMessage()) supposed to be just a global function in the app, and not be wrapped up at all? If so, am I supposed to send a function pointer (to the message pump) as a parameter to each of the classes, when making new objects?
I noticed and read all the answers, yet noone mentioned an elegang solution, I have used a while ago. I will sum it up with several points, to help you with the theory:
1. WinMain is a memory located piece of code, in C convention defined as a __stdcall function, which means the function generated has a certain type of "calling-contract". Calling contract is easy: it is just agreement between the caller and callee, as to who cleans the stack, are the arguments pushed right to left or left to right etc. If you ever coded in Assembly, you would know that even in C++ it all still boils down to this :)
2. WinMain is called by Windows System process, which is a wrap for ring-0 (kernel, or Windows core) thread, which basically is responsible for keeping the GUI alive - it pumps and dispatches messages and so on. Since the WinMain function gets called by the system, the system has no idea what an object is, much less what a class is and what is C++ or OOP. So, even though hacks exist to simulate a __thiscall type of call, where "this" parameter is passed to function to make it behave as a member, I dont think it is elegant, as someone pointed out here - it clutters the code, and is heavily platform and compiler dependent. Hence the better coders make WinMain static, as it should be, or even global function, to make it even simpler and then...
3. You need to figure out when your WinMain is called, which object (your Window' or its subclass object) this procedure belongs to, in other words, which window basically system "is talking about". Simpler put, you must route your code further to some sort of HandleMessage method in your window class, which is NOT static. You need to route from a statically called WinMain of which the only relevant parameter is "HWND hWnd", to a method of your class.
How to route:
Read on the "Window properties" (MSDN) with its GetProp function especially, and/or "Window Class functions"(MSDN) with its GetWindowLong function (less desireable because of platform dependency). What you do is when you create a window handle, you use SetProp to add the address of your relevant window class instance (object) as a property of the window handle. Given a window handle, you will always know which object it refers to. Then in the static WinMain function you use something like this:
Code:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM w, LPARAM l)
{
Window* p = (Window*)GetProp(hWnd, "pWnd"); //must be previously declared
p->OnWindowMessage(msg, w, l);
}
This is one of many ways to do this. MFC, for instance uses a "safer" approach (GetProp usage here casts a HANDLE to a Window* which MAY OR MAY NOT be of the same binary size, so a truncation may occur, although highly unlikely ever, since HANDLE in windows IS a pointer. Nevertheless a potential issue). MFC uses what is called a "window map", where each MFC window handle refers to an MFC Window object. This is slower, since you need to lookup the map, yet it is future-proof. Personally, not a bad idea at all, I think.
Hope this helped. This is meant as an addition to all said.
Re: Wrapping up a window class or two
I agree that using machine code stored as variable(s) is not portable but there is absolutely no overhead.
Let me tell you what overhead is:
1. create a map of handles and 'this' pointers
2. jump into static / global function
3. during WM_CREATE or similar message insert a pair of 'this' and hWnd into map (internally implemented as dynamic heap allocation which is slow)
4. during any other message lookup the map to find 'this' pointer that is associated with current hWnd
5. when obtained 'this' call appropriate member function
6. when a window is destroyed remove this-hwnd pair from the map
It is overhead because :
1. it jumps from function to function (slow)
2. it uses heap for dynamic allocation (slow)
3. uses too many processor instuctions
Using windows properties is equally slow because 'properties' mechanism is internally implemented as a map.
Re: Wrapping up a window class or two
Quote:
Originally Posted by mkuhac
I agree that using machine code stored as variable(s) is not portable but there is absolutely no overhead.
Let me tell you what overhead is:
1. create a map of handles and 'this' pointers
2. jump into static / global function
3. during WM_CREATE or similar message insert a pair of 'this' and hWnd into map (internally implemented as dynamic heap allocation which is slow)
4. during any other message lookup the map to find 'this' pointer that is associated with current hWnd
5. when obtained 'this' call appropriate member function
6. when a window is destroyed remove this-hwnd pair from the map
It is overhead because :
1. it jumps from function to function (slow)
2. it uses heap for dynamic allocation (slow)
3. uses too many processor instuctions
Using windows properties is equally slow because 'properties' mechanism is internally implemented as a map.
I already pointed out in my last post what my opinion about "perfomance" and "slow" is. The point still stands. "Slow" and "performance" related matters to moderate extent are of NO relevance.
Run a loop with looking up 1000000 window objects from their handles using window properties, and see how long it takes. An average application operates with 10 windows at most at a time, so I dont see any specific reason to use assembler to speed up the application in this way. Optimise the logic first, I say.
Re: Wrapping up a window class or two [Resolved]
Quote:
Originally Posted by Amn
This is one of many ways to do this. MFC, for instance uses a "safer" approach (GetProp usage here casts a HANDLE to a Window* which MAY OR MAY NOT be of the same binary size, so a truncation may occur, although highly unlikely ever, since HANDLE in windows IS a pointer. Nevertheless a potential issue). MFC uses what is called a "window map", where each MFC window handle refers to an MFC Window object. This is slower, since you need to lookup the map, yet it is future-proof. Personally, not a bad idea at all, I think.
I hope that there is a "window map" local to each thread (with a Tls), because on multiple-processor machines, the synchronisations need of the map, even if it is not a real problem, is really bad.
Why to don't use a simple and elegant solution?
There is one!
Use the SetWindowLongPtr function with GWLP_USERDATA to save a pointer to the object into the window handle. And there is no pointer-size problem.
And if you want to let the GWLP_USERDATA for an other usage, there is even a better solution : set the cbWndExtra field of the WNDCLASSEX structure to sizeof(MyWindowClass *) and call SetWindowLongPtr with a zero index. The cbWndExtra field only exists to provide such usages.
Even if the SetWindowLongPtr's documentation is relatively recent, it is compatible with old windows (just #defined to SetWindowLong).
Re: Wrapping up a window class or two
GetProp and SetProp are more elegant and portable than SetWindowLongPtr i think. basically they allow storing properties for a window, be it a handle or a pointer. The multithreading is not an issue, because there is no map involved, it is just a property of a window and maps the handle 1-1 to a property value you store.
SetWindowLongPtr may be ok as well, since it implies that it stores a pointer which is exactly what one needs, when the system needs to map a handle to a class object pointer.
And once again, performance is irrelevant, at least in this case, because properties are very fast, so is Set/GetWindowLongPtr and you dont need to do ugly assembler hacks which only work on a x86 platform anyway. I used to think like that (assembly) when I was 16 or something, but a lot changed since then, outside and inside ;)