以前, 看见很多程序有这个功能,觉得这个功能太好了.并且很cool.
只需要在Today界面上点击这个图标,你的应用程序就会弹出来,实在是一个不错的功能.相当于桌面上的最大化和最小化.
相信在桌面上解决这个问题实在是easy,本质上是加个托盘图标.
切换到正题上来.
如何加入?查了一下.net cf库,你会发现没有提供相应的类以及函数.不过不要紧,如果有Windows API的Windows相关编程经验,你会注意到下面的问题还是相对简单的.
查找一下Windows提供的API,你会发现一个一个结构NOTIFYICONDATA.让我们看看这个结构干什么用的.下面的信息来自于MSDN:
NOTIFYICONDATA结构包含了系统处理任务栏状态区域信息的信息.
此结构为:
DWORD cbSize;//结构的大小
HWND hWnd; //于任务栏图标相关的窗体句柄
UINT uID; //任务栏图标的应用程序定义的标志符.
UINT uFlags; //包含有效数据的标记
UINT uCallbackMessage; //回调消息的标志符
HICON hIcon; //图标的句柄
WCHAR szTip[64]; //tips
} NOTIFYICONDATA, *PNOTIFYICONDATA;
看了这个结构,就知道大概意思了.注意到此结构需要窗体的句柄,图标的句柄,以及事件的标志.有了这3个家伙,我们就可以实现了.
那么哪一个函数调用此结构呢?答案是Shell_NotifyIcon,看看Shell_NotifyIcon的定义(MSDN):
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
此方法有2个参数,前者指定发送的消息值它有3种消息: NIM_ADD,NIM_MODIFY,NIM_DELETE.这些就是对任务栏图标的操作.第二个参数就是NOTIFYICONDATA的指针形式.
怎么样,知道怎么做了吧.
好了,说了这么多开始实现它吧.
首先写写NotifyIcon类吧,它用来增加和删除任务栏的图标.代码如下:
/// IconNotify class, is used to add/remove the icon in Today screen.Also can send a notification to application.
/// </summary>
public class IconNotify
{
//Declare click event
public event System.EventHandler Click;
private WindowSink windowSink;
private int uID = 5000;
//Constructor
public IconNotify()
{
//Create instance of the MessageWindow subclass
windowSink = new WindowSink(this);
windowSink.uID = uID;
}
//Destructor
~IconNotify()
{
Remove();
}
public void Add(IntPtr hIcon)
{
TrayMessage(windowSink.Hwnd, NIM_ADD, (uint)uID, hIcon);
}
public void Remove()
{
TrayMessage(windowSink.Hwnd, NIM_DELETE, (uint)uID, IntPtr.Zero);
}
public void Modify(IntPtr hIcon)
{
TrayMessage(windowSink.Hwnd, NIM_MODIFY, (uint)uID, hIcon);
}
private void TrayMessage(IntPtr hwnd, int dwMessage, uint uID, IntPtr hIcon)
{
NOTIFYICONDATA notdata = new NOTIFYICONDATA();
notdata.cbSize = 152;
notdata.hIcon = hIcon;
notdata.hWnd = hwnd;
notdata.uCallbackMessage = WM_NOTIFY_TRAY;
notdata.uFlags = NIF_MESSAGE | NIF_ICON;
notdata.uID = uID;
int ret = Shell_NotifyIcon(dwMessage, ref notdata);
}
#region API Declarations
internal const int WM_LBUTTONDOWN = 0x0201;
//User defined message
internal const int WM_NOTIFY_TRAY = 0x0400 + 2001;
internal const int NIM_ADD = 0x00000000;
internal const int NIM_MODIFY = 0x00000001;
internal const int NIM_DELETE = 0x00000002;
const int NIF_MESSAGE = 0x00000001;
const int NIF_ICON = 0x00000002;
/// <summary>
/// Contains information that the system needs to process taskbar status area messages.
/// </summary>
internal struct NOTIFYICONDATA
{
/// <summary>
/// Size of this structure, in bytes.
/// </summary>
internal int cbSize;
internal IntPtr hWnd;
internal uint uID;
internal uint uFlags;
internal uint uCallbackMessage;
internal IntPtr hIcon;
}
[DllImport("coredll.dll")]
internal static extern int Shell_NotifyIcon(
int dwMessage,ref NOTIFYICONDATA pnid);
[DllImport("coredll.dll")]
internal static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("coredll.dll")]
internal static extern int ShowWindow(
IntPtr hWnd,
int nCmdShow);
[DllImport("coredll.dll")]
internal static extern IntPtr GetFocus();
#endregion
}
但是看了上面的代码,总觉得少了一点什么东西似的,对,那就是消息的触发.那么点击了任务栏的图标之后如何触发事件呢?首先我们得实现Tray Icon(托盘图标)事件,在此事件里,需要更进一步的实现WM_LBUTTONDOWN事件.但是如何实现了呢?幸运的是.net cf提供了一个Microsoft.WindowsCE.Forms.Message类,它提供了托管消息与非托管消息的交互.这样就好办了.代码如下:
internal class WindowSink : Microsoft.WindowsCE.Forms.MessageWindow
{
//Private members
private int m_uID = 0;
private IconNotify notifyIcon;
//Constructor
public WindowSink(IconNotify notIcon)
{
notifyIcon = notIcon;
}
public int uID
{
set
{
m_uID = value;
}
}
protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message msg)
{
if (msg.Msg == WM_NOTIFY_TRAY)
{
if((int)msg.LParam == WM_LBUTTONDOWN)
{
if ((int)msg.WParam == m_uID)
{
//If somebody hooked, raise the event
if (notifyIcon.Click != null)
notifyIcon.Click(notifyIcon, null);
}
}
}
}
}
#endregion
FAQ:
1)如何得到窗体的句柄?
调用FindWindow()方法.具体参见MSDN.
2)如何调用Icon的句柄?
调用LoadIcon().具体参见MSDN.
3)如何加入点击消息?
实现NotifyIcon.Click事件.
4)如何得到里面的常数?
2种方法:1是直接根据MSDN在VC下的头文件里找.2是调用API Text Viewer工具.不过以上2种方法都需要你安装VS98.
参考:http://www.microsoft.com/downloads/details.aspx?FamilyId=5A8384C0-34A5-47D1-BB50-E5E261288AE3&displaylang=en
以上大部分代码来自此.