Глобальный хук на чистом бейсике по идее tyomitch-а

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 11:11

По многочисленным ссылкам в обсуждениях нашёл хук на чистом бейсике от tyomitch

К сожалению, он был сложен для моего понимания и сильно запутан трейными часиками :)
К тому же, пугал меня .tlb-шкой, которая по-прежнему остаётся для меня в разряде белой магии.

Да простит меня уважаемый автор, я выбросил из примера всё, что не относится к хуку как таковому (и часики, и субклассинг и tlb)

Помогите, пожалуйста, разобраться, что я сделал не так и что не так понял: хук на своё окно ставится, а на чужие - нет... Причём, рушит эти самые чужие проги, а сам не падает :)

Библиотека:
Код: Выделить всё
'clsHook
Option Explicit

Public Property Get AddressOfHookProc() As Long
    AddressOfHookProc = i(AddressOf HookProc) 'получить из класса адрес процедуры, которая на самом деле в модуле
End Property

Private Function i(ByVal x As Long) As Long
    i = x
End Function

Public Property Get DllBase() As Long
    DllBase = App.hInstance
End Property

Public Sub implimentsMe(h As iHook) 'подключить интерфейс
  Set myHook = h
  myHook.HookProc 0, 0, 0 'показать, что подключился
End Sub

Код: Выделить всё
'iHook
Option Explicit

Public Function HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

End Function

Код: Выделить всё
'modHook
Option Explicit

Public myHook As iHook 'интерфейс, который будет передавать события нашего хука

Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long

Public Function HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    myHook.HookProc code, wParam, lParam
    HookProc = CallNextHookEx(0, code, wParam, lParam)
End Function

Программа:
Код: Выделить всё
'form1
Option Explicit
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long

Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long

Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
   
    Const HWND_TOPMOST = -1
    Const HWND_NOTOPMOST = -2
    Const SWP_NOMOVE = &H2
    Const SWP_NOSIZE = &H1
    Const SWP_NOACTIVATE = &H10
    Const SWP_SHOWWINDOW = &H40

Dim hw As Long, newId As Long

Private hHook As Long

Const WH_KEYBOARD = 2&

Implements iHook

Private Sub Form_Load()
    implimentsMe Me ' сообщаем в длл, что события хука нужно слать нам
   
    hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOfHookProc _
       , DllBase, App.ThreadID) 'ставим хук на самого себя


    SetWindowPos hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE
    timer1.Interval = 200 'по таймеру проверяю, не изменился ли фокус ввода
End Sub

Private Sub Form_Unload(Cancel As Integer)
  UnhookWindowsHookEx hHook
End Sub

Private Function iHook_HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Caption = Hex(wParam) & "  " & Hex(lParam)
End Function

Private Sub timer1_Timer()
Dim h As Long
h = GetForegroundWindow 'окно верхнего уровня
If h <> hwnd Then ' если это не мы
  If hw <> h Then ' и не то окно, которое мы уже смотрим
    hw = h
    newId = GetWindowThreadProcessId(hw, 0)
   
    If hHook Then UnhookWindowsHookEx hHook
    hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOfHookProc _
       , DllBase, newId) ' пытаемся переставить хук на другой процесс
  End If
 
End If

End Sub


Добавлено позже:
Кстати - СПАСИБО ВСЕМ :D - я таки допеределывал пример! см. в конце этой темы. И даже до состояния готового контрола! см.Кирпичи
Последний раз редактировалось arthur2 30.12.2008 (Вт) 1:21, всего редактировалось 2 раз(а).
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 11:27

arthur2 писал(а):К сожалению, он был сложен для моего понимания и сильно запутан трейными часиками :)
К тому же, пугал меня .tlb-шкой, которая по-прежнему остаётся для меня в разряде белой магии.

Да простит меня уважаемый автор, я выбросил из примера всё, что не относится к хуку как таковому (и часики, и субклассинг и tlb)

