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

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

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

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

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

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

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

  • Модуль не found

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

Рассматриваемые комментарии к удаленному ответу на последний, Автор Hans Passant, читает:

Вы используете .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 , если хотите, или вы можете вставить следующие два файла.

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

  1. Создайте новый консольный проект, .NET 4.0
  2. Добавьте другой проект библиотеки классов, также .NET 4.0
  3. Добавьте ссылку на проект библиотеки классов из консоли. программный проект
  4. Вставьте содержимое Program.cs ниже в файл Program.cs, который у вас есть в проекте консоли.
  5. Вставьте содержимое 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);
    }
}

14
задан Community 23 May 2017 в 11:53
поделиться