8

Using code to hook the console close event from this thread, I sometimes get a NullReferenceException with no stacktrace (most of the times I don't). It happens in both release and debug and "break when an exception is thrown" doesn't help (it breaks, but the stack trace is still empty). I never get this exception when I exit my application normally (which is hitting enter and thus releasing a Console.ReadLine). The Application event log has 2 entries:

Application: MyApp.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.NullReferenceException Stack:

And:

Faulting application name: Gateway.exe, version: 1.0.0.0, time stamp: 0x4e284101 Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000 Exception code: 0xc0000005 Fault offset: 0x004d41ce Faulting process id: 0xf00 Faulting application start time: 0x01cc47b827e19a6e Faulting application path: C:\dev\MyApp.exe Faulting module path: unknown Report Id: 689c1caa-b3ab-11e0-ba1b-00247e777f12

Google has revealed some bugs and issues with SetConsoleCtrlHandler, so I'm wondering if this is a lost battle.

Community
  • 1
  • 1
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198

2 Answers2

14

The most typical issue with code like that is not keeping a reference to the delegate instance. The one you pass as the first argument to SetConsoleCtrlHandler(). The garbage collector cannot see references held to a delegate object by unmanaged code. So this will, eventually, bomb when the garbage collector runs:

 SetConsoleCtrlHandler(Handler, true);

which is the exact same thing as

 SetConsoleCtrlHandler(new EventHandler(Handler), true);

assuming you used the types in the linked code. The author of that code carefully avoided this issue by making _handler a static variable. As opposed to the temporary delegate instance that is created by the previous two lines of code. Storing it in a static variable ensures it stays referenced for the life of the program. The Right Thing to do in this particular case since you are actually interested in the events until the program ends.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • This makes a lot of sense, as I was sometimes getting "Attempted to read or write protected memory". I was actually using your code :) http://stackoverflow.com/questions/4646827/on-exit-for-a-console-application/4647168#4647168 – Ohad Schneider Jul 22 '11 at 03:20
  • That's about the value of one of the ~hundred fifty beers I've been promised. It's yours, cheers. – Hans Passant Jul 22 '11 at 03:58
  • Cheers ! I'll accept as soon as I test in the office tomorrow :) – Ohad Schneider Jul 22 '11 at 04:19
  • This just saved me from many hours debugging, probably. Thanks! – Joost May 06 '13 at 21:36
0

For the vb.net bods who are struggling with this, my code is ...

'declaration
Private Declare Function SetConsoleCtrlHandler Lib "kernel32" (ByVal handlerRoutine As ConsoleEventDelegate, ByVal add As Boolean) As Boolean
Public Delegate Function ConsoleEventDelegate(ByVal [event] As ConsoleEvent) As Boolean

'The close function...
Public Function Application_ConsoleEvent(ByVal [event] As ConsoleEvent) As Boolean
    Console.WriteLine("We're closing it all down: ")
    Return False
End Function

'creating the handler. 
If Not SetConsoleCtrlHandler(New ConsoleEventDelegate(AddressOf Application_ConsoleEvent), True) Then
    Console.WriteLine("Unable to install console event handler.")
    Exit Sub
End If
seanyboy
  • 5,623
  • 7
  • 43
  • 56