如何在 Windows 关机时正常关闭控制台应用程序 [英] How to Close Console Application Gracefully on Windows Shutdown

查看:55
本文介绍了如何在 Windows 关机时正常关闭控制台应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Windows 关闭时正常关闭我的 vb.net 控制台应用程序.我找到了调用 Win32 函数 SetConsoleCtrlHandler 的示例,它们基本上都如下所示:

I am trying to close my vb.net console app gracefully when windows shutdown occurs. I have found examples that call the Win32 function SetConsoleCtrlHandler that all basically look like this:

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

这很好用,直到我将它合并到我现有的程序中,当我遇到这个异常时:

This works fine until I incorporate it into muy existing program when I get this exception:

CallbackOnCollectedDelegate 被检测到消息:对类型为AISLogger!AISLogger.Module1+ConsoleEventDelegate::Invoke"的垃圾回收委托进行了回调.这可能会导致应用程序崩溃、损坏和数据丢失.将委托传递给非托管代码时,托管应用程序必须使它们保持活动状态,直到保证它们永远不会被调用.

CallbackOnCollectedDelegate was detected Message: A callback was made on a garbage collected delegate of type 'AISLogger!AISLogger.Module1+ConsoleEventDelegate::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

大量搜索表明问题是由未引用委托对象引起的,因此超出范围,因此被垃圾收集器处理.这似乎是通过在上面的示例中将 GC.Collect 添加到主循环中并在关闭控制台窗口或按 ctrl-C 时获得相同的异常来确认的.问题是,我不明白引​​用委托"是什么意思?对我来说,这听起来像是将变量分配给函数???我怎样才能在VB中做到这一点?有很多 C# 示例,但我无法将它们翻译成 VB.

Much searching indicates that the problem is caused by the the delegate object not being referenced and so is going out of scope and so being disposed of by the garbage collector. This seems to be confirmed by adding a GC.Collect into the main loop in the example above and getting the same exception when closing the console window or pressing ctrl-C. The trouble is, I don't understand what is meant by 'referencing the delegate'? This sounds to me like assigning a variable to a function??? How can I do this in VB? There are lots of C# examples of this but I can't translate them into VB.

谢谢.

推荐答案

    If Not SetConsoleCtrlHandler(AddressOf Application_ConsoleEvent, True) Then

这句话会让你陷入困境.它即时创建一个委托实例并将其传递给非托管代码.但是垃圾收集器无法看到该非托管代码持有的引用.你需要自己存储它,这样它就不会被垃圾收集.让它看起来像这样:

This is the statement that gets you into trouble. It creates a delegate instance on-the-fly and passes it to unmanaged code. But the garbage collector cannot see the reference held by that unmanaged code. You'll need to store it yourself so it won't be garbage collected. Make that look like this:

Private handler As ConsoleEventDelegate

Sub Main()
    handler = AddressOf Application_ConsoleEvent
    If Not SetConsoleCtrlHandler(handler, True) Then
       '' etc...

handler 变量现在保持对它的引用,并在程序的生命周期内保持引用,因为它是在模块中声明的.

The handler variable now keeps it referenced and does so for the life of the program since it is declared in a Module.

顺便说一句,您无法取消关闭,但这是另一个问题.

You cannot cancel a shutdown btw, but that's another issue.

这篇关于如何在 Windows 关机时正常关闭控制台应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