-1

アプリが手動で閉じられない場合に備えて、私のコードで win32.systemevents.sessionended イベントをキャッチして、セッションの終わりまでにアプリ データの保存を続行してください。プロジェクトは少し成長しましたが、それはもうありません..? 私は数日間意味のあるものを見つけようとしましたが、実際には何も見つかりませんでした.. MonitorResolutionChanged のような別のシステムイベントをキャッチしようとすると、うまくいきますが、これはうまくいきません. また、mainWindow(アプリフォーム..)内に登録しようとしましたが、何もありません:-(何か考えてください?関連するすべての情報は、void Mainまで最初にあるはずですが、必要な場合や必要な場合に備えてすべて入れますもっと見るには..どうもありがとう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() を適切にオーバーライドします。これは、フォームがシャットダウン、ログオフなどの際にユーザーまたはシステムによって手動で閉じられるときに呼び出されるか、メイン form.Closing の 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();
                }
            }

sessionended を開始するには、メッセージ ポンプを実行する必要があることに注意してください。Application.run() はそれを実現します。

私の場合、ご覧のとおり、アプリを閉じないように非表示にするためだけにリダイレクトを閉じていたため、さらに深く掘り下げる必要がありました(アプリを通知イレアアイコンに非表示にし、必要なときに手動で閉じます..)残念ながら、予期せず送信者が常にこれであるため、これが呼び出されたときに状況を指定する何らかの方法を使用する必要がありました..? これは、WndProc をオーバーリングし、適切なメッセージをキャッチすることによって行われます。ここでは、ウィンドウ内のすべて (ディスクの挿入/削除など) をほとんど聞くことができますが、フォームにのみフックされ、さ​​まざまな定義を手動で定義する必要があるため、実装はそれほど単純ではありません。値と構造体を比較し、それらの値と比較します..それ以外は非常に単純です:

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

システムはおそらく常に mainForm.close() を呼び出そうとするため、ポイント 1 を省略できる可能性があります。システムのシャットダウンに対応するために主に提案されているソリューションです..

これが誰かの役に立てば幸いです。プラハ・トーマスからの挨拶

于 2012-12-18T14:38:36.343 に答える
1

ここにあなたが試すことができるものがあります

シャットダウンの場合は、OnShutdown メソッドをオーバーライドします。

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

ログオフの場合:

まず、サービス コンストラクターでイベント ハンドラーを 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 に答える