Вот сижу тут и думаю, что Код (Text): switch (Msg) { case WM_1://WM_CREATE например case WM_2: ... case WM_USER: case WM_USER+1: ... }; не очень эффективно. Намного красивее и эффективней сделать Код (Text): typedef unsigned long(*PEventHandle)(Control* Sender,WPARAM wParam,LPARAM lParam); LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { Control* c=GetControl(hwnd); if(c!=NULL) { if(uMsg<c->MaxEvent) { if(c->EventHandles[uMsg]!=NULL) { return c->EventHandles[uMsg](c,wParam,lParam); } } } } Можно впринципе не проверять что у нас нет обработчика, а при инициализации забивать все обработчики пустой функцией, и даже заранее учесть максимальный номер сообщения. Есть ли тут какие-нить проблемы кроме немного большего расхода памяти???
Если номер сообщения большой, то расход действительно может быть значительным. Можно и бинарное дерево использовать, где ключ номер сообщения, а значение тот же указатель на функцию. Или так -): Код (Text): if (uMsg<sizeof(UINT)/2) { if (uMsg<sizeof(UINT)/4) { } else { } } else { } Но вот когда это действительно актуально, вот в чём вопрос.
А ещё эффективнее (по быстродействию. Про память временно забудем =Р) создать таблицу соответствий ID сообщений и адресов их обработчиков. По смещению 0 должен лежать адрес обработчика сообщения с минимальным ID. Выборка должна производиться примерно так: Код (Text): MOV EAX, uMsg; MOV EAX, DWORD PTR [tblOffset+EAX*4-min_ID*4]; JMP EAX; однако это затратно с точки зрения памяти. Впрочем, саму таблицу тоже можно строить в режиме реалтайма. UPD: +1
DEEP Спасибо))) ну примерно это я и предлагаю, только на Си))) Booster а актуальность - если делать свою библиотеку например. Сколько конечный программе захочет сделать пользовательских сообщений - предсказать нереально. Не будешь же руками писать все обработчики, чтобы потом их переопределяли для своих нужд.
SuperNova Так то оно конечно так, но я не представляю как оно будет работать, при добавлении произвольных сообщений. Резервировать всю память что ли? По-моему для этой задачи бинарное дерево в самый раз. Как например сделано в mfc: есть массив, каждый элемент которого - ключ, значение (MsgID, callback). А в обработчике происходит бинарный поиск, то есть в начале тыкаем в середину массива, если у нас MsgID меньше, то тыкаем в середину верхней половины, ну и так далее. Есно массив должен быть отсортирован. С другой cтороны в mfc этот массив формируется на этапе компиляции, и потом не меняется. Для рантайма возможно лучше подойдет динамическое дерево, наподобии std::map.
Уважающие себя компиляторы Си (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