-1

请在我的代码中尝试捕获 win32.systemevents.sessionended 事件,以便在会话结束时继续保存我的应用程序数据,以防应用程序未手动关闭.. 前一段时间这一直在工作,现在我有了我的项目长大了,它不再是..?几天来我一直试图找到一些有意义的东西,但实际上什么也没找到。当我尝试捕捉另一个像 MonitorResolutionChanged 这样的系统事件时,它运行良好,但这个不是。我也尝试在 mainWindow 中注册(应用程序表单..),什么都没有看到更多.. 非常感谢 Tomas 我的代码:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
using MovablePython; // my own class within this project
using Avn; //my own referenced assembly 

namespace DirDist
{
     class Program
    {
        private static string appGuid = "Cddbserviceman";
        private static System.Windows.Forms.ContextMenu nIMenu;
        internal static System.Windows.Forms.NotifyIcon notifyIcon1;
        private static MenuItem showItem;
        public static MenuItem justCDsItem;
        private static MenuItem searchItem;
        private static MenuItem settingsItem;
        private static MenuItem quitItem;

        internal static Form1 mainWindow;
        private static Hotkey hk;
        internal static Registration.LicenceState mode; // app mode - registered/trial/blocked/demaged ..
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        { 
            using (Mutex mutex = new Mutex(false, appGuid))
            {
                if (!mutex.WaitOne(0, false))
                {
                    MessageBox.Show("CDDB is already running on your machine \n  (Check status bar for access ..)");
                    return;
                }
                GC.Collect();

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                mode = Registration.Startup();

                Program.mainWindow = new Form1();
                mainWindow.Activate();
                //mainWindow.Validate();
                //mainWindow.Update();
                mainWindow.Visible = false;
                PutIcon();

                //Microsoft.Win32.SystemEvents.SessionEnded += SystemEvents_SessionEnded;
                Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);//**zkousime zda funguje pro hibernaci ..
                RegisterHotKey(true);   
                Application.Run();
            }   
        }

        static void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
        {
            //MessageBox.Show("SessionEnded fired");

            RegisterHotKey(false);

            notifyIcon1.Visible = false;
            notifyIcon1.Dispose();
            notifyIcon1 = null;


            if (!mainWindow.dBSaved) mainWindow.SaveDb(Form1.settings.dBPath);
            if (mainWindow.index != null) mainWindow.SaveIndex(Form1.settings.indexPath);
            Microsoft.Win32.SystemEvents.SessionEnded -= new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
            mainWindow.Close();
        }

        // zaregistruje globalni hotkey ctrl+shift+F Pro hledani
        private static void RegisterHotKey(bool active)
        {
            if (!active)
            {
                if (hk != null) hk.Unregister();
            }
            else
            {
                if(hk ==null) hk = new Hotkey();

                hk.KeyCode = Keys.F;
                //hk.Windows = true;
                hk.Shift = true;
                hk.Control = true;
                //hk.Pressed += delegate { Console.WriteLine("Windows+1 pressed!"); };
                hk.Pressed += delegate { searchItemClick(new object(), new EventArgs()); };

                if (hk.GetCanRegister(mainWindow)) hk.Register(mainWindow);
                else ; // just do nothing
            }
        }