Вся магия этого примера -- в "поднятии за шнурки" рантайма изнутри хука (работа с атомами и DoDirtyBusiness).
Без этого, ничего не заработает. С декларами вместо TLB -- тоже.
Изображение

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 11:39

tyomitch
Я понимаю, что не работает из-за той части, смысла которой я не понимаю :)

Тогда другой вопрос: а почему тогда хук работает в моём варианте, хоть и только для своего окна? Ведь hookproc внутри библиотеки срабатывает!

Изначально я так понял, что чтобы хук установился, достаточно в SetWindowsHookEx передать адрес процедуры, которая лежит не у себя, а снаружи... Выходит, этого недостаточно

Помоги понять? Только пожалуйста - как для тупого :)

Вся магия этого примера -- в "поднятии за шнурки" рантайма изнутри хука (работа с атомами и DoDirtyBusiness).
Без этого, ничего не заработает. С декларами вместо TLB -- тоже.

Нельзя ли "поднять рантайм" не изнутри хука, а снаружи?
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 11:54

arthur2 писал(а):Я понимаю, что не работает из-за той части, смысла которой я не понимаю :)

Значит нужно разбираться, а не отрезать всё непонятное ;-)

arthur2 писал(а):Тогда другой вопрос: а почему тогда хук работает в моём варианте, хоть и только для своего окна? Ведь hookproc внутри библиотеки срабатывает!

Потому что в твоём процессе рантайм уже поднят.
В любой другой VB6-проге тоже сработает, хочешь -- проверь.

arthur2 писал(а):Изначально я так понял, что чтобы хук установился, достаточно в SetWindowsHookEx передать адрес процедуры, которая лежит не у себя, а снаружи... Выходит, этого недостаточно

Помоги понять? Только пожалуйста - как для тупого :)

Книжка Курланда с подробным описанием всех процессов у меня осталась далеко :-(
Вкратце, единственная поддерживаемая точка входа в VB6 DLL -- через создание объекта. При входе в DLL любым другим способом (например, по хуку), рантайм не инициализируется. В тонком вакууме, без рантайма, могут работать только API, объявленные в TLB.
Изображение

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 12:10

Значит нужно разбираться, а не отрезать всё непонятное

Это и есть способ разбираться: оставляем только понятное и смотрим - а работает ли :) После этого смотрим, что из непонятного нужно понять, чтобы заработало. И спрашиваем у автора, как понять это самое непонятно :)

Вкратце, единственная поддерживаемая точка входа в VB6 DLL -- через создание объекта. При входе в DLL любым другим способом (например, по хуку), рантайм не инициализируется. В тонком вакууме, без рантайма, могут работать только API, объявленные в TLB.


А если я просто внутри самой библиотеки создам какой-нибудь объект, рантайм не проинициируется? Объявлю что-нибудь смешное типа fnt as new stdfont :) (уже попробовал, не помогло)

Ещё я попробовал заменить globalmultiuse на просто multiuse и создать экземпляр класса set clhook as new clshook
Почему это не инициирует рантайм?
Код: Выделить всё
Private Sub Form_Load()
Set clHook = New clsHook
    clHook.implimentsMe Me ' сообщаем в длл, что события хука нужно слать нам
    AddressOfHookProc = clHook.AddressOfHookProc
    DllBase = clHook.DllBase
    hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOfHookProc _
       , DllBase, App.ThreadID) 'ставим хук на самого себя
' ... и далее то же самое

В любой другой VB6-проге тоже сработает, хочешь -- проверь.
Нет, другие вб-проги тоже дохнут от моего хука. Он один не падает :)
Последний раз редактировалось arthur2 26.12.2008 (Пт) 12:18, всего редактировалось 1 раз.
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 12:16

Инициировать рантайм нужно всякий раз, когда устанавливается новый хук? чтобы он инициировался в том процессе, на который хук ставится? Так я понял?

