Я пытаюсь изящно закрыть мое консольное приложение vb.net при завершении работы Windows. Я нашел примеры, которые вызывают Win32-функцию SetConsoleCtrlHandler, которые в основном выглядят так:
Module Module1
Public Enum ConsoleEvent
CTRL_C_EVENT = 0
CTRL_BREAK_EVENT = 1
CTRL_CLOSE_EVENT = 2
CTRL_LOGOFF_EVENT = 5
CTRL_SHUTDOWN_EVENT = 6
End Enum
Private Declare Function SetConsoleCtrlHandler Lib "kernel32" (ByVal handlerRoutine As ConsoleEventDelegate, ByVal add As Boolean) As Boolean
Public Delegate Function ConsoleEventDelegate(ByVal MyEvent As ConsoleEvent) As Boolean
Sub Main()
If Not SetConsoleCtrlHandler(AddressOf Application_ConsoleEvent, True) Then
Console.Write("Unable to install console event handler.")
End If
'Main loop
Do While True
Threading.Thread.Sleep(500)
Console.WriteLine("Main loop executing")
Loop
End Sub
Public Function Application_ConsoleEvent(ByVal [event] As ConsoleEvent) As Boolean
Dim cancel As Boolean = False
Select Case [event]
Case ConsoleEvent.CTRL_C_EVENT
MsgBox("CTRL+C received!")
Case ConsoleEvent.CTRL_BREAK_EVENT
MsgBox("CTRL+BREAK received!")
Case ConsoleEvent.CTRL_CLOSE_EVENT
MsgBox("Program being closed!")
Case ConsoleEvent.CTRL_LOGOFF_EVENT
MsgBox("User is logging off!")
Case ConsoleEvent.CTRL_SHUTDOWN_EVENT
MsgBox("Windows is shutting down.")
' My cleanup code here
End Select
Return cancel ' handling the event.
End Function
Это работает нормально, пока я не включу его в существующую программу, когда я получу это исключение:
Обнаружен CallbackOnCollectedDelegate. Сообщение: обратный вызов был выполнен для делегата типа «AISLogger! AISLogger.Module1 + ConsoleEventDelegate :: Invoke» со сборкой мусора. Это может вызвать сбои приложения, повреждение и потерю данных. При передаче делегатов неуправляемому коду они должны поддерживаться управляемым приложением до тех пор, пока не будет гарантировано, что они никогда не будут вызваны.
Большой поиск указывает на то, что проблема вызвана тем, что объект делегата не упоминается, поэтому он выходит за пределы области видимости и, таким образом, удаляется сборщиком мусора. Кажется, это подтверждается добавлением GC.Collect в основной цикл в приведенном выше примере и получением того же исключения при закрытии окна консоли или нажатии ctrl-C. Проблема в том, что я не понимаю, что имеется в виду под «ссылкой на делегата»? Для меня это звучит как присвоение переменной функции ??? Как я могу сделать это в VB? Есть много примеров этого на C #, но я не могу перевести их на VB.
Спасибо.