Если надо подменить функцию сообщений окна, то можно так сделать:
class cBase3DApplication // класс приложения { public: void CreateDisplay(); // создаем окно static LRESULT CALLBACK StaticWndProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); // глобальная функция LRESULT DisplayWndProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); // моя функция обработки сообщений ... }; void cBase3DApplication :: CreateDisplay( ) { WNDCLASSEX wc; wc.style = CS_BYTEALIGNCLIENT | ...; wc.lpfnWndProc = StaticWndProc; RegisterClassEx( &wc); ... hAppWnd = CreateWindow( ..., this); // this как собственные данные } LRESULT CALLBACK cBase3DApplication :: StaticWndProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { if( Message == WM_CREATE) SetWindowLong( hWnd, GWL_USERDATA, ( LONG)( ( CREATESTRUCT FAR*) lParam)->lpCreateParams); // 1 раз вызов cBase3DApplication *appDest = ( cBase3DApplication*) GetWindowLong( hWnd, GWL_USERDATA); // получаем указатель if( appDest) return appDest->DisplayWndProc( hWnd, Message, wParam, lParam); // юзаем свою функцию сообщений else return DefWindowProc( hWnd, Message, wParam, lParam); // иначе по умолчанию }// LRESULT CALLBACK cBase3DApplication :: StaticWndProc()
_vasa_
Functor<> *pFunc = (Functor<> *) GetWindowLong( hWnd, GWL_USERDATA); ( *pFunc)( ); // вызов cBase3DApplication :: MyFunc(); ты не передал параметры. И код не скомпилится похоже. Потому как тип класса не известен, прототип метода тоже.
и какой же тогда вообще смысл в функторе.
Можно туда запихать указатель на экземпляр класса, самому вызывать метод - самое логичное решение. (В книжке Феня Юаня есть класс для этого).
Ni3
понятно, так и подумал сначала.
GLEB
Все данные класса можно передать через CREATESTRUCT, обработав сообщение WM_CREATE.
Если действительно нужно вызывать функции-члены, то рекомендую использовать уже упоминавшийся Loki::Functor, библиотеку sigslot или libsigc++ (последняя довольно тяжеловесная по сравнению с первыми двумя).
_vasa_
Этот трик делается немного по-другому:
void RenderWIndow::createWindow() { // .... WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcex.lpfnWndProc = wndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof( void*); // sizeof user data - this pointer !!! wcex.hInstance = GetModuleHandle( NULL); wcex.hIcon = NULL; wcex.hCursor = LoadCursor( NULL, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszMenuName = NULL; wcex.lpszClassName = "my_window"; wcex.hIconSm = NULL; if( RegisterClassEx( &wcex) == 0) { //error handling } window_handle = CreateWindowEx( WS_EX_APPWINDOW, "my_window", "my_window", WS_OVERLAPPEDWINDOW, 0, 0, width, height, 0, NULL, GetModuleHandle( null_ptr), this); // this - pointer to our class (e.g. RenderWindow or something) // .... } LRESULT CALLBACK RenderWindow::wndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { RenderWindow* my_window = null_ptr; if( message != WM_CREATE) { my_window = reinterpret_cast<RenderWindow*>( GetWindowLong( hwnd, 0)); // unsafe cast } switch( message) { case WM_CREATE: { LPCREATESTRUCT lpcs = ( LPCREATESTRUCT)lparam; my_window = ( RenderWindow*)( lpcs->lpCreateParams); // getting RenderWindow pointer SetWindowLong( hwnd, 0, reinterpret_cast<long>( my_window)); // unsafe cast break; } // .... } // .... }
gexogen
Я идею токо дал, а скомпилится или нет можеш сам проверить, если чуть доделать то скомпилится обязательно.
Если работает map<int, Loki::Functor<>>::iterator->second(), то почему не вставить вместо указателя на функтор тот же итератор, списка например или мапа. Тогда точно скомпилится и сработает.
Просто нет времени эксперименты ставить :)
Ghost2
reinterpret_cast уважаю, спешил, каюсь...
Ну и на закуску:
#include <windows.h> #include <stdio.h> typedef unsigned __int32 uint32; typedef unsigned __int16 uint16; typedef unsigned __int8 uint8; #include <PshPack1.h> // voodoo magic bag struct thunk { uint16 a; uint8 b; uint32 c; void* param; uint8 d; void* pfn; uint16 e; }; #include <PopPack.h> // Пришивает к функции доп. параметр. // It's magic! template< class func_ptr1, class func_ptr2 > func_ptr1 voodoo_magic(func_ptr2 func, void* param ) { thunk* p = new thunk; p->a = 0x34FF; p->b = 0x24; p->c = 0x042444C7; p->param = param; p->d = 0xB8; p->pfn = func; p->e = 0xE0FF; return ( func_ptr1)p; } ///////////////////////////////////////////////////////// // Это наша функция-коллбэк. Доп. параметр внаглую ставится в начало. VOID CALLBACK MyTimerProc( void* userdata, HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) { printf( "User data @ 0x%p\n", userdata ); } int main( ) { // А вот так используется магия вуду: TIMERPROC magic = voodoo_magic< TIMERPROC >( &MyTimerProc, ( void*)0x12345 ); SetTimer( 0, 0, 1000, magic ); MSG msg; while( TRUE == GetMessage( &msg,0,0,0) ) { TranslateMessage( &msg ); DispatchMessageA( &msg ); } // Недостаток: к сожалению, придется удалить руками. Тут уж магия бессильна. delete ( void*)magic; }
Пример рабочий. Таким же образом (вызовом шаблонной функции) можно пришивать доп. параметр к любым другим колбэкам.
на win7(х32) не работает*(((
Тема в архиве.