Хорошо, без рантайма не заработает, но один-то раз в hookproc программа должна зайти - ведь и в твоём примере все фокусы с поднятием за шнурки запускаются оттуда :) Но не заходит...
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 13:02

arthur2 писал(а):Инициировать рантайм нужно всякий раз, когда устанавливается новый хук?

Один раз в жизни процесса.

arthur2 писал(а):чтобы он инициировался в том процессе, на который хук ставится? Так я понял?

Верно.

arthur2 писал(а):Хорошо, без рантайма не заработает, но один-то раз в hookproc программа должна зайти - ведь и в твоём примере все фокусы с поднятием за шнурки запускаются оттуда :) Но не заходит...

Как проверяешь, что не заходит?
Если рушится, это как раз значит, что заходит.

arthur2 писал(а):Ещё я попробовал заменить globalmultiuse на просто multiuse и создать экземпляр класса set clhook as new clshook
Почему это не инициирует рантайм?

Потому что As New требует рантайма. См. выше: без него могут работать только API из TLB.
Изображение

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 13:28

Как проверяешь, что не заходит?
Если рушится, это как раз значит, что заходит.

Рушится, но не моя прога, а та, на которую пытаюсь ставить хук :) Рушится как раз тогда, когда я в этой другой, уже хукнутой, программе жму клавишу. А моя как ни в чём ни бывало. Может, дело в том, что я ставлю не тот хук? Не на WH_CALLWNDPROCRET, а на WH_KEYBOARD? и поэтому с HC_ACTION хук не срабатывает?

Инициировать рантайм нужно всякий раз, когда устанавливается новый хук?

Один раз в жизни процесса.

Так если я хук переставляю на другой процесс - нужно переинициировать рантайм?

Потому что As New требует рантайма

Так я и сделал это, чтобы он потребовал рантайма :) А раз на этом требовании бейсик не сдох, значит он свой рантайм получил?
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 13:50

arthur2 писал(а):
Как проверяешь, что не заходит?
Если рушится, это как раз значит, что заходит.

Рушится, но не моя прога, а та, на которую пытаюсь ставить хук :) Рушится как раз тогда, когда я в этой другой, уже хукнутой, программе жму клавишу. А моя как ни в чём ни бывало. Может, дело в том, что я ставлю не тот хук? Не на WH_CALLWNDPROCRET, а на WH_KEYBOARD? и поэтому с HC_ACTION хук не срабатывает?

Всё совершенно верно: заходит, выполняет невыполнимое, и рушится.
Ты же не ожидаешь, что обработчик хука будет выполняться в поставившем процессе, верно?


arthur2 писал(а):
Инициировать рантайм нужно всякий раз, когда устанавливается новый хук?

Один раз в жизни процесса.

Так если я хук переставляю на другой процесс - нужно переинициировать рантайм?

Не "пере"инициировать, а инициировать плюс ещё и в новом процессе.
Хотя в старом почистить за собой тоже нелишне :-)


arthur2 писал(а):
Потому что As New требует рантайма

Так я и сделал это, чтобы он потребовал рантайма :) А раз на этом требовании бейсик не сдох, значит он свой рантайм получил?

Бейсик не умрёт никогда: после того, как хук поставлен, он в стороне и не у дел.
Изображение

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 14:03

Не "пере"инициировать, а инициировать плюс ещё и в новом процессе.

