專案概覽
本專案示範如何使用 C++ Builder (VCL 框架) 開發一款實用的定時關機工具。核心功能包含:即時顯示系統時間、日期時間選擇器設定關機時刻、倒數計時顯示、關機條件驗證、以及呼叫 Windows API 執行系統關機。適用於下載任務、排程備份、節能管理等場景。
介面元件佈局與屬性設定
| 元件 | 類型 | 名稱 | 關鍵屬性 | 用途 |
| GroupBox1 | TGroupBox | grpCurrentTime | Caption="目前系統時間" | 分組容器 |
| DateTimePicker1 | TDateTimePicker | dtpCurrDate | Kind=dtkDate, Mode=dmUpDown, Enabled=False | 顯示目前日期 |
| DateTimePicker2 | TDateTimePicker | dtpCurrTime | Kind=dtkTime, Mode=dmUpDown, Enabled=False, Format="HH:mm:ss" | 顯示目前時間 |
| GroupBox2 | TGroupBox | grpShutdownTime | Caption="預設關機時間" | 分組容器 |
| DateTimePicker3 | TDateTimePicker | dtpSetDate | Kind=dtkDate, Mode=dmUpDown | 設定關機日期 |
| DateTimePicker4 | TDateTimePicker | dtpSetTime | Kind=dtkTime, Mode=dmUpDown, Format="HH:mm:ss" | 設定關機時間 |
| CheckBox1 | TCheckBox | chkEnable | Caption="啟用定時關機", Enabled=False | 主開關 |
| Timer1 | TTimer | tmrMain | Interval=1000 (1秒), Enabled=True | 核心輪詢器 |
| Edit1 (可選) | TEdit | edtCountdown | ReadOnly=True, Alignment=taCenter | 倒數計時顯示 |
核心程式碼實作
1. 表單建立初始化
void __fastcall TForm1::FormCreate(TObject *Sender) {
// 初始化狀態
chkEnable->Checked = false;
chkEnable->Enabled = false;
// 以目前時間初始化所有選擇器
TDateTime now = Now();
dtpCurrDate->DateTime = now;
dtpCurrTime->DateTime = now;
dtpSetDate->DateTime = now;
dtpSetTime->DateTime = now;
}
2. Timer 核心邏輯 (每秒執行)
void __fastcall TForm1::tmrMainTimer(TObject *Sender) {
TDateTime now = Now();
// 更新即時顯示
dtpCurrDate->DateTime = now;
dtpCurrTime->DateTime = now;
// 合併使用者設定的日期與時間
TDateTime targetDateTime = dtpSetDate->Date + dtpSetTime->Time;
// 驗證目標時間有效性 (必須大於現在)
bool isValid = (targetDateTime > now);
chkEnable->Enabled = isValid;
if (!isValid) chkEnable->Checked = false;
// 檢查關機條件
if (chkEnable->Checked && (targetDateTime <= now + (1.0/86400.0))) { // 1秒容差
ExecuteShutdown();
}
// 選擇性:更新倒數計時顯示
if (edtCountdown) {
double diff = targetDateTime - now;
if (diff > 0) {
int seconds = (int)(diff * 86400); // 天轉秒
edtCountdown->Text = FormatFloat("#,##0 秒", seconds);
} else {
edtCountdown->Text = "時間已到";
}
}
}
3. 日期/時間聯動同步
// 日期改變同步至時間選擇器 (保持時間部分)
void __fastcall TForm1::dtpSetDateChange(TObject *Sender) {
dtpSetTime->Date = dtpSetDate->Date;
ValidateTargetTime();
}
// 時間改變同步至日期選擇器 (保持日期部分)
void __fastcall TForm1::dtpSetTimeChange(TObject *Sender) {
dtpSetDate->Date = dtpSetTime->Date;
ValidateTargetTime();
}
void __fastcall TForm1::ValidateTargetTime() {
TDateTime target = dtpSetDate->Date + dtpSetTime->Time;
bool valid = (target > Now());
chkEnable->Enabled = valid;
if (!valid) chkEnable->Checked = false;
}
4. 執行系統關機
void __fastcall TForm1::ExecuteShutdown() {
// 停止計時器避免重複觸發
tmrMain->Enabled = false;
// 使用 Windows API 安全關機
// EWX_SHUTDOWN = 0x00000001 (關機)
// EWX_POWEROFF = 0x00000008 (切斷電源,需硬體支援)
// EWX_FORCE = 0x00000004 (強制關閉應用程式)
// EWX_FORCEIFHUNG = 0x00000010 (僅強制無回應程式)
DWORD dwFlags = EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCEIFHUNG;
DWORD dwReason = 0; // 可選:SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION
if (!ExitWindowsEx(dwFlags, dwReason)) {
DWORD err = GetLastError();
ShowMessage("關機失敗,錯誤碼: " + IntToStr(err) + "\n請嘗試以管理員身分執行。");
tmrMain->Enabled = true; // 重新啟用
}
// 成功時系統將關機,程式自然結束
}
進階功能擴充建議
- 多種關機模式:新增 RadioGroup 選擇「關機/重新開機/登出/休眠/睡眠」,對應
EWX_REBOOT、EWX_LOGOFF、SetSuspendState
- 排程重複:加入 TCheckListBox 選擇星期幾,儲存設定至登錄檔/INI 檔
- 啟動最小化至系統匣:搭配
Shell_NotifyIcon 實現背景常駐
- 關機前警告:倒數 60 秒顯示模態對話框,提供取消機會
- 命令列參數支援:支援 `/shutdown 22:30 /force` 等參數啟動
- 權限提升:Manifest 設定
requireAdministrator 或程式碼檢測重啟提權
常見問題排查
| 現象 | 可能原因 | 解決方案 |
| 關機不生效 | 權限不足 / 群組原則限制 | 以管理員執行,檢查本機安全原則「關閉系統」權限 |
| 時間誤差超過 1 秒 | Timer 間隔非精確 / 系統負載 | 使用多媒體計時器 timeSetEvent 或接受秒級誤差 |
| 日期時間選擇器顯示異常 | 地區設定格式衝突 | 明確設定 Format 屬性,避免依賴系統預設 |
| 應用程式關閉後排程失效 | 無背景服務機制 | 改寫為 Windows Service 或使用工作排程器 |