//wndw.h
// wrapping a window
#pragma once
namespace GE_{ namespace win{
struct windowmessage
{
HWND hWnd;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
LRESULT lResult;
windowmessage(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam)
{hWnd = _hWnd; uMsg = _uMsg; wParam = _wParam; lParam = _lParam; lResult = 0;}
NMHDR& nmhdr() { return *(NMHDR*)lParam; }
WORD lParamLo() { return LOWORD(lParam); }
WORD lParamHi() { return HIWORD(lParam); }
WORD wParamLo() { return LOWORD(wParam); }
WORD wParamHi() { return HIWORD(wParam); }
};
class message_handler:
public stdx1::event_handler<windowmessage*>
{
public:
typedef stdx1::event_source::state* nexter;
// yuu can shortcut a call as _nexter->do_next();
virtual bool on_message(windowmessage* _pmsg, UINT _mapID, nexter& _nexter)
{ return false; }
virtual bool on_event(windowmessage* const & pmsg, stdx1::event_source::state* pState)
{ return on_message(pmsg, 0, pState); }
};
//######## CLASS _window. #######
// normalym you'll deriv ite and pass your class to stdx1::Handle
// i.e.: class yourwindow: public _window
// {
// virtual bool on_event(windowmessage* const & pmsg, stdx1::event_source::state* pState);
// };
// typedef stdx1::Handle<yourwindow> YourWindow;
class _window:
public stdx1::HandableRefcounter<stdx1::RefcountableValue<HWND> >,
public message_handler
{
protected:
struct data:
public stdx1::event_handler<windowmessage*>
{
stdx1::event_source event;
WNDPROC prev_wndproc;
virtual bool on_event(windowmessage* const & pmsg, stdx1::event_source::state* pState)
{
pmsg->lResult = CallWindowProc(prev_wndproc, pmsg->hWnd, pmsg->uMsg, pmsg->wParam, pmsg->lParam);
return true;
}
};
typedef std::map<HWND, data> datamap_type;
static datamap_type& datamap()
{ static stdx1::Global<datamap_type>::ref g_r = stdx1::Global<datamap_type>::get(); return g_r(); }
#pragma warning(push)
#pragma warning(disable: 4244)
//NOTE review the type casts for W64 ...
static void reclass(HWND hWnd)
{
data& d = datamap()[hWnd];
SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)d.prev_wndproc);
datamap().erase(hWnd);
}
#pragma warning(pop)
//the window procedure used to sublclass every window
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
windowmessage msg(hWnd,uMsg,wParam,lParam); //remaps function parameters
stdx1::event_source& evt = datamap()[hWnd].event;
evt.fire(&msg); //fire to the specific HWND handles
if(msg.uMsg == WM_NCDESTROY)
{
reclass(hWnd);
if (hWnd == hMainWnd())
PostQuitMessage(0);
}
return msg.lResult;
}
#pragma warning(push)
#pragma warning(disable: 4312 4244)
//NOTE review the type casts for W64 ...
static void subclass(HWND hWnd)
{
data& d = datamap()[hWnd];
d.prev_wndproc = (WNDPROC) SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)_window::WindowProc);
d.Hook(d.event); //autohook
}
#pragma warning(pop)
virtual void on_firstref()
{
//we are the firse referring hook: subclass the widow and place the default evenbt handler
subclass(*this);
}
virtual void on_addref()
{
data& d = datamap()[*this];
Hook(d.event);
}
virtual void on_release()
{
if(!!*this)
{
data& d = datamap()[*this];
Unhook(d.event);
}
}
//creation hook mamagement
struct createdata
{
HHOOK hhook;
_window* creating;
CRITICAL_SECTION cs;
createdata() { hhook = NULL; creating = NULL; InitializeCriticalSection(&cs); }
};
static createdata& _createdta() { static createdata d; return d; }
static LRESULT CALLBACK WinhookCallWndProc(
int nCode, // hook code
WPARAM wParam, // current-process flag
LPARAM lParam // message data
)
{
if(nCode == HC_ACTION)
{
CWPSTRUCT& ps = *(CWPSTRUCT*)lParam;
if(ps.message == WM_NCCREATE) //if a window is in creation
{
_window* crt = _createdta().creating;
HHOOK hhook = _createdta().hhook;
STRACE(trc, 3, ("Processing creation hook %p\n", hhook))
if(crt && !*crt)
{
if(!hMainWnd()) hMainWnd() = ps.hwnd;
crt->_set(ps.hwnd); //subclass it !
}
LRESULT ret = 0;
SRETRACE(trc, ("Unhooking creation hook %p\n", hhook));
LeaveCriticalSection(&_createdta().cs);
if(hhook)
{
LRESULT ret = CallNextHookEx(hhook, nCode, wParam, lParam);
UnhookWindowsHookEx(hhook);
}
return ret;
}
}
return CallNextHookEx(_createdta().hhook, nCode, wParam, lParam); //default action (window procedure ... an consequent dispatching)
}
protected:
//OVERLOAD THIS FUNCTION TO DO MESSAGE CRACKING
virtual bool on_message(windowmessage* _pmsg, UINT _mapID, nexter& _nexter)
{ return false; }
virtual bool on_event(windowmessage* const & pmsg, stdx1::event_source::state* pState)
{
bool b = on_message(pmsg, 0, pState);
if(pmsg->uMsg == WM_NCDESTROY && pmsg->hWnd == *this)
_clear(); //detach the wrapper
return b;
}
public:
bool SetCreateHook()
{
EnterCriticalSection(&_createdta().cs);
//only one tread here, until creation is completed
_createdta().creating = this;
_createdta().hhook = SetWindowsHookEx(WH_CALLWNDPROC, WinhookCallWndProc, NULL, GetCurrentThreadId());
STRACE(trc,3,("Setted Creation hook %p\n", _createdta().hhook));
return true;
}
};
//############# _window specifics: ##############
//windowholder: destroy the window if it has the last release
class _window_holder: public _window
{
protected:
virtual void on_lastrelease()
{ PostMessage(*this, WM_CLOSE,0,0); }
};
//WND dynamic: for on-heap leaving hooks
//note: uses delete_onidle: don't use it with application
//that doesn't use win::Messageloop.
//(or ... fire yourself the Messageloop::idle_event)
class _window_onheap:
public _window,
public delete_onidle
{
private:
bool bDelete;
protected:
_window_onheap() { bDelete = false; }
virtual bool on_event(windowmessage* const & pmsg, stdx1::event_source::state* pState)
{
if(pmsg->hWnd == *this && pmsg->uMsg == WM_NCDESTROY)
{ post_delete(); }
return _window::on_event(pmsg, pState);
}
};
//basic dialog procedure
template<bool b_SetFocus>
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wP, LPARAM lP)
{
if(msg == WM_INITDIALOG) return b_SetFocus;
if(msg == WM_COMMAND && (wP == IDOK || wP == IDCANCEL))
{
EndDialog(hwnd,wP);
return true;
}
return FALSE;
}
}}