Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > помогите разобраться с макросом HANDLE_MSG


Автор: yngwie19 24.12.2008, 00:17
Всем привет. В книге Финогенова "WIN32 Основы программирования" дошел до раздела Макрос HANDLE_MSG после прочтения которого есть несколько вопросов:

1) Правильно Я понимаю, что использование данного макроса применяется лишь для того чтобы уменьшить структуру swtch-case в оконной процедуре? В принципе можно обходиться без него?
2) В книге дается пример макроса входящего в состав WINDOWSX.H:
Код

#define HANDLE_MSG(hwnd,message,fn)\
   case(messae): return HANDLE_##message((hwnd),(wParam),(lParam),(fn))

2а) Это Я так понимаю общий вид макроса, который используется для всех сообщений. Так?
Для сообщения WM_DESTROY он преобразуется в
Код

case(WM_DESTROY): return HANDLE_WM_DESTROY((hwnd),(wParam),(lParam),(OnDestroy)) /*OnDestroy - оконная функция определенная для передачи сообщения PostQuitMessage(0) */

2б) Почему кстати hwnd,lParam,wParam и функция в отельных скобках?
Далее пишут: Для макроса HANDLE_WM_DESTROY дано следующее макроопределение:
Код

#define HANDLE_WM_DESTROY(hwnd,wParam,lParam,fn) ((fn)(hwnd),0L)
 
Подставив это определение вместо WM_DESTROY и опустив ненужные скобки получим окончательное макрорасширение
case WM_DESTROY:return (OnDetroy(hwnd,0L));

Объясните поалуйста вместо чего мы подставяем расширенный макрос WM_DESTROY и что это вообще за странный параметр "0L"?

Автор: jonie 24.12.2008, 01:04
Цитата

1) Правильно Я понимаю, что использование данного макроса применяется лишь для того чтобы уменьшить структуру swtch-case в оконной процедуре? В принципе можно обходиться без него?
да.

Цитата

2а) Это Я так понимаю общий вид макроса, который используется для всех сообщений. Так?
угу. в общем-то используется для улучшения читабельности кода... и заставляет "стандартизировать" его...

Цитата

2б) Почему кстати hwnd,lParam,wParam и функция в отельных скобках?
потому что define - зло. прикинь что будет например в макросе:
Код

//нехороший пример
#define max(x,y) x>y?x:y
int x=3;y=2;
int m = max(x+=5, y); //что вернется)?


чет я последнее не очень понял, чет там из контекста как-то урвано..

Автор: yngwie19 24.12.2008, 08:32
jonie, Спасибо за ответы.
 

Цитата(jonie @  24.12.2008,  01:04 Найти цитируемый пост)
чет я последнее не очень понял, чет там из контекста как-то урвано.. 

В книге дается расширенный вид макроса, полученный н основе  общего вида макроса:
Код

 case(WM_DESTROY): return HANDLE_WM_DESTROY((hwnd),(wParam),(lParam),(OnDestroy)) 

А также дается макроопределение для WM_DESTROY
Код

#define HANDLE_WM_DESTROY(hwnd,wParam,lParam,fn) ((fn)(hwnd),0L)

И говорят:
Цитата(yngwie19 @  24.12.2008,  00:17 Найти цитируемый пост)
Подставив это определение вместо WM_DESTROY и опустив ненужные скобки получим окончательное макрорасширение
case WM_DESTROY:return (OnDetroy(hwnd,0L));


Это чтож получается, чтобы для каждого сообщения правильно написать Марос, нужно смотреть определения в windowsx.h и все время подставлять те определения сообщений, которые нужно?
Что это за параметр 0L? 
Да и еще вопрос, зачем тут нужен return? без него макрос описывается не правиьно?

Автор: jonie 24.12.2008, 13:58
Цитата

Да и еще вопрос, зачем тут нужен return? без него макрос описывается не правиьно?
иначе выполнится следующий case


