Не удалось установить 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.csusing 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.csusing 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);
}
}