Low Level Keyboard Hooks in C#

D

daFritz

Hi!
I need to prevent Task-Switching in my App, so I tried to implement a
low level keyboard hook in a extra class. But it seems that the
Parameters are not passed correctly to my Hook function. Similar
Examples in VB .NET work correctly.

Heres the Source Code:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;

public class LowLevelKeyboardHook :IDisposable
{
[DllImport("user32.dll")]
private static extern int SetWindowsHookExA(int IDHook, IntPtr lpfn,
int hMod,
int dwThreadID);

[DllImport("user32.dll")]
private static extern int UnhookWindowsHookEx(int hHook);

[DllImport("user32.dll")]
private static extern int CallNextHookEx(int hHook, int nCode, int
wParam, ref KBDLLHOOKSTRUCT lParam);

private delegate int LowLevelKeyboardProc(int nCode, int wParam,
KBDLLHOOKSTRUCT lParam);

public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

private const int WH_KEYBOARD_LL = 13;
private int intLLKey;

public LowLevelKeyboardHook()
{
intLLKey = SetWindowsHookExA(WH_KEYBOARD_LL, new
LowLevelKeyboardProc(WindowKeyHook).Method.MethodHandle.GetFunctionPointer(),
System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(),
0);
}

public int WindowKeyHook(int nCode, int wParam, KBDLLHOOKSTRUCT
lParam)
{
bool killKey = false;

if(killKey)
{
return 1;
}
else
{
return 0;
}
}

public void Dispose()
{
UnhookWindowsHookEx(intLLKey);
}
}


[b:2c1b8f9cf8]and the VB-Code, which worked[/b:2c1b8f9cf8]

Public Class frmMain
Inherits System.Windows.Forms.Form

