Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Message Map, обработка виндовских сообщений 
:(
    Опции темы
Jcs
Дата 29.9.2003, 20:29 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Подскажите, пожалуйста, если кто знает, как связать конкретное сообщение (к примеру WM_CREATE) c нестатической функцией-членом класса. Можно, конечно, использовать и статические, выдирая при этом указатель на конкретный экземпляр класса из описателя окна, и вызывая из него нестатическую функцию, но как-то не охота забивать класс парами функций на каждое сообщение. Заранее спасибо.
  Вверх
mr.DUDA
Дата 29.9.2003, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



Если програмить на MFC или ATL/WTL, то всё просто - там юзается простой макрос типа BEGIN_MESSAGE_MAP/END_MESSAGE_MAP (или DECLARE_MESSAGE_MAP), внутри него связывается любое сообщение с конкретной нестатической функцией. Или ты про чистый WinAPI ?


--------------------
user posted image
PM MAIL WWW   Вверх
Jcs
Дата 30.9.2003, 03:40 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Спасибо за ответ, я про WIN API в чистом виде, в самих MFC к месссаджам привязаны нестатические функции, а я сколько ни пытался, даже указатель на ф-цию-член класса (нестатическую) выдрать не могу... Как они так сделали..
  Вверх
RAN
Дата 30.9.2003, 09:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Это вопрос ко мне. Я уже где-то отвечал. Я делаю так, как ты написал:
Цитата
выдирая указатель на конкретный экземпляр класса из описателя окна, и вызывая из него нестатическую функцию

Но только я не понял, почему две функиции. Функция одна, и она не статическая. Вот пример класса:

Код

#ifndef WND_H
#define WND_H

#include "windows.h"

class CWnd {
private:
HWND hwnd;
static const char lpszClassName[];
static LRESULT CALLBACK Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
void OnSize(int nWidth, int nHeight);
void OnMove(int nLeft, int nTop);
void OnPaint(HDC dc, LPRECT lpRect);
public:
CWnd(HWND hOwner, int Left, int Top, int Width, int Height);
~CWnd();
static void RegisterClass();
static void UnregisterClass();
inline HWND getHandle() { return hwnd; }
};

#endif //WND_H


Код

const char CWnd::lpszClassName[] = "InventoryCardNavigator";

CWnd::CWnd(HWND hOwner, int Left, int Top, int Width, int Height)
{
   CreateWindowEx(WS_EX_CLIENTEDGE, const_cast<char*>(lpszClassName), NULL, WS_CHILD | WS_VISIBLE,
 Left, Top, Width, Height, hOwner, NULL, hInst, (LPVOID)this);
}

CWnd::~CWnd()
{
DestroyWindow(hwnd);
}

LRESULT CALLBACK CWnd::Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch( uMsg )
{
case WM_CREATE:
 SetWindowLong(hwnd, 0, LONG( LPCREATESTRUCT(lParam)->lpCreateParams ) );
 ((CWnd*) ( LPCREATESTRUCT(lParam)->lpCreateParams ))->OnCreate(hwnd, LPCREATESTRUCT(lParam));
    break;
case WM_PAINT:
 {
  PAINTSTRUCT ps;
  HDC DC = BeginPaint(hwnd, &ps);
  SetBkMode(DC, TRANSPARENT);
  ((CWnd*)GetWindowLong(hwnd, 0))->OnPaint(DC, &ps.rcPaint);
  EndPaint(hwnd, &ps);
 }
 return 0;
case WM_SIZE:
 ((CWnd*)GetWindowLong(hwnd, 0))->OnSize(LOWORD(lParam), HIWORD(lParam));
 break;
case WM_MOVE:
 ((CWnd*)GetWindowLong(hwnd, 0))->OnMove(LOWORD(lParam), HIWORD(lParam));
 break;
}
return( DefWindowProc( hwnd, uMsg, wParam, lParam ) );
}

void CWnd::OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
CWnd::hwnd = hwnd;
}

void CWnd::OnSize(int nWidth, int nHeight)
{

}

void CWnd::OnMove(int nLeft, int nTop)
{

}

void CWnd::OnPaint(HDC dc, LPRECT lpRect)
{

}

void CWnd::RegisterClass()
{
WNDCLASS wcl;
wcl.style = 0;
wcl.lpfnWndProc = CWnd::Proc;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 4;
wcl.hInstance = hInst;
wcl.hIcon = NULL;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcl.lpszMenuName = NULL;
wcl.lpszClassName = lpszClassName;
::RegisterClass(&wcl);
}