        private static void PutIcon()
        {
            if (notifyIcon1 == null)
            {   
                showItem = new MenuItem ("&Show interface", new System.EventHandler (showInfaceClick));
                justCDsItem = new MenuItem ("&Jus'CDs",new System.EventHandler ( justCDsClick));
                justCDsItem.Checked = Form1.settings.justCDs;
                searchItem = new MenuItem("Search CDDB",new System.EventHandler (searchItemClick));
                searchItem.Shortcut = Shortcut.CtrlShiftF;
                searchItem.ShowShortcut = true;
                settingsItem = new MenuItem("Settings", new System.EventHandler(settingsItemClick));
                quitItem = new MenuItem("&Quit", new System.EventHandler(quitItemClick));

                nIMenu = new System.Windows.Forms.ContextMenu(new MenuItem[5] { showItem, justCDsItem, searchItem,settingsItem, quitItem });


                notifyIcon1 = new System.Windows.Forms.NotifyIcon();
                notifyIcon1.ContextMenu = nIMenu;
                notifyIcon1.Icon = new System.Drawing.Icon(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Icon1.ico");
                //notifyIcon1.Icon = new System.Drawing.Icon(System.IO.Path.GetDirectoryName( 
                //System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase ) + "Icon1.ico");
                //notifyIcon1.Icon = new System.Drawing.Icon("Icon1.ico");
                notifyIcon1.DoubleClick += new EventHandler(notifyIcon1_DoubleClick);
                notifyIcon1.Visible = true;
            }
        }

        /* private static void notifyIcon1_MouseMove(object sender, MouseEventArgs mea)
         * aby to fungovalo je treba upravit contextmenu na contextmenustrip a taky ty items .. az nakonec
         * je tu kolem uz rozdelana priprava ..
        {
            notifyIcon1.ShowBalloonTip(2000,AppName,"Active",ToolTipIcon.None);
        } */

        // clicks on NotificationIcon context menu ..
        private static void showInfaceClick(object sender, EventArgs e)
        {
            mainWindow.tabControl1.SelectedIndex = 0;
            mainWindow.Show();
        }

        private static void justCDsClick(object sender, EventArgs e)
        {
            Form1.settings.justCDs = mainWindow.checkBox1.Checked = justCDsItem.Checked = !Form1.settings.justCDs;
            if (mainWindow.Visible) mainWindow.Update();
        }

        private static void searchItemClick(object sender, EventArgs e)
        {
            mainWindow.tabControl1.SelectedIndex = 1 ;
            //this.Size = new Size(this.Width, SystemInformation.PrimaryMonitorSize.Height);
            mainWindow.Location = new System.Drawing.Point(SystemInformation.PrimaryMonitorSize.Width - mainWindow.Width, SystemInformation.PrimaryMonitorSize.Height - mainWindow.Height);
            //mainWindow.Location = new System.Drawing.Point(880, 500);
            mainWindow.Show();
        }

        private static void settingsItemClick(object sender, EventArgs e)
        {
            mainWindow.tabPage3_GotFocus(new Object(), new EventArgs());
            mainWindow.tabControl1.SelectedIndex = 2;
            mainWindow.Show();
        }

        public static void quitItemClick(object sender, EventArgs e)
        {
            if (DialogResult.Cancel == MessageBox.Show("Really exit application and stop scanning?",Form1.AppName,MessageBoxButtons.OKCancel,MessageBoxIcon.Question)) return;
            if (!mainWindow.dBSaved) mainWindow.SaveDb(Form1.settings.dBPath);
            //if (mainWindow.index != null) mainWindow.SaveIndex(Form1.settings.indexPath);
            if (Form1.settings.fileIndex) mainWindow.SaveIndex(Form1.settings.indexPath);
            mainWindow.Close();
            mainWindow = null;
            notifyIcon1.Visible = false;
            Application.Exit();
        }

        static void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            //if (!mainWindow.Visible) mainWindow.WindowState = FormWindowState.Normal; else mainWindow.WindowState = FormWindowState.Minimized;
            //if (!mainWindow.Visible) mainWindow.Show(); else mainWindow.Hide();
            if (!mainWindow.Visible) mainWindow.Visible = true; else mainWindow.Visible = false;      
        }
    }
}
4

2 回答 2

5

