Sto se tice neznanja Windows-a, nas Linux-asa, evo kako sam napravio Window klasu za moj vraper oko Win32 api,
kako bi prvi parametar u window proc bio this pointer ;)
Code:
#include "Window.h"
class Window::Thunk{
friend class Window;
public:
Thunk(Window*);
void SetDestroyed(){ destroyed_ = true; }
void AddRef()
{
++ref_;
}
void ReleaseRef(bool dest = false)
{
--ref_;
if(ref_ <= 0)
if(dest)delete this;
else destroyed_=true;
}
~Thunk(){ delete[] code_; instances_--;}
private:
static void Destroy();
Thunk(const Thunk&);
Thunk& operator=(const Thunk&);
BYTE* code_;
bool destroyed_;
int ref_;
class Test{
public:
~Test(){ if (Thunk::instances_)MessageBox(NULL,"THUNK INSTANCES","",MB_OK);}
};
static Test test;
static int instances_;
};
Window::Thunk::Test Window::Thunk::test;
Window::Test Window::test;
int Window::instances_ = 0;
int Window::Thunk::instances_ = 0;
Window::Window(bool isDlg)
:hwnd_(0),orig_proc_(0),wnd_class_(0),thunk_(0),ref_(1)
{
thunk_ = new Thunk(this);
wnd_proc_ = (WNDPROC)thunk_->code_;
instances_++;
}
Window::~Window()
{
instances_--;
if(IsWindow())
{
if(orig_proc_)
SetWindowLongPtr(GWLP_WNDPROC,(LONG_PTR)orig_proc_);
else
SetWindowLongPtr(GWLP_WNDPROC,(LONG_PTR)DefWindowProc);
DestroyWindow();
}
if(wnd_class_)::UnregisterClass((LPCTSTR)wnd_class_,(HINSTANCE)GetWindowLongPtr(GWLP_HINSTANCE));
if(thunk_)thunk_->ReleaseRef(true);
}
void Window::Create(DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
)
{
if(hwnd_)
{
MessageBox(NULL,"Window already created","",MB_ICONEXCLAMATION | MB_OK);
return;
}
if(!lpClassName && !wnd_class_)
{
WNDCLASSEX wincl = RegisterClass(wnd_proc_);
if (wnd_class_ = ::RegisterClassEx (&wincl),!wnd_class_)
{
DWORD error = GetLastError();
char buf[4096];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buf, sizeof buf,NULL);
throw std::runtime_error(buf);
}
}
hwnd_ = ::CreateWindowEx(dwExStyle,
lpClassName?lpClassName:(LPCTSTR)wnd_class_,
lpWindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam);
if (!hwnd_)
{
DWORD error = GetLastError();
char buf[4096];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buf, sizeof buf,NULL);
throw std::runtime_error(buf);
}
WNDPROC proc = (WNDPROC)SetWindowLongPtr(GWLP_WNDPROC,(LONG_PTR)wnd_proc_);
if (proc != wnd_proc_)orig_proc_ = proc;
}
LRESULT CALLBACK Window::WindowProc(Window* pThis,HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
LRESULT rc;Thunk* pThunk=pThis->thunk_;
if(pThis->hwnd_ != hwnd)pThis->hwnd_ = hwnd;
try
{
AutoRef<Thunk> apThunk(pThunk);
apThunk->AddRef();
rc = pThis->ProcessMessages(hwnd,message,wParam,lParam);
}catch(...)
{
if(pThunk->destroyed_)delete pThunk;
throw;
}
return rc;
}
__declspec(naked) LRESULT CALLBACK Window::CodeProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
Window* pThis;Thunk* pThunk;
LRESULT rc;
__asm
{
mov eax, end;
sub eax, begin; // eax == size
mov ebx, tag;
sub ebx, begin; // ebx == tag offset
mov ecx, begin;
ret;
}
begin:
__asm
{
push ebp;
mov ebp,esp;
sub esp,__LOCAL_SIZE;
}
__asm mov dword ptr [pThis],0x0;
tag:
pThunk = pThis->thunk_;
__asm // rc = WindowProc(pThis,hwnd,message,wParam,lParam);
{
push dword ptr[lParam];
push dword ptr[wParam];
push dword ptr[message];
push dword ptr[hwnd];
push dword ptr[pThis];
mov edx, dword ptr[Window::WindowProc];
call edx;
mov dword ptr[rc], eax;
}
if(pThunk->destroyed_)
{
__asm
{
mov eax, dword ptr[rc];
mov ecx, dword ptr[pThunk];
mov esp,ebp;
pop ebp;
mov edx, dword ptr[Window::Thunk::Destroy];
jmp edx; // we don't wont Destroy to return since this function will be deleted
}
}
__asm
{
mov eax,dword ptr [rc];
mov esp,ebp;
pop ebp;
ret 0x10; // __stdcall stack cleanup
}
end:;
}
Window::Thunk::Thunk(Window* pThis):destroyed_(false),ref_(1)
{
instances_++;
size_t lsize,lmod,lbegin;
__asm
{
call Window::CodeProc;
mov dword ptr[lsize], eax;
mov dword ptr[lmod], ebx;
mov dword ptr[lbegin], ecx;
}
code_ = new BYTE[lsize];
void *pDst = code_;
__asm //memcpy(pDst,code,lsize);
{
mov esi, dword ptr[lbegin];
mov edi, dword ptr[pDst];
mov ecx, dword ptr[lsize];
cld;
rep movsb;
}
__asm // modify mov var,0 to mov var,address
{
mov eax, dword ptr[pThis];
mov ebx, dword ptr[pDst];
add ebx, dword ptr[lmod];
mov dword ptr[ebx-4], eax;
}
DWORD oldprotect;
if(!VirtualProtect(code_, lsize, PAGE_EXECUTE_READWRITE, &oldprotect))
{
DWORD error = GetLastError();
char buf[4096];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buf, sizeof buf,NULL);
delete code_;
throw std::runtime_error(buf);
}
FlushInstructionCache(GetCurrentProcess(), code_, lsize);
}
__declspec(naked) void Window::Thunk::Destroy()
{
Thunk* pThunk;
__asm
{
push ebp;
mov ebp,esp;
sub esp,__LOCAL_SIZE;
push eax; // save rc
mov dword ptr[pThunk],ecx
}
delete pThunk;
__asm
{
pop eax; // restore rc
mov esp,ebp;
pop ebp;
ret 0x10; //// __stdcall stack cleanup from code proc
}
}