Falha no SetWindowsHookEx no .NET 4.0 na máquina de 32 bits com "módulo não encontrado"?

Encontrei perguntas semelhantes nesta página, mas não consigo descobrir como interpretar as respostas ou se são realmente duplicadas.

Aqui estão as possíveis duplicatas que encontrei, com comentários:

SetWindowsHookEx retorna 0 ao compilar para a estrutura .NET 4.0 em máquinas de 32 bits

Parece não retornar 0 no meu, mas notei que o identificador relatado quando falha (.NET 4.0 em 32 bits) é muito diferente do identificador relatado quando é executado (.NET 3.5 em 32 bits), como identificador de falha = 523727 e identificador de trabalho = 172738378.

Chamar SetWindowsHookEx dentro do depurador VS2008 sempre retorna NULL

Posso reprovar meu problema ao executar fora do Visual Studio

Módulo não encontrado

Isso parece muito promissor, exceto que os comentários à resposta excluída mencionam que eu deveria usar o LoadLibrary e o GetProcAddress para carregar o user32.dll no .NET 4.0, pois algo sobre o carregamento de assemblies foi alterado. Tenho certeza, no entanto, de que não é o meu próprio módulo, mas não sei se isso se aplica.

Os comentários em questão sobre a resposta excluída da última, de Hans Passant, diz:

Você está usando o .NET 4.0? Seu CLR mudou a maneira como os assemblies são carregados, não há mais uma chamada LoadLibrary, não haverá identificador de módulo para eles. Usar GetEntryAssembly () seria outra correção. - Hans Passant 5 de maio às 19:43

Então, qual é a palavra aqui? Você está usando o .NET 4.0? Você tentou usar o LoadLibrary ("user32.dll") para obter um identificador de DLL utilizável? - Hans Passant 6 de maio às 15:43

Tenho certeza de que não preciso fazer isso, mas obviamente não tenho 100% de certeza. A pergunta que me resta se precisar alterar isso é por que funciona no sistema operacional de 64 bits, quando compilado paraAny CPU, mas não funciona em 32 bits, em nenhuma configuração.

Se, de fato, algo mudou em relação ao carregamento de assemblies .NET, para que eu não obtenha um identificador adequado para a biblioteca de classes, tenho as seguintes perguntas:

Existe alguma maneira de enganar isso para fazer o que eu quero, sem precisar fazer o downgrade para o .NET 3.5 ou alterar a biblioteca do hook para não gerenciada?Por que funciona ao executar no sistema operacional de 64 bits, mas não no de 32 bits?

fundo

Criei um programa, no .NET 4.0, que usa SetWindowsHookEx com o tipo de gancho WH_KEYBOARD_LL para capturar pressionamentos de tecla. Isso funciona muito bem no meu Windows 7 de 64 bits, mas trava com um "módulo não encontrado" quando o gancho do teclado é instalado no Windows 7 de 32 bits.

Aqui está o que eu tentei:

Compile para x86, execute no SO de 64 bits, trava com o "módulo não encontrado"Compile para x86, execute no SO de 32 bits, travaCompilar para qualquer CPU, rodar em SO de 64 bits, roda bemCompilar para qualquer CPU, executado em SO de 32 bits, falhaAlterne para o .NET 3.5 e repita os quatro casos acima, todos eles funcionam

Prefiro não mudar meu código para o .NET 3.5, pois estou usando algumas das minhas bibliotecas de classes para facilitar o trabalho, e o código mais recente é apenas no .NET 4.0.

Você podebaixe um arquivo .ZIP com tudo como um projeto do Visual Studio 2010 se desejar, ou você pode colar nos dois arquivos a seguir.

Para recriar se você deseja seguir esse caminho:

Crie um novo projeto de console, .NET 4.0Adicione outro projeto de biblioteca de classes, também o .NET 4.0Adicione uma referência ao projeto da biblioteca de classes no projeto do programa de consoleCole o conteúdo Program.cs abaixo no arquivo Program.cs que você possui no projeto do consoleCole o conteúdo do Hook.cs abaixo em um arquivo no projeto da biblioteca de classes. Você pode colá-lo no arquivo padrão Class1.cs ou adicionar outro arquivo. Vocênão podes coloque isso no projeto do console

Em seguida, crie e execute, teste várias configurações.

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

questionAnswers(3)

yourAnswerToTheQuestion