SetWindowsHookEx in .NET 4.0 auf 32-Bit-Computer mit "Modul nicht gefunden" fehlgeschlagen?

Ich habe auf dieser Seite ähnliche Fragen gefunden, kann aber nicht herausfinden, wie die Antworten zu interpretieren sind, oder herausfinden, ob es sich wirklich um Duplikate handelt.

Hier sind die möglichen Duplikate, die ich mit Kommentaren gefunden habe:

SetWindowsHookEx gibt 0 zurück, wenn für das .NET 4.0-Framework auf 32-Bit-Computern kompiliert wird.

s scheint bei mir keine 0 zurückzugeben, aber ich habe festgestellt, dass das Handle, das bei einem Absturz gemeldet wurde (.NET 4.0 auf 32-Bit), sich stark von dem Handle unterscheidet, das bei der Ausführung gemeldet wurde (.NET 3.5 auf 32-Bit). , wie Crash-Handle = 523727 und Working-Handle = 172738378.

Calling SetWindowsHookEx im VS2008-Debugger gibt immer NULL zurück

Ich kann mein Problem erneut anzeigen, wenn es außerhalb von Visual Studio ausgeführt wird.

Module nicht gefunden

Dies scheint am vielversprechendsten, außer dass in den Kommentaren zu der gelöschten Antwort erwähnt wird, dass ich LoadLibrary und GetProcAddress verwenden sollte, um user32.dll in .NET 4.0 zu laden, da sich etwas zum Laden von Assemblys geändert hat. Ich bin mir jedoch ziemlich sicher, dass es mein eigenes Modul ist, das es nicht finden kann, aber ich weiß nicht, ob dies zutrifft.

Die fraglichen Kommentare zu der gelöschten Antwort auf die letzte, von Hans Passant, lauten:

Verwenden Sie .NET 4.0? Die CLR hat die Art und Weise geändert, in der Assemblys geladen werden. Es gibt keinen LoadLibrary-Aufruf mehr und kein Modul-Handle für sie. Die Verwendung von GetEntryAssembly () wäre ein weiterer Fix. - Hans Passant 5. Mai um 19: 43

Also, was ist das Wort hier? Verwenden Sie .NET 4.0? Haben Sie versucht, mit LoadLibrary ("user32.dll") ein verwendbares DLL-Handle zu erhalten? - Hans Passant 6. Mai um 15: 43

Ich bin mir ziemlich sicher, dass ich das nicht tun muss, aber offensichtlich bin ich mir nicht 100% sicher. Die Frage, die mir bleibt, wenn ich dies ändern muss, ist, warum es unter 64-Bit-Betriebssystemen funktioniert, wenn es für @ kompiliert wurdAny CPU, funktioniert aber in keiner Konfiguration mit 32-Bit.

Wenn sich beim Laden von .NET-Assemblys tatsächlich etwas geändert hat, sodass ich für die Klassenbibliothek kein geeignetes Handle erhalte, habe ich die folgenden Fragen:

Ist es eine Möglichkeit, dies zu tun, was ich will, ohne auf .NET 3.5 downgraden oder die Hook-Bibliothek in nicht verwaltet ändern zu müssen?Warum funktioniert es unter 64-Bit-Betriebssystemen, aber nicht unter 32-Bit-Betriebssystemen?

Hintergrun

Ich habe in .NET 4.0 ein Programm erstellt, das SetWindowsHookEx mit dem Hook-Typ WH_KEYBOARD_LL verwendet, um Tastendrücke zu erfassen. Dies funktioniert gut unter meinem 64-Bit-Windows 7, stürzt jedoch mit einem "nicht gefundenen Modul" ab, wenn der Tastatur-Hook unter 32-Bit-Windows 7 installiert ist.

Hier ist, was ich versucht habe:

Compile for x86, lauffähig unter 64-Bit-Betriebssystemen, stürzt mit "Modul nicht gefunden" abCompile for x86, 32-Bit-Betriebssystem, stürzt abCompile for Any CPU, läuft auf 64-Bit-Betriebssystemen, läuft gutCompile for Any CPU, 32-Bit-Betriebssystem, stürzt abechseln Sie zu .NET 3.5 und wiederholen Sie die obigen vier Fälle. Sie funktionieren all

Ich würde meinen Code lieber nicht auf .NET 3.5 umstellen, da ich einige meiner Klassenbibliotheken verwende, um die Arbeit zu erleichtern. Der neueste Code ist nur in .NET 4.0 verfügbar.

Du kannstdownload einer .ZIP-Datei mit allem, was als Visual Studio 2010-Projekt vorliegt, wenn Sie möchten, oder Sie können die folgenden zwei Dateien einfügen.

Um neu zu erstellen, wenn Sie diesen Weg gehen möchten:

Erstelle ein neues Konsolenprojekt, .NET 4.0Füge ein weiteres Klassenbibliotheksprojekt hinzu, ebenfalls .NET 4.0Hinzufügen eines Verweises auf das Klassenbibliotheksprojekt aus dem KonsolenprogrammprojektPaste in den Program.cs-Inhalt unten in die Program.cs-Datei, die du im Konsolenprojekt hastGeben Sie den Inhalt von Hook.cs in eine Datei im Klassenbibliotheksprojekt ein. Sie können es in die Standarddatei Class1.cs einfügen oder eine andere Datei hinzufügen. Dukann nich Setzen Sie dies in das Konsolenprojekt

Testen Sie anschließend die verschiedenen Konfigurationen, und führen Sie sie aus.

Program.cs
using System;
using HookLib;

namespace HookTest
{
    class Program
    {
        static void Main()
        {
            var hook = new Hook();

            Console.Out.WriteLine("hooking");
            hook.Enable();
            Console.Out.WriteLine("hooked");

            Console.Out.WriteLine("unhooking");
            hook.Disable();
            Console.Out.WriteLine("unhooked");
        }
    }
}
Hook.cs
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;

namespace HookLib
{
    public class Hook
    {
        private IntPtr _Handle;
        private HookProcDelegate _Hook;

        public void Enable()
        {
            Module module = Assembly.GetExecutingAssembly().GetModules()[0];
            if (module != null)
                Console.Out.WriteLine("found module");
            IntPtr moduleHandle = Marshal.GetHINSTANCE(module);
            if (moduleHandle != IntPtr.Zero)
                Console.Out.WriteLine("got module handle: " +
                    moduleHandle.ToString());
            _Hook = HookProc;
            _Handle = SetWindowsHookEx(WH_KEYBOARD_LL, _Hook, moduleHandle, 0);
            if (_Handle == IntPtr.Zero)
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        public void Disable()
        {
            bool ok = UnhookWindowsHookEx(_Handle);
            _Handle = IntPtr.Zero;
            if (!ok)
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        private delegate int HookProcDelegate(
            int code, IntPtr wParam, IntPtr lParam);

        private int HookProc(int code, IntPtr wParam, IntPtr lParam)
        {
            return CallNextHookEx(_Handle, code, wParam, lParam);
        }

        private const int WH_KEYBOARD_LL = 13;

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(
            int hookType, HookProcDelegate lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int CallNextHookEx(
            IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
    }
}

Antworten auf die Frage(6)

Ihre Antwort auf die Frage