Теоретически, понятно :)
Я сейчас отложил все переставления с процесса на процесс и пытаюсь поставить хук хотя бы на один-единственный процесс. Сменил WH_KEYBOARD снова на WH_CALLWNDPROCRET, вернул тлб и фокус с атомами... Блокнот от хука как дох, так и дохнет :(
Ни одного ответа от hookproc так и не получил, если только окно не моё.
Код: Выделить всё
Public Function HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    If code = HC_ACTION Then
       If 0 = FindAtom(MsgName) Then DoDirtyBusiness
    End If

'вот досюда должен  же код хоть раз дойти? Не доходит :(
    myHook.HookProc code, wParam, lParam

    HookProc = CallNextHookEx(0, code, wParam, lParam)
   
End Function

Public Sub DoDirtyBusiness()
    AddAtom MsgName
    CoInitialize 0
Dim IID_IUnknown As IID, pUnk As IUnknown
    With IID_IUnknown
        .Data4(0) = &HC0
        .Data4(7) = &H46
    End With
    CoCreateInstance CLSIDFromProgID(ProgID), Nothing, CLSCTX_INPROC_SERVER, IID_IUnknown, pUnk
    Set Bogus = pUnk
End Sub
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 14:54

Поставил debugbreak прямо на входе в hookproc. При хуке на своём окне, как и предполагалось, debugbreak сработал.
При хуке на чужом окне не сработал! Значит, в hookproc программа всё-таки не заходит. Ни разу :(
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 15:09

Ок, ещё раз и крупно.

Ты осознаёшь, что обработчик хука выполняется в целевом процессе, а не в поставившем?

В частности, под отладчиком ты его абсолютно никак не прогонишь.
Изображение

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 15:18

Да, осознаю. Упражняюсь на скомпилированной библиотеке.

(а под отладчиком - и на своём окне не прогнал бы, ведь так? раз знаю, что на своём окне код работает, значит наверное тестю не под отладчиком, ведь так?)
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 15:32

Тогда объясни ещё раз, как ты определяешь, что до обработчика выполнение не доходит.


Про правильное применение магии: ProdID своей библиотеки прописал в коде верный?
Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение Хакер » 26.12.2008 (Пт) 15:40

Артур, а чем тебя не устраивает FNDLL?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 15:45

Тогда объясни ещё раз, как ты определяешь, что до обработчика выполнение не доходит.

Ставлю прямо на входе DebugBreak

Код: Выделить всё
Public Function HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    DebugBreak
    If code = HC_ACTION Then
       If 0 = FindAtom(MsgName) Then DoDirtyBusiness
    End If
'и т.д.

Если хукаю своё окно, breakpoint срабатывает, если чужое - не срабатывает.

Про правильное применение магии: ProdID своей библиотеки прописал в коде верный?
"prjHook.clsHook", как и у тебя. Правда, у меня в библиотеке есть ещё iHook, но в любом случае - до этого места код просто не доходит.

Может, я неправильно определяю id процесса по окну?
Код: Выделить всё
    newId = GetWindowThreadProcessId(hw, 0)
    hHook = SetWindowsHookEx(12, AddressOfHookProc  , DllBase, newId)

(Окно нахожу то - проверяю по заголовку)
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение Хакер » 26.12.2008 (Пт) 15:48

А мой вопрос ты проигнорировал?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 15:57

arthur2 писал(а):Ставлю прямо на входе DebugBreak

Он объявлен в TLB?

Но вообще, предположения у меня закончились, так что давай свой код :-)
Изображение

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 15:57

Хакер
Почему, устраивает :) Я уже даже пробовал её, но не знал, куда применить :) А про хуки я начал разбираться буквально вчера. И начал с примера tyomitch потому, что меня привлекло "чистый бейсик". А уж когда у меня получилось хукнуть своё окно вроде как через внешнюю библиотеки и показалось, что так же просто будет хукнуть чужое, я вообще загорелся.

Оказалось, что не так и просто :(

А в можно сделать внутри FNDLL интерфейс и implemens его снаружи? (пока не разбирался)
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 16:01

Хакер
С чего ты взял-то. Твой вопрос я увидел, когда размещал свой предыдущий ответ :)

Он объявлен в TLB?
Ага, в твоей, которая с примером :) Код сейчас соберу
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение Хакер » 26.12.2008 (Пт) 16:10

Библа, сделанная с установленным FNDLL — продолжает оставаться полноценной ActiveXDLL-библой. Т.е. она так же может иметь классы, интерфейсы, добавляться в References, регистрироваться/анрегистрироваться. Но при этом инициализация рантайма в ней происходит не по созданию объекта, а сразу же при загрузке, и публичные функции в модулях можно экспортировать.

Только вот зачем тебе вообще понадобились интерфейсы и классы при хукинге я понять не могу.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 16:19

В программе:
Код: Выделить всё
Option Explicit
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long

Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
   
    Const HWND_TOPMOST = -1
    Const HWND_NOTOPMOST = -2
    Const SWP_NOMOVE = &H2
    Const SWP_NOSIZE = &H1
    Const SWP_NOACTIVATE = &H10
    Const SWP_SHOWWINDOW = &H40

Dim hw As Long, newId As Long

Private hHook As Long ', AddressOfHookProc As Long, DllBase As Long


Const WH_KEYBOARD = 2&
Private Const WH_CALLWNDPROCRET = 12
Implements iHook


Private Sub Form_Load()
'Set clHook = New clsHook
    implimentsMe Me ' сообщаем в длл, что события хука нужно слать нам
'    hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOfHookProc _
       , DllBase, App.ThreadID) 'ставим хук на самого себя
'   clHook.DoDiBu

    SetWindowPos hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE
    timer1.Interval = 2000 'даю себе пару секунд, чтобы выбрать окно для хука
                           '(или не даю, и тода хукнится своё окно)
End Sub

Private Sub Form_Unload(Cancel As Integer)
  UnhookWindowsHookEx hHook
End Sub

Private Function iHook_HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Caption = Hex(wParam) & "  " & Hex(lParam)
   UnhookWindowsHookEx hHook ' хочу получить хотя бы одно сообщение
End Function

Private Sub timer1_Timer()
Dim h As Long

h = GetForegroundWindow 'окно верхнего уровня
  If hw <> h Then ' и не то окно, которое мы уже смотрим
    hw = h
    Dim s As String
    s = Space(101)
    GetWindowText hw, s, 100
    Caption = s 'проверяю, то ли окно нашёл
    newId = GetWindowThreadProcessId(hw, 0)
   
    If hHook Then UnhookWindowsHookEx hHook
   
    hHook = SetWindowsHookEx(12, AddressOfHookProc _
       , DllBase, newId)
   timer1.Enabled = False
  End If
End Sub

В библиотеке:
Модуль
Код: Выделить всё
Option Explicit

Public myHook As iHook 'интерфейс,  который будет передавать события нашего хука

Private Const ProgID = "prjHook.clsHook" 'fix as appropriate
Private Const MsgName = "MyVeryOwn hook" 'fix as appropriate
Private Bogus As Object 'as long as an object is alive in apartment, we can do our business
Private Declare Function DeleteAtom Lib "kernel32" (ByVal nAtom As Integer) As Integer
Private Declare Function GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private Const HC_ACTION = 0
Private Const GWL_WNDPROC = -4
Private Const WM_USER = &H400
Public m_hwnd As Long
Dim hw As Long, OldWndProc As Long

Public Function HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    DebugBreak
    If code = HC_ACTION Then
       If 0 = FindAtom(MsgName) Then DoDirtyBusiness
    End If
    myHook.HookProc 1, wParam, lParam

    HookProc = CallNextHookEx(0, code, wParam, lParam)
   
End Function


Public Sub DoDirtyBusiness()
    AddAtom MsgName
    CoInitialize 0
Dim IID_IUnknown As IID, pUnk As IUnknown
    With IID_IUnknown
        .Data4(0) = &HC0
        .Data4(7) = &H46
    End With
    CoCreateInstance CLSIDFromProgID(ProgID), Nothing, CLSCTX_INPROC_SERVER, IID_IUnknown, pUnk
    Set Bogus = pUnk