好的。所以这是捕获和解决方案。在 Windows 中,不确定是 win32.systemevents.sessionended 应该被提升还是 form.close() 会被操作系统首先调用。此外,如果首先调用 form.close() ,则即使由于取消关闭过程而没有关闭和处置表单,也会省略 sessionended。在我的系统中,当我运行一些注册表清理软件后,这种行为发生了变化。无论如何理解这一点,我们必须照顾这两种可能的情况。1. 捕捉 win32.systemevents.sessionended(或 sessionending)事件,无论什么更适合我们的需求,并且是

 .
    .
   [STAThread]
    static void Main()
    { 
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);

            Program.mainWindow = new Form1();
            mainWindow.Activate();
            mainWindow.Visible = false;
            PutIcon();           
            RegisterHotKey(true);   
            Application.Run();
        }   
    }

    public static void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
    {
        // do whatever needed and exit application ..
        RegisterHotKey(false);
        notifyIcon1.Visible = false;
        notifyIcon1.Dispose();
        notifyIcon1 = null;


        if (!mainWindow.dBSaved) mainWindow.SaveDb(Form1.settings.dBPath);
        if (mainWindow.index != null) mainWindow.SaveIndex(Form1.settings.indexPath);
        Microsoft.Win32.SystemEvents.SessionEnded -= new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);

        if (mainWindow != null)
        {
            mainWindow.Dispose();
            mainWindow = null;
        }
        Application.Exit();
    }

2. 正确覆盖 form.OnClosing(),因为当用户或系统在关闭、注销等时手动关闭表单或为主表单创建 hanler 时,会调用此函数。关闭:

 public Form1()
    {
        this.Closing += new CancelEventHandler(this.Form1_Closing);
        InitializeComponent();
    }

    private void Form1_Closing(Object sender, CancelEventArgs e)
            {
                if (systemShutdown) Program.SystemEvents_SessionEnded(this, new Microsoft.Win32.SessionEndedEventArgs(Microsoft.Win32.SessionEndReasons.SystemShutdown));
                else
                {
                    e.Cancel = true;
                    this.Hide();
                }
            }

只想提一下,必须运行消息泵才能启动会话。Application.run() 实现了这一点。

在我的情况下,正如您所看到的,我必须更深入地挖掘,因为我关闭重定向只是为了隐藏应用程序而不是关闭它(我只是将应用程序隐藏到通知 irea 图标并在需要时手动关闭它......)所以我必须使用某种方式来指定调用 this 时的情况,因为 sender 不幸且意外地总是 this ..?这是通过覆盖 WndProc 并捕获 propper 消息来完成的。在这里,您几乎可以收听窗口内的所有内容(例如插入/删除的光盘),但它仅与表单挂钩,并且实现通常不那么简单,因为您必须手动定义各种值和结构并与这些值进行比较..除此之外它非常简单:

private static int WM_QUERYENDSESSION = 0x11;
private static bool systemShutdown = false;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if (m.Msg==WM_QUERYENDSESSION)
    {
        systemShutdown = true;
    }
    base.WndProc(ref m);

}

这是在这里找到的:http: //msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.sessionending.aspx

再想一想,我们可能会省略第 1 点,因为系统可能总是会尝试调用 mainForm.close() 但我保留它,因为一旦它再次以不同的顺序运行这些东西,我就无法确定 Windows 的行为......而且它是对系统关闭做出反应的主要建议解决方案..

希望这对某人有帮助。来自布拉格托马斯的问候

于 2012-12-18T14:38:36.343 回答
1

这是你可以尝试的东西

对于关机,覆盖 OnShutdown 方法:

protected override void OnShutdown()
{
    //your code here
    base.OnShutdown();
}

对于注销:

首先,在 Service Constructor 中向 Microsoft.Win32.SystemEvents.SessionEnded 添加一个事件处理程序:

public MyService()
{
    InitializeComponent;
    Microsoft.Win32.SystemEvents.SessionEnded += new Microsoft.Win32.SessionEndedEventHandler(SystemEvents_SessionEnded);
}

然后添加处理程序:

void SystemEvents_SessionEnded(object sender, Microsoft.Win32.SessionEndedEventArgs e)
{
    //your code here
}

这应该捕获任何结束的会话,包括控制台本身(运行服务的那个)。

于 2012-12-15T17:14:36.753 回答