Войти
ПрограммированиеФорумОбщее

С++ указатель на метод (2 стр)

Страницы: 1 2
#15
10:07, 7 сен 2008

Если надо подменить функцию сообщений окна, то можно так сделать:

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()
#16
10:26, 7 сен 2008

_vasa_

 Functor<> *pFunc = (Functor<> *) GetWindowLong(hWnd, GWL_USERDATA);
  (*pFunc)(); // вызов cBase3DApplication :: MyFunc();
ты не передал параметры. И код не скомпилится похоже. Потому как тип класса не известен, прототип метода тоже.

и какой же тогда вообще смысл в функторе.
Можно туда запихать указатель на экземпляр класса, самому вызывать метод - самое логичное решение. (В книжке Феня Юаня есть класс для этого).

Ni3
понятно, так и подумал сначала.

#17
3:19, 8 сен 2008

GLEB

Все данные класса можно передать через CREATESTRUCT, обработав сообщение WM_CREATE.
Если действительно нужно вызывать функции-члены, то рекомендую использовать уже упоминавшийся Loki::Functor, библиотеку sigslot или libsigc++ (последняя довольно тяжеловесная по сравнению с первыми двумя).

#18
3:20, 8 сен 2008

_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;
    }
    // ....
  }
  // ....
}
#19
1:02, 9 сен 2008

gexogen
Я идею токо дал, а скомпилится или нет можеш сам проверить, если чуть доделать то скомпилится обязательно.
Если работает map<int, Loki::Functor<>>::iterator->second(), то почему не вставить вместо указателя на функтор тот же итератор, списка например или мапа. Тогда точно скомпилится и сработает.
Просто нет времени эксперименты ставить :)

Ghost2
reinterpret_cast уважаю, спешил, каюсь...

#20
3:58, 9 сен 2008

Ну и на закуску:

#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;
}

Пример рабочий. Таким же образом (вызовом шаблонной функции) можно пришивать доп. параметр к любым другим колбэкам.

Прошло более 1 года
#21
23:07, 18 мар 2010

на win7(х32) не работает*(((

Страницы: 1 2
ПрограммированиеФорумОбщее

Тема в архиве.