Jump to content
  • Advertisement

Archived

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

Goblin

WndProc() Inside a Window Class

This topic is 6079 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
Advertisement
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 be
passed to Win32 API requiring a callback address. This is a clever idea of ATL
team, 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 a
use 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

Share this post


Link to post
Share on other sites
Ohh, scary...
It looks like it''s compiler dependent...does it work for other compilers than VC++?

Share this post


Link to post
Share on other sites
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?"

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
    
/*
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

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!