Не удалось установить WindowsWookEx в .NET 4.0 на 32-разрядной машине с «модулем не найден»?

Я нашел похожие вопросы на этой странице, но я не могу понять, как интерпретировать ответы или выяснить, действительно ли они дублируют друг друга.

Вот возможные дубликаты, которые я нашел, с комментариями:

SetWindowsHookEx возвращает 0 при компиляции для .NET 4.0 framework на 32-битных машинах

Похоже, он не возвращает 0, но я заметил, что дескриптор, сообщаемый при сбое (.NET 4.0 на 32-битной), сильно отличается от дескриптора, сообщаемого при запуске (.NET 3.5 на 32-битной), как ручка аварии = 523727 и рабочая ручка = 172738378.

Вызов SetWindowsHookEx внутри отладчика VS2008 всегда возвращает NULL

Я могу воспроизвести мою проблему при запуске вне Visual Studio

Модуль не найден

Это кажется наиболее многообещающим, за исключением того, что в комментариях к удаленному ответу упоминается, что я должен использовать LoadLibrary и GetProcAddress для загрузки user32.dll в .NET 4.0, поскольку что-то в загрузке сборок изменилось. Я, однако, уверен, что это мой собственный модуль, который он не может найти, но я не знаю, применимо ли это.

В комментариях к удаленному ответу Ханса Пассанта об этом последнем ответе говорится:

Вы используете .NET 4.0? Его CLR изменил способ загрузки сборок, больше нет вызова LoadLibrary, для них не будет дескриптора модуля. Использование GetEntryAssembly () вместо этого было бы другим исправлением. - Ганс Пассант 5 мая в 19:43

Итак, что здесь за слово? Вы используете .NET 4.0? Вы пытались использовать LoadLibrary ("user32.dll"), чтобы получить полезный дескриптор DLL? - Ганс Пассант 6 мая в 15:43

Я уверен, что мне не нужно этого делать, но, очевидно, я не уверен на 100%. Вопрос, который мне оставляют, если мне нужно изменить это, почему он работает на 64-битной ОС, когда скомпилирован дляAny CPU, но не работает на 32-битной, в любой конфигурации.

Если действительно что-то изменилось в отношении загрузки сборок .NET, так что я не могу правильно описать библиотеку классов, у меня есть следующие вопросы:

Есть ли способ, как я могу обмануть это, делая то, что я хочу, без необходимости переходить на .NET 3.5 или изменять библиотеку подключений на неуправляемую?Почему это работает при работе на 64-битной ОС, а не на 32-битной?

Фон

Я создал программу в .NET 4.0, которая использует SetWindowsHookEx с типом ловушки WH_KEYBOARD_LL для захвата нажатий клавиш. Это хорошо работает на моей 64-битной Windows 7, но вылетает с «модулем не найден», когда клавиатура подключена на 32-битной Windows 7.

Вот что я попробовал:

Скомпилируйте для x86, запустите на 64-битной ОС, вылетает с "модулем не найден"Скомпилировать для x86, запустить на 32-битной ОС, вылетаетКомпиляция для любого процессора, работает на 64-битной ОС, работает хорошоКомпилировать для любого процессора, работать на 32-битной ОС, вылетаетПереключитесь на .NET 3.5 и повторите вышеописанные четыре случая, все они работают

Я бы предпочел не переключать свой код на .NET 3.5, так как я использую несколько своих библиотек классов для облегчения работы, а последний код только в .NET 4.0.

Вы можетескачайте .ZIP-файл со всем, как проект Visual Studio 2010 если хотите, или вы можете вставить следующие два файла.

Чтобы восстановить, если вы хотите пойти по этому маршруту:

Создайте новый консольный проект .NET 4.0Добавьте еще один проект библиотеки классов, также .NET 4.0Добавить ссылку на проект библиотеки классов из проекта консольной программыВставьте содержимое Program.cs ниже в файл Program.cs, который есть в консольном проекте.Вставьте содержимое Hook.cs ниже в файл в проекте библиотеки классов. Вы можете вставить его в файл Class1.cs по умолчанию или добавить другой файл. Выне могу положить это в консольный проект

Затем соберите и запустите, протестируйте различные конфигурации.

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);
    }
}

Ответы на вопрос(3)

Ваш ответ на вопрос