2010-08-25 45 views
6

J'essaie de définir un crochet de clavier Windows de bas niveau pour saisir trois touches enfoncées même si l'application n'est pas mise au point. Pour ce faire, je vous appelle SetWindowsHookEx commeSetWindowsHookEx renvoie 0 lors de la compilation pour l'infrastructure .NET 4.0 dans les machines 32 bits

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

Cela permet de travailler sur des machines 32bits et 64bits en utilisant le .NET Framework 3.5, mais après mise à niveau vers le .NET Framework 4.0 ne fonctionne plus sur les machines 32bits.

Est-ce que quelqu'un sait comment résoudre ceci afin que je puisse utiliser le Framework 4.0 et le faire fonctionner sur les machines 32 bits et 64 bits?

+1

Dans .NET 4.0, SetWindowsHookEx retourne 0 pour moi avec une erreur de procédure Hook non valide. – tofutim

Répondre

21

importer le dll comme ceci:

[DllImport("kernel32.dll")] 
    public static extern IntPtr GetModuleHandle(string name); 

puis utilisez

GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName) 

pour remplacer

Marshal.GetHINSTANCE(
    Assembly.GetExecutingAssembly().GetModules()[0] 
+1

Avait le même problème et la solution était le changement de code suggéré, en utilisant GetModuleHandle (...) pour obtenir le handle. – user2928227

+0

Merci. Cela a fonctionné parfaitement pour moi. Je n'obtenais pas le module principal. Je recevais le module actuel et il retournait 0. –

+0

Même problème ici.Écriture d'un gestionnaire de fenêtres rapide afin que je puisse appuyer sur une touche, faire glisser un rectangle sur l'écran, et que la fenêtre s'aligne sur elle. Dug up un vieux module "GlobalHooks" j'ai écrit il ya des siècles pour. NET 2.0, et découvert que SetWindowsHookEx échouait avec zéro. Cela a résolu le problème. J'ai également noté que je devais boucler toutes les clés appelant GetAsyncKeyState, plutôt que de simplement faire un seul appel à GetKeyboardState, parce qu'il échoue avec des problèmes de threading, comme s'il n'obtiendrait pas les états de touches de modification correctement quand d'autres applications sont au premier plan. GetAsyncKeyState doit être utilisé. – Triynko

1

Résolu en ciblant chaque plate-forme séparément. Configuré VS pour compiler à la fois une version Win32 et Win64 et déployer sur les machines x86 et x64 leur binaire correspondant.

Le Win32 ou le x86 s'exécute sur les machines 32 bits et 64 bits.

2

De la documentation de SetWindowsHookEx

hMod [en]
HINSTANCE
Une poignée à la DLL contenant la procédure de raccordement pointée par le paramètre lpfn. Le paramètre hMod doit être défini sur NULL si le paramètre dwThreadId spécifie un thread créé par le processus en cours et si la procédure de hook se trouve dans le code associé au processus en cours.

Donc, vous devriez être de passage dans IntPtr.Zero pour NULL

//install hook 
    hKeyboardHook = SetWindowsHookEx(
    WH_KEYBOARD_LL, 
    KeyboardHookProcedure, 
    IntPtr.Zero, 
    0); 
0

Hans Passant:

Toute poignée du module fera car il ne soit pas réellement utilisé pour crochets de bas niveau, pas besoin DLL à injecter pour les faire fonctionner. Certains soin dans la sélection d'un est nécessaire pour .NET 4 depuis son CLR ne plus falsifie les poignées de module pour les assemblages gérés pure. Un bon à utiliser est celui que vous obtenez de pinvoking LoadLibrary ("user32.dll") puisqu'il est toujours déjà chargé. Vous n'êtes pas obligé d'appeler FreeLibrary().

Vous aurez besoin de cette déclaration pour appeler LoadLibrary:

[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Auto)] 
private static extern IntPtr LoadLibrary(string fileName);