前言:
你可以把这篇文章定义为一篇蛋疼的文章,应为这个东西不怎么实用,还费神,没事折腾这做什么。恩,的确,蛋疼。我也同意,就算蛋疼也有它的小众范围,当你不想做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进去也蛋疼下吧!
附加题:
还有一个小蛋疼的地方,就是后台运行,从任务栏隐藏,只留托盘图标,自己思考下吧,都可以实现。