насколько я понимаю из обрывочных сведений идея авторов следующая:
"абстракция 0-ого уровня" : используем switch(umsg) { case WM_CRATE: .... break; .... }
"1-ый уровень" : 
Код

#define HANDLE_MSG(hwnd,message,fn)\
   case(messae): return HANDLE_##message((hwnd),(wParam),(lParam),(fn))
получаем :
Код

BEGIN_MSG_MAP
  HANDLE_MSG(hwnd, WM_CREATE, OnWMCreate);
  HANDLE_MSG(hwnd, WM_OTHER, OnWMOther);
END_MSG_MAP

"2-ой уровень":
Код

BEGIN_MSG_MAP
 HANDLE_WM_DESTROY(блаблабла)
END_MSG_MAP

DWORD OnDetroy(HWND hwnd, DWORD stuff)
{
 ....
}


чета типа того..

Автор: yngwie19 24.12.2008, 14:48
jonie, 
Цитата(jonie @  24.12.2008,  13:58 Найти цитируемый пост)
иначе выполнится следующий case

а почему тогда если макросы не использовать то мы вместо return пишем break

Код

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch(msg)
{
  case WM_DESTROY:
       PostQuitMessage(0);
       break;                           //Когда используется break, то в вызывающую функцию ничего не возвращается
  default:
       return DefWindowProc(hwnd,msg,wParam,lParam);
}
 
а при использовании макроса мы получаем
Код

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   case WM_DESTROY:
      return OnDestroy(hwnd);  // Здесь оконная процедура возвращает результат работы функции OnDestroy, а он равен void
   default: 
      return DefWindowProc(hwnd,msg,wParam,lParam);
}

и еще вопрос:

Цитата(yngwie19 @  24.12.2008,  08:32 Найти цитируемый пост)
Цитата(yngwie19 @  24.12.2008,  00:17 )
Подставив это определение вместо WM_DESTROY и опустив ненужные скобки получим окончательное макрорасширение
case WM_DESTROY:return (OnDetroy(hwnd,0L));

что это за параметр 0L для чего он тут используется,нам он вообще нужен?

Автор: mes 24.12.2008, 15:12
Цитата(yngwie19 @  24.12.2008,  14:48 Найти цитируемый пост)

а почему тогда если макросы не использовать то мы вместо return пишем break

не так.. если используем ретурн то брейк ставить не надо.
а ретурн ставим для возвращения результа функции ассоцированной с сообщением

а макросы используются для скрытия процесса ассоциации  сообщения с конкретной  функцией класса.

Добавлено через 35 секунд
Цитата(yngwie19 @  24.12.2008,  14:48 Найти цитируемый пост)

что это за параметр 0L

L означает что тип long.

Автор: GremlinProg 24.12.2008, 15:29
yngwie19, я так понимаю, ты спрашиваешь параметр функции, определенной в WTL или MFC, а здесь API
переместить тему?
или я не прав?

вобщем, тема мигрировала в Visual C++/MFC/WTL

Автор: yngwie19 25.12.2008, 00:11
GremlinProg, Это макрос чистого WINAPI, зачем перенесли?

Цитата(mes @  24.12.2008,  15:12 Найти цитируемый пост)
L означает что тип long. 

для какой переменной?

Автор: mes 25.12.2008, 13:56
Цитата(yngwie19 @  25.12.2008,  00:11 Найти цитируемый пост)
для какой переменной? 

для числовых констант
Код

5 - значение типа int
5.0 - значение типа double
5L - значение типа long


Добавлено через 1 минуту и 15 секунд
Цитата(yngwie19 @  25.12.2008,  00:11 Найти цитируемый пост)
Это макрос чистого WINAPI,

A в какой библиотеке определен данный макрос?  smile 

Автор: yngwie19 25.12.2008, 20:02
Цитата(mes @  25.12.2008,  13:56 Найти цитируемый пост)
A в какой библиотеке определен данный макрос? 

