前言:你可以把這篇文章定義為一篇蛋疼的文章,應為這個東西不怎麼實用,還費神,沒事折騰這做什麼。恩,的確,蛋疼。我也同意,就算蛋疼也有它的小眾範圍,當你不想做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進去也蛋疼下吧!
附加題:還有一個小蛋疼的地方,就是後台運行,從工作列隱藏,只留托盤表徵圖,自己思考下吧,都可以實現。