復合控件將多個標準控件 (按鈕、編輯框、單選鈕等) 組合在一個對話框模板中,封裝為單一 ActiveX 控件。開發體驗近似 MFC 對話框程式,適合建構複雜 UI 組件。
TrueShutDownShutDownCtrl
自動生成對話框模板 (IDD_SHUTDOWNCTRL),拖放控件:
IDC_HOUR (時)、IDC_MINUTE (分)IDC_OK (確定/重設)IDC_TIME (當前時間)、IDC_STIME (剩餘時間)IDC_RADIO1 (關機)、IDC_RADIO2 (重啟)、IDC_RADIO3 (強制關機)
在 ClassView 右鍵 CShutDownCtrl → Add Window Message Handler:
IDC_OK + BN_CLICKED → OnClickedOkWM_TIMER → OnTimerWM_INITDIALOG → OnInitDialogBN_CLICKED → OnClickedRadio1/2/3
protected:
int IsOK; // 0=未設定, 1=倒數中
int m_nType; // 1=關機, 2=重啟, 3=強制關機
CShutDownCtrl() { IsOK = 0; m_nType = 0; }
OnInitDialog:啟動兩個定時器
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
::SetTimer(m_hWnd, 0, 5000, NULL); // 5秒檢查關機時間
::SetTimer(m_hWnd, 1, 1000, NULL); // 1秒更新顯示時間
return 0;
}
OnTimer:核心邏輯
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
SYSTEMTIME str;
CHAR str1[20], str_h[10], str_m[10];
::GetLocalTime(&str);
// 更新當前時間顯示 (Timer 1)
sprintf(str1, "%2d時%2d分%2d秒", str.wHour, str.wMinute, str.wSecond);
SetDlgItemText(IDC_TIME, str1);
// 讀取設定關機時間
GetDlgItemText(IDC_HOUR, str_h, sizeof(str_h));
GetDlgItemText(IDC_MINUTE, str_m, sizeof(str_m));
// 計算並顯示剩餘時間
if(IsOK == 1)
GetSTime(str.wHour, str.wMinute, atoi(str_h), atoi(str_m), str.wSecond);
// 檢查是否到達關機時間 (Timer 0)
if(wParam == 0 && IsOK == 1 &&
str.wHour == atoi(str_h) && str.wMinute == atoi(str_m)) {
switch(m_nType) {
case 1: ExitWindowsEx(EWX_SHUTDOWN, 0); break; // 關機
case 2: ExitWindowsEx(EWX_REBOOT, 0); break; // 重啟
case 3: ExitWindowsEx(EWX_FORCE, 0); break; // 強制關機
}
}
return 0;
}
GetSTime:計算剩餘時間
void CShutDownCtrl::GetSTime(int H, int M, int h, int m, int s) {
CHAR str[20];
m -= 1; // 秒數調整
if(h < H) h += 24; // 跨午夜
if(m < M) { m += 60; h -= 1; } // 分鐘借位
sprintf(str, "%2d時%2d分%2d秒", h-H, m-M, 60-s);
SetDlgItemText(IDC_STIME, str);
}
OnClickedOk:切換設定/運行狀態
LRESULT OnClickedOk(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) {
if(IsOK == 0) { // 進入倒數模式
::EnableWindow(::GetDlgItem(m_hWnd, IDC_HOUR), FALSE);
::EnableWindow(::GetDlgItem(m_hWnd, IDC_MINUTE), FALSE);
SetDlgItemText(IDC_OK, "重設");
IsOK = 1;
} else { // 重設模式
::EnableWindow(::GetDlgItem(m_hWnd, IDC_HOUR), TRUE);
::EnableWindow(::GetDlgItem(m_hWnd, IDC_MINUTE), TRUE);
SetDlgItemText(IDC_OK, "確定");
SetDlgItemText(IDC_STIME, "");
IsOK = 0;
}
return 0;
}
LRESULT OnClickedRadio1(...) { m_nType = 1; return 0; } // 關機
LRESULT OnClickedRadio2(...) { m_nType = 2; return 0; } // 重啟
LRESULT OnClickedRadio3(...) { m_nType = 3; return 0; } // 強制
ShutDownCtrl.htm (ATL 自動生成的測試頁) 即可在 IE 中測試。CreateWindow。MESSAGE_HANDLER/COMMAND_HANDLER 宏,類似 MFC 但更輕量。wParam 對應 SetTimer 的 nIDEvent (0 和 1)。ExitWindowsEx 需適當權限 (通常需 SE_SHUTDOWN_NAME)。GetSTime 處理「設定時間 < 當前時間」視為次日。復合控件開發本質上是「對話框程式組件化」。掌握 ATL 專案結構、對話框資源、訊息處理、COM 介面導出四大塊,即可將任意 MFC 對話框功能封裝為可重用 ActiveX 控件。本範例展示完整生命週期:初始化 → 使用者互動 → 定時檢查 → 系統操作。