void CWnd::UnregisterClass()
{
::UnregisterClass(lpszClassName, hInst);
}



Этот код получился "вырезанием" из реального проекта и исправлением кое-чего. Поэтому возможно что-то не так, но принцип такой.
Особенности использования: приходиться вызывать для каждого класса функции RegisterClass и UnregisterClass. Это возможно обойти. Но мне показалось, что так лучше. А так можно в конструкторе класса проверять зарегистрирован класс и если нет, то вызывать RegisterClass. А unregisterclass вообще не вызывать.

P.S. Кстати, это класс child-окна.
PM MAIL ICQ   Вверх
Jcs
Дата 30.9.2003, 10:27 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Это действительно работает, только я пытался избежать использования switch в функции обработки окна. Для этого использовал свой класс CMsgMap, в котором каждому конкретному сообщению сопоствляется своя функция обработки.. Может это, конечно, требуется не всем, но мне в проекте надо функцию обработки генерить на лету, в зависимости от состояния приложения. Но похоже все-таки придется использовать статические функции, передавая им указатель на экземпляр класса. Как выяснилось, нестатические тоже его получают, только при помощи компилятора, так что разницы особой не будет. Спасибо за отклик.
  Вверх
RAN
Дата 30.9.2003, 14:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Цитата
не в проекте надо функцию обработки генерить на лету, в зависимости от состояния приложения

Ну, так давай подумаем вместе. Может чего родится интересное. Напиши поподробнее задачу.
PM MAIL ICQ   Вверх
Unregistered
Дата 1.10.2003, 06:16 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Изначально задача была - каждому сообщению сопоставить функцию, адрес которой пишется в таблицу сообщений. Обработчик окна должен был искать сообщение в таблице и вызывать соответствующую функцию, причем хотелось, чтобы все функции принимали именно то, что им надо, т.е. OnCreate должна только принимать указатель на структуру LPCREATESTRUCT и больше ничего.
Но так, как придется использовать указатель на функцию, то для каждого такого типа функций нужно будет определять прототипы. Поэтому пока у меня все функции-обрабочики сообщений имеют один тип (принимают HWND,WPARAM и LPARAM), причем если они члены какого-либо класса, то все они статические, так как указатель для нестатических функций-членов получить нельзя. В этой реализации не все удобно, но вроде работает.
  Вверх
Fantasist
Дата 1.10.2003, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата
причем если они члены какого-либо класса, то все они статические, так как указатель для нестатических функций-членов получить нельзя


Почему нельзя, все можно. Естесственно, этот указатель не совсем указатель - это скорее смещение относительно экземпляра класса и не имеет смысла без экземпляра класса. Однако ведь тебе не нужно вызывать метод без экземпляра класса, не так ли?

Делаешь что-нибудь типа:

Код

class CMsgHandler
{
public:
virtual int HandleMsg(WPARAM wParam, LPARAM lParam) {return 0; };
virtual int HandleMsg2(WPARAM wParam, LPARAM lParam) {return 0; };
virtual int HandleMsg3(WPARAM wParam, LPARAM lParam) {return 0; };
};


typedef int (CMsgHandler::*handlerPointer)(int);

std::map<int,handlerPointer> message_map;

int main()
{
  message_map[WM_MSG1]=&CMsgHandler::HandleMsg;  
  message_map[WM_MSG2]=&CMsgHandler::HandleMsg2;  
  message_map[WM_MSG3]=&CMsgHandler::HandleMsg3;  
}

LRESULT CALLBACK CWnd::Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  СMsgHandler* msh=(СMsgHandler*)GetWindowLong(hwnd, 0);

  (msh->*message_map[uMsg])(wParam,lParam);
}



Это как идея. В реальности все схема будет слегка другая, но принцип тот же.

Это сообщение отредактировал(а) Fantasist - 1.10.2003, 19:26


--------------------
Волны гасят ветер...
PM MAIL   Вверх
mr.DUDA
Дата 1.10.2003, 22:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 25
Всего: 232



[/QUOTE]message_map[WM_MSG1]=&CMsgHandler::HandleMsg;[QUOTE]
Уверен, что можно получить указатель на нестатический компонент-функцию класса ? имхо, закавыка у Jcs именно со статическими членами класса - окна (не хочет он их использовать), а более никак не получить указатель на ф-цию / указатель на this внутри функции оконного класса. Последнее достижимо только с пом. GetWindowLong (как предложил RAN).


