Подмена обработчика сообщений при помощи SetWindowLong
От: Dr.Korbin  
Дата: 26.03.10 22:45
Оценка:
Здравствуйте!

Хочется при помощи SetWindowLong поменять обработчик сообщений на свой. Всё проходит успешно, однако при завершении программы процесс не завершается корректно, остаётся в списке процессов в диспетчере задач.

В интернете нашёл, что при закрытии стоит менять адрес обработчика на старый. Однако это не помогает

В этом примере при выборе какого-либо пункта меню вместо обработки этого пункта показывается MessageBox с uMsg, wParam и lParam.

...
    pOldProc = (WNDPROC)(SetWindowLong(hWnd, GWL_WNDPROC, (LONG)(WindowProc)));
...

int WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_COMMAND)
    {
        char buf[1000];
        sprintf_s(buf, 999, "%d %d %d", uMsg, wParam, lParam);
        MessageBox(hwnd, buf, 0, 0);
        //SetWindowLong(hwnd, GWL_WNDPROC, (LONG)pOldProc);
        return TRUE;
    }
    if ((uMsg == WM_CLOSE) || (uMsg == WM_DESTROY))
    {
        SetWindowLong(hwnd, GWL_WNDPROC, (LONG)pOldProc);
    }
    return CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam);
}


Примечательно, что если раскомментировать второй SetWindowLong, то MessageBox, конечно же, появится всего лишь один раз, но зато программа завершится корректно.

Стоит Windows 7, если это существенно.

Заранее спасибо.
Re: Подмена обработчика сообщений при помощи SetWindowLong
От: Melamed Россия  
Дата: 27.03.10 09:39
Оценка:
Здравствуйте, Dr.Korbin, Вы писали:

DK>Здравствуйте!


DK>Хочется при помощи SetWindowLong поменять обработчик сообщений на свой. Всё проходит успешно, однако при завершении программы процесс не завершается корректно, остаётся в списке процессов в диспетчере задач.


DK>В интернете нашёл, что при закрытии стоит менять адрес обработчика на старый. Однако это не помогает


DK>В этом примере при выборе какого-либо пункта меню вместо обработки этого пункта показывается MessageBox с uMsg, wParam и lParam.


DK>
DK>...
DK>    pOldProc = (WNDPROC)(SetWindowLong(hWnd, GWL_WNDPROC, (LONG)(WindowProc)));
DK>...

DK>int WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
DK>{
DK>    if (uMsg == WM_COMMAND)
DK>    {
DK>        char buf[1000];
DK>        sprintf_s(buf, 999, "%d %d %d", uMsg, wParam, lParam);
DK>        MessageBox(hwnd, buf, 0, 0);
DK>        //SetWindowLong(hwnd, GWL_WNDPROC, (LONG)pOldProc);
DK>        return TRUE;
DK>    }
DK>    if ((uMsg == WM_CLOSE) || (uMsg == WM_DESTROY))
DK>    {
DK>        SetWindowLong(hwnd, GWL_WNDPROC, (LONG)pOldProc);
DK>    }
DK>    return CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam);
DK>}
DK>


DK>Примечательно, что если раскомментировать второй SetWindowLong, то MessageBox, конечно же, появится всего лишь один раз, но зато программа завершится корректно.


DK>Стоит Windows 7, если это существенно.


DK>Заранее спасибо.


В этом случае попробуй вместо закоментированной строчки поставить строчку

      CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam);


И посмотри что получиться. И в зависимости от результата плеши дальше.
Re: Подмена обработчика сообщений при помощи SetWindowLong
От: kvasya  
Дата: 30.03.10 05:38
Оценка:
Здравствуйте, Dr.Korbin, Вы писали:

Если "глушить" обработку не требуется — лучше всегда давать поработать оригинальной функции (тем более "чужих" классов окон):

...
return CallWindowProc(pOldProc, hwnd, uMsg, wParam, lParam);


но я что-то не вижу как приведенный код может повлиять на "процесс не завершается корректно, остаётся в списке процессов в диспетчере задач."; потоков нет, которые как-либо связанны с этим "пунктом меню"? может на событии остается ждать, стек смотрел?

зы.
буфер лучше нулить:

        char buf[1000];
        ZeroMemory( buf, 1000 );
        sprintf_s(buf, 999, "%d %d %d", uMsg, wParam, lParam);
        MessageBox(hwnd, buf, 0, 0);
Re: Подмена обработчика сообщений при помощи SetWindowLong
От: Guard_h4s Россия  
Дата: 30.03.10 06:39
Оценка:
Здравствуйте, Dr.Korbin, Вы писали:

DK>Примечательно, что если раскомментировать второй SetWindowLong, то MessageBox, конечно же, появится всего лишь один раз, но зато программа завершится корректно.


DK>Стоит Windows 7, если это существенно.


Интересно, а зачем понадобилось подменять оконную процедуру для окна верхнего уровня(WM_CLOSE вы для кого ловите?) Обычно это окно и так ваше =))
Очевидно что WM_CLOSE не доходит до дефотного обработчика, соответственно не заканчивается цикл обработки сообщений. Проверяйте что вы вызываете.
Re: Подмена обработчика сообщений при помощи SetWindowLong
От: CEMb  
Дата: 30.03.10 09:23
Оценка:
Здравствуйте, Dr.Korbin, Вы писали:

DK>Примечательно, что если раскомментировать второй SetWindowLong, то MessageBox, конечно же, появится всего лишь один раз, но зато программа завершится корректно.


Отсюда мысль, вызывается ли вообще WM_CLOSE или WM_DESTROY? Есть подозрение, что нет.
Надо попробовать обработать WM_NCDESTROY, хотя, если уже NcDestroy, то уже поздно рассабклашиваться поэтому лучше спаем посмотреть это НЕсабклашеное окно и посмотреть, какие сообщения к нему приходят(но не факт, что именно им обрабатываются) в момент закрытия.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.