Solved

Using hooks in VB?

Posted on 1998-04-01
19
356 Views
Last Modified: 2012-06-21
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
0
Comment
Question by:sunjian061197
  • 6
  • 5
  • 3
  • +2
19 Comments
 
LVL 39

Expert Comment

by:abel
ID: 1460202
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
 
LVL 6

Expert Comment

by:clifABB
ID: 1460203
What version of VB are you using?
0
 

Author Comment

by:sunjian061197
ID: 1460204
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
 
LVL 6

Expert Comment

by:clifABB
ID: 1460205
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
 

Author Comment

by:sunjian061197
ID: 1460206
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
 
LVL 2

Expert Comment

by:marti
ID: 1460207
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
 

Author Comment

by:sunjian061197
ID: 1460208
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
 
LVL 2

Expert Comment

by:marti
ID: 1460209
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
 
LVL 2

Expert Comment

by:marti
ID: 1460210
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
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 6

Expert Comment

by:clifABB
ID: 1460211
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
 
LVL 39

Expert Comment

by:abel
ID: 1460212
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
 
LVL 7

Accepted Solution

by:
kamall earned 200 total points
ID: 1460213
'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
 

Author Comment

by:sunjian061197
ID: 1460214
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
 
LVL 39

Expert Comment

by:abel
ID: 1460215
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
 
LVL 39

Expert Comment

by:abel
ID: 1460216
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
 

Author Comment

by:sunjian061197
ID: 1460217
Thank you very much abel! I am going to start right away...

sun jian
0
 
LVL 39

Expert Comment

by:abel
ID: 1460218
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
 
LVL 7

Expert Comment

by:kamall
ID: 1460219
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
 
LVL 39

Expert Comment

by:abel
ID: 1460220
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

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now