天天看點

關機實作詳解

以前一直想自己寫一個定時關機的程式,但一直沒有實作,現在終于寫好了

對于這樣的一個功能,其實是很簡單的。裡面主要設計的技術就是怎樣去寫關機的代碼段了。

因而我主要解析一下自動關機的具體實作。

對于這個功能的實作由四步實作:

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);     //開始關機 

繼續閱讀