c#-4.0 - lowlevelkeyboardproc - c# keyboard hook
SetWindowsHookEx devuelve 0 al compilar para el marco.NET 4.0 en máquinas de 32 bits (4)
Estoy tratando de establecer un gancho de teclado de Windows de bajo nivel para tomar tres teclas presionadas incluso si la aplicación no está enfocada. Para hacer esto, estoy llamando a SetWindowsHookEx como
// Create an instance of HookProc.
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
//install hook
hKeyboardHook = SetWindowsHookEx(
WH_KEYBOARD_LL,
KeyboardHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
//If SetWindowsHookEx fails.
if (hKeyboardHook == 0)
{
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
Stop(false, true, false);
//Initializes and throws a new instance of the Win32Exception class with the specified error.
throw new Win32Exception(errorCode);
}
Esto solía funcionar en máquinas de 32 bits y 64 bits con .NET Framework 3.5, pero después de actualizar a .NET Framework 4.0 dejó de funcionar en máquinas de 32 bits.
¿Alguien sabe cómo resolver esto para poder usar el Framework 4.0 y hacer que esto funcione tanto en máquinas de 32 bits como de 64 bits?
De la documentación para SetWindowsHookEx
hMod [en]
HINSTANCE
Un identificador para el archivo DLL que contiene el procedimiento de enlace apuntado por el parámetro lpfn. El parámetro hMod debe establecerse en NULL si el parámetro dwThreadId especifica un subproceso creado por el proceso actual y si el procedimiento de enlace está dentro del código asociado con el proceso actual.
Entonces deberías pasar IntPtr.Zero por NULL
//install hook
hKeyboardHook = SetWindowsHookEx(
WH_KEYBOARD_LL,
KeyboardHookProcedure,
IntPtr.Zero,
0);
Lo resolvió seleccionando cada plataforma por separado. VS configurado para compilar tanto una versión de Win32 como una de Win64 y desplegar en las máquinas x86 y x64 su correspondiente binario.
El Win32 o x86 se ejecuta en máquinas de 32 bits y 64 bits.
importar el dll de esta manera:
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
luego usa
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName)
para reemplazar
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]
Cualquier manejador de módulo funcionará, ya que en realidad no se usa para los enganches de bajo nivel, no es necesario inyectar DLL para que funcionen. Se requiere cierto cuidado en la selección de .NET 4 ya que su CLR ya no simula los identificadores de módulo para ensamblajes administrados puros. Uno bueno para usar es el que obtienes de pinvoking LoadLibrary ("user32.dll") ya que siempre está cargado. No tiene que llamar a FreeLibrary ().
Necesitarás esta declaración para llamar a LoadLibrary:
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Auto)] private static extern IntPtr LoadLibrary(string fileName);