WndProc() Inside a Window Class
For awhile I was simple using a static WndProc() function and a singleton of the class for windows, but then I realized I couldn't use the same window class for dialogs or anything, and I couldn't have more than one instance.
So... my question is what's the best way to get WndProc() inside a class. I've heard that you can reserve extra memory through the window class and then put a pointer to the class instance through that... but I'm really unsure of how to accomplish this. Another idea I had was having a static std::map and associating each HWND with a pointer to the class instance, but I was told that was not worth the trouble. Any help would be appreciated, thanks.
-----------------
The Goblin (madgob@aol.com)
-----------------
"Before critisizing somebody, walk a mile in their shoes. That way, when you do critisize them, not only will you be a mile away, but you'll also have their shoes!"
Edited by - Goblin on November 22, 2001 5:04:59 PM
How do I turn my message procedure into a member of a class?
Next time, please search the forums. There have been at least 3 threads on this in the last month alone.
[Edit:] Punctuation.
Edited by - Oluseyi on November 22, 2001 6:43:15 PM
Next time, please search the forums. There have been at least 3 threads on this in the last month alone.
[Edit:] Punctuation.
Edited by - Oluseyi on November 22, 2001 6:43:15 PM
About the encapsulated window class you may or may not like this suggestion.
but look at this
(sorry for the length but i find this INCREDIBLY USEFUL and i think others may too)
#ifndef _M_IX86
#pragma message("CAuxThunk/CAuxStdThunk is implemented for X86 only!")
#endif
#pragma pack(push, 1)
template <class T>
class CAuxThunk
{
BYTE m_mov; // mov ecx, %pThis
DWORD m_this; //
BYTE m_jmp; // jmp func
DWORD m_relproc; // relative jmp
public:
typedef void (T::*TMFP)();
void InitThunk(TMFP method, const T* pThis)
{
union {
DWORD func;
TMFP method;
} addr;
addr.method = method;
m_mov = 0xB9;
m_this = (DWORD)pThis;
m_jmp = 0xE9;
m_relproc = addr.func - (DWORD)(this+1);
FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
}
FARPROC GetThunk() const {
_ASSERTE(m_mov == 0xB9);
return (FARPROC)this; }
};
template <class T>
class CAuxStdThunk
{
BYTE m_mov; // mov eax, %pThis
DWORD m_this; //
DWORD m_xchg_push; // xchg eax, [esp] : push eax
BYTE m_jmp; // jmp func
DWORD m_relproc; // relative jmp
public:
typedef void (__stdcall T::*TMFP)();
void InitThunk(TMFP method, const T* pThis)
{
union {
DWORD func;
TMFP method;
} addr;
addr.method = method;
m_mov = 0xB8;
m_this = (DWORD)pThis;
m_xchg_push = 0x50240487;
m_jmp = 0xE9;
m_relproc = addr.func - (DWORD)(this+1);
FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
}
FARPROC GetThunk() const {
_ASSERTE(m_mov == 0xB8);
return (FARPROC)this; }
};
#pragma pack(pop) // CAuxThunk
#endif //_AtlAux2_78310e22_e3e6_4f10_9af5_a4e485060097
*****************************************
EDIT: if you can't read the code above, just highlight all the text
*****************************************
for your case you would use it like....
Edited by - KlePt0 on November 22, 2001 8:14:49 PM
but look at this
(sorry for the length but i find this INCREDIBLY USEFUL and i think others may too)
////////////////////////////////////////////////////////////////////////////////// ATL/AUX -- COM/ATL Useful Helpers// Copyright (c) by Andrew Nosenko (andien@geocities.com), 1997-99// http://www.geocities.com/~andien/atlaux.htm// Version: 1.10.0011/* óðåçàííàÿ ââåðñèÿ*/#ifndef _AtlAux2_78310e22_e3e6_4f10_9af5_a4e485060097#define _AtlAux2_78310e22_e3e6_4f10_9af5_a4e485060097#if _MSC_VER > 1000 #pragma once#endif // _MSC_VER > 1000/////////////////////////////////////////////////////////////////////////////////* Win32 Callback thunking, the main idea was taken from ATL.Thunks could be used to turn an object+method pair into a closure that could bepassed to Win32 API requiring a callback address. This is a clever idea of ATLteam, I've only tried to propagate it over a general case.Thunks are very suitable and efficient way to avoid tiresome TLS/CritSecs/maps(when providing apartment threading and reentrancy).CAuxThunk<> is provided for __thiscall methods, CAuxStdThunk<> is for __stdcall.Here is an example of how to set up Win32 hook the reentrant way, without ause of global variable:class CHook: public CAuxThunk<CHook>{public: CHook(): m_hhook(NULL) { InitThunk((TMFP)CBTHook, this); } LRESULT CBTHook(int nCode, WPARAM wParam, LPARAM lParam); BOOL Hook() { m_hook = SetWindowsHookEx(WH_CBT, (HOOKPROC)GetThunk(), NULL, GetCurrentThreadId()); return (BOOL)m_hook; } HHOOK m_hhook;...};LRESULT CHook::CBTHook(int nCode, WPARAM wParam, LPARAM lParam){ if ( nCode == HCBT_CREATEWND ) { UnhookWindowsHookEx(m_hook); HWND hwnd = (HWND)wParam; // do whatever we want with HWND ... } return CallNextHookEx(m_hook, nCode, wParam, lParam);}Another example. I need to process an event in my IE4 simple object(windowless) *asynchronously* and use SetTimer API for that.Unfortunately, TIMERPROC doesn't take any context info.Here is how it has been solved:struct TIMEOUT: CAuxThunk<TIMEOUT> { UINT m_timerID; CONTEXT m_contex; TIMEOUT(CONTEXT& contex): m_contex(contex) { InitThunk((TMFP)TimerProc, this); } void TimerProc(HWND, UINT, UINT idEvent, DWORD dwTime); ...};void TIMEOUT::TimerProc(HWND, UINT, UINT idEvent, DWORD dwTime){ KillTimer(NULL, m_timerID); // one-shot callback // do any processing task ... delete this;}HRESULT CSimpleObj::Post(CONTEXT& contex) { TIMEOUT* pTimeout = new TIMEOUT(context); pTimeout->m_timerID = ::SetTimer(NULL, 0, timeout, (TIMERPROC)pTimeout->GetThunk());}//////////////////////////////////////////////////////////////////////////////*/
#ifndef _M_IX86
#pragma message("CAuxThunk/CAuxStdThunk is implemented for X86 only!")
#endif
#pragma pack(push, 1)
template <class T>
class CAuxThunk
{
BYTE m_mov; // mov ecx, %pThis
DWORD m_this; //
BYTE m_jmp; // jmp func
DWORD m_relproc; // relative jmp
public:
typedef void (T::*TMFP)();
void InitThunk(TMFP method, const T* pThis)
{
union {
DWORD func;
TMFP method;
} addr;
addr.method = method;
m_mov = 0xB9;
m_this = (DWORD)pThis;
m_jmp = 0xE9;
m_relproc = addr.func - (DWORD)(this+1);
FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
}
FARPROC GetThunk() const {
_ASSERTE(m_mov == 0xB9);
return (FARPROC)this; }
};
template <class T>
class CAuxStdThunk
{
BYTE m_mov; // mov eax, %pThis
DWORD m_this; //
DWORD m_xchg_push; // xchg eax, [esp] : push eax
BYTE m_jmp; // jmp func
DWORD m_relproc; // relative jmp
public:
typedef void (__stdcall T::*TMFP)();
void InitThunk(TMFP method, const T* pThis)
{
union {
DWORD func;
TMFP method;
} addr;
addr.method = method;
m_mov = 0xB8;
m_this = (DWORD)pThis;
m_xchg_push = 0x50240487;
m_jmp = 0xE9;
m_relproc = addr.func - (DWORD)(this+1);
FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this));
}
FARPROC GetThunk() const {
_ASSERTE(m_mov == 0xB8);
return (FARPROC)this; }
};
#pragma pack(pop) // CAuxThunk
#endif //_AtlAux2_78310e22_e3e6_4f10_9af5_a4e485060097
*****************************************
EDIT: if you can't read the code above, just highlight all the text
*****************************************
for your case you would use it like....
class CMyWindow : public CAuxThunk<CMyWindow>{public: CMyWindow() { InitThunk((TMFB)MyWindowProc); } // Notice its not static or different in anyway from // normal member function LRESULT MyWindowProc(HWND,UINT,WPARAM,LPARAM); BOOL Create() { ...... WNDCLASS Class; .... Class.lpfnWndProc=(WNDPROC)GetThunk(); ...... }}
Edited by - KlePt0 on November 22, 2001 8:14:49 PM
Ohh, scary...
It looks like it''s compiler dependent...does it work for other compilers than VC++?
It looks like it''s compiler dependent...does it work for other compilers than VC++?
quote:Original post by amag
Ohh, scary...
It looks like it''s compiler dependent...
GUIDs scare you?
[OT:] The February 2001 Platform SDK CAB files containing GDI+ had the files named using GUIDs, and there was a comment about that on CodeProject.com: "Microsoft developers are so obsessed with GUIDs, I wonder how they name their children?"
Picture it..."Hey Johnnie_A_18djtlsucm_85jso8nb, pass me the monkey wrench, will ya?"
Interesting... KlePt0
But, shouldn''t this line
InitThunk((TMFB)MyWindowProc);
be this
InitThunk((CAuxThunk::TMFP)MyWindowProc,this);
But, even then it still doesn''t work.
I think there is an easier way, but I''ll have to try it first.
But, shouldn''t this line
InitThunk((TMFB)MyWindowProc);
be this
InitThunk((CAuxThunk::TMFP)MyWindowProc,this);
But, even then it still doesn''t work.
I think there is an easier way, but I''ll have to try it first.
/*template <class T> class Thunk{ BYTE asm86[12];public: typedef void (__stdcall T::*ThunkType)(); void InitThunk(ThunkType method, const T *pthis) { union uPtr { BYTE *byte; DWORD *dword; ThunkType method; }; uPtr pAsm86; pAsm86.byte = asm86; uPtr pFn; pFn.method = method; *pAsm86.byte++ = 0x58; //pop eax *pAsm86.byte++ = 0x68; //push pthis *pAsm86.dword++ = (DWORD)pthis; *pAsm86.byte++ = 0x50; //push eax *pAsm86.byte++ = 0xE9; //jmp method *pAsm86.dword++ = (DWORD)pFn.dword - (DWORD)(this+1); //This function is valid only on multiprocessor computers. //FlushInstructionCache(GetCurrentProcess(), this, sizeof(*this)); } FARPROC GetThunk() const { return (FARPROC)this; }};class Window : private Thunk<Window>{ LRESULT CALLBACK WindowProc(HWND,UINT,WPARAM,LPARAM);public: Window() { InitThunk((Thunk<Window>::ThunkType)WindowProc,this); WNDCLASSEX wc; wc.lpfnWndProc=(WNDPROC)GetThunk(); } };//*/
Edited by - burp on November 23, 2001 2:48:55 PM
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement