Using hooks in VB?

Hi,

  Can anyone tell me how to use hooks in VB? I want to write a screen capture program and want to detect the key pressed message even when the user is using another application so that I know when to start screen capturing?
  It would be great if you can give me some sample codes...
  Thanks.

sun jian
sunjian061197Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

abelCommented:
What key do you want to detect? Do you mean the PrtScrn? Or do you want a key, let's say F12, to activate your program/capture function? If your app is to run on that key, you can also set a hotkey for a shortcut. That hotkey will be systemwide.
Hooks are most easily implemented using the MsgHoo32.ocx from Mabry Software. It's freeware and can be used for distribution. With that control you can select a window (hwnd) and messages you want to hook and the _Message event will be called whenever a message is send to the window you specified. The problem is that you will need a systemwide hook, and as far as I know, it isn't possible using that ocx.
0
clifABBCommented:
What version of VB are you using?
0
sunjian061197Author Commented:
Hi abel,

  I went to Mabry Software's website and found lots of controlls but I didn't find the MsgHoo32.ocx you mentioned. Can you tell me where I can find a copy of it?

To clifABB: I am using VB5.0
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

clifABBCommented:
You're in luck with VB5, you don't have to use MsgHook or any of the 3rd party controls.  The AddressOf keyword will give you your hooking:

In a Bas Module (not form or class!) place the following code:

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

Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long

Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const WH_KEYBOARD = 2

Type lParam
  LoVal As Long
  HiVal As Long
End Type

Global g_hHook As Long

Public Sub KeyboardProc(lCode As Long, wPar As Long, lPar As lParam)
  Dim lRes As Long
 
  lRes = CallNextHookEx(g_hHook, lCode, wPar, lPar)

  'Process key strokes here, wPar is the keycode
End Sub


Then when you want to start the hook, use this code:

  g_hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, 0&, App.ThreadID)


IMPORTANT!!! You MUST unhook before closing your app with the code:

  lRes = UnhookWindowsHookEx(g_hHook)

0
sunjian061197Author Commented:
Hi clifABB,

  I have tried your code and it compiles well. But when I run it, I got error message 'This program has performed an illegal operation and will be shut down...'. My code is very simple, and actually it just installs the hook function when the form is loaded. The code is below:

------module1---------
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

Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long

Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const WH_KEYBOARD = 2

Type lParam
  LoVal As Long
  HiVal As Long
End Type

Global g_hHook As Long


Public Sub KeyboardProc(lCode As Long, wPar As Long, lPar As lParam)
  Dim lRes As Long
   
  lRes = CallNextHookEx(g_hHook, lCode, wPar, lPar)
  'Process key strokes here, wPar is the keycode
  'I didn't even do anything here!!!
End Sub
---------end of module1-------------

---------form1--------------
Private Sub Form_Load()
  g_hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, 0&, App.ThreadID)
End Sub

Private Sub Form_Unload(Cancel As Integer)
  lRes = UnhookWindowsHookEx(g_hHook)
End Sub
---------end of form1------------------

0
martiCommented:
Hi sunjian,
May be you will not appreciate my answer but according to microsoft  Q177992 of KB it's not posible to create keybord hook using 'pure' VB. Please refer to Q177992 of KB(the end of the article)
0
sunjian061197Author Commented:
Hi marti:

  So what do you mean by 'pure' VB? If I have DLL calls in a VB program, is that considered as pure? If not, can u give me an example of some 'impure' VB? :-)
0
martiCommented:
The above article means that for making a system keybord hook the KeyboardProc should be located in DLL not in OLE type DLL(which VB creates). But you can create App hook and the example is given in that article.
0
martiCommented:
The above article means that for making a system keybord hook the KeyboardProc should be located in DLL not in OLE type DLL(which VB creates). But you can create App hook and the example is given in that article.
0
clifABBCommented:
My apologies, I submitted the above code without complete testing.  
I was running NT and, although I didn't get any error, my test app just shut down.  I assumed it was because I was using NT (which requires WH_KEYBOARD_LL).

Spyworks 5 (standard) from Desaware has a hook control.  There web address is www.desaware.com
0
abelCommented:
The answer of clifABB is good, but if you still want to try that msghoo32 thing, here's a link to it:
ftp://ftp.ism.ru/pub/drivers/sound/SB32_FM/RAD_AK1/WIN95/MSGHOO32.OC_

But I'm not 100% sure it's the right one. If not, I can mail you the right one if you want. It's strange that Mabry doesn't supply the ocx anymore and that it's hard to find one on the net. A few months ago I remember that I found several good links and it was downloadable from Mabry as well.

Regards, Abel
0
kamallCommented:
'Message Hooking in VB w/o a custom control
'Hook messages from the system and other applications in VB5 'without the use of a custom control!


Private Const WM_SIZE = &H5
Private Const WM_MOVE = &H3
Private Const WM_WINDOWPOSCHANGED = &H47

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 GWL_WNDPROC = (-4)
       Private OriginalWndProc As Long

Public Sub HookWindow(hWnd As Long)

       OriginalWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf
       MessageSpy)
End Sub


Public Sub FreeWindow(hWnd As Long)

       SetWindowLong hWnd, GWL_WNDPROC, OriginalWndProc
End Sub


Private Function MessageSpy(ByVal hWnd As Long, ByVal Msg As Long,

       ByVal wParam As
       Long, _
       ByVal lParam As Long) As Long
       '     'Test the message received...
       Select Case Msg
        Case WM_SIZE: Debug.Print "WM_Size message."
        Case WM_MOVE: Debug.Print "WM_Move message."
        Case WM_WINDOWPOSCHANGED: Debug.Print "WM_WINDOWPOSCHANGED
       message."
End Select

'     'Pass it on to the normal window processor.
MessageSpy = CallWindowProc(OriginalWndProc, hWnd, Msg, wParam,
lParam)
End Function


0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sunjian061197Author Commented:
Thanks, Kamall, for your answer. But I have two problems here:
1. How do I get the 'hwnd' of a specific window that I want to hook its message?
2. How do I get hooked to the system instead of an application?
0
abelCommented:
A more correct link to the 16 and 32 bit versions of MsgHook from Mabry is found here:
http://www.arcatapet.com/vb.html
or more directly:
http://www.arcatapet.com/msghook.zip

These versions of the msghook controls appear to be the correct ones and the same as the original ones from Mabry.

You can use the api-function FindWindow to find a window to hook to. You can also use EnumWindows in conjunction with AddressOf and EnumWindowsProc to get all the windows at once (I mean one by one: you are enumerating) and then do with it what you like.

To create a SYSTEMWIDE hook, you cannot use SetWindowLong, you must use SetWindowHookEx, but to set that systemwide, you need a DLL. To set it to another window then your own, you must be very carefull. This is what Microsoft's comment is about that in the "Remarks" section of the function:
"The SetWindowLong function fails if the window specified by the hWnd parameter does not belong to the same process as the calling thread."
and:
"Calling SetWindowLong with the GWL_WNDPROC index creates a subclass of the window class used to create the window. An application should not subclass a window created by another process. The SetWindowLong function creates the window subclass by changing the window procedure associated with a particular window, causing Windows to call the new window procedure instead of the previous one. An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc. This allows the application to create a chain of window procedures."

But it the Answer of kamall he already took care of that part.

I'm not sure if the MsgHoo32.ocx can be set to a systemwide hook. The hWnd property should probably be set to 0, but I never tested it.

Regards, Abel
0
abelCommented:
BTW The SpyWorks 5.0 tool, mentioned by clifABB, is definitely able to set systemwide hooks via VB and has lots of demo-projects to explain the pitfalls you can encounter when setting a hook to detect key-presses. BUT the control is not freeware (msghook is).
0
sunjian061197Author Commented:
Thank you very much abel! I am going to start right away...

sun jian
0
abelCommented:
Sun jian,
Not that I really mind, but accepting kamalls answer locks the question for me unless I pay 10 percent of the points (20 points in this case), which I did, to read your comment. If you think the thread is not yet to it's end (you may still encounter some problems) you better wait a while before accepting an answer and only post comments. Only to kamall the answer is free of points, which will prevent other experts to add their contributions to your thread.
But you probably know all that already. I hope the solution(s) work out well enough for you.

Regards, Abel
0
kamallCommented:
sunjian,
Regarding your last two questions, abel has provided worthy information, and I actually have no more to add.

abel,
Thank you very much for your comments.
Regards to all.
0
abelCommented:
One thing to add here (I thought I'd posted it already, but probably not, or on another thread). MsgHoo32.ocx CANNOT be used to set a systemwide hook. Just thought I had to let you know...

Regards, Abel
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.