Ну ловите, коль интересно (я так его в архивах и не нашел. Написал по новой и снабдил некоторыми комментариями)
--- TEST_CALLER.CPP -------------------------------------------------------------------
// Method caller
// Преобразовывает __stdcall (aka CALLBACK, WINAPI, etc) в thiscall.
// Created on April 26-27, 2001 by AV.
// Use free, but please уважайте копирайты! :-)
// Да, чуть не забыл: у MSVC++ и Borland C++ Builder'a разные методы вызова
// thiscall-функций (то бишь методов): MSVC++ запихивает this в ECX, а
// Builder — последним параметром в стек. В связи с этим на Builder'е для реализации
// нижеприведенного придется повозиться побольше. А пока что хочу только заметить:
// *** INCOMPATIBLE WITH C++ BUILDER! FOR USE ONLY IN MICROSOFT VISUAL C++!!! ***
// В любом случае за последствия от использования кода ответственности никакой не несу.
// Сами проверяйте! :-)
#include <windows.h>
// Итак, эдесь начинается объект Caller.
//-----------------------------------------------------------
//
// Создание и привязка: wc.lpfnWndProc = CreateCaller (wnd, CWnd::WndProc);
// Удаление: DeleteCaller (Caller);
// Ввиду того, что C++ не разрешает casting из
// LRESULT (CClass::*_thiscall)(HWND, UINT, WPARAM, LPARAM) в void*, приходится
// извращаться. Данная функция просто возвращает первый параметр как void*, а
// многоточие (...) отключает проверку типов.
// Необходимо для отключения выравнивания переменных внутри структуры TCallerSuruct
#pragma pack (push, 1)
// Итак, собственно главная функция
char* __CreateCaller (void* Class, void* Method)
{
// Реально Caller представляет из себя две инструкции:
// mov ecx, address_of_class_instance
// jmp class_method
// Восстановить предыдущий параметр выравнивания
#pragma pack (pop)
//--------------------------------------------------------------
// Все. Дальше — простая иллюстрация работы
class CWindow {
private:
HWND hwnd; // no comments
static ATOM WClass; // класс этого окна. Один на все экземпляры, потому и static
static WNDPROC Caller; // экземпляр Caller'a. Так как один на класс, то тоже один.
static int UsageCount; // количество экземпляров данного окна. Как только оно достигает
// нуля, класс и Caller освобождаются.
if (hwnd) {
ShowWindow (hwnd, SW_SHOW);
UpdateWindow (hwnd);
// Увеличим счетчик
UsageCount++;
}
}
CWindow::~CWindow ()
{
// Уменьшим счетчик. Если он равен нулю (окон больне не осталось), освободим
// занятые ресурсы.
if (!--UsageCount) {
UnregisterClass ((LPSTR) WClass, (HINSTANCE) GetModuleHandle (NULL));
WClass = NULL;
DeleteCaller (Caller);
}
}
// Это наша НУ ПРОСТО СУПЕР навороченная оконная процедура :-)
LRESULT CWindow::WndProc (HWND hwndWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Вообще-то этого здесь не надо...
if (uMsg == WM_DESTROY)
PostQuitMessage (0);
return DefWindowProc (hwndWindow, uMsg, wParam, lParam);
}
// А теперь посмотрите на WinMain. Просто создаем экземпляр CWindow и радуемся жизни!
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
{
MSG msg;
CWindow wnd;