探討三個實用的 C++/MFC 技術細節:未引用參數抑制警告、向任務欄按鈕右鍵選單添加自訂命令、MFC 系統命令路由機制。
最高警告等級 /W4 會報告未使用的參數(C4100)。兩種常見抑制方法:
#define UNREFERENCED_PARAMETER(P) (P)
int SomeFunction(int arg1, int arg2)
{
UNREFERENCED_PARAMETER(arg2); // 展開為 "arg2;",無副作用,無代碼生成
return arg1 + 5;
}
適用於必須符合 API 簽名(如 MFC OnSize(UINT nType, int cx, int cy))但不使用某參數的情況。
void CMyWnd::OnSize(UINT /* nType */, int cx, int cy) { ... }
使參數無名,編譯器不再警告。但若參數在 _DEBUG 區塊(如 ASSERT)中被使用,Release 建構時會再次觸發警告,此時必須用宏。
#pragma warning(push)
#pragma warning(disable: 4100)
void SomeFunction(int arg1, int arg2) { ... }
#pragma warning(pop)
適用於大範圍抑制,MFC 大量使用此法。
任務欄按鈕右鍵選單即視窗的系統選單(同標題列圖示右鍵或 Alt+Space)。
圖 1:系統選單
透過 GetSystemMenu(FALSE) 取得選單指標,AppendMenu 添加項目。但 MFC 預設不處理系統選單命令(屬 WM_SYSCOMMAND 非 WM_COMMAND)。
自訂類 CSysCmdRouter 繼承 CSubclassWnd,子類化主框架,攔截 WM_SYSCOMMAND:
WM_COMMAND,進入 MFC 標準命令路由(可由 View、Document、App 等處理)。同時攔截 WM_INITMENUPOPUP,清除 bSysMenu 標誌,使 ON_UPDATE_COMMAND_UI 對系統選單項也生效(啟用/停用、打勾)。
int CMainFrame::OnCreate(...)
{
CMenu* pMenu = GetSystemMenu(FALSE);
pMenu->AppendMenu(MF_STRING, ID_MYCMD1, "My Command 1");
pMenu->AppendMenu(MF_STRING, ID_MYCMD2, "My Command 2");
m_sysCmdHook.Init(this); // 啟用路由
return 0;
}
之後即可用標準 ON_COMMAND/ON_UPDATE_COMMAND_UI 處理 ID_MYCMD1/2。
圖 3:任務欄選單效果
IBM 工程師 David J. Bradley 設計。需兩手操作防誤觸,原為開發人員秘密重啟鍵,後成「三指敬禮」喚出任務管理器。
本文配套原始碼含 CSysCmdRouter 完整實作與測試程式 TBMenu。