--------------------
user posted image
PM MAIL WWW   Вверх
Fantasist
Дата 2.10.2003, 01:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата
Уверен, что можно получить указатель на нестатический компонент-функцию класса ?


Именно. Указатель на член класса. Таковой указатель, как я уже упоминал, не имеет смысла без указателя на экземпляр класса. Он сам по себе не является указателем, а является, так сказать "смещением" к члену класса. А вот экземпляр класса мы и храним в WindowLong.
Как я понял, проблема была в том, чтобы не делать switch в процедуре обработки окна, а делать динамический мэппинг сообщений к процедурам обработки. Вот примерно таким способом его можно и сделать.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
RAN
Дата 2.10.2003, 10:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Jcs, давай по порядку:

Из твоего топика я понял, что ты хочешь объять необъятное. Тебе нужен универсальные механизм для создания карты сообщений. Причём функции могут быть как членами класса, так и обячными глобальными. Конечно, нет ничего невозможного, но это сложно. Моё предложение тогда такое: в CreateWindow последним параметром передавать либо указатель на экземпляр класса, либо NULL. А в обработчике сообщений анализировать это значение. Если оно NULL, то вызывать _cdecl, иначе _thiscall. Проблема заключается в том, как узнать адрес функции и в том, что если тебе нужно в одном и том же окне совмещать и thiscall и cdecl, то придётся при регистрации функции передавать уазатель на экземпляр класса или NULL. Фуф, ну и намудрил я. Например:
Код

typedef int (CMsgHandler::*handlerPointer)(int);

typedef struct {
   void* This;
   handlerPointer func;
} MessProc;

std::map<int,MessProc> message_map;


Как можно получить адрес функции - члена класса?
class A {
public:
void func();
};

A::func ?

Витруальную можно найти в vtable, но это тоже не хорошо. Потому что в каждом компиляторе этот механизм может реализовываться по своему. (то что в VC и Builder есть различия знаю точно. Сам проверял)

PM MAIL ICQ   Вверх
Jcs
Дата 2.10.2003, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 156
Регистрация: 1.10.2003

Репутация: нет
Всего: нет



Цена использования нестатических функций в карте сообщений выше, чем получаемые преимущества, поэтому обработчик конкретного мессаджа должен быть статическим. Карта сообщений сейчас являет собой динамически связанный список, хотя как мне кажется в том способе, который предложили fantasist и RAN поиск сообщений будет происходить бытсрее.
PM   Вверх
RAN
Дата 2.10.2003, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Цитата
Карта сообщений сейчас являет собой динамически связанный список, хотя как мне кажется в том способе, который предложили fantasist и RAN поиск сообщений будет происходить бытсрее.

Это почему? map - это тоже список. Если тебя интересует скорость, то надо выделить память

typedef LRESULT (*MSG_PROC) (HWND , WPARAM ,LPARAM );
MSG_PROC* Map = new MSG_PROC[WM_USER];

Обнулить эту область памяти. И потом добавлять в массив функции обработки сообщений. Это будет самый быстрый map.
LRESULT CALLBACK CWnd::Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
MSG_PROC msgproc = Map[uMsg];
return( msgproc ? *msgproc(hwnd, wParam, lParam) : DefWindowProc( hwnd, uMsg, wParam, lParam ) );
}

PM MAIL ICQ   Вверх
Fantasist
Дата 2.10.2003, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата
Это почему? map - это тоже список.


map - это не список. Чаще всего это дерево, оптимизированное для быстрого поиска по ключу. Конечно, самый быстрый способ взятие значения по ключу целого типа - это хранить эти значения в массиве. Единственный недостаток - надо выделить память сразу под весь возможный диапазон ключей.
Как алтернатива - hash_map почти то же самое, что массив, но ограниченный.

Цитата
Как можно получить адрес функции - члена класса?


Я все выше уже написал. Внимательно посмотрите приведенный мною код. Это стардант С++.



--------------------
Волны гасят ветер...
PM MAIL   Вверх
RAN
Дата 2.10.2003, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Цитата
Я все выше уже написал. Внимательно посмотрите приведенный мною код. Это стардант С++.

Хорошо. А можно динамически получать адрес виртуальной функции?

CMsgHandler obj;
obj.HandleMsg - адрес функции?

PM MAIL ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0709 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.