Определить адресс функции

Общие вопросы, не зависящие от языка реализации.

Модераторы: Duncon, Hawk, Romeo, Eugie

Ответить
l.rod
Сообщения: 5
Зарегистрирован: 14 сен 2009, 22:58

Вообщем хочу сделать небольшую обертку для winAPI, и появились проблема. В моем классе есть оконная функция (WndProc), а как определить ее адресс, чтоб указать его в структуре WNDCLASSEX?

и еще один вопрос - скажем есть класс A и создаем 2 новых класса на основе А

class B : public A.......

так вот, в классе А есть функция, которую определить нужно в классах В и С
где то так.

Код: Выделить всё

class A
{
		void f(void);
};

class В : public A
{
	void f(void)
	{
		int i = 1+1;
	}
};

class С : public A
{
	void f(void)
	{
		int i = 4+5;
	}
};

при этом будет ли определена функция в класса-потомках - не извесно
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

В моем классе есть оконная функция (WndProc), а как определить ее адресс, чтоб указать его в структуре WNDCLASSEX?
Функция GetClassInfo используется для получения информации об уже существующем (зарегистрированном) классе.
Если сам создаёшь оконный класс, то полю lpfnWndProc структуры WNDCLASS просто указываешь имя твоей функции - это и есть её адрес.
l.rod
Сообщения: 5
Зарегистрирован: 14 сен 2009, 22:58

видимо не так обьяснил, вот что мне нужно:

я создал свой класс Window, у которого есть метод

LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

и свойство WNDCLASS wc;

так вот, как что мне указать в полу этой структуры?

если написать

Код: Выделить всё

wc.lpfnWndProc = Window::WndProc
компилятор говорит, что ошибка и надо написать так

Код: Выделить всё

wc.lpfnWndProc = &Window::WndProc
но тогда пишет что несоответствие типов
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Сделай так:

Код: Выделить всё

static LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
А this прикрепи к окну с помощью SetWindowLong и параметра GWL_USERDATA.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
l.rod
Сообщения: 5
Зарегистрирован: 14 сен 2009, 22:58

Romeo писал(а):Сделай так:

Код: Выделить всё

static LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
А this прикрепи к окну с помощью SetWindowLong и параметра GWL_USERDATA.
а как поможет GWL_USERDATA и this? может тогда уж нужно GWL_WNDPROC ???
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Если ты хочешь, чтобы для данного окна вызвались функции данного объекта класса, то нужно каким-то образом связать this и окно. Так как, функция-обработчик оконных сообщений обязана быть статической (в силу строго задания её прототипа), то единственное, как можно привязать this к окну, это через GWL_USERDATA. Если не ошибаюсь, то именно так выполняет привязку MFC.

Подход состоит в следующем:

Код: Выделить всё

class CMyWindow
{
public:
   void CreateWindow( /* some parameters, i.g. window title */)
   {
      WNDCLASSEX wcl;
      wcl.lpfnWndProc = &GlobalWndProc;

      ...

      HWND hWnd = ::CreateWindowEx( /* do not set WS_VISIBLE style */ , wcl, ...);
      ::SetWindowLong(hWnd, GWL_USERDATA, (long)this);
      ::ShowWindow(hWnd, SW_SHOW);
   }

private:
   static LRESULT CALLBACK GlobalWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
   {
      long nThis = GetWindowLong(hWnd, GWL_USERDATA);
      CMyWindow* pThis = (CMyWindow*)nThis;
      if (pThis)
      {
         return pThis->WndProc(hWnd, message, wParam, lParam);
      }
      return ::WindowProc(hWnd, message, wParam, lParam);
   }

   LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
   {
      // your impelentation
   }
}
При таком подходе есть свои тонкости, например, WM_CREATE твоя процедура не получит. Это можно обойти, если послать в CreateWindow в качестве последнего параметра тоже this и предусмотреть этот вариант развития событий в GlobalWndProc.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
l.rod
Сообщения: 5
Зарегистрирован: 14 сен 2009, 22:58

вот теперь понял, только непонятно, кочему моя функция не получит сообщение WM_CREATE, ведь все, что получит глобальная, передастся WndProc?


да, а это почему?

/* do not set WS_VISIBLE style */

и как я понял, глобальная функция даже не должна быть членом класса?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Дело в том, что нету возможности проставить User Data для окна до его создания. Так, как WM_CREATE генерируется внутри функции CreateWindow сразу после физического создания окна , то это сообщение прилетит в GlobalWndProc ещё до того, как this был проставлен в User Data. Как следствие, твоя WndProc не будет вызвана. Решить эту проблему можно, передав в CreateWindow указатель на this в качестве последнего параметра и корректно обработав эту ситуацию внутри GlobalWndProc.

По поводу WS_VISIBLE. Если ты установишь этот стиль, то помимо сообщения WM_CREATE ты пропустишь ещё массу сообщений: WM_SIZE, WM_SHOWWINDOW, WM_PAINT и т.д., которые будут сгенерированы операционной системой в момент показа окна.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
l.rod
Сообщения: 5
Зарегистрирован: 14 сен 2009, 22:58

снято с обсуждения :)
Ответить