Как лучше обрабатывать сообщения окнам?

Тема в разделе "WASM.BEGINNERS", создана пользователем SuperNova, 3 июл 2008.

  1. SuperNova

    SuperNova New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    4
    Вот сижу тут и думаю, что
    Код (Text):
    1. switch (Msg)
    2. {
    3. case WM_1://WM_CREATE например
    4. case WM_2:
    5. ...
    6. case WM_USER:
    7. case WM_USER+1:
    8. ...
    9. };
    не очень эффективно.

    Намного красивее и эффективней сделать

    Код (Text):
    1. typedef unsigned long(*PEventHandle)(Control* Sender,WPARAM wParam,LPARAM lParam);
    2.  
    3. LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
    4. {
    5.  Control* c=GetControl(hwnd);
    6.  if(c!=NULL)
    7.  {
    8.   if(uMsg<c->MaxEvent)
    9.   {
    10.    if(c->EventHandles[uMsg]!=NULL)
    11.    {
    12.     return c->EventHandles[uMsg](c,wParam,lParam);
    13.    }
    14.   }
    15.  }
    16. }
    Можно впринципе не проверять что у нас нет обработчика, а при инициализации забивать все обработчики пустой функцией, и даже заранее учесть максимальный номер сообщения.

    Есть ли тут какие-нить проблемы кроме немного большего расхода памяти???
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Если номер сообщения большой, то расход действительно может быть значительным.
    Можно и бинарное дерево использовать, где ключ номер сообщения, а значение тот же указатель на функцию. Или так -):
    Код (Text):
    1. if (uMsg<sizeof(UINT)/2)
    2. {
    3.   if (uMsg<sizeof(UINT)/4)
    4.   {
    5.    
    6.   }
    7.   else
    8.   {
    9.   }
    10. }
    11. else
    12. {
    13. }
    Но вот когда это действительно актуально, вот в чём вопрос.
     
  3. DEEP

    DEEP Андрей

    Публикаций:
    0
    Регистрация:
    27 апр 2008
    Сообщения:
    491
    Адрес:
    г. Владимир
    А ещё эффективнее (по быстродействию. Про память временно забудем =Р) создать таблицу соответствий ID сообщений и адресов их обработчиков. По смещению 0 должен лежать адрес обработчика сообщения с минимальным ID. Выборка должна производиться примерно так:
    Код (Text):
    1. MOV EAX, uMsg;
    2. MOV EAX, DWORD PTR [tblOffset+EAX*4-min_ID*4];
    3. JMP EAX;
    однако это затратно с точки зрения памяти. Впрочем, саму таблицу тоже можно строить в режиме реалтайма.

    UPD:

    +1
     
  4. SuperNova

    SuperNova New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    4
    DEEP
    Спасибо))) ну примерно это я и предлагаю, только на Си)))

    Booster
    а актуальность - если делать свою библиотеку например. Сколько конечный программе захочет сделать пользовательских сообщений - предсказать нереально. Не будешь же руками писать все обработчики, чтобы потом их переопределяли для своих нужд.
     
  5. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    --- обогнали :)
     
  6. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    SuperNova
    Так то оно конечно так, но я не представляю как оно будет работать, при добавлении произвольных сообщений. Резервировать всю память что ли? По-моему для этой задачи бинарное дерево в самый раз. Как например сделано в mfc: есть массив, каждый элемент которого - ключ, значение (MsgID, callback). А в обработчике происходит бинарный поиск, то есть в начале тыкаем в середину массива, если у нас MsgID меньше, то тыкаем в середину верхней половины, ну и так далее. Есно массив должен быть отсортирован.

    С другой cтороны в mfc этот массив формируется на этапе компиляции, и потом не меняется. Для рантайма возможно лучше подойдет динамическое дерево, наподобии std::map.
     
  7. diamond

    diamond New Member

    Публикаций:
    0
    Регистрация:
    21 май 2004
    Сообщения:
    507
    Адрес:
    Russia
    Уважающие себя компиляторы Си (vc,gcc,icc) сами могут соптимизировать длинные switch. Для длинных почти заполненных диапазонов это обычно бывает что-то типа "sub eax,MinValue / cmp eax,MaxValue-MinValue / ja default / jmp [SwitchTable+eax*4]"; для длинных реже заполненных диапазонов вместо простого jmp по таблице может встретиться "movzx ecx,byte [SwitchVariants+eax] / jmp [SwitchTable+ecx*4]"; для совсем редко заполненных это обычно бывает что-то типа двоичного дерева; для объединения нескольких диапазонов возможны комбинации.
    Вот, к примеру: http://wasm.ru/article.php?article=1009002
     
  8. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.708
    Вот здесь рассматривалось