Questa la considero una notizia molto importante, perchè
da quando mi ero messo in testa di realizzare Happy Sign che
volevo riuscirci, e questa mattina ho avuto la soluzione. Dunque, il tema è
quello di realizzare un global hook sulla tastiera.
A cosa serve? Beh, senza scendere troppo in dettaglio, si tratta di un
meccanismo tramite il quale una nostra applicazione può intercettare tutti gli
eventi di tastiera e mouse anche se la nostra applicazione non ha il focus. Il
mio Happy Sign ne aveva bisogno perchè volevo fare in modo di
poter inserire una firma dentro Outlook Express (o Thunderbird, per
par-condicio) semplicemente premendo una combinazione, come Shift+F5, per
esempio. Beh, insomma, sembrava che questa cosa con VS2005 fosse impossibile. Il
codice che avevo usato, o che ho riesumato fuori questa mattina, è il
seguente:
public void Start()
{
// install Keyboard hook
if(hKeyboardHook == 0)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,
KeyboardHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
//If SetWindowsHookEx fails.
if(hKeyboardHook == 0 ) {
Stop();
throw new Exception("SetWindowsHookEx ist failed.");
}
}
}
Questo metodo Start è incluso in una classe apposita
UserActivityHook. Se provate a compilarlo con VS2005, tutto ok.
Ma è in fase di run-time che la chiamata a SetWindowsHookEx
fallisce, e l'hook di fatto non viene installato. La chiamata avviene con i
seguenti parametri:
hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,
KeyboardHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
0);
ovvero:
- una costante WH_KEYBOARD_DLL che ci dice quale hook vogliamo installare.
In questo caso 13.
- un delegate, che ci dice quale funzione viene eseguita quando premiamo un
tasto
- un puntatore all'istanza della nostra applicazione
- l'ID del thread che, non so dettagliare ulteriormente, è 0
Risoluzione
Il codice è corretto, se lo provate con
VS2003, tutto funziona regolarmente. Con VS2005, banalmente, dobbiamo andare
nelle proprietà del progetto, spostarci sotto il tab Debug e
disattivare la CheckBox "Enable the Visual Studio hosting process" (enabled by
default). Questa risposta, arrivata su un mio post del 25/11/2005 sul
newsgroup dotnet.framework.windowsforms di Microsoft, è di un
certo Timm Martin e mi ha permesso, finalmente, di avere
global hook funzionante in un'applicazione C# 2.0!!! Il minimo che posso fare è linkare qua il suo
sito: http://www.mini-tools.com. Grazie, Timm, ovunque tu sia!