以前一直想自己寫一個定時關機的程式,但一直沒有實作,現在終于寫好了
對于這樣的一個功能,其實是很簡單的。裡面主要設計的技術就是怎樣去寫關機的代碼段了。
因而我主要解析一下自動關機的具體實作。
對于這個功能的實作由四步實作:
1. 調用OpenProcessToken函數,實作設定關機程序的通路辨別(access token)(MSDN解釋:opens the access token associated with a process.)
該函數總共有三個參數,HANDLE ProcessHandle參數用于目前程式的執行個體句柄,可用函數GetCurrentHandle( )擷取,DWORD DesiredAcess參數用于辨別要擷取的權限, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY分别表示可以實作或是屏蔽優先權和可以實作擷取通路辨別,PHANDLE TokenHandle用于擷取擷取通路辨別後的句柄
2. 調用LookupPrivilegeValue函數,擷取本地計算機唯一辨別(LUID),并且擷取關機權限.(MSDN解釋:retrieves the locally unique identifier (LUID) used on a specified system to locally represent the specified privilege name.)
BOOL WINAPI LookupPrivilegeValue(LPCTSTR lpSystemName, LPCTSTR lpName PLUID lpLuid)第一個參數為要擷取優先權的計算機名稱,NULL值表示本地計算機,第二個參數為辨別優先權的名稱,可以是ID也可以為相應的字元串,如 SE_SHUTDOWN_NAME(或是"SeShutdownPrivilege")表示該程序具有關機的權限,或SE_SECURITY_NAME表示有管理稽核和安全日志權限.第三個參數用于傳進變量擷取已辨別計算機的LUID.
3. 調用AdjustTokenPrivileges函數,擷取關機的權限.(MSDN解釋: enables or disables privileges in the specified access token.)
BOOL WINAPI AdjustTokenPrivileges( HANDLE TokenHandle,BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);第一個參數為一個需要被修改的指針,并且它需要具有SE_PRIVILEGE_ENABLED權限,第二個參數true表示屏蔽所有權限,忽略NewState參數,若為false則用NewState參數設定目前參數,指向一個TOKEN_PRIVILEGES指針,BufferLength參數訓示PreviousState參數的長度,如果PreviousState參數為NULL,則其為0,PreviousState參數訓示前一TOKEN_PRIVILEGES指針, ReturnLength 參數應為NULL如果PreviousState參數為NULL
4. 調用ExitWindowsEx或是InitiateSystemShutdown函數實作最後的關機功能.
BOOL ExitWindowsEx(UINT uFlags,DWORD dwReserved);用于立即關機uFlags辨別關機選項,EWX_POWEROFF為關機,EWX_REBOOT為重新開機,後一個參數被保留
BOOL WINAPI InitiateSystemShutdown(LPTSTR lpMachineName,LPTSTR lpMessage, DWORD dwTimeout, BOOL bForceAppsClosed, BOOL bRebootAfterShutdown);記錄關機的原因,lpMachineName參數辨別主機名,NULL為本機,或是網絡中的一個主機名。lpMessage在關機對話框中顯示資訊,可以為NULL值,dwTimeout設定對話框的顯示時間,即對話框出現後的關機剩餘時間,bForceAppsClosed若要強制關機,則設定為TRUE,它強制關閉為儲存的檔案,否則設定為FALSE, bRebootAfterShutdownTRUE為重新開機,FALSE為關機
程式代碼如下:
TOKEN_PRIVILEGES tkp;
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
MessageBox("OpenProcessToken failed!");
}
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid); //獲得本地機唯一的辨別
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); //調整獲得的權限
if (GetLastError() != ERROR_SUCCESS)
{
MessageBox("AdjustTokenPrivileges enable failed!");
}
bool fResult =InitiateSystemShutdown(
NULL, // 要關的計算機使用者名,可在區域網路網中關掉對方的機器,NULL表示關本機
"定時關機已經啟動,請做好儲存工作!", // 顯示的消息
10, // 關機所需的時間
TRUE,
FALSE); //設為TRUE為重起,設為FALSE為關機
if(!fResult)
{
MessageBox("InitiateSystemShutdown failed.");
}
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
MessageBox("AdjustTokenPrivileges disable failed.");
}
ExitWindowsEx(EWX_SHUTDOWN,0); //開始關機