蛋疼的讓C#控制檯程序(Console)像窗體(Winform)一樣(關閉,托盤圖標,事件響應,手動退出等)

前言:
你可以把這篇文章定義爲一篇蛋疼的文章,應爲這個東西不怎麼實用,還費神,沒事折騰這做什麼。恩,的確,蛋疼。我也同意,就算蛋疼也有它的小衆範圍,當你不想做webservers,winform等,就想蛋疼的拿控制檯來做服務,做程序,行嗎?行,但是控制檯一點關閉就退出了,有時會點錯,控制檯沒有托盤圖標,想最小化到托盤圖標等,還有什麼蛋疼的想法,來吧,讓我們來實現他們。

需要了解:
console application是控制檯程序。
控制檯不是winform,我們不能設置它的關閉事件等。
控制檯雖然可以通過添加引用來增加托盤圖標,但是托盤圖標沒有事件。
哇,怎麼都是不能,那不是不能實現。

所以你還需要了解:
我們可以通過引用外部dll的api來捕獲到關閉事件等。
我們可以給控制檯添加消息事件循環來捕獲事件響應讓托盤圖標可以觸發事件。

那麼我們的思路是:
禁用關閉按鈕,讓用戶在控制檯輸入exit進行退出,當控制檯被其他事件關閉時可以進行處理。
用Application.DoEvents()來捕獲消息事件處理,但是要用死循環來控制,那麼我們怎麼監聽輸入呢?
我們在開一個線程用來監聽輸入。
蛋疼的可以,搞個這還這麼麻煩!

別慌,還需要你解決的問題:
先了解我給出的代碼實現了什麼。實現了禁用關閉按鈕,托盤圖標的添加和事件的處理。
你要做的是什麼,當然你可以不做,如果你也想蛋疼一下,就來解決下這個問題吧。
退出控制檯時,托盤圖標沒有消失,唉,這是bug,怎麼解決?
捕獲關閉事件,在要關閉時清除托盤圖標。
先告訴你可以實現,我以實驗成功,這裏沒有放出來是讓你也蛋疼下。
好了,代碼如下:
/*
 * 控制檯禁用關閉按鈕並最小化到系統托盤演示
 * 
 * 通過ConsoleWin32類來進行控制
 * 添加引用 System.Runtime.InteropServices; 和 System.Threading; 用於禁用關閉按鈕
 * 添加引用 System.Drawing; 和 System.Windows.Forms; 用於系統托盤
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;

namespace Tray_beta_1
{
    class Program
    {
        static bool _IsExit = false;

        static void Main(string[] args)
        {
            Console.Title = "TestConsoleLikeWin32";
            ConsoleWin32Helper.ShowNotifyIcon();
            ConsoleWin32Helper.DisableCloseButton(Console.Title);

            Thread threadMonitorInput = new Thread(new ThreadStart(MonitorInput));
            threadMonitorInput.Start();

            while (true)
            {
                Application.DoEvents();
                if (_IsExit)
                {
                    break;
                }
            }
        }

        static void MonitorInput()
        {
            while (true)
            {
                string input = Console.ReadLine();
                if (input == "exit")
                {
                    _IsExit = true;
                    Thread.CurrentThread.Abort();
                }
            }
        }
    }

    class ConsoleWin32Helper
    {
        static ConsoleWin32Helper()
        {
            _NotifyIcon.Icon = new Icon(@"G:\BruceLi Test\ConsoleAppTest\ConsoleApps\Tray\small.ico");
            _NotifyIcon.Visible = false;
            _NotifyIcon.Text = "tray";

            ContextMenu menu = new ContextMenu();
            MenuItem item = new MenuItem();
            item.Text = "右鍵菜單,還沒有添加事件";
            item.Index = 0;

            menu.MenuItems.Add(item);
            _NotifyIcon.ContextMenu = menu;

            _NotifyIcon.MouseDoubleClick += new MouseEventHandler(_NotifyIcon_MouseDoubleClick);

        }

        static void _NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Console.WriteLine("托盤被雙擊.");
        }

        #region 禁用關閉按鈕
        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "GetSystemMenu")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, IntPtr bRevert);

        [DllImport("user32.dll", EntryPoint = "RemoveMenu")]
        static extern IntPtr RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);

        /// <summary>
        /// 禁用關閉按鈕
        /// </summary>
        /// <param name="consoleName">控制檯名字</param>
        public static void DisableCloseButton(string title)
        {
            //線程睡眠,確保closebtn中能夠正常FindWindow,否則有時會Find失敗。。
            Thread.Sleep(100);

            IntPtr windowHandle = FindWindow(null, title);
            IntPtr closeMenu = GetSystemMenu(windowHandle, IntPtr.Zero);
            uint SC_CLOSE = 0xF060;
            RemoveMenu(closeMenu, SC_CLOSE, 0x0);
        }
        public static bool IsExistsConsole(string title)
        {
            IntPtr windowHandle = FindWindow(null, title);
            if (windowHandle.Equals(IntPtr.Zero)) return false;

            return true;
        }
        #endregion

        #region 托盤圖標
        static NotifyIcon _NotifyIcon = new NotifyIcon();
        public static void ShowNotifyIcon()
        {
            _NotifyIcon.Visible = true;
            _NotifyIcon.ShowBalloonTip(3000, "", "我是托盤圖標,用右鍵點擊我試試,還可以雙擊看看。", ToolTipIcon.None);
        }
        public static void HideNotifyIcon()
        {
            _NotifyIcon.Visible = false;
        }

        #endregion
    }
}
END:
來建立個項目把代碼copy進去也蛋疼下吧!

附加題:
還有一個小蛋疼的地方,就是後臺運行,從任務欄隱藏,只留托盤圖標,自己思考下吧,都可以實現。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章