系统托盘在我们使用的程序中很普遍,下面我们来看一个很不错的例子,使用Win32 API实现,对理解系统托盘有些帮助。
001 | #include <windows.h> |
002 | #define IDR_PAUSE 12 |
003 | #define IDR_START 13 |
004 | /* |
005 | #include <shellapi.h> |
006 | #pragma comment(lib, "shell32.lib") |
007 | */ |
008 | LPCTSTR szAppName = TEXT( "服务程序" ); |
009 | LPCTSTR szWndName = TEXT( "服务程序" ); |
010 | HMENU hmenu; //菜单句柄 |
011 |
012 | LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
013 | { |
014 | NOTIFYICONDATA nid; |
015 | UINT WM_TASKBARCREATED; |
016 | POINT pt; //用于接收鼠标坐标 |
017 | int xx; //用于接收菜单选项返回值 |
018 |
019 | // 不要修改TaskbarCreated,这是系统任务栏自定义的消息 |
020 | WM_TASKBARCREATED = RegisterWindowMessage(TEXT( "TaskbarCreated" )); |
021 | switch (message) |
022 | { |
023 | case WM_CREATE: //窗口创建时候的消息. |
024 | nid.cbSize = sizeof (nid); |
025 | nid.hWnd = hwnd; |
026 | nid.uID = 0; |
027 | nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; |
028 | nid.uCallbackMessage = WM_USER; |
029 | nid.hIcon = LoadIcon(NULL, IDI_APPLICATION); |
030 | lstrcpy(nid.szTip, szAppName); |
031 | Shell_NotifyIcon(NIM_ADD, &nid); |
032 | hmenu=CreatePopupMenu(); //生成菜单 |
033 | AppendMenu(hmenu,MF_STRING,IDR_PAUSE, "暂停服务" ); //为菜单添加两个选项 |
034 | AppendMenu(hmenu,MF_STRING,IDR_START, "恢复服务" ); |
035 | break ; |
036 | case WM_USER: //连续使用该程序时候的消息. |
037 | if (lParam == WM_LBUTTONDOWN) |
038 | MessageBox(hwnd, TEXT( "Win32 API 实现系统托盘程序,双击托盘可以退出!" ), szAppName, MB_OK); |
039 | if (lParam == WM_LBUTTONDBLCLK) //双击托盘的消息,退出. |
040 | SendMessage(hwnd, WM_CLOSE, wParam, lParam); |
041 | if (lParam == WM_RBUTTONDOWN) |
042 | { |
043 | GetCursorPos(&pt); //取鼠标坐标 |
044 | ::SetForegroundWindow(hwnd); //解决在菜单外单击左键菜单不消失的问题 |
045 | EnableMenuItem(hmenu,IDR_PAUSE,MF_GRAYED); //让菜单中的某一项变灰 |
046 | xx=TrackPopupMenu(hmenu,TPM_RETURNCMD,pt.x,pt.y,NULL,hwnd,NULL); //显示菜单并获取选项ID |
047 | if (xx==IDR_PAUSE) MessageBox(hwnd, TEXT( "111" ), szAppName, MB_OK); |
048 | if (xx==IDR_START) MessageBox(hwnd, TEXT( "222" ), szAppName, MB_OK); |
049 | if (xx==0) PostMessage(hwnd,WM_LBUTTONDOWN,NULL,NULL); |
050 | //MessageBox(hwnd, TEXT("右键"), szAppName, MB_OK); |
051 | } |
052 | break ; |
053 | case WM_DESTROY: //窗口销毁时候的消息. |
054 | Shell_NotifyIcon(NIM_DELETE, &nid); |
055 | PostQuitMessage(0); |
056 | break ; |
057 | default : |
058 | /* |
059 | * 防止当Explorer.exe 崩溃以后,程序在系统系统托盘中的图标就消失 |
060 | * |
061 | * 原理:Explorer.exe 重新载入后会重建系统任务栏。当系统任务栏建立的时候会向系统内所有 |
062 | * 注册接收TaskbarCreated 消息的顶级窗口发送一条消息,我们只需要捕捉这个消息,并重建系 |
063 | * 统托盘的图标即可。 |
064 | */ |
065 | if (message == WM_TASKBARCREATED) |
066 | SendMessage(hwnd, WM_CREATE, wParam, lParam); |
067 | break ; |
068 | } |
069 | return DefWindowProc(hwnd, message, wParam, lParam); |
070 | } |
071 |
072 | int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, |
073 | LPSTR szCmdLine, int iCmdShow) |
074 | { |
075 | HWND hwnd; |
076 | MSG msg; |
077 | WNDCLASS wndclass; |
078 |
079 | HWND handle = FindWindow(NULL, szWndName); |
080 | if (handle != NULL) |
081 | { |
082 | MessageBox(NULL, TEXT( "Application is already running" ), szAppName, MB_ICONERROR); |
083 | return 0; |
084 | } |
085 |
086 | wndclass.style = CS_HREDRAW | CS_VREDRAW; |
087 | wndclass.lpfnWndProc = WndProc; |
088 | wndclass.cbClsExtra = 0; |
089 | wndclass.cbWndExtra = 0; |
090 | wndclass.hInstance = hInstance; |
091 | wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); |
092 | wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); |
093 | wndclass.hbrBackground = ( HBRUSH )GetStockObject(WHITE_BRUSH); |
094 | wndclass.lpszMenuName = NULL; |
095 | wndclass.lpszClassName = szAppName; |
096 |
097 | if (!RegisterClass(&wndclass)) |
098 | { |
099 | MessageBox(NULL, TEXT( "This program requires Windows NT!" ), szAppName, MB_ICONERROR); |
100 | return 0; |
101 | } |
102 |
103 | // 此处使用WS_EX_TOOLWINDOW 属性来隐藏显示在任务栏上的窗口程序按钮 |
104 | hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, |
105 | szAppName, szWndName, |
106 | WS_POPUP, |
107 | CW_USEDEFAULT, |
108 | CW_USEDEFAULT, |
109 | CW_USEDEFAULT, |
110 | CW_USEDEFAULT, |
111 | NULL, NULL, hInstance, NULL); |
112 |
113 | ShowWindow(hwnd, iCmdShow); |
114 | UpdateWindow(hwnd); |
115 |
116 | while (GetMessage(&msg, NULL, 0, 0)) |
117 | { |
118 | TranslateMessage(&msg); |
119 | DispatchMessage(&msg); |
120 | } |
121 | return msg.wParam; |
122 | } |