2013-07-27 16 views
13

Sto provando a utilizzare la libreria Gma.UserActivityMonitor in un progetto e ho riscontrato un errore che non riesco a superare da solo.Gma.UserActivityMonitor & SetWindowsHookEx error 126

Nel file HookManager.Callbacks.cs c'è un metodo statico chiamato EnsureSubscribedToGlobalMouseEvents con il seguente codice (più o meno):

var asm = Assembly.GetExecutingAssembly().GetModules()[0]; 
var mar = Marshal.GetHINSTANCE(asm); 
s_MouseHookHandle = SetWindowsHookEx(
    WH_MOUSE_LL, 
    s_MouseDelegate, 
    mar, 
    0); 
//If SetWindowsHookEx fails. 
if (s_MouseHookHandle == 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 

    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
    throw new Win32Exception(errorCode); 
} 

Il SetWindowsHookEx restituisce sempre 0 e il codice di cui sopra mantiene un'eccezione con il messaggio The specified module could not be found e la chiamata a Marshal.GetLastWin32Error restituisce il codice 126. Posso eseguire correttamente la demo fornita con il progetto originale di Gma.UserActivityMonitor ma poiché il mio progetto è un po 'troppo complicato da spiegare qui non posso entrare nei dettagli spiegando la sua differenza con il mio. Spero solo che qualcuno possa indovinare il problema.

BTW, nelle Domande frequenti del progetto si dice che altri hanno un problema vicino al mio (con SetWindowsHookEx errore di ritorno) quando lo Enable Visual Studio hosting process viene controllato solo quando il progetto è debuggato. Così ho deselezionato quella casella nella mia e ho ancora lo stesso problema, e non solo in modalità di debug, ma anche quando faccio doppio clic sul file di rilascio in Windows Explorer (non è coinvolto Visual Studio).

Per fornire ulteriori informazioni, nel progetto dimostrativo (che funziona correttamente) la variabile asm punta a {Gma.UserActivityMonitor.dll} e lo stesso nel mio progetto che viene generata l'eccezione!

+0

potrebbe essere correlato alla testimonianza dei processi coinvolti ... – Yahia

+0

Potresti spiegarci di più o indicarmi la risorsa giusta? – Mehran

+0

L'aggancio di solito comporta che alcuni codici diventino parte dei processi di destinazione. Questo può essere ottenuto in modi diversi, ma fondamentalmente qualsiasi differenza nel controllo del processo, i processi collegati e il sistema operativo possono portare a problemi e/o comportamenti erratici. – Yahia

risposta

27

Questo tipo di codice non funziona più su .NET 4 e versioni successive. Il codice di errore che si ottiene è altrimenti descrittivo, 126 = "Impossibile trovare il modulo specificato". Che ti dice che la variabile "mar" contiene spazzatura.

.NET 4 ha avuto un cambiamento CLR piuttosto significativo, non fa più finta che il codice jitted risieda all'interno dei moduli non gestiti. Quindi Marshal.GetHINSTANCE() non funziona più. Il codice diventa quindi sciatto, si dimentica di controllare il valore restituito, testarlo per (IntPtr) -1 è necessario per rilevare l'errore e dichiarare il disastro. Abbastanza comune per il codice che trovi su Codeproject, un sacco di bug e sciatteria che non possono essere risolti dai contributori. Non il modello SO :)

SetWindowsHookEx() è un po 'scomodo per gli hook di basso livello. Richiede un handle di modulo valido e lo controlla, ma in realtà non lo usa. Questo è stato risolto in Windows, da qualche parte intorno a Win7 SP1. Sebbene fosse certamente destinato a essere una soluzione utile, in realtà ha peggiorato il problema. Perché ora potrebbe funzionare sulla tua macchina di sviluppo ma non sulla macchina dell'utente.

Anyhoo, la correzione è semplice, è sufficiente prendere un handle di modulo valido. È possibile ottenere uno da un modulo che è sempre presente in un'applicazione gestita, è necessario pinvoke LoadLibrary per farlo:

var mar = LoadLibrary("user32.dll"); 
s_MouseHookHandle = SetWindowsHookEx(
    WH_MOUSE_LL, 
    s_MouseDelegate, 
    mar, 
    0); 

Non c'è bisogno di chiamare FreeLibrary(), che il modulo rimane caricata fino a quando il programma termina in ogni caso .

+0

Grazie Hans, ha funzionato perfettamente. Voglio solo aggiungere che sono riuscito a trovare il problema. La tua soluzione sarà la soluzione che userò ma volevo solo chiederti i tuoi pensieri sulla mia nuova scoperta, se vuoi. Il problema era che il "target della piattaforma" del mio progetto era impostato su x86 mentre il mio sistema operativo era Windows 7x64. Altre scelte come 'x64' e' Any CPU' funzionano sulla mia macchina, ma la tua soluzione funziona indipendentemente dal 'Target della piattaforma', quindi ho intenzione di andare con quello dato che ho progetti Win32 scritti in C++ nella mia soluzione. Pensi che la tua soluzione sia solida anche in altri sistemi operativi come Windows XP, Vista o Windows 8? – Mehran

+0

Nella risposta ho sottolineato esplicitamente che l'obiettivo era quello di funzionare su qualsiasi versione di Windows. –

+0

Mi dispiace, mi sono perso. Grazie mille. – Mehran