windowsx.h

Автор: Earnest 25.12.2008, 21:07
Возврашаю тему в WinAPI - это таки оно.

Автор: GremlinProg 25.12.2008, 21:34
HANDLE_MSG, теперь оно )

yngwie19, нули здесь нужны для того, чтобы обработчики сообщений, пересылающие менее трех параметров, можно было задать в одной форме:
Код

LRESULT (*HANDLER)(HWND,WPARAM,LPARAM);

т.е. как раз для того, чтобы не смотреть определения в windowsx.h и не искать, какой тип функции передать макросу в параметре fn, т.е. для HANDLE_MSG, все обработчики имеют 3 параметра

Автор: yngwie19 26.12.2008, 00:15
Ребят а вообще в практике, часто используют макросы?

Автор: yngwie19 26.12.2008, 00:38
И еще вопросик при использовании макроса для функции WM_PAINT.
Скажите пожалуйста когда мы описываем функцию OnDestroy для макроса HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy), то мы знаем, что она будет вызована в случае если мы например закроем окно. А что касается использования функции WM_PAINT, то Я так понял, что ее винда вызывает сама. Дело в том что в книге дано описание макроса HANDLE_MSG(hwnd,WM_PAINT,OnPaint), но нигде явно не указывается, что мы ее каким-либо образом вызываем. Т.е получается мы ее просто описали, а вызываем не мы. Поясите пожалуйста когда и кто посылает данное собщение в обработчик сообщений, а главное в какой момент.

Автор: mes 26.12.2008, 03:14
Цитата(yngwie19 @  26.12.2008,  00:38 Найти цитируемый пост)
Поясите пожалуйста когда и кто посылает данное собщение в обработчик сообщений, а главное в какой момент.

WM_PAINT посылается виндой окну, когда она считает, что оно(или его часть) должно перерисоваться.  
Т.е когда (становиться) видна часть окна помеченная как невалидная. (т.е та часть окна которая по каким то причинам предполагается, что была затерта и сейчас нужно показать ее юзеру)
Программа сама может инициировать перерисовку (точнее сказать посылку окну сообщения WM_PAINT) путем "инвалидования" определенной области.

подробнее тут:
http://msdn.microsoft.com/en-us/library/ms534870.aspx





Автор: yngwie19 26.12.2008, 17:36
mes, Спасибо

Автор: yngwie19 26.12.2008, 23:29
mes, Скажи пожалуйста, мне при использовании макросов не нужно все время смотреть как он разворачивается с помощью определений в windowsx.h, могу ли Я для каждого сообщения просто запомнить какие параметры функция должна принимать и какое возвращать. Ведь при использовании макроса в оконной процедуре мы все время пишем
Код

switch(msg)
{
  HANDLE_MSG(hwnd,"сообщение","функция обработки сообщения");
}

Эта часть всегда стандартная?

Автор: mes 26.12.2008, 23:53
Цитата(yngwie19 @  26.12.2008,  23:29 Найти цитируемый пост)
, мне при использовании макросов не нужно все время смотреть как он разворачивается с помощью определений в windowsx.h,

так макросы для этого и ввели, чтоб скрыть черную работу по транспортировке сообщения в нужную функцию..
Вид конечной функции можно подглядывать в библиотеке .. он показан в комментах перед определением макроса конкретного сообщения.

Цитата

/* void Cls_OnCopy(HWND hwnd) */ - так должна выглядить конечная функция для сообщения WM_COPY
#define HANDLE_WM_COPY...



Добавлено через 1 минуту и 10 секунд
Цитата(yngwie19 @  26.12.2008,  23:29 Найти цитируемый пост)

Эта часть всегда стандартная? 

да, для всех сообщений определенных в библиотеке.

Автор: yngwie19 27.12.2008, 08:55
mes, Спасибо еще раз

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)