Может у кого уже готовый есть.. Я нашел один-отличный! Но работает только с одним окном. При постановке hooka на второе окно, в первом начинаются глюки.
Может у кого уже готовый есть.. Я нашел один-отличный!(позволяет отлавливать событие как до,так и после его наступления.. также есть возможность замены сообщения своим.) Но работает только с одним окном. При постановке hooka на второе окно, в первом начинаются глюки.
У меня в одной процедуре принимал сообщения от 3-х контролов и формы. Вроде глюков не наблюдал.
В конце концов можно на каждый приёмник сообщений выделить по одной процедуре.
-Сообщения должны отлавливаться в СВОИХ окошках (VB6). .. кнопки,текстовые поля и combo,listboxы и т.д. Короче говоря хук должен ставиться на любое окно в своем приложении.
-В событии должно передаваться само сообщение со всеми параметрами(lParam, wParam и т.д.включая hWnd окна которое получило данное сообщение),причем ByRef - чтобы можно было при необходимости заменить мессагу или параметр своими данными.
-Желательно наличие свойства,которое определяло бы когда информировать? After, Before того как окно обработает полученное сообщение(по-умолчанию Before)
-Субклассировщик должен работать не с одним окном, а с несколькими одновременно!Количество заранее не известно.
В принципе,всё вышесказанное я сделал.. НО! я не могу добиться,чтобы он работал с несколькими окнами... Поскульку используемая AdressOf функция ОБЯЗАНА распологаться в стандартном модуле, то данные по новому окну затирают предыдущие данные.. Другими словами я не могу добиться разделения переменных!!!Всю голову уже сломал!! ВЫРУЧАЙТЕ!!
И потом,если кому-то удастся сделать все вышеперечисленное (тому респект).. То я думаю,его надо будет обязательно выложить на сайте.Многие спасибо скажут!!!. Я облазил все известные мне VB-сайты.. Но НИ ОДНОГО приличного субклассировщика там нет!!!(я тестировал их 16 штук) А у нас будет!
Насколько я понимаю, на VB6 сделать это вполне реально..
По порядку.
1. Запоминаем адрес старой CallBack функции.
Public OldCBFunc_Form1 as Long, OldCBFunc_Command1 as long
OldCBFunc_Form1=SetWindowLong(Form1.hwnd, GWL_WNDPROC, AddressOf CommonCallback)
OldCBFunc_Command1=SetWindowLong(Command1.hwnd, GWL_WNDPROC, AddressOf CommonCallback)
2. В самой CallBack функции работаем только с тем окном, чьё hWnd поступило.
Function CommonCallback(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case hWnd
Case Form1.hWnd
'Поступило сообщение в Form1
Case Command1.hwnd
'Поступило сообщение в Command1
End Select
3. Вызываем родную CallBack функцию для текущего окна. В принципе, если необходимо чтобы сообщение не поступило, то просто обнуляем его (uMsg=0)
Select Case hWnd
Case Form1.hWnd
CommonCallback=CallWindowProc(OldCBFunc_Form1, hwnd, uMsg, wParam, lParam)
Case Command1.hwnd
CommonCallback=CallWindowProc(OldCBFunc_Command1, hwnd, uMsg, wParam, lParam)
End Select
End Function
Т.е. в самом окне(форме или кнопке) хранится адрес функции, которая будет принимать сообщения для окна. Когда окну посылается сообщение, она вызывает функцию по этому адресу. Что то наподобие CALL FuncName. Только, в отличие от VB, функция вызывается не по имени, а по адресу (типа CALL DWORD в Power Basic). Вот ты этот адрес и подменяешь.
А т.к. все CallBack функции одинаковы, то и подменить можно функцию для любого окна. В Power Basic например, если ты не указываешь CallBack функцию для контрола, то по умолчанию все сообщения передаются родителю. И это верно не только для PB, а для любого языка, совместимого с ОС (независимового от внутреннего интерпретатора).
Вот посмотри что получится на самом деле.
Посылаем сообщение окну
SendMessage Command1.hWnd,WM_LBUTTONCLICK,wParam,lParam
Кнопка в свою очередь вызывает функцию, обрабатывающую сообщения
Что то типа:
- Сложить все параметры в стёке:
PUSH lParam
PUSH wParam
PUSH WM_LBUTTONCLICK
PUSH Command1.hWnd
- Вызвать функцию по известному адресу:
CALL GWL_WNDPROC
Функция сама вынет параметры из стёка. На этом её самостоятельность и заканчивается. Всё остальное ты должен запрограммировать сам. А определить какое окно её вызвало можно по парамерту hWnd.
С сабклассингом я разобрался.На данный момент у меня проблема заключается немного в другом.
Возможно ли из ехе-шника вызвать функцию расположенную в длл, а длл в свою очередь вызывает функцию расположенную в ехе.. Сейчас попробую объяснить.. Для начала должен сказать, что весь сабклассинг я пранирую засунуть в длл(кроме одной ф-и), иначе отладка в пошаговом режиме превращается в кошмар...
вот кусок твоей CallBack функции:
Select Case hWnd Case Form1.hWnd
Вот тут необходимо вызвать функцию расположенную в ехе,для того чтобы при необходимости можно было заменить uMsg, wParam, lParam!!! ,чтобы каждый раз длл не перекомпилировать.
А вот как это сделать? ума не приложу!!!
CommonCallback=CallWindowProc(OldCBFunc_Form1, hwnd, uMsg, wParam, lParam) Case Command1.hwnd CommonCallback=CallWindowProc(OldCBFunc_Command1, hwnd, uMsg, wParam, lParam) End Select
Для того чтобы вызвать функцию из внешнего модуля, она должна быть экспортной - т.е. её адрес должен быть прописан в секции экспорта EXE или DLL. А в вызывающем модуле она должна быть объявлена (DECLARE SUB ProcName LIB "MODULE!!!" Arguments).
---
>вызвать функцию расположенную в ехе
- В принципе наверное такое можно сделать, но только не в VB. Тебе нужно сложить все параметры в стёке, а потом CALL ProcAddr. Если второе сделать легко с помощью AddressOf, то для первого ЯВУ должен поддерживать АСМ.
===
заменить uMsg, wParam, lParam можно прямо в функции CommonCallback
просто пишешь uMsg=Value
потом
CommonCallback=CallWindowProc(OldCBFunc_Form1, hwnd, uMsg, wParam, lParam)
это вызывает родную Callback функцию для формы (ту, которая генерирует события: типа Form_Click, Form_Size и т.д.).
А так как сообщение изменено, то в форму поступает не родное uMsg, а значение Value.
===
Я вообщето делал по другому. Ложил на форму контрол, а из внешнего модуля слал туда сообщения или менял какое либо из его свойств. И в них уже обрабатывал то, что хочет внешний модуль.
Пример DLL
Sub DLL_SUB (byval hWnd_Text1 as long)
SetWindowText hWnd_Text1, NewText$
End Sub
Пример EXE
Private Sub Text1_Change()
If len(Text1)>0 then Call AnotherProc
End Sub