“系統ShutDown”屬于Windows系統的一種基本服務(wù)。功能上有“關(guān)閉系統”,“注銷(xiāo)用戶(hù)”,“鎖定工作站”3中操作。SDK中提供了幾個(gè)函數,來(lái)對此服務(wù)進(jìn)行調用。
“關(guān)閉系統”功能使計算機可以被安全的關(guān)閉。所有在文件系統里緩沖的內容都被強制寫(xiě)入磁盤(pán)。然后,顯示相應的對話(huà)框,提示用戶(hù)計算機將被關(guān)閉或者已經(jīng)準備好被關(guān)閉??蛇x的情況一般是計算機在關(guān)閉后重起,而不是直接切斷電源。
如果一個(gè)進(jìn)程調用“注銷(xiāo)”功能函數,則該進(jìn)程所在的安全環(huán)境范圍內的所有進(jìn)程都被終止,使當前的用戶(hù)退出系統。一個(gè)登陸對話(huà)框被顯示,期待新用戶(hù)的登陸。
“鎖定工作站”功能使你可以在離開(kāi)計算機的時(shí)候,保護計算機屏幕不被未授權的用戶(hù)看到。要解除鎖定,必須用管理員或著(zhù)授權用戶(hù)的賬號和密碼重新登陸。
如何關(guān)閉系統:
程序可以用兩種方式關(guān)閉本地或遠程計算機
直接關(guān)閉系統
關(guān)閉系統并重啟
Windows NT/2000 及后續版本: 程序必須擁有SE_SHUTDOWN_NAME權限才能成功調用關(guān)閉函數。
ExitWindowsEx函數可以用來(lái)關(guān)閉系統。如函數成功調用,系統對每個(gè)窗口發(fā)送WM_QUERYENDSESSION 消息,詢(xún)問(wèn)窗口所屬的程序是否可以被終止。收到此消息的程序應該進(jìn)行響應,清除環(huán)境釋放資源,然后返回TRUE表示自己可以被終止。然而調用ExitWindowEx的時(shí)候如果指定了EXW_FORCE,則系統強行終止相關(guān)的進(jìn)程并關(guān)閉,這樣可能導致數據的丟失。
這是一段在NT/2000中調用ExitWindowEx關(guān)閉系統的程序(強制關(guān)閉所有程序)。
在windows95/98/me中直接調用ExitWindowEx即可。
-----------------------------------------------------------------------------------------------------------
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// Get a token for this process.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
Error("OpenProcessToken");
// Get the LUID for the shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES)NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS)
error("AdjustTokenPrivileges");
// Shut down the system and force all applications to close.
if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0))
error("ExitWindowsEx");
-----------------------------------------------------------------------------------------------------------
Windows NT/2000以及后續版本:
InitiateSystemShutdown函數可以指定一段延時(shí),在進(jìn)行延時(shí)計數的時(shí)候,在將被關(guān)閉的目標計算機上顯示一個(gè)對話(huà)框,提示用戶(hù)盡快注銷(xiāo)。一旦計數結束,系統則立刻被關(guān)閉。在此之前,可以調用AbortSystemShutdown函數停止計數,取消相應的關(guān)閉操作。InitiateSystemShutdown也可以指定讓系統重啟。
InitiateSystemShutdown有一個(gè)參數LPTSTR lpMachineName,可以指定為網(wǎng)絡(luò )上的計算機名字,也就是說(shuō),可以關(guān)閉網(wǎng)絡(luò )上的他計算機(如果你的用戶(hù)在該計算機上有足夠的權限的話(huà))。
以下這個(gè)例子調用InitiateSystemShutdown函數關(guān)閉用戶(hù)已經(jīng)登陸的本地計算機(要關(guān)閉遠程計算機將InitSystemShutdown第一個(gè)參數由NULL改為正確的計算機名字或)。同樣的,也需要先獲得SE_SHUTDOWN_NAME權限。
---------------------------------------------------------------------------------------------------------
HANDLE hToken; // handle to process token
TOKEN_PRIVILEGES tkp; // pointer to token structure
BOOL fResult; // system shutdown flag
// Get the current process token handle so we can get shutdown
// privilege.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
ErrorHandler("OpenProcessToken failed.");
// Get the LUID for shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS)
ErrorHandler("AdjustTokenPrivileges enable failed.");
// Display the shutdown dialog box and start the time-out countdown.
fResult = InitiateSystemShutdown( NULL, // shut down local computer
"Click on the main window and press \
the Escape key to cancel shutdown.", // message to user
20, // time-out period
FALSE, // ask user to close apps
TRUE); // reboot after shutdown
if (!fResult)
{
ErrorHandler("InitiateSystemShutdown failed.");
}
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
ErrorHandler("AdjustTokenPrivileges disable failed.");
}
---------------------------------------------------------------------------------------------
而使用AbortSystemShutoown取消InitialSystemShutdown操作的代碼如下(記住要在延時(shí)結束前執行才能起作用
// Get the current process token handle so we can get shutdown
// privilege.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
ErrorHandler("OpenProcessToken failed.");
}
// Get the LUID for shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES)NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS)
{
ErrorHandler("AdjustTokenPrivileges enable failed.");
}
// Prevent the system from shutting down.
fResult = AbortSystemShutdown(NULL);
if (!fResult)
{
ErrorHandler("AbortSystemShutdown failed.");
}
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
ErrorHandler("AdjustTokenPrivileges disable failed.");
}
break;
關(guān)于用戶(hù)權限(Privileges)的詳細信息,可以參見(jiàn)MSDN
如何注銷(xiāo)當前用戶(hù)
可以使用ExitWindows或ExitWindowsEx函數注銷(xiāo)當前用戶(hù)。
在默認的情況下,當程序調用ExitWindows或ExitWindowsEx注銷(xiāo)的時(shí)候,WM_QUERYENDSESSION消息也被發(fā)送到系統內的每個(gè)窗口。窗口所屬的程序響應此消息并且返回TRUE表示可以被關(guān)閉,如果任意一個(gè)程序返回FALSE,注銷(xiāo)操作將被取消。
Windows NT/2000以及后續版本:
當一個(gè)程序響應WM_QUERYENDSESSION并返回TRUE,那么它就會(huì )立刻接受到WM_ENDSESSION消息并馬上結束,而不管其他的程序是怎么樣回應WM_QUERYENDSESSION消息的。
Windows 95/98/Me:只有當系統內所有的程序都對WM_QUERYENDSESSION消息回應TRUE之后,他們才會(huì )一起接受到WM_ENDSESSION 消息,然后結束。
如果要強制關(guān)閉所有的程序,使用ExitWindowsEx函數,指定EXW_FORCE標志。如果這樣做,系統不發(fā)送WM_QUERYENDSESSION 消息,而直接終止正在運行的程序。
在注銷(xiāo)的時(shí)候,系統還向每一個(gè)進(jìn)程發(fā)送CTRL_LOGOFF_EVENT 控制碼??刂婆_程序可以注冊一個(gè)HandlerRoutine例程來(lái)處理這個(gè)控制碼(使用SetConsoleCtrlHandler函數)。(更多的關(guān)于控制臺的控制碼,參見(jiàn)MSDN里“HandlerRoutine”有關(guān)章節)
綜上所述:只有所有的程序都允許退出,注銷(xiāo)操作才能成功。如果某一個(gè)程序響應WM_QUERYENDSESSION并返回FALSE ,用戶(hù)則不能被注銷(xiāo)。這樣就可以寫(xiě)出防止用戶(hù)注銷(xiāo)或關(guān)閉的程序(非強制情況)。
//這是注銷(xiāo)當前用戶(hù)的代碼
ExitWindows(0, 0);
//響應WM_QUERYENDSESSION消息,如果在彈出消息框里選擇NO,則取消注銷(xiāo)。
case WM_QUERYENDSESSION:
{
int r;
r = MessageBox(NULL, "Shut down?","WM_QUERYENDSESSION", MB_YESNO);
// Return TRUE to allow shutdown, FALSE to stop.
return r == IDYES;
break;
}
如何鎖定工作站
使用LockWorkStation函數即可鎖定工作站。系統會(huì )顯示一個(gè)鎖定對話(huà)框,告訴用戶(hù)此工作站正在使用并且已經(jīng)被鎖定,可以被執行鎖定的用戶(hù)或管理員解鎖,解鎖的方式是按下CTRL_ALT_DEL并用正確的賬號和密碼登陸。
LockWorkStation函數成功調用的條件是:
調用者必須是運行在系統交互桌面上的一般進(jìn)程。
必須已經(jīng)有用戶(hù)登陸到系統
工作站未被鎖定。
擁有正常窗口和消息隊列的程序通過(guò)WM_QUERYENDSESSION或WM_ENDSESSION消息獲得關(guān)閉通知。
控制臺則是在其控制流程(Handle Routines)里接受關(guān)閉通知。要注冊一個(gè)控制臺控制流程,應該使用SetConsoleCtrlHandler函數
服務(wù)程序在其控制流程里接受退出通知。要注冊一個(gè)服務(wù)控制流程,應該使用RegisterServiceCtrlHandlerEx函數。
關(guān)閉系統函數列表
函數名 函數功能描述
AbortSystemShutdown 取消由InitSystemShutdown引起的系統關(guān)閉操作
ExitWindows 注銷(xiāo)當前用戶(hù)
ExitWindowsEx 注銷(xiāo)用戶(hù),關(guān)閉計算機,關(guān)閉計算機并且重啟
InitiateSystemShutdown 發(fā)起關(guān)閉系統操作,可以選擇關(guān)閉后重啟
InitiateSystemShutdownEx 同InitiateSystemShutdown,擴展的功能是可以在系統
事件日志(事件號6006)中寫(xiě)入一個(gè)用戶(hù)指定的雙字節碼
LockWorkStation 鎖定工作站
系統關(guān)閉消息
WM_ENDSESSION
wParam
表示是否要終止程序。如果是TRUE,指令該程序終止,否則是FALSE
lParam
表示用戶(hù)注銷(xiāo)還是系統被關(guān)閉。如果此參數包含ENDSESSION_LOGOFF(lParam在這里是按位取值的)位,則表示是用戶(hù)注銷(xiāo)
Windows 2000 以及后續版本:如果lParam ==0,則表示系統被關(guān)閉。
程序收到此消息,如果wParam為T(mén)RUE,在完成消息處理后,程序隨時(shí)都有可能被關(guān)閉。所以在此消息的處理過(guò)程里,應該盡量完成程序銷(xiāo)毀前所需要進(jìn)行的工作。
WM_QUERYENDSESSION
wParam
保留,未使用
lParam
同WM_ENDSESSION;
DefWindowProc默認返回:TRUE
聯(lián)系客服