Declare Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Integer, ByVal lpfn As
LowLevelKeyboardProcDelegate, ByVal hMod As Integer, ByVal dwThreadId
As Integer) As Integer
Declare Function UnhookWindowsHookEx Lib "user32" Alias
"UnhookWindowsHookEx" (ByVal hHook As Integer) As Integer
Delegate Function LowLevelKeyboardProcDelegate(ByVal nCode As
Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As
Integer
Declare Function CallNextHookEx Lib "user32" Alias
"CallNextHookEx" (ByVal hHook As Integer, ByVal nCode As Integer,
ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer

Const WH_KEYBOARD_LL = 13

Structure KBDLLHOOKSTRUCT
Dim vkCode As Integer
Dim scanCode As Integer
Dim flags As Integer
Dim time As Integer
Dim dwExtraInfo As Integer
End Structure

Dim intLLKey As Integer

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form
Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.lblInfo = New System.Windows.Forms.Label()
Me.SuspendLayout()
'
'lblInfo
'
Me.lblInfo.Location = New System.Drawing.Point(16, 16)
Me.lblInfo.Name = "lblInfo"
Me.lblInfo.Size = New System.Drawing.Size(216, 88)
Me.lblInfo.TabIndex = 0
Me.lblInfo.Text = "Alt-Tab, Alt-Esc, Ctrl-Esc, and the Windows
key are disabled. Ctrl-Alt-Del and Al" & _
"t-F4 are still enabled. Close the application to reset the
keyboard. While this " & _
"program is running, the low-level keyboard effect is
global."
'
'frmMain
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(248, 118)
Me.Controls.AddRange(New System.Windows.Forms.Control()
{Me.lblInfo})
Me.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedDialog
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.Name = "frmMain"
Me.StartPosition =
System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "LowLevel Keyboard Hook"
Me.ResumeLayout(False)

End Sub

#End Region

Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf
LowLevelKeyboardProc,
System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32(),
0)
End Sub

Private Sub frmMain_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
UnhookWindowsHookEx(intLLKey)
End Sub

Private Function LowLevelKeyboardProc(ByVal nCode As Integer,
ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer
Dim blnEat As Boolean = False

Debug.WriteLine(nCode.ToString())

Select Case wParam
Case 256, 257, 260, 261
'Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key
blnEat = ((lParam.vkCode = 9) AndAlso (lParam.flags =
32)) Or _
((lParam.vkCode = 27) AndAlso (lParam.flags = 32))
Or _
((lParam.vkCode = 27) AndAlso (lParam.flags = 0))
Or _
((lParam.vkCode = 91) AndAlso (lParam.flags = 1))
Or _
((lParam.vkCode = 92) AndAlso (lParam.flags = 1))
End Select

If blnEat = True Then
Return 1
Else
Return CallNextHookEx(0, nCode, wParam, lParam)
End If
End Function
Friend WithEvents lblInfo As System.Windows.Forms.Label
End Class

hopefully somebody can help me!
thanks daFritz
 
M

Mattias Sjögren

intLLKey = SetWindowsHookExA(WH_KEYBOARD_LL, new
LowLevelKeyboardProc(WindowKeyHook).Method.MethodHandle.GetFunctionPointer(),
System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(),
0);

The second parameter should be a delegate, just like in the VB.NET
code. GetFunctionPointer() will not work as expected.



Mattias
 
J

john conwell

From what it looks like, you are trying to prevent OS
keyboard messaged from being processed by your app?

you might try to take a look at using the IMessageFilter
interface. This is a clean, totally managed way to do
this. When the keyboard event fires, the interfaces
PreFilterMessage function gets fired. you can then just
return the value of your killKey bool.

-----Original Message-----
Hi!
I need to prevent Task-Switching in my App, so I tried to implement a
low level keyboard hook in a extra class. But it seems that the
Parameters are not passed correctly to my Hook function. Similar
Examples in VB .NET work correctly.

Heres the Source Code:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;

public class LowLevelKeyboardHook :IDisposable
{
[DllImport("user32.dll")]
private static extern int SetWindowsHookExA (int IDHook, IntPtr lpfn,
int hMod,
int dwThreadID);

[DllImport("user32.dll")]
private static extern int
UnhookWindowsHookEx(int hHook);
[DllImport("user32.dll")]
private static extern int CallNextHookEx (int hHook, int nCode, int
wParam, ref KBDLLHOOKSTRUCT lParam);

private delegate int LowLevelKeyboardProc(int nCode, int wParam,
KBDLLHOOKSTRUCT lParam);

public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

private const int WH_KEYBOARD_LL = 13;
private int intLLKey;

public LowLevelKeyboardHook()
{
intLLKey = SetWindowsHookExA (WH_KEYBOARD_LL, new
LowLevelKeyboardProc (WindowKeyHook).Method.MethodHandle.GetFunctionPointer(),
System.Runtime.InteropServices.Marshal.GetHINSTANCE
(System.Reflection.Assembly.GetExecutingAssembly
().GetModules()[0]).ToInt32(),
0);
}

public int WindowKeyHook(int nCode, int wParam, KBDLLHOOKSTRUCT
lParam)
{
bool killKey = false;

if(killKey)
{
return 1;
}
else
{
return 0;
}
}

public void Dispose()
{
UnhookWindowsHookEx(intLLKey);
}
}


[b:2c1b8f9cf8]and the VB-Code, which worked[/b:2c1b8f9cf8]

Public Class frmMain
Inherits System.Windows.Forms.Form

Declare Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Integer, ByVal lpfn As
LowLevelKeyboardProcDelegate, ByVal hMod As Integer, ByVal dwThreadId
As Integer) As Integer
Declare Function UnhookWindowsHookEx Lib "user32" Alias
"UnhookWindowsHookEx" (ByVal hHook As Integer) As Integer
Delegate Function LowLevelKeyboardProcDelegate(ByVal nCode As
Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As
Integer
Declare Function CallNextHookEx Lib "user32" Alias
"CallNextHookEx" (ByVal hHook As Integer, ByVal nCode As Integer,
ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer

Const WH_KEYBOARD_LL = 13

Structure KBDLLHOOKSTRUCT
Dim vkCode As Integer
Dim scanCode As Integer
Dim flags As Integer
Dim time As Integer
Dim dwExtraInfo As Integer
End Structure

Dim intLLKey As Integer

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form
Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.lblInfo = New System.Windows.Forms.Label()
Me.SuspendLayout()
'
'lblInfo
'
Me.lblInfo.Location = New System.Drawing.Point (16, 16)
Me.lblInfo.Name = "lblInfo"
Me.lblInfo.Size = New System.Drawing.Size(216, 88)
Me.lblInfo.TabIndex = 0
Me.lblInfo.Text = "Alt-Tab, Alt-Esc, Ctrl-Esc, and the Windows
key are disabled. Ctrl-Alt-Del and Al" & _
"t-F4 are still enabled. Close the application to reset the
keyboard. While this " & _
"program is running, the low-level keyboard effect is
global."
'
'frmMain
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(248, 118)
Me.Controls.AddRange(New System.Windows.Forms.Control()
{Me.lblInfo})
Me.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedDialog
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.Name = "frmMain"
Me.StartPosition =
System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "LowLevel Keyboard Hook"
Me.ResumeLayout(False)

End Sub

#End Region

Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf
LowLevelKeyboardProc,
System.Runtime.InteropServices.Marshal.GetHINSTANCE
(System.Reflection.Assembly.GetExecutingAssembly.GetModules
()(0)).ToInt32(),
0)
End Sub

Private Sub frmMain_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
UnhookWindowsHookEx(intLLKey)
End Sub

Private Function LowLevelKeyboardProc(ByVal nCode As Integer,
ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer
Dim blnEat As Boolean = False

Debug.WriteLine(nCode.ToString())

Select Case wParam
Case 256, 257, 260, 261
'Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key
blnEat = ((lParam.vkCode = 9) AndAlso (lParam.flags =
32)) Or _
((lParam.vkCode = 27) AndAlso (lParam.flags = 32))
Or _
((lParam.vkCode = 27) AndAlso (lParam.flags = 0))
Or _
((lParam.vkCode = 91) AndAlso (lParam.flags = 1))
Or _
((lParam.vkCode = 92) AndAlso (lParam.flags = 1))
End Select

If blnEat = True Then
Return 1
Else
Return CallNextHookEx(0, nCode, wParam, lParam)
End If
End Function
Friend WithEvents lblInfo As System.Windows.Forms.Label
End Class

hopefully somebody can help me!
thanks daFritz



----== Posted via Newsfeed.Com - Unlimited-Uncensored- Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
.
 
D

daFritz

Thanks, the provided links helped a lot understanding Low Level
Hooks;

:wink: daFritz
 
D

daFritz

The IMessageFilter is a good idea, but since the alt + tab message (or
similar hotkeys) are directly passed to windows (not over my app) it
won't work for me.

daFritz
 
N

netcom

HookAPI is the API SDK that setup SYSTEM-WIDE hooks for all windows
platform,it could easily hook 32-bit windows system APIs or 32-bit
user-defined DLL, it could be used easily,and what you need to do is
only writing a DLL file named mydll.dll or mydll_9x.dll.

I think it will helpful for you.Please see the detail information at
http://www.programsalon.com/en/hookapi.htm
 
M

Mountain Bikn' Guy

I have one app that uses Alt-mouseClick commands to enter a special
customization mode. However, due to the KVM I use, all mouse clicks are sent
as Alt-Click messages. This doesn't bother most software. However, it makes
that one certain program unusable (normal commands can't be processed). Does
anyone have any ideas how I could solve this issue? Could I write a program
to translate Alt-Clicks to regular clicks? It sounds like what I need is
similar to the topic of the OP. Thanks!
Regards,
Mountain

daFritz said:
Hi!
I need to prevent Task-Switching in my App, so I tried to implement a
low level keyboard hook in a extra class. But it seems that the
Parameters are not passed correctly to my Hook function. Similar
Examples in VB .NET work correctly.

Heres the Source Code:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;

public class LowLevelKeyboardHook :IDisposable
{
[DllImport("user32.dll")]
private static extern int SetWindowsHookExA(int IDHook, IntPtr lpfn,
int hMod,
int dwThreadID);

[DllImport("user32.dll")]
private static extern int UnhookWindowsHookEx(int hHook);

[DllImport("user32.dll")]
private static extern int CallNextHookEx(int hHook, int nCode, int
wParam, ref KBDLLHOOKSTRUCT lParam);

private delegate int LowLevelKeyboardProc(int nCode, int wParam,
KBDLLHOOKSTRUCT lParam);

public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

private const int WH_KEYBOARD_LL = 13;
private int intLLKey;

public LowLevelKeyboardHook()
{
intLLKey = SetWindowsHookExA(WH_KEYBOARD_LL, new
LowLevelKeyboardProc(WindowKeyHook).Method.MethodHandle.GetFunctionPointer()
,System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assemb
ly.GetExecutingAssembly().GetModules()[0]).ToInt32(),
0);
}

public int WindowKeyHook(int nCode, int wParam, KBDLLHOOKSTRUCT
lParam)
{
bool killKey = false;

if(killKey)
{
return 1;
}
else
{
return 0;
}
}

public void Dispose()
{
UnhookWindowsHookEx(intLLKey);
}
}


[b:2c1b8f9cf8]and the VB-Code, which worked[/b:2c1b8f9cf8]

Public Class frmMain
Inherits System.Windows.Forms.Form

Declare Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Integer, ByVal lpfn As
LowLevelKeyboardProcDelegate, ByVal hMod As Integer, ByVal dwThreadId
As Integer) As Integer
Declare Function UnhookWindowsHookEx Lib "user32" Alias
"UnhookWindowsHookEx" (ByVal hHook As Integer) As Integer
Delegate Function LowLevelKeyboardProcDelegate(ByVal nCode As
Integer, ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As
Integer
Declare Function CallNextHookEx Lib "user32" Alias
"CallNextHookEx" (ByVal hHook As Integer, ByVal nCode As Integer,
ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer

Const WH_KEYBOARD_LL = 13

Structure KBDLLHOOKSTRUCT
Dim vkCode As Integer
Dim scanCode As Integer
Dim flags As Integer
Dim time As Integer
Dim dwExtraInfo As Integer
End Structure

Dim intLLKey As Integer

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form
Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.lblInfo = New System.Windows.Forms.Label()
Me.SuspendLayout()
'
'lblInfo
'
Me.lblInfo.Location = New System.Drawing.Point(16, 16)
Me.lblInfo.Name = "lblInfo"
Me.lblInfo.Size = New System.Drawing.Size(216, 88)
Me.lblInfo.TabIndex = 0
Me.lblInfo.Text = "Alt-Tab, Alt-Esc, Ctrl-Esc, and the Windows
key are disabled. Ctrl-Alt-Del and Al" & _
"t-F4 are still enabled. Close the application to reset the
keyboard. While this " & _
"program is running, the low-level keyboard effect is
global."
'
'frmMain
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(248, 118)
Me.Controls.AddRange(New System.Windows.Forms.Control()
{Me.lblInfo})
Me.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedDialog
Me.MaximizeBox = False
Me.MinimizeBox = False
Me.Name = "frmMain"
Me.StartPosition =
System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "LowLevel Keyboard Hook"
Me.ResumeLayout(False)

End Sub

#End Region

Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf
LowLevelKeyboardProc,
System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assemb
ly.GetExecutingAssembly.GetModules()(0)).ToInt32(),
0)
End Sub

Private Sub frmMain_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
UnhookWindowsHookEx(intLLKey)
End Sub

Private Function LowLevelKeyboardProc(ByVal nCode As Integer,
ByVal wParam As Integer, ByRef lParam As KBDLLHOOKSTRUCT) As Integer
Dim blnEat As Boolean = False

Debug.WriteLine(nCode.ToString())

Select Case wParam
Case 256, 257, 260, 261
'Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key
blnEat = ((lParam.vkCode = 9) AndAlso (lParam.flags =
32)) Or _
((lParam.vkCode = 27) AndAlso (lParam.flags = 32))
Or _
((lParam.vkCode = 27) AndAlso (lParam.flags = 0))
Or _
((lParam.vkCode = 91) AndAlso (lParam.flags = 1))
Or _
((lParam.vkCode = 92) AndAlso (lParam.flags = 1))
End Select

If blnEat = True Then
Return 1
Else
Return CallNextHookEx(0, nCode, wParam, lParam)
End If
End Function
Friend WithEvents lblInfo As System.Windows.Forms.Label
End Class

hopefully somebody can help me!
thanks daFritz



----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top