Exception caused by anonymous method
Problem: I recently compiled a low-level keyboard hook, usingC #Production, so we useWin32 API. However, exceptions may occur in the near future due to illegal memory access.
Debugging finds that exceptions cannot be captured.
StaticClassProgram
{
PrivateStaticHooklogHooklog;
/// <Summary>
/// The main entry point for the application.
/// </Summary>
[ Stathread ]
Static Void Main ()
{
Hooklog = New Hooklog ( Form1 . Apppath );
Application . Enablevisualstyles ();
Application . Setcompatibletextrenderingdefault ( False );
Application . Threadexception + = New System. Threading. threadexceptioneventhandler (application_threadexception );
Application . Run (New Form1 ());
}
StaticVoidApplication_threadexception (Object sender, system. Threading. threadexceptioneventargs E)
{
Hooklog. logexceptioninfo (E. Exception );
}
}
Exception occurs inApplication. Run (New form1 ())OfCodeLine.
The prompt is:HookprocThe callback function is released. So I understood what was going on.
Where,HookprocIs a declared delegate callback type:
Public Delegate Intptr Hookproc(IntNcode,IntptrWparam,IntptrLparam );
This type is consistentWindowsThe callback Letter of the hook is consistent with the prototype.
Hook installation function:
Public VoidSetup ()
{
If(Handle! =Intptr. Zero)
Return;
Using(ProcessProcess =Process. Getcurrentprocess ())
{
Using(ProcessmoduleModule = process. mainmodule)
{
// Handle = WIN32API. setwindowshookex (windowshooktypes. wh_keyboard_ll,
// New hookproc (processkeyevent), WIN32API. getmodulehandle (module. modulename), // 0 );
Handle =WIN32API. Setwindowshookex (Windowshooktypes. Wh_keyboard_ll,
Kbdhookproc,WIN32API. Getmodulehandle (module. modulename), 0 );
If(Handle! =Intptr. Zero)
WIN32API. Messagebeep (Messagebeeptypes. Iconexclamation );
}
}
}
The code that causes exceptions is highlighted in green. Because anonymous delegation is directly used. That is, the generated object is a temporary object,New hookproc (processkeyevent)This object is not saved. Therefore, for the part of the managed code, the delegate callback object will exist as a temporary variable.
However, by callingWin32 API --- setwindowshookexThe object is passed to the unmanaged code. In this way, a problem occurs. The managed code section recycles the most temporary object of the object because it is found that it is not referenced anywhere in the managed code. The unmanaged code will still call this callback, because it cannot know that the hosted code has released this pointer. This is why an out-of-bounds access exception cannot be captured shortly after running.
Modify the following line of code to be commented out,ProgramIt is normal.
Handle =WIN32API. Setwindowshookex (Windowshooktypes. Wh_keyboard_ll,Kbdhookproc,WIN32API. Getmodulehandle (module. modulename), 0 );
CodeKbdhookprocIs a member variable declared in the class:
/// <Summary>
/// Keyboard hook callback function
/// </Summary>
Private Hookproc Kbdhookproc;
/// <Summary>
/// Constructor
/// </Summary>
Public Lowlevelkeboardhook ()
{
Disposed = False ;
Handle = Intptr . Zero;
Kbdhookproc = New Hookproc (processkeyevent );
}
/// <Summary>
/// Keyboard hook processing function
/// </Summary>
Private Intptr Processkeyevent ( Int Ncode, Intptr Wparam, Intptr Lparam)
{
KBDLLHOOKSTRUCT ? RFS = Marshal . Ptrtostructure (lparam, Typeof ( KBDLLHOOKSTRUCT )) As KBDLLHOOKSTRUCT ?;
If (Keyboardevent! = Null & RFS. hasvalue)
{
Int Tag = wparam. toint32 ();
If (TAG = ( Int )Windowsmessagetypes . Wm_keydown | tag = ( Int ) Windowsmessagetypes . Wm_syskeydown)
Keyboardevent (ncode, RFS. value. vkcode, RFS. value. Flags );
}
Return WIN32API . Callnexthookex (handle, ncode, wparam, lparam );
}
In this way, it does not seem to change much. However, the class member variables remember this callback delegate object, so it will not be recycled by garbage collection.
Therefore, when using anonymous functions, anonymous delegation, and anonymous temporary objects, you must be extremely careful when it comes to unmanaged code.