【问题标题】:C# Execute code before application exits for background appC#在后台应用程序退出之前执行代码
【发布时间】:2017-08-30 12:38:08
【问题描述】:

这不是此post 的副本。我从这篇文章中得到了我的解决方案,但它不起作用更不用说我的应用程序是 winforms 应用程序,而不是控制台应用程序。

所以我有一个在后台运行的项目。基本上,我创建了一个 Windows 窗体应用程序,但我没有调用 Program.cs 中的窗体。我创建了一个在应用程序退出时监听的类:

class ShutDownManager
    {
        public ShutDownManager()
        {
            _handler += new EventHandler(Handler);
            SetConsoleCtrlHandler(_handler, true);
        }
        static bool exitSystem = false;


        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

        private delegate bool EventHandler(CtrlType sig);
        static EventHandler _handler;

        enum CtrlType
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT = 1,
            CTRL_CLOSE_EVENT = 2,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT = 6
        }

        private static bool Handler(CtrlType sig)
        {
            Console.Writeline("I'M OUT OF HERE");


            return true;
        }

    }

我在 Program.cs 的 Main 函数中创建了这个类的一个实例。 然而,这似乎没有火。它在控制台应用程序中就像一个魅力,但是当涉及到我的表单应用程序(没有表单)时它不起作用。 可能是什么问题?

我在 Main 中的代码:

static void Main()
{
     ShutDownManager sdm = new ShutDownManager();
     StartUpManager.AddApplicationToCurrentUserStartup();
     Timers timers = new Timers();
}

【问题讨论】:

  • 首先:当您不想使用 winforms 时,为什么要使用 winforms 应用程序?您需要一个 winforms 应用程序与您的控制台应用程序有什么区别?
  • @MightyBadaboom 我希望我的应用程序在后台运行,并且在不调用表单的情况下创建一个 winforms 应用程序会被 windows 自动识别为后台应用程序。
  • 你了解winform事件循环的工作原理吗?你确定SetConsoleCtrlHandler 可以在没有控制台的情况下工作吗?您可以在Main 中显示您的代码吗?
  • 如果该代码在控制台中运行并且您不需要 UI,那么为什么不在后台运行该控制台应用程序。
  • 这是一个非常hacky的方法来创建一个后台程序。我建议查看How to create a Service 以获得实现您想要的“正确”方式。至于在退出前执行代码,请查看this 答案。

标签: c#


【解决方案1】:

让我分解一下您的情况:摘自 docs.microsoft.com on SetConsoleCtrlHandler

每个控制台进程都有自己的应用程序定义的 HandlerRoutine 函数列表,用于处理 CTRL+C 和 CTRL+BREAK 信号。处理函数还处理用户关闭控制台、注销或关闭系统时系统生成的信号。控制台进程通过调用 SetConsoleCtrlHandler 函数添加或删除额外的处理函数,这不会影响其他进程的处理函数列表。

如您所见,这似乎仅指控制台进程。它不能告诉你其他应用程序何时退出,而只能告诉你这个应用程序。此外,它可以通知您LOGOFFSHUTDOWN。此外,由于没有控制台(因为您需要后台进程),因此不涉及 CTRL-C 或 CTRL-BREAK 处理。
结论:最好的情况是您只能通知LOGOFFSHUTDOWN

winforms 应用同一页面的相关信息:

此函数为控制台应用程序和服务提供类似于 WM_QUERYENDSESSION 为图形应用程序提供的通知,并带有消息泵。

 

你的代码有什么问题?

嗯,它的设计目的是在系统有LOGOFFSHUTDOWN 应用程序运行时时提供回调。不用说,您的应用程序已经退出以接收此类事件。所以你必须在注册回调后等待。

 

最好的方法是什么?

您应该为此编写一个服务。如果我没记错的话,服务已经收到LOGOFFSHUTDOWN 的通知 How to write a simple C# service 有一个很好的例子。

编辑:

如需更全面的了解,您可能需要查看MSDN docs about ServiceBase class。此外,您应该查看OnSessionChange 事件,它会收到有关all session events 的通知。它有一些有用的代码摘录在SessionChangeDescription class docOnShutdown event 也是如此

现在如果你不能做 windows 服务,你将不得不从你的 winform 应用程序创建一个Form 并使窗体不可见。然后您应该处理WM_QUERYENDSESSION event 或使用SystemEvents.SessionEnding Event 来处理这种情况

示例代码

var frm = new Form();
frm.Activated += (s, e) => { frm.Visible = false; };
SystemEvents.SessionEnded += (s, e) => { /* your code to handle logoff and shutdown */ };
Application.Run(frm);

【讨论】:

  • 好的,这就解释了为什么我的代码不起作用。但是该应用程序已经部署,Windows Servce 不是一个选项。
  • @user6879072 检查编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多