標準 MessageBox 配合 MB_YESNO 顯示的按鈕文字取決於系統區域語言設定:中文環境下固定為「是」/「否」。若需強制顯示英文「Yes」/「No」(如國際化測試、特定 UI 規範),不能僅靠參數控制,必須攔截對話框創建過程修改子控件文字。
Windows 在彈出模態對話框(包括 MessageBox)前會發送 HCBT_ACTIVATE 通知給 WH_CBT 鉤子。此時對話框已創建但未顯示,可安全修改按鈕文字。
#include
HHOOK g_hHook = NULL;
LRESULT CALLBACK CBTHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HCBT_ACTIVATE) {
HWND hDlg = (HWND)wParam;
// 修改 IDYES / IDNO 按鈕文字
SetDlgItemText(hDlg, IDYES, "&Yes");
SetDlgItemText(hDlg, IDNO, "&No");
// 任務完成,立即卸載鉤子,避免影響其他對話框
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) {
// 安裝線程級 CBT 鉤子
g_hHook = SetWindowsHookEx(WH_CBT, CBTHookProc, hInst, GetCurrentThreadId());
if (g_hHook) {
MessageBox(NULL, "Are you handsome?", "Test", MB_ICONINFORMATION | MB_YESNO);
} else {
MessageBox(NULL, "Failed to install hook", "Error", MB_ICONERROR);
}
return 0;
}
| 步驟 | API / 參數 | 說明 |
|---|---|---|
| 安裝鉤子 | SetWindowsHookEx(WH_CBT, ...) | 線程級鉤子足夠,僅攔截當前線程的對話框;第三參數傳 hInst 確保 DLL 注入正確。 |
| 判斷時機 | nCode == HCBT_ACTIVATE | 此時對話框句柄在 wParam,所有子控件已創建,可直接 SetDlgItemText。 |
| 修改文字 | SetDlgItemText(hDlg, IDYES, "&Yes") | & 設定快捷鍵 (Alt+Y / Alt+N);IDYES/IDNO 為標準按鈕控件 ID。 |
| 及時卸載 | UnhookWindowsHookEx | 只需修改一次,立即卸載避免副作用(如影響後續其他 MessageBox)。 |
WH_GETMESSAGE、WH_CALLWNDPROC 等無法在對話框創建初期拿到句柄修改文字。NULL 或跨進程,需將回調函數放入 DLL,否則 SetWindowsHookEx 會失敗返回 NULL。WM_INITDIALOG 階段再次修改,或使用 DLGTEMPLATEEX 自定義對話框模板。SetWindowsHookEx 在 64 位進程中同樣有效。IDOK/IDCANCEL、IDABORT/IDRETRY/IDIGNORE 等標準按鈕文字。GetWindowRect/MoveWindow 可調整按鈕寬度以適應長文字(如德語「Abbrechen」)。CDialogEx 或 TaskDialog (Vista+)。此 Hook 技巧輕量、無副作用,是解決「MessageBox 按鈕文字國際化」最經濟的方案之一。