某些專用應用(如自助終端機、工業控制介面、考試系統)需鎖定視窗狀態,防止使用者移動、調整大小、最大化/最小化、拖曳分割條。本文系統性解決 MFC SDI/MDI 應用程式的視窗鎖定問題,涵蓋非客戶區點擊測試、系統選單清理、狀態列大小控制桿移除、分割視窗鎖定等完整方案。
Windows 透過 WM_NCHITTEST 判斷滑鼠位於視窗哪個非客戶區(標題列、邊框、按鈕等)。預設處理返回 HTCAPTION(標題列)、HTLEFT/HTRIGHT(邊框)等代碼,觸發移動/調整大小。重寫此訊息,將不想要的代碼映射為 HTBORDER(不可調整的邊框),即可阻擋操作,同時保持視窗可被點擊激活。
UINT CMainFrame::OnNcHitTest(CPoint point)
{
UINT hit = CFrameWnd::OnNcHitTest(point);
static BYTE DisallowCodes[] = {
HTLEFT, HTRIGHT, HTTOP, HTBOTTOM,
HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT,
HTSIZE, HTCAPTION
};
for (BYTE code : DisallowCodes) {
if (hit == code) return HTBORDER;
}
return hit;
}
移除「移動」、「大小」、「最小化」、「最大化」、「還原」等選單項:
static UINT BadCommands[] = {
SC_SIZE, SC_MOVE, SC_MINIMIZE, SC_MAXIMIZE, SC_RESTORE, 0
};
CMenu* pSysMenu = GetSystemMenu(FALSE);
for (int i = 0; BadCommands[i]; i++) {
pSysMenu->RemoveMenu(BadCommands[i], MF_BYCOMMAND);
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style &= ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
return CFrameWnd::PreCreateWindow(cs);
}
狀態列右下角的三角形控制桿由 WS_THICKFRAME 風格決定。在建立狀態列前暫時移除此風格,建立完成後恢復:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
ModifyStyle(WS_THICKFRAME, 0); // 移除粗框架
m_wndStatusBar.Create(this); // 建立狀態列(無控制桿)
ModifyStyle(0, WS_THICKFRAME); // 恢復粗框架
return 0;
}
原理:MFC 在
CStatusBar::Create()時檢查視窗風格決定是否建立大小控制桿。欺騙 MFC 可一次解決,事後無 API 可動態移除控制桿。
自訂 CSplitterWnd 衍生類別,重寫滑鼠訊息直接返回:
class CMySplitterWnd : public CSplitterWnd {
void OnLButtonDown(UINT, CPoint) { return; } // 禁止拖曳
void OnMouseMove(UINT, CPoint) { return; } // 禁止游標變更
// DoKeyboardSplit 由選單命令觸發,直接從選單移除「視窗|分割」即可
};
對應 CSplitterWnd 原始碼邏輯:
OnLButtonDown → HitTest() → StartTracking()OnMouseMove → 設定分割游標(雙向箭頭)| 操作途徑 | 阻擋方法 |
|---|---|
| 標題列拖曳移動 | WM_NCHITTEST 映射 HTCAPTION → HTBORDER |
| 邊框拖曳調整大小 | WM_NCHITTEST 映射 HTLEFT/HTRIGHT/HTSIZE 等 → HTBORDER |
| 最大化/最小化按鈕 | PreCreateWindow 移除 WS_MINIMIZEBOX/WS_MAXIMIZEBOX |
| 系統選單命令 | OnCreate 移除 SC_MOVE/SC_SIZE/SC_MINIMIZE/SC_MAXIMIZE/SC_RESTORE |
| 狀態列大小控制桿 | 建立狀態列前暫時移除 WS_THICKFRAME |
| 分割條拖曳 | CSplitterWnd 衍生類重寫 OnLButtonDown/OnMouseMove |
| 鍵盤分割命令 | 資源編輯器移除「視窗|分割」選單項 |
WM_NCHITTEST 技巧HTBORDER 行為一致DisallowCodes 移除對應代碼即可透過 WM_NCHITTEST 攔截非客戶區點擊、清理系統選單、欺騙狀態列建立邏輯、重寫分割視窗滑鼠處理,可構建完全鎖定的 MFC 主視窗。這套方案在工業自動化、資訊安全終端、公開資訊查詢系統等領域經實戰驗證可靠。完整範例程式碼請參考附件專案。