End Sub

класс
Код: Выделить всё
Option Explicit

Public Property Get AddressOfHookProc() As Long
    AddressOfHookProc = i(AddressOf HookProc) 'получить из класса адресс процедуры, которая на самом деле в модуле
End Property

Private Function i(ByVal x As Long) As Long
    i = x
End Function

Public Property Get DllBase() As Long
    DllBase = App.hInstance
End Property

Public Sub implimentsMe(h As iHook) 'подключить интерфейс
  Set myHook = h
End Sub


интерфейс:
Код: Выделить всё
Option Explicit
Public Function HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

End Function
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 16:23

Хакер
Только вот зачем тебе вообще понадобились интерфейсы и классы при хукинге я понять не могу.

Чтобы код хука писать не в библиотеке, а снаружи. Мне вообще очень нравится использовать интерфейсы: и субклассинг у меня с ними, и таймер :) Можно, конечно, делать события класса. Но я тестил, события генеряться в десять раз медленнее, чем передаются по интерфейсу.
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение Хакер » 26.12.2008 (Пт) 16:32

У тебя класс обработчик и класс-информатор в разных апартаментах. VB об этом что-нибудь знает?


Но я тестил, события генеряться в десять раз медленнее, чем передаются по интерфейсу.

Зато события могут обрабатываться сразу несколькими объектами-наблюдателями.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 16:39

У тебя класс обработчик и класс-информатор в разных апартаментах. VB об этом что-нибудь знает?

не понял :oops:

- Но я тестил, события генеряться в десять раз медленнее, чем передаются по интерфейсу.

- Зато события могут обрабатываться сразу несколькими объектами-наблюдателями.

Для меня это было не важно. Собственно, где понадобятся события, буду использовать события, а где удобнее интерфейсами - интерфейсы :)
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение Хакер » 26.12.2008 (Пт) 17:04

Чтобы код хука писать не в библиотеке, а снаружи.

Говоря тупо и некорректно:
У тебя код библиотеки оказывается внутри одной программы, а код "снаружи" — в другой. Обе обломаются, если будут использовать неотмаршалленный интерфейсный указатель друг на друга.

Перефразировав, можно сказать: как у тебя осуществляется связь между процессом, в которой что-то хукнуто, и основным процессом?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 17:37

если будут использовать неотмаршалленный интерфейсный указатель друг на друга
хоть я этого и не понял, но, насколько могу судить, этого как-то можно и нужно избежать? Если я делаю неправильно, то как надо?
Артур
 
   

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение Хакер » 26.12.2008 (Пт) 18:21

Я не знаю, что ты делаешь. Но есть предположение, что твой объект вызывает метод другого объекта и при этом второй находится в другом процессе. Я прав?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение arthur2 » 26.12.2008 (Пт) 18:37

В библиотеке в классе есть функция:
Код: Выделить всё
Public Sub setInterface(h As iHook) 'подключить интерфейс
  Set myHook = h
End Sub

В модуле библиотеки в обработчике хука (ну, или того, из чего нужно вызвать нужное действие):
Код: Выделить всё
    myHook.HookProc code, wParam, lParam


В форме в программе:
Код: Выделить всё
Implements iHook

Private Sub Form_Load()
    setInterface Me
End Sub

Private Function iHook_HookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  ' ля-ля-ля
End Function
Артур
 
   

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Re: Глобальный хук на чистом бейсике по идее tyomitch-а

Сообщение tyomitch » 26.12.2008 (Пт) 18:51

Хакер писал(а):есть предположение, что твой объект вызывает метод другого объекта и при этом второй находится в другом процессе

Хакер оказался прав.
Даже отвлекаясь от того, что нужен маршалинг: myHook в твоём процессе свой, в целевом свой. Даже после того, как ты в своём вызвал setInterface, в целевом там остался Nothing.
Изображение

След.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 95

    TopList