伺服器或無人值守工作站常需在指定時間自動關機。本程式支援 Windows 95/98/Me 與 NT/2000/XP 兩大核心架構,功能包含:時間驗證、倒數提醒、強制關機、取消關機、托盤常駐、單一實例、攔截系統關機訊息讓使用者決定是否允許關閉。完整源碼附於文末。
| 功能 | Win 9x 實作 | NT/2000/XP 實作 |
|---|---|---|
| 關機 API | ExitWindowsEx(EWX_SHUTDOWN+EWX_FORCE, 0) | OpenProcessToken → AdjustTokenPrivileges(SeShutdownPrivilege) → InitiateSystemShutdown |
| 倒數顯示 | 自訂視窗置頂顯示 | 系統內建倒數對話框 |
| 取消關機 | 停止 Timer | AbortSystemShutdown(電腦名) |
function GetOSVersion: String;
var OSVer: TOSVersionInfo;
begin
OSVer.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
if GetVersionEx(OSVer) then
case OSVer.dwPlatformId of
VER_PLATFORM_WIN32_NT: Result := 'Windows NT/2000/XP';
VER_PLATFORM_WIN32_WINDOWS: Result := 'Windows 95/98/Me';
end;
end;
function EnableShutdownPriv: Boolean;
var hToken: THandle; TP: TOKEN_PRIVILEGES; RetLen: DWORD;
begin
Result := False;
if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then begin
if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', TP.Privileges[0].Luid) then begin
TP.PrivilegeCount := 1;
TP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
Result := AdjustTokenPrivileges(hToken, False, TP, 0, nil, RetLen);
end;
CloseHandle(hToken);
end;
end;
procedure ShowInTray;
begin
Tray.cbSize := SizeOf(Tray);
Tray.Wnd := Handle;
Tray.uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;
Tray.uCallbackMessage := WM_USER;
Tray.hIcon := Application.Icon.Handle;
Tray.szTip := '定時關機';
Shell_NotifyIcon(NIM_ADD, @Tray);
end;
procedure TrayMenu(var Msg: TMessage);
var Pt: TPoint;
begin
if Msg.LParam = WM_RBUTTONDOWN then begin
GetCursorPos(Pt);
PopupMenu1.Popup(Pt.X, Pt.Y);
end;
end;
procedure WMQueryEndSession(var Msg: TWMQueryEndSession); message WM_QUERYENDSESSION;
begin
if MessageDlg('確定要關閉 Windows?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then
Msg.Result := 0 // 拒絕關機
else
Msg.Result := 1; // 允許關機
end;
procedure FormCreate(Sender: TObject);
begin
if GlobalFindAtom('AUTO_SHUTDOWN_APP') = 0 then
Atom := GlobalAddAtom('AUTO_SHUTDOWN_APP')
else begin
ShowMessage('程式已在執行中!');
Halt;
end;
end;
procedure FormDestroy(Sender: TObject);
begin
GlobalDeleteAtom(Atom);
Shell_NotifyIcon(NIM_DELETE, @Tray);
end;
unit AutoShut1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Menus, AppEvnts, ShellAPI;
type TForm1 = class(TForm)
Timer1, Timer2: TTimer;
ApplicationEvents1: TApplicationEvents;
PopupMenu1: TPopupMenu;
Edit1, Edit2: TEdit; // 目前時間、設定關機時間
Label1, Label2, Label3: TLabel;
Btn_OK, Btn_Abort: TButton;
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
procedure Btn_OKClick(Sender: TObject);
procedure Btn_AbortClick(Sender: TObject);
procedure TimeSetClick(Sender: TObject);
procedure ExitClick(Sender: TObject);
procedure Edit2KeyPress(Sender: TObject; var Key: Char);
procedure WMQueryEndSession(var Msg: TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure TrayMenu(var Msg: TMessage); message WM_USER;
private
Tray: NOTIFYICONDATA;
procedure ShowInTray;
public
end;
var Form1: TForm1; Atom: Integer; TimeDelay: Integer;
implementation
{$R *.dfm}
// ... 上述所有函數實作 ...
// 關鍵邏輯:
// Timer1: 每秒更新目前時間,比對 Edit2 設定時間
// Timer2: 觸發後 30 秒倒數,到期執行關機
// Btn_OK: 驗證時間格式 HH:MM,通過則最小化至托盤
// Btn_Abort: 取消關機 (NT 呼叫 AbortSystemShutdown)
// Edit2KeyPress: Enter 觸發 Btn_OK
end.
此程式展示 Delphi 呼叫 Win32 API 處理系統級任務的典型模式:版本分支、特權提升、訊息攔截、托盤常駐、單一實例,可直接套用於其他系統管理工具開發。