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 ;)