WndProc() Inside a Window Class

Started by
5 comments, last by Goblin 22 years, 4 months ago
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
- The Goblin (madgob@aol.com)
Advertisement
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
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)

    ////////////////////////////////////////////////////////////////////////////////// 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
Bobby Ward - COM Guru in training
Ohh, scary...
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.
    /*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