原文地址: http://hi.baidu.com/biboheart/item/5d17f8068c1c8a9c3c42e2dc
第一步:窗口最小化到托盤,顯示圖標。
這一步在網上一搜,真的很多文章,基本上都可以用吧。有的是在OnSize中最化時畫圖標,隱藏窗口;有的是在初始化時畫圖標,在OnSysCommand中判斷最大化和最小化時進行窗口顯示隱藏。我選擇了后者。一開始在后面的步驟遇到了麻煩,最后第二種方法完成了。諒沒再去試第一種方法。在OnSysCommand中顯示隱藏,效果挺好的。
我的開發環境是VS2008,創建一個對話框應用程序,選中包含最小化框(因為要最小化到托盤)。因為我的程序只是設計成在屏幕右小角顯示一個小窗口來開啟、停止、配置服務的一些操作。所以不要最大化功能。
1、XXXDlg.h中聲明一個方法用作顯示托盤圖標。void _fnToTray();
XXXDlg.cpp中實現如下
//在桌面右下角顯示托盤圖標
void CXXXDlg::_fnToTray()
{
NOTIFYICONDATA nid;
nid.cbSize = sizeof( NOTIFYICONDATA );
nid.hWnd = m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
nid.uCallbackMessage = WM_SYSTEMTRAY;
nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
wcscpy_s(nid.szTip, _T("服務管理器"));
::Shell_NotifyIcon(NIM_ADD,&nid );
}
2、修改CXXXDlg::OnSysCommand(UINT nID, LPARAM lParam)方法,橙色為增加的代碼
void CXXXDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else if(nID == SC_MAXIMIZE) //最大化
{
this->ShowWindow(SW_SHOW);
}
else if(nID == SC_MINIMIZE) //最小化,把他隱藏起來
{
this->ShowWindow(SW_HIDE);
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
3、在資源中新建一個菜單資源,我這里為IDR_MENU1,在菜單中添加一個子菜單,設ID為ID_EXIT,文字為
“退出”。
4、在targetver.h文件中,最后添加一行#define WM_SYSTEMTRAY WM_USER+1
5、在XXXDlg.h文件中,添加方法聲明:
afx_msg LRESULT OnSystemTray(WPARAM wParam, LPARAM lParam);
6、在XXXDlg.cpp文件中,BEGIN_MESSAGE_MAP(CXXXDlg,CDialog)和END_MESSAGE_MAP()之間增加
ON_MESSAGE(WM_SYSTEMTRAY,OnSystemTray)
7、在XXXDlg.cpp文件中,實現方法:
LRESULT CXXXDlg::OnSystemTray(WPARAM wParam, LPARAM lParam)
{
if ( wParam = IDR_MAINFRAME )
{
switch( lParam )
{
case WM_LBUTTONDOWN: //左鍵點擊托盤圖標顯示窗口
this->ShowWindow(SW_NORMAL);
break;
case WM_RBUTTONDOWN: //右鍵點擊托盤圖標顯示菜單
CMenu menu;
menu.LoadMenu(IDR_MENU1);
POINT pt;
::GetCursorPos(&pt);
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTALIGN, pt.x, pt.y, this);
break;
}
}
return 1;
}
8、聲明右鍵菜單:在XXXDlg.h中聲明afx_msg void OnExit();
9、在XXXDlg.cpp中BEGIN_MESSAGE_MAP(CXXXDlg,CDialog)和END_MESSAGE_MAP()之間增加
ON_COMMAND(ID_EXIT,OnExit)
10、在XXXDlg.cpp中實現退出
void CXXXDlg::OnExit()
{
this->PostMessageW(WM_QUIT);
}
11、在程序的OnDestroy()消息中移除圖標
void CXXXDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: 在此處添加消息處理程序代碼
NOTIFYICONDATA nid;
nid.cbSize = sizeof( NOTIFYICONDATA );
nid.hWnd = m_hWnd;
nid.uID = IDR_MAINFRAME;
nid.uFlags = 0;
::Shell_NotifyIcon( NIM_DELETE,&nid );
}
12、一切准備好了。在CXXXDlg::OnInitDialog()中添加
_fnToTray();
//-----------------------氣泡窗體-----------------------------------
void CTimingDlg::ShowInfo()
{
m_Htnd.cbSize = sizeof(NOTIFYICONDATA);
m_Htnd.hWnd = GetSafeHwnd();
m_Htnd.uFlags = NIF_INFO;
m_Htnd.uID=IDR_MAINFRAME;
m_Htnd.dwInfoFlags=1;
m_Htnd.uTimeout = 3000;
wcscpy(m_Htnd.szInfoTitle,_T("氣泡標題"));
wcscpy(m_Htnd.szInfo,_T("氣泡內容"));
Shell_NotifyIcon(NIM_MODIFY,&m_Htnd);
}
//-----------------------------------------------------------------
第二步:在屏幕右下角顯示窗口
這步代碼很少,實現起來簡單。
1、在CXXXDlg.h中聲明一個方法void _fnShowRBOfWindow();
2、實現在CXXXDlg.cpp中
//在桌面右下角顯示
void CCCRFIDServiceManagerDlg::_fnShowRBOfWindow()
{
// 獲得桌面大小
CRect rectWorkArea;
SystemParametersInfo(SPI_GETWORKAREA,0,&rectWorkArea,SPIF_SENDCHANGE);
// 獲得對話框大小
CRect rectDlg;
GetWindowRect(&rectDlg);
int nW = rectDlg.Width();
int nH = rectDlg.Height();
// 將窗口設置到右下角
SetWindowPos(NULL,rectWorkArea.right-nW,rectWorkArea.bottom-nH,nW,nH,SWP_NOSIZE);
}
3、在CXXXDlg::OnInitDialog()中添加
_fnShowRBOfWindow();
這樣就實現了程序窗口顯示在桌面右下角
第三步:實現程序啟動時無窗口、任務欄不顯示。只有在托盤顯示了一個圖標。
這一步如果只是在CXXXDlg.cpp的某處調用ShowWindow(SW_HIDE),不容易實現,實現了也不能得到好的效果,有的會閃一下。最后試下以下方法,運行起來效果挺好。
1、在CXXXApp.h中添加一個變量:CWnd m_wndOwner;
2、在CXXXApp.cpp::InitInstance()中修改添加(橙色為修改內容):
BOOL CCCRFIDServiceManagerApp::InitInstance()
{
// 如果一個運行在 Windows XP 上的應用程序清單指定要
// 使用 ComCtl32.dll 版本 6 或更高版本來啟用可視化方式,
//則需要 InitCommonControlsEx()。否則,將無法創建窗口。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 將它設置為包括所有要在應用程序中使用的
// 公共控件類。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
AfxEnableControlContainer();
// 標准初始化
// 如果未使用這些功能並希望減小
// 最終可執行文件的大小,則應移除下列
// 不需要的特定初始化例程
// 更改用於存儲設置的注冊表項
// TODO: 應適當修改該字符串,
// 例如修改為公司或組織名
SetRegistryKey(_T("應用程序向導生成的本地應用程序"));
if ( m_wndOwner.m_hWnd == NULL )
{
LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
if ( !m_wndOwner.CreateEx(0, pstrOwnerClass, _T(""), //創建一個隱藏的彈出樣式的窗口
WS_POPUP, CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, 0) )
return FALSE;
}
CXXXDlg dlg(&m_wndOwner);
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: 在此放置處理何時用
// “確定”來關閉對話框的代碼
}
else if (nResponse == IDCANCEL)
{
// TODO: 在此放置處理何時用
// “取消”來關閉對話框的代碼
}
if (m_wndOwner.m_hWnd != NULL)
{
m_wndOwner.DestroyWindow();
}
// 由於對話框已關閉,所以將返回 FALSE 以便退出應用程序,
// 而不是啟動應用程序的消息泵。
return FALSE;
}
3、編輯CXXX.rc()查看代碼編輯。找到EXSTYLE WS_EX_APPWINDOW刪除。
4、在CXXXDlg.cpp::OnInitDialog()中添加(在CXXXDlg.h中添加變量WINDOWPLACEMENT m_wp)
m_wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(&m_wp); //恢復時用
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
wp.flags = WPF_RESTORETOMAXIMIZED;
wp.showCmd = SW_HIDE;
SetWindowPlacement(&wp);
在第一步中的OnSystemTray(WPARAM wParam, LPARAM lParam)修改如下:
LRESULT CCCRFIDServiceManagerDlg::OnSystemTray(WPARAM wParam, LPARAM lParam)
{
if ( wParam = IDR_MAINFRAME )
{
switch( lParam )
{
case WM_LBUTTONDOWN:
this->ShowWindow(SW_NORMAL);
SetWindowPlacement(&m_wp);
break;
case WM_RBUTTONDOWN:
CMenu menu;
menu.LoadMenu(IDR_MENU_RBUTTON);
POINT pt;
::GetCursorPos(&pt);
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTALIGN, pt.x, pt.y, this);
break;
}
}
return 1;
}