I am trying to make a program that will be able to detect keyloggers on my system by installing a global hook on WH_DEBUG. My problem is, that GetModuleHandle (and - it seems - all of the other, more obscure ways of getting the module handle) return with null. I was hoping that someone here would be able to shed some light on the situation.
MainForm.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace MouseTimer
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
public static void log(String ltxt)
{
((MainForm)Application.OpenForms[0]).richTextBox1.Text += ltxt+"\n";
((MainForm)Application.OpenForms[0]).richTextBox1.SelectionStart = ((MainForm)Application.OpenForms[0]).richTextBox1.Text.Length;
((MainForm)Application.OpenForms[0]).richTextBox1.ScrollToCaret();
}
public int DbgEvt(int code, IntPtr wParam, IntPtr lParam)
{
log("DBGEVT: "+wParam.ToString());
return 0;
}
void MainFormLoad(object sender, EventArgs e)
{
WindowsHook wh = new WindowsHook(HookType.WH_DEBUG, DbgEvt);
wh.Install();
}
}
}
WindowsHook.cs:
public class WindowsHook
{
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
protected IntPtr m_hhook = IntPtr.Zero;
protected HookProc m_filterFunc = null;
protected HookType m_hookType;
public delegate void HookEventHandler(object sender, HookEventArgs e);
public event HookEventHandler HookInvoked;
protected void OnHookInvoked(HookEventArgs e)
{
if (HookInvoked != null)
HookInvoked(this, e);
}
public WindowsHook(HookType hook)
{
m_hookType = hook;
m_filterFunc = new HookProc(this.CoreHookProc);
}
public WindowsHook(HookType hook, HookProc func)
{
m_hookType = hook;
m_filterFunc = func;
}
protected int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
return CallNextHookEx(m_hhook, code, wParam, lParam);
HookEventArgs e = new HookEventArgs();
e.HookCode = code;
e.wParam = wParam;
e.lParam = lParam;
OnHookInvoked(e);
return CallNextHookEx(m_hhook, code, wParam, lParam);
}
public void Install()
{
using (Process p = Process.GetCurrentProcess())
using (ProcessModule m = p.MainModule)
{
m_hhook = SetWindowsHookEx(m_hookType, m_filterFunc,
GetModuleHandle(m.ModuleName), 0);
}
}
public void Uninstall()
{
UnhookWindowsHookEx(m_hhook);
m_hhook = IntPtr.Zero;
}
public bool IsInstalled
{
get{ return m_hhook != IntPtr.Zero; }
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
protected static extern IntPtr SetWindowsHookEx(HookType code,
HookProc func,
IntPtr hInstance,
int threadID);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
protected static extern int UnhookWindowsHookEx(IntPtr hhook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
protected static extern int CallNextHookEx(IntPtr hhook,
int code, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
The thing is, when I try a (low-level) mouse hook, it hooks just fine without the module handle. So I'm not sure what the problem is. Can anyone help?
Thanks in advance,
Mike
Global hooks are not supported for .Net.
See here: http://support.microsoft.com/kb/318804?wa=wsignin1.0
From which I quote:
Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL
low-level hook, you cannot implement global hooks in the Microsoft
.NET Framework. To install a global hook, a hook must have a native
DLL export to inject itself in another process that requires a valid,
consistent function to call into. This behavior requires a DLL export.
The .NET Framework does not support DLL exports. Managed code has no
concept of a consistent value for a function pointer because these
function pointers are proxies that are built dynamically.
Related
I have a problem that when executing this code in my winform application, it runs normally but when running on the console it gets an error message, it seems that KeyEventHandler is only used in winform, yes What can be replaced in the console application. Here is my hook function:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace Websevice_Core_Console
{
class Y2KeyboardHook
{
#region Win32 API Functions and Constants
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
KeyboardHookDelegate lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string lpModuleName);
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x101;
#endregion
private KeyboardHookDelegate _hookProc;
private IntPtr _hookHandle = IntPtr.Zero;
public delegate IntPtr KeyboardHookDelegate(int nCode, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardHookStruct
{
public int VirtualKeyCode;
public int ScanCode;
public int Flags;
public int Time;
public int ExtraInfo;
}
#region Keyboard Events
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion
// destructor
~Y2KeyboardHook()
{
Uninstall();
}
public void Install()
{
_hookProc = KeyboardHookProc;
_hookHandle = SetupHook(_hookProc);
if (_hookHandle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
private IntPtr SetupHook(KeyboardHookDelegate hookProc)
{
IntPtr hInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
}
private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
KeyboardHookStruct kbStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
if (wParam == (IntPtr)WM_KEYDOWN)
{
if (KeyDown != null)
KeyDown(null, new KeyEventArgs((Keys)kbStruct.VirtualKeyCode));
}
else if (wParam == (IntPtr)WM_KEYUP)
{
if (KeyUp != null)
KeyUp(null, new KeyEventArgs((Keys)kbStruct.VirtualKeyCode));
}
}
return CallNextHookEx(_hookHandle, nCode, wParam, lParam);
}
public void Uninstall()
{
UnhookWindowsHookEx(_hookHandle);
}
}
}
Here is how I use it:
_y2KeyboardHook.KeyDown += (sender, e) =>// ghi nhan thong tin tu ban phim
{
if (e.KeyCode.ToString() != "")
{
Console.WriteLine("Hello "+KeyCode);
}
}
I got an error message on 2 lines
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
Can anyone help me, thanks a lot!
Given the code you posted and the vague "I got an error message" (which is not an actual question nor a useful problem statement…always be specific), it seems likely you are not referencing System.Windows.Forms.dll. On the other hand, if you aren't referencing the Winforms assembly, it's not clear why you don't also get an error where you use KeyEventArgs, since that's defined in the same assembly.
That said, assuming the error you're getting for your use of KeyEventHandler is simply that it's not defined, you can define the same type for your own use:
public delegate void KeyEventHandler(object sender, KeyEventArgs e);
I.e., just copy the delegate type declaration from the documentation.
Now, all that said, if you aren't referencing the Winforms assembly, and you are getting an error message as expected with the KeyEventArgs type as well, as would be expected, you might want to consider not copying the Winforms implementation of this approach, and just declaring your own event args type with your own event handler. The only thing you're returning is the virtual key code, so you might as well define your own types for that:
class KeyboardHookEventArgs : EventArgs
{
public int VirtualKeyCode { get; }
public KeyboardHookEventArgs(int virtualKeyCode)
{
VirtualKeyCode = virtualKeyCode;
}
}
…then the events:
public event EventHandler<KeyboardHookEventArgs> KeyDown;
public event EventHandler<KeyboardHookEventArgs> KeyUp;
Where you create the args object like new KeyboardHookEventArgs(kbStruct.VirtualKeyCode) instead.
Note that your event-raising implementation is not thread-safe. It would be more safe, and more idiomatic in C#, to use the null-conditional operator, e.g.:
if (wParam == (IntPtr)WM_KEYDOWN)
{
KeyDown?.Invoke(this, new KeyboardHookEventArgs(kbStruct.VirtualKeyCode));
}
You should also pass a correct value for sender, i.e. this as I've shown above. If you want for the event to have no sender, then it (and the rest of the class) should just be static.
HI i have a following code that reads mouse event
using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
public enum MouseKeyType
{
MouseMoveOnly=512,
MouseLeftKeyDown=513,
MouseLeftKeyup=514,
MouseRightKeyDown = 516,
MouseRightKeyup = 517,
MouseMiddleKeyDown = 519,
MouseMiddleKeyup = 520,
MouseScroll=522
}
[StructLayout(LayoutKind.Sequential)]
public class MouseEventData
{
public Point point;
private int mouseData;
private int flags;
public int time;
//public int dwExtraInfo;
public bool IsScrollUp
{
get
{
return mouseData > -1;
}
}
public MouseKeyType mouseKeyType;
}
public class gc
{
// Event
public delegate void gcMouseEvents(object source, MouseEventData e);
public event gcMouseEvents gcevent;
// WIN32 hook
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int SetWindowsHookEx( int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
//just a delegate to simplify the type of
private delegate int HookProc(int nCode,int wParam, IntPtr lParam);
private HookProc _hookCallback;
public gc()
{
_hookCallback = new HookProc((x,y,z)=>
{
//string output = JsonConvert.SerializeObject(ptr);
//Console.WriteLine(output);
if (gcevent!=null)
{
MouseEventData ptr = (MouseEventData)Marshal.PtrToStructure(z, typeof(MouseEventData));
ptr.mouseKeyType = (MouseKeyType)y;
gcevent(this, ptr);
}
return 0;
});
SetWindowsHookEx(
14,
_hookCallback,
Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
0);
}
}
This seems to work fine in a form application when code placed in that project. BUt when code is placed in an console library and and a reference added then it dosent work..
I tried adding dlls to windows form etc and played with static etc but nothing seems to work when its
placed in a dll
I'm creating a desktop UWP app and I need to set a global low level mouse hook to detect and change the position of it when it is moved to certain locations of the screen.
It works fine while my app's window is in focus and the values get logged correctly to the output window(meaning that the hook is working correctly).
This UWP app isn't going to be on the store and will only be used on a Windows 10 desktop (1903+).
I've tried calling SetWindowsHookEx on a different thread (which didn't do anything).
Tried also passing a thread ID when calling SetWindowsHookEx to no avail.
Also tried using the following restricted capabilities to prevent the app to suspend when not on focus: extendedExecutionUnconstrained and extendedBackgroundTaskTime along with the PreventFromSuspending method shown here.
Another thing I tried was to set uiAccess to true on the app manifest, which also didn't work.
The global hook is supposed to work even when the app isn't in the foreground, but instead it just works when it has the active window focus.
#region Structures
[StructLayout(LayoutKind.Sequential)]
/* MSLLHOOKSTRUCT */
public struct NativeMouseLowLevelHook
{
public override string ToString()
{
return $"{nameof(Point)}: {Point}, {nameof(MouseData)}: {MouseData}, {nameof(Flags)}: {Flags}";
}
public NativePoint Point;
public int MouseData;
public int Flags;
public int Time;
public UIntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public class NativePoint
{
public override string ToString()
{
return $"{nameof(X)}: {X}, {nameof(Y)}: {Y}";
}
public int X;
public int Y;
}
#endregion
#region Hook
public class ManagedMouseHook : SafeHandleZeroOrMinusOneIsInvalid
{
public static List<ManagedMouseHook> KnownHooks { get; set; } = new List<ManagedMouseHook>();
public HookProc HookImpl { get; set; }
public ManagedMouseHook() : base(true)
{
Hook();
}
private void Hook()
{
HookImpl = NativeHookCallback;
KnownHooks.Add(this);
using (var curProcess = Process.GetCurrentProcess())
using (var curModule = curProcess.MainModule)
{
DoHook(curModule);
}
}
private void DoHook(ProcessModule curModule)
{
SetHandle(SetWindowsHookEx(14 /*WH_MOUSE_LL*/, HookImpl, GetModuleHandle(curModule.ModuleName), 0));
}
private bool UnHook()
{
var result = UnhookWindowsHookEx(DangerousGetHandle());
KnownHooks.Remove(this);
HookImpl = null;
return result;
}
/* LowLevelMouseProc */
private IntPtr NativeHookCallback(int code, IntPtr wparam, IntPtr lparam)
{
if (code >= 0)
{
var info = (NativeMouseLowLevelHook) Marshal.PtrToStructure(lparam,
typeof(NativeMouseLowLevelHook));
Debug.WriteLine(info); //Output example: Point: X: 408, Y: 535, MouseData: 0, Flags: 0
return new IntPtr(-1);
}
return CallNextHookEx(IntPtr.Zero, code, wparam, lparam);
}
protected override bool ReleaseHandle()
{
return UnHook();
}
}
#endregion
#region Interop
public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, ulong dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,
IntPtr lParam);
#endregion
Then, to start using it:
public ManagedMouseHook MouseHook { get; set; }
MouseHook/*property*/ = new ManagedMouseHook();
And to unhook:
MouseHook/*property*/.Close();
UWP apps are running in the sandbox, so that doesn't sound strange. If you think a bit it is a security problem if the app can receive such an input and as 'Security' is listed as No.1 characteristic of the UWP this behavior is expected.
I've decided with the help of the comments that the best way to do this is to use my UWP app as a front-end and using a win32 app for the hooking functionality itself.
I'm using the following code trying to get OS wide keyboard inputs with no luck:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
while(true)
continue;
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine(vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
HookCallback is simply not being called. I have a suspicion it's trying to listen only to a form which doesn't exist rather than running system wide.
Low-level Windows hooks internally use Windows messaging. The thread that calls SetWindowsHookEx must have the message loop in the end, which allows to call HookCallback function. In C++ message loop looks like this:
MSG msg;
BOOL result;
for (;;)
{
result = GetMessage(&msg, nullptr, 0, 0);
if (result <= 0)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Find all required PInvoke definitions for GetMessage, TranslateMessage, DispatchMessage and MSG, translate this code to C# and place it instead of your endless loop while(true). You can find all this stuff at PInvoke.Net, see also this Microsoft forum discussion:
Console keyboard hook not getting called
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ed5be22c-cef8-4615-a625-d05caf113afc/console-keyboard-hook-not-getting-called?forum=csharpgeneral
I'm obviously very late but just hoping I could help (if the OP haven't have yet the help he/she needed) so I'm posting my answer.
It says in the MSDN documentation that when you want to set a system-wide hook, you must give the hMod parameter a
handle to the DLL containing the hook procedure pointed to by the lpfn
parameter
and
If the dwThreadId parameter is zero or specifies the identifier of a
thread created by a different process, the lpfn parameter must point
to a hook procedure in a DLL
but, look at this:
SetWindowsHookEx(2, kbdHookProc, GetModuleHandle("user32"), 0)
kbdHookProc is a function in my C# winforms application but the value I gave in the hMod parameter is the hinstance obtained by loading user32.dll via GetModuleHandle. I am using the keyboard hook (WH_KEYBOARD) to monitor locking of capslock, numlock and scroll lock keys. Don't ask me why I did that and would it work or why it works because I don't know but, yes, IT WORKS!
For a full answer to this;
As Alex says, you'll need a message loop to process windows messages and call your hooks,
public class MessageLoop
{
[DllImport("user32.dll")]
private static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,
uint wMsgFilterMax);
[DllImport("user32.dll")]
private static extern bool TranslateMessage([In] ref MSG lpMsg);
[DllImport("user32.dll")]
private static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
IntPtr hwnd;
uint message;
UIntPtr wParam;
IntPtr lParam;
int time;
POINT pt;
int lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
X = x;
Y = y;
}
public static implicit operator System.Drawing.Point(POINT p)
{
return new System.Drawing.Point(p.X, p.Y);
}
public static implicit operator POINT(System.Drawing.Point p)
{
return new POINT(p.X, p.Y);
}
public override string ToString()
{
return $"X: {X}, Y: {Y}";
}
}
private Action InitialAction { get; }
private Thread? Thread { get; set; }
public bool IsRunning { get; private set; }
public MessageLoop(Action initialAction)
{
InitialAction = initialAction;
}
public void Start()
{
IsRunning = true;
Thread = new Thread(() =>
{
InitialAction.Invoke();
while (IsRunning)
{
var result = GetMessage(out var message, IntPtr.Zero, 0, 0);
if (result <= 0)
{
Stop();
continue;
}
TranslateMessage(ref message);
DispatchMessage(ref message);
}
});
Thread.Start();
}
public void Stop()
{
IsRunning = false;
}
}
I use a separate thread here to avoid blocking the main thread.
The InterceptKeys class as shown in the question needs no modification;
class InterceptKeys
{
// ...
public static void Main()
{
var loop = new MessageLoop(() => {
_hookID = SetHook(_proc);
});
while (Console.ReadKey(true) != ConsoleKey.X) // For exemplary purposes
{
continue;
}
loop.Stop();
}
// ...
}
I had been working on a key-logger in C#, windows forms, and I'm stuck up on some point.When I run my code, it works fine and records 20-25 keystrokes, but after that the program suddenly crashes and these are the error messages shown: (the first one completely stumps me)
1.A callback was made on a garbage collected delegate of type 'karan_keylogger!karan_keylogger.Form1+LowLevelKeyboardProc::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
2.Then it shows 'Object Reference not set to an instance of the object.(Iam familiar with this one)
Code is as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Timers;
using System.Diagnostics;
namespace karan_keylogger
{
public partial class Form1 : Form
{
KeysConverter kc;
private delegate IntPtr LowLevelKeyboardProc(int nc,IntPtr wparam,IntPtr lparam);
//private static LowLevelKeyboardProc keyhook = detect;
StreamWriter sw;
private const int WM_KEYDOWN = 0x0100;
bool shiftDown, inBetween, numLockPressed;
string currWindow, prevWindow,path;
IntPtr x;
[DllImport("User32.dll")]
public static extern int GetWindowText(int hwnd, StringBuilder s, int nMaxCount);
[DllImport("User32.dll")]
public static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public Form1()
{
InitializeComponent();
kc = new KeysConverter();
path="E:\\data.txt";
shiftDown = false;
//shiftUp = true;
inBetween = false;
numLockPressed = false;
currWindow = getTitle();
prevWindow = currWindow;
File.SetAttributes(path,FileAttributes.Normal);
sw = new StreamWriter(path, true);
sw.AutoFlush = true;
sw.WriteLine("Time: "+DateTime.Now.ToShortTimeString()+" Date: "+DateTime.Now.ToShortDateString()+" Window: "+currWindow+"- ");
File.SetAttributes(path, FileAttributes.Hidden | FileAttributes.ReadOnly);
LowLevelKeyboardProc keyhook = new LowLevelKeyboardProc(detect);
Process curProcess = Process.GetCurrentProcess();
ProcessModule curModule = curProcess.MainModule;
//private delegate IntPtr LowLevelKeyboardProc(int nc,IntPtr wparam,IntPtr lparam);
x = SetWindowsHookEx(13, keyhook, GetModuleHandle(curModule.ModuleName),0);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnhookWindowsHookEx(x);
}
private string getTitle()
{
int handle = GetForegroundWindow();
StringBuilder sb = new StringBuilder(1000);
GetWindowText(handle, sb, 1000);
string winText = sb.ToString();
return winText;
}
private IntPtr detect(int ncode, IntPtr wparam, IntPtr lparam)
{
// logic for keystroke storing
return CallNextHookEx(x, ncode, wparam, lparam);
}
}
}
Any help would be really appreciated, this is a pet project!..
As the error message says, unmanaged code will not keep managed resources alive. You're creating a local variable, keyhook and passing it to SetWindowHookEx (i.e. into unmanaged code).
Then you exit your constructor, the keyhook variable goes out of scope, from your code's point of view it's no longer referenced anywhere, and that means it's ready for garbage collection. But the unmanaged code will keep using it. When the garbage collector sets in, the delegate is lost, and you'll get the error message.
Simply declare your delegate as a class member, rather than a local variable.
private LowLevelKeyboardProc keyhook;
Make keyhook a member of your form instead of a local var in the constructor
public partial class Form1: Form
{
LowLevelKeyboardProc keyhook;
public Form1()
{
keyhook = new LowLevelKeyboardProc(detect);
}
}