2013-11-10 4 views
0

Я хочу изменить обработчик сообщений для старого старого приложения, которое мы используем, но у вас больше нет источника. В dll, что у нас есть источник, я хочу перехватить оконные сообщения, а затем передать их в приложение. Это возможно? Я пробовал что-то вроде:Как зарегистрировать другой обработчик сообщения win32

WNDPROC lpfnWndProc = NULL; 

void GetHandler() 
{ 
    HINSTANCE hInstance = GetModuleHandle(NULL); 
    HWND hWnd = GetActiveWindow(); 

    WCHAR lpClassName[1024]; 

    GetClassName(hWnd,lpClassName,1024); 

    WNDCLASSEX wc; 

    GetClassInfoEx(hInstance, lpClassName, &wc); 

    lpfnWndProc = wc.lpfnWndProc; 

    wc.lpfnWndProc = NewMessageProc; 

    RegisterClassEx(&wc); 
} 

Однако GetActiveWindow не удается и просто возвращает NULL. Есть ли более простой способ сделать это. Infact Я был бы счастлив, если бы мог просто добавить другого обработчика сообщений.

+0

Важный вопрос: ваша DLL загружена в адресное пространство старого приложения? Если answser НЕТ, вы должны начать с адресации (с помощью DLL-инъекции, возможно, через Hooking). Если answser да, можете ли вы сделать свой DLL-код в том же потоке, что и окно, которое вы хотите подкласса ?. Если ДА, используйте SetWindowSubclass, если NOT, используйте перехват сообщения для перехода в хороший поток, а затем в SubClass. – manuell

+0

@manuell Вы не можете выполнить код .dll ** без ** загрузки его в адресное пространство приложения. Ваш вопрос - как указано - не имеет смысла. – IInspectable

+0

@IInspectable Я просто спрашивал, была ли DLL загружена в том же процессе, что и тот, который размещает окно для подкласса. В чем проблема? – manuell

ответ

1

Я бы использовал SetWindowSubclass после получения HWND окна, в котором вы хотите изменить поведение. SetWindowLong был устаревшим как способ изменить WndProc окна назад в то время, когда вышла версия CommCtrl.dll 6. MSDN может рассказать вам все об этой части истории и ее мотивации - просто найдите SetWindowSubclass.

Как известно, при условии, что вызывающий поток имеет активное окно, ваш код просто создаст новый оконный класс с теми же атрибутами, что и ваше целевое окно, хотя и с другим WndProc - он не установит wndproc существующего окно .. - (отсюда и мое упоминание о SetWindowLong и SetWindowSubclass)

EDIT: Или leaast, было бы, не для контроля, я сделал по этому вопросу. Как указано в комментарии ниже, этот вызов RegisterClass на самом деле завершится неудачей - вы не можете зарегистрировать одно и то же имя класса более одного раза.

 

 

Вы должны также, вероятно, посмотрите на функцию FindWindow - просто дать ему NULL lpWindowName, и (известный) класс-имя целевого окна. В случае, если желаемое окно не является тем, которое было возвращено, вы можете использовать EnumWindows. Просто позвоните GetClassName в функцию обратного вызова, которую вы передаете в EnumWindows, подклассифицируя все/все окна, имя класса которых соответствует имени класса целевого окна.

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

+1

Вызывающий поток будет ** не ** создавать новый класс окна. Вызов 'RegisterClassEx' просто провалится. Вы не можете повторно зарегистрировать класс окна с тем же именем существующего класса окна. – IInspectable

+0

Хорошая добыча! Спасибо (еще раз) IInspectable .. :) – enhzflep

2

Неясно, хотите ли вы подклассы конкретных элементов управления или всех окон определенного класса окон.

Если вы хотите подклассифицировать определенные элементы управления, раздел Subclassing Controls в MSDN описывает, как это сделать, как для ComCtl32.dll версии 6 и выше, так и устаревшую процедуру непосредственной замены оконной процедуры элемента управления.

Если вы хотите подклассифицировать все элементы управления определенного класса окон, вам придется изменить записи, хранящиеся в зарегистрированном классе окна, используя SetClassLongPtr. Обратите внимание, что это повлияет только на окна, созданные впоследствии с этим классом окна. Это немного Catch 22, так как вам нужно иметь дескриптор окна при вызове SetClassLongPtr, ограничивая применимость подкласса класса окна.

Что касается кода, который вы в курсе, есть целый ряд вопросов:

Ваш вызов GetModuleHandle получает неправильный HINSTANCE, а именно, что из вызывающего приложения. Поскольку вам нужен дескриптор модуля модуля, который регистрирует класс окна, вы должны передать имя .dll, которое реализует элементы управления.

Вызов GetActiveWindow может включать или не возвращать значение в зависимости от того, действительно ли вызывающий поток имеет активное окно. В вашем случае это, по-видимому, нет, поэтому вам нужно другое средство для восстановления дескриптора окна, например FindWindowEx.

Ваш последний звонок RegisterClassEx не делает то, что вы думаете: он просто провалится, поскольку вы не можете перерегистрировать класс окна с тем же именем существующего класса окна. Вместо этого вам нужно позвонить SetClassLongPtr, как показано выше.

+0

Привет, IInpectpect моя dll не реализует никаких элементов управления и (я думаю). Я хочу, чтобы основное окно приложений, так как оно будет иметь сообщение proc, которое я хочу заменить. На самом деле мое понимание всего этого довольно плохое. Могу ли я просто создать локальный (невидимый) элемент управления, который не имеет ничего общего с исходным приложением (т.е. локально в dll), и он получит оконные сообщения, не касаясь обработчика сообщений исходных приложений? Извините за немного n00b ... Спасибо – user176168

+0

@user Создание «перехватчика» управления невозможно. Сообщения не передаются в дикую природу, а отправляются непосредственно получателям при вызове 'DispatchMessage'. Вы должны так или иначе перехватывать обработку сообщений; Элементы управления подклассами - это самый чистый подход к этому. – IInspectable

Смежные вопросы