Windows XP系統中如何屏蔽 Ctrl+Alt+Del、Alt+Tab以及Ctrl+Esc鍵序列
編譯/northtibet
關鍵字:Ctrl+Alt+Del,Alt+Tab,Ctrl+Esc,VK_LWIN,VK_RWIN,Task bar,Task Manager,工作列,工作管理員。
下載本文原始碼: TrapKeys.zip (95KB)
對於用過Windows的人,幾乎沒有人不知道Ctrl+Alt+Del按鍵組合,尤其是在使用經常死機的Windows9x時,使用它的頻率更高,這一按鍵組合是專門為了系統安全起見提供的緊急出口。VC知識庫線上雜誌第11期,ac952_z_cn在他的個人專欄中寫過一篇關於這方面的文章:“WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL”。因此本文側重於介紹在Windows XP中如何?屏蔽CTRL+ALT+DEL按鍵組合,也就是工作管理員,任務切換按鍵組合(Alt+Tab),工作列和“開始”菜單(Ctrl+Esc,VK_LWIN,VK_RWIN)。這個方法也能應用於Windows 2000環境。
在Windows 9x/Me系統中,屏蔽Ctrl+Alt+Del和各種任務開關鍵的方法是通過下面的方法實現的:
BOOL bOldState;SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &bOldState, 0);
MS大佬認為這種方法很業餘,所以在Windows NT/2000/XP中對此進行了修改。在這些較新的Windows版本中使用者登陸使用Winlogon和GINA——Graphical Identification and Authentication,意思是圖形化的身份認證,挺嚇唬人的是不是!其實就那麼回事。Winlogon是Windows系統的一部分,它專門提供互動式登陸支援,而GINA則是Winlogon用來實現認證的一個DLL——這個DLL就是msgina.dll。WlxInitialize、WlxActivateUserShell便是其中輸出,當然不知這兩個,還有別的。前者進行自身的初始化,後者啟用使用者的外殼程式。Windows就是用這個DLL來實現使用者名稱+口令的身份認證的,但是開發人員可以用自己的GINA代替msgina.dll。例如,實現智慧卡、視網膜掃描器、DNA檢查等等認證機制來代替輸入使用者名稱+口令形式的身份檢查。 下面的表格中列出了與GINA有關的全部函數。其中有一個是WlxLoggedOnSAS,當按下Ctrl+Alt+Del 鍵時,Winlogon便調用這個函數。
(表一)GINA 函數一覽表
函數 |
描述 |
WlxActivateUserShell |
啟用使用者外殼程式 |
WlxDisplayLockedNotice |
允許GINA DLL 顯示鎖定資訊 |
WlxDisplaySASNotice |
當沒有使用者登陸時,Winlogon調用此函數 |
WlxDisplayStatusMessage |
Winlogon 用一個狀態資訊調用此函數進行顯示 |
WlxGetConsoleSwitchCredentials |
Winlogon調用此函數讀取當前登陸使用者的信任資訊,並透明地將它們傳到目標會話 |
WlxGetStatusMessage |
Winlogon 調用此函數擷取目前狀態資訊 |
WlxInitialize |
針對指定的視窗位置進行GINA DLL初始化 |
WlxIsLockOk |
驗證工作站正常鎖定 |
WlxIslogoffOk |
驗證登出正常 |
WlxLoggedOnSAS |
使用者已登陸並且工作站沒有被加鎖,如果此時接收到SAS事件,則Winlogon 調用此函數 |
WlxLoggedOutSAS |
沒有使用者登陸,如果此時收到SAS事件,則Winlogon 調用此函數 |
WlxLogoff |
請求登出操作時通知GINA DLL |
WlxNegotiate |
表示當前的Winlogon版本是否能使用GINA DLL |
WlxNetworkProviderLoad |
在載入網路服務提供者收集了身份和認證資訊後,Winlogon 調用此函數 |
WlxRemoveStatusMessage |
Winlogon 調用此函數告訴GINA DLL 停止顯示狀態資訊 |
WlxScreensaverNotify |
允許GINA與螢幕保護裝置操作互動 |
WlxShutdown |
在關閉之前Winlogon 調用此函數,允許GINA實現任何關閉任務,例如從讀卡機中退出智慧卡 |
WlxStartApplication |
當系統需要在使用者的上下文中啟動應用程式時調用此函數 |
WlxWkstaLockedSAS |
當工作站被鎖定,如果接收到一個SAS,則Winlogon 調用此函數 |
在預設情況下,GINA顯示登陸對話方塊,使用者輸入使用者名稱及口令。所以要想屏蔽掉Ctrl+Alt+Del,則可以寫一個新的MyGina.dll,其中提供介面調用msgina.dll的函數WlxLoggedOnSAS,從而實現Ctrl+Alt+Del屏蔽。或者編寫一個鍵盤驅動程式來實現。
難道屏蔽Ctrl+Alt+Del真的象上述所說的那麼麻煩嗎?有沒有更好的方法呢?答案是肯定的。所以忘掉GINA吧,使用作業系統的原則設定完全可以搞掂這個問題。方法是進入"開始"菜單,選擇"運行",然後在運行對話方塊中輸入"gpedit.msc",啟動Windows系統的組策略編輯器。在左邊窗格查看"使用者配置|系統管理範本|系統|登入/登出",則在右邊窗格策略裡不難發現"禁用工作管理員"一項。二所示:
圖一 組策略編輯器
通過對這個策略的設定可以屏蔽掉Ctrl+Alt+Del。如果要通過編寫代碼來實現,則必須操作下面的登錄機碼:
HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableTaskMgr = dword:1
如此設定之後,則在Windows XP中,如果使用者按下Ctrl+Alt+Del,則會彈出一個出錯對話方塊,二所示:
圖二 錯誤資訊
注意這裡假設在控制台中“使用者帳號”管理的“選擇登入和登出選項”設定啟用了“使用歡迎畫面”一項。三所示:
圖三 登入選項
否則,XP將使用Windows的傳統登入模式,要求使用者輸入帳戶名稱。並且Ctrl+Alt+Del按鍵組合的 行為也和傳統的行為一樣,註冊表中DisableTaskMgr的設定也只是將登入/登出對話方塊中的工作管理員按鈕屏蔽或置灰。 有人可能會問,有關工作管理員的文檔又沒有明確說明,那你是怎麼知道DisableTaskMgr是用來禁用工作管理員的呢?告訴你吧, 我是在使用GPEDIT時發現的。GPEDIT是一個非常有用的工具,不僅可以用它來編輯策略,還可以用它來發現策略。利用這個工具 可以輕鬆控制Windows的許多東西,從許可許可權的存取到是否使用IE的傳統外觀,從是否顯示對話方塊中的Places Bar到是否用Ctrl+Alt+Del 啟動工作管理員。總之用它可以配置上百個介面行為,因此它是一個足以讓系統管理員垂延三尺的工具。 一旦找到了感興趣的策略,那如何知道相應的註冊表位置呢?有兩種方法。第一種是比較粗魯的辦法:在修改策略的前後將註冊表輸出到 一個.reg檔案,然後比較它們有什麼不同。所有的策略無外乎以下的四個註冊表鍵:
// 使用者指定HKEY_CURRENT_USER\Software\PoliciesHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies// 機器指定HKEY_LOCAL_MACHINE\Software\PoliciesHKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies
第二種方法是直搗資訊源頭--檢查描述策略的系統管理範本檔案(.adm)。下面是Windows XP的system.adm檔案對 DisableTaskMgr的描述:(Windows 2000對此的描述稍有不同,其細節請參考Windows 2000的資源開發包)
CATEGORY !!CADOptions#if version >= 4EXPLAIN !!CADOptions_Help#endifKEYNAME "Software\Microsoft\Windows\CurrentVersion\Policies\System"POLICY !!DisableTaskMgr#if version >= 4SUPPORTED !!SUPPORTED_Win2k#endifEXPLAIN !!DisableTaskMgr_HelpVALUENAME "DisableTaskMgr"END POLICY;; More Ctrl+Alt+Del policies here...;END CATEGORY ; Ctrl+Alt+Del options…………DisableTaskMgr_Help="防止使用者啟動''工作管理員''(Taskmgr.exe)。\n\n如果該設定被啟用,並且使用者試圖啟動工作管理員,系統會顯示訊息,解釋是一個策略禁止了這個操作。\n\n工作管理員讓使用者啟動或終止程式,監視電腦效能,查看及監視電腦上所有運行中的程式 (包含系統服務), 搜尋程式的執行檔案名稱,及更改程式啟動並執行優先順序。"DisableTaskMgr="刪除工作管理員"
以上是DisableTaskMgr的描述片斷
正是在這段描述中KEYNAME 和VALUENAME指定了註冊表的索引值對。利用這種方法,你可以為自己的應用程式建立系統管理範本和策略,但編輯和瀏覽.adm模板檔案的編輯器必須支援Unicode字元。如Notepad或者WordPad等都可以。此外,使用系統管理範本檔案,系統管理員可以用它為整個組織配置需要的策略——由此可以看出,此檔案在系統中的地位舉足輕重!有關範本管理員檔案格式的詳細資料請參考平台SDK。最後需要強調的是DisableTaskMgr只是禁用Ctrl+Alt+Del的功能。下面我們來討論如何捕獲它的按鍵序列。要想截獲Ctrl+Alt+Del,有三種可選擇的方法:
- 1、 編寫一個GINA代理;此方法我們在以後的文章中介紹。實際上,ac952_z_cn的個人專欄文章:“WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL”使用的就是這種方法。
- 2、 編寫一個鍵盤驅動程式;本文例子程式使用的方法。
- 3、 用自己的程式代替工作管理員程式TaskMgr.exe。
屏蔽Ctrl+Alt+Del解決方案的具體實現細節請參考本文的例子代碼。
下面讓我們來解決屏蔽任務切換鍵序列的問題,這些鍵序列包括Alt+Tab、Ctrl+Esc、Alt+Esc、VK_LWIN/VK_RWIN以及工作列。在很早以前的Window 3.1年代,處理這個問題的方法是通過WM_SYSKEYDOWN實現。到了Windows 9x時期,本文前面提到過對這個問題的處理方法,使用SPI_SETSCREENSAVERRUNNING。但是進入Windows NT 4.0 (SP3 +),Windows 2000以及Windows XP時代,對這個問題的處理已經有所不同,必須寫一個低級的鍵盤驅動鉤子。不要怕,因為要實現這個鉤子並不是很難。本文下面會介紹如何?這個鍵盤鉤子。一般來講,系統級鉤子必須是一個DLL。下面是本文提供的一個鍵盤鉤子DLL的原始碼片斷(TaskKeyHook.dll):
標頭檔//////////////////////////////////////////////////////////////////TaskKeyHook.h//#define DLLIMPORT __declspec(dllimport)DLLIMPORT BOOL DisableTaskKeys(BOOL bEnable, BOOL bBeep);DLLIMPORT BOOL AreTaskKeysDisabled();實現檔案////////////////////////////////////////////////////////////////// TaskKeyHook.cpp//#define _WIN32_WINNT 0x0500 // for KBDLLHOOKSTRUCT#include <afxwin.h> // MFC core and standard components#define DLLEXPORT __declspec(dllexport)//////////////////// App (DLL) object//class CTaskKeyHookDll : public CWinApp {public:CTaskKeyHookDll() { }~CTaskKeyHookDll() { }} MyDll;////////////////////////////////////////////////// 下面的代碼錶示這一部分在此DLL所有執行個體之間共用// 低級鍵盤鉤子一定是系統級的鉤子//#pragma data_seg (".mydata")HHOOK g_hHookKbdLL = NULL; // 鉤子控制代碼BOOL g_bBeep = FALSE; // 按下非法鍵時蜂鳴響鈴#pragma data_seg ()#pragma comment(linker, "/SECTION:.mydata,RWS") // 告訴連結器:建立資料共用段//////////////////////////////////// 低級鍵盤鉤子// 截獲任務轉換鍵:不傳遞直接返回//LRESULT CALLBACK MyTaskKeyHookLL(int nCode, WPARAM wp, LPARAM lp){KBDLLHOOKSTRUCT *pkh = (KBDLLHOOKSTRUCT *) lp;if (nCode==HC_ACTION) {BOOL bCtrlKeyDown =GetAsyncKeyState(VK_CONTROL)>>((sizeof(SHORT) * 8) - 1);if ((pkh->vkCode==VK_ESCAPE && bCtrlKeyDown) || // Ctrl+Esc// Alt+TAB(pkh->vkCode==VK_TAB && pkh->flags & LLKHF_ALTDOWN) ||// Alt+Esc(pkh->vkCode==VK_ESCAPE && pkh->flags & LLKHF_ALTDOWN)||(pkh->vkCode==VK_LWIN || pkh->vkCode==VK_RWIN)) { // 開始菜單if (g_bBeep && (wp==WM_SYSKEYDOWN||wp==WM_KEYDOWN))MessageBeep(0); // 蜂鳴return 1; // 不再往CallNextHookEx傳遞,直接返回}}return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);}////////////////////////////////////////////////// 是否屏蔽任務鍵序列——也就是說鍵盤鉤子是否安裝?// 註:這裡假設沒有其它鉤子做同樣的事情//DLLEXPORT BOOL AreTaskKeysDisabled(){return g_hHookKbdLL != NULL;}////////////////////////////////////////////////// 屏蔽任務鍵:安裝低級鍵盤構// 返回當前是否屏蔽標誌(TRUE/FALSE)//DLLEXPORT BOOL DisableTaskKeys(BOOL bDisable, BOOL bBeep){if (bDisable) {if (!g_hHookKbdLL) {g_hHookKbdLL = SetWindowsHookEx(WH_KEYBOARD_LL,MyTaskKeyHookLL, MyDll.m_hInstance, 0);}} else if (g_hHookKbdLL != NULL) {UnhookWindowsHookEx(g_hHookKbdLL);g_hHookKbdLL = NULL;}g_bBeep = bBeep;return AreTaskKeysDisabled();}
TaskKeyHook 輸出兩個函數:DisableTaskKeys 和 AreTaskKeysDisabled。前者安裝WH_KEYBOARD_LL 鉤子;後者判斷這個鉤子是否安裝。此鍵盤鉤子的處理思路是截獲Alt+Tab,Ctrl+Esc,Alt+Esc以及Windows 鍵VK_LWIN/VK_RWIN,關於這兩個鍵,稍候會有詳細描述。當鉤子碰到這些鍵時,它直接返回到調用者,而不是將處理傳遞給CallNextHookEx 。
LRESULT CALLBACK MyTaskKeyHookLL(...){if (/* 任務鍵*)return 1; // 立即返回return CallNextHookEx(...);}
TaskKeyHook的大部分實現都很簡單。只有一個地方用到了一點小技巧:既使用#pragma data_seg 命名包含全程資料的資料區段,並且用#pragma comment (linker...)告訴連結器讓這個資料區段為共用段。實現細節請參考原始碼。 本文附帶的例子程式(TrapKeys.exe)彙集了上述幾個有關屏蔽鍵盤按鍵序列的功能,除此之外,它還有一個功能就是禁用工作列。因為既然禁用了任務轉換鍵,那麼一般來說,也必然要禁用工作列,否則禁用任務轉換鍵就沒有意義了。禁用工作列的具體方法如下:
HWND hwnd = FindWindow("Shell_traywnd", NULL);//找到工作列EnableWindow(hwnd, FALSE); // 禁用工作列
四是例子程式運行畫面:
圖四 TrapKeys程式運行畫面
以下是TrapKeys程式的實現代碼:
/////////////////////////////////////////////////// TrapKeys.cpp//#include "stdafx.h"#include "resource.h"#include "StatLink.h"#include "TaskKeyMgr.h"////////////////////// 主對話方塊//class CMyDialog : public CDialog {public:CMyDialog(CWnd* pParent = NULL) : CDialog(IDD_MYDIALOG, pParent) { }protected:HICON m_hIcon;CStaticLink m_wndLink1;CStaticLink m_wndLink2;CStaticLink m_wndLink3;virtual BOOL OnInitDialog();// 命令/UI 的更新處理afx_msg void OnDisableTaskMgr();afx_msg void OnDisableTaskKeys();afx_msg void OnDisableTaskbar();afx_msg void OnUpdateDisableTaskMgr(CCmdUI* pCmdUI);afx_msg void OnUpdateDisableTaskKeys(CCmdUI* pCmdUI);afx_msg void OnUpdateDisableTaskbar(CCmdUI* pCmdUI);afx_msg LRESULT OnKickIdle(WPARAM,LPARAM);DECLARE_MESSAGE_MAP()};///////////////////////////////////////////////////////// 標準的MFC 對話方塊應用類代碼。//class CMyApp : public CWinApp {public:virtual BOOL InitInstance() {// 初始化app:運行對話方塊CMyDialog dlg;m_pMainWnd = &dlg;dlg.DoModal();return FALSE;}virtual int ExitInstance() {// 為了按全起見,在退出程式的時候,將所有禁用的項目複原CTaskKeyMgr::Disable(CTaskKeyMgr::ALL, FALSE);return 0;}} theApp;BEGIN_MESSAGE_MAP(CMyDialog, CDialog)ON_COMMAND(IDC_DISABLE_TASKKEYS,OnDisableTaskKeys)ON_COMMAND(IDC_DISABLE_TASKBAR, OnDisableTaskbar)ON_COMMAND(IDC_DISABLE_TASKMGR, OnDisableTaskMgr)ON_UPDATE_COMMAND_UI(IDC_DISABLE_TASKKEYS, OnUpdateDisableTaskKeys)ON_UPDATE_COMMAND_UI(IDC_DISABLE_TASKBAR, OnUpdateDisableTaskbar)ON_UPDATE_COMMAND_UI(IDC_DISABLE_TASKMGR, OnUpdateDisableTaskMgr)ON_MESSAGE(WM_KICKIDLE,OnKickIdle)END_MESSAGE_MAP()///////////////////////////////////////////////// 初始化對話方塊:子類化超連結柄加栽表徵圖//BOOL CMyDialog::OnInitDialog(){CDialog::OnInitDialog();// 初始化超連結m_wndLink1.SubclassDlgItem(IDC_EMAIL,this);m_wndLink2.SubclassDlgItem(IDC_VCKBASEURL,this);m_wndLink3.SubclassDlgItem(IDC_VCKBASELINK,this);// 自己設定對話方塊表徵圖。MFC不會為對話方塊應用程式設定它m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);SetIcon(m_hIcon, TRUE); // 打表徵圖SetIcon(m_hIcon, FALSE); // 小表徵圖return TRUE;}////////////////////////////////////////////////////////// 命令/UI 更新處理:寫這些東西應該很輕鬆。void CMyDialog::OnDisableTaskKeys(){CTaskKeyMgr::Disable(CTaskKeyMgr::TASKKEYS,!CTaskKeyMgr::AreTaskKeysDisabled(), TRUE); // 蜂鳴}void CMyDialog::OnUpdateDisableTaskKeys(CCmdUI* pCmdUI){pCmdUI->SetCheck(CTaskKeyMgr::AreTaskKeysDisabled());}void CMyDialog::OnDisableTaskbar(){CTaskKeyMgr::Disable(CTaskKeyMgr::TASKBAR,!CTaskKeyMgr::IsTaskBarDisabled());}void CMyDialog::OnUpdateDisableTaskbar(CCmdUI* pCmdUI){pCmdUI->SetCheck(CTaskKeyMgr::IsTaskBarDisabled());}void CMyDialog::OnDisableTaskMgr(){CTaskKeyMgr::Disable(CTaskKeyMgr::TASKMGR,!CTaskKeyMgr::IsTaskMgrDisabled());}void CMyDialog::OnUpdateDisableTaskMgr(CCmdUI* pCmdUI){pCmdUI->SetCheck(CTaskKeyMgr::IsTaskMgrDisabled());}////////////////////////////////////////////////////////// 要想讓ON_UPDATE_COMMAND_UI正常工作,這是必需的。//LRESULT CMyDialog::OnKickIdle(WPARAM wp, LPARAM lCount){UpdateDialogControls(this, TRUE);return 0;}
按上述方法儘管禁用了工作列,但是還有一個機關沒有處理,那就是按下Windows鍵仍然可以彈出“開始”菜單。顯然在處理VK_LWIN之前,工作列不會檢查是否被啟用。一般來講,如果某個視窗被屏蔽掉,那麼它就不再會處理使用者在這個視窗的輸入——這就是所謂的禁用(Disable)的含義。通常調用EnableWindow(FALSE)後自然就達到了這個目的。但是處理VK_LWIN/VK_RWIN按鍵的代碼決不會去檢查工作列啟用/禁用狀態。對此,本文的處理辦法仍然是利用鍵盤鉤子。修改一下TaskKeyHook實現,增加對Windows鍵的捕獲。這樣按下“開始”菜單鍵之後什麼也不會發生。希望沒有漏掉其它的按鍵。如果哪位讀者發現漏掉了什麼鍵,請和我聯絡,以便把它加到鍵盤鉤子中去。為了簡單起見,我在類CTaskKeyMgr中封裝了所有禁用的函數。下面是這個類的定義擊實現檔案:
TaskKeyMgr////////////////////////////////////////// TaskKeyMgr.h//#pragma once#include "TaskKeyHook.h"/////////////////////////////////////////////////////////////////////// 使用這個類禁用任務鍵,工作管理員或工作列。// 用相應的標誌調用Disable,如:CTaskMgrKeys::Disable(CTaskMgrKeys::ALL);//class CTaskKeyMgr {public:enum {TASKMGR = 0x01, // 禁用工作管理員(Ctrl+Alt+Del)TASKKEYS = 0x02, //禁用任務轉換鍵(Alt-TAB, etc)TASKBAR = 0x04, //禁用工作列ALL=0xFFFF //禁用所有東西L};static void Disable(DWORD dwItem,BOOL bDisable,BOOL bBeep=FALSE);static BOOL IsTaskMgrDisabled();static BOOL IsTaskBarDisabled();static BOOL AreTaskKeysDisabled() {return ::AreTaskKeysDisabled(); // 調用 DLL}};CPP實現////////////////////////////////////////////////////////////////// TaskKeyMgr.cpp//#include "StdAfx.h"#include "TaskKeyMgr.h"#define HKCU HKEY_CURRENT_USER// 用于禁用工作管理員策略的註冊表索引值對LPCTSTR KEY_DisableTaskMgr ="Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";LPCTSTR VAL_DisableTaskMgr = "DisableTaskMgr";///////////////////////////////////////////// 禁用相關的任務鍵//// dwFlags = 表示禁用什麼// bDisable = 禁用為 (TRUE) ,否則為啟用 (FALSE)// bBeep = 按下非法鍵是否蜂鳴(指標對任務鍵)//void CTaskKeyMgr::Disable(DWORD dwFlags, BOOL bDisable, BOOL bBeep){// 工作管理員 (Ctrl+Alt+Del)if (dwFlags & TASKMGR) {HKEY hk;if (RegOpenKey(HKCU, KEY_DisableTaskMgr,&hk)!=ERROR_SUCCESS)RegCreateKey(HKCU, KEY_DisableTaskMgr, &hk);if (bDisable) { // 禁用工作管理員(disable TM): set policy = 1DWORD val=1;RegSetValueEx(hk, VAL_DisableTaskMgr, NULL,REG_DWORD, (BYTE*)&val, sizeof(val));} else { // 啟用工作管理員(enable TM)RegDeleteValue(hk,VAL_DisableTaskMgr);}}// 任務鍵 (Alt-TAB etc)if (dwFlags & TASKKEYS)::DisableTaskKeys(bDisable,bBeep); // 安裝鍵盤鉤// 工作列if (dwFlags & TASKBAR) {HWND hwnd = FindWindow("Shell_traywnd", NULL);EnableWindow(hwnd, !bDisable);}}BOOL CTaskKeyMgr::IsTaskBarDisabled(){HWND hwnd = FindWindow("Shell_traywnd", NULL);return IsWindow(hwnd) ? !IsWindowEnabled(hwnd) : TRUE;}BOOL CTaskKeyMgr::IsTaskMgrDisabled(){HKEY hk;if (RegOpenKey(HKCU, KEY_DisableTaskMgr, &hk)!=ERROR_SUCCESS)return FALSE; // 沒有此鍵,不禁用DWORD val=0;DWORD len=4;return RegQueryValueEx(hk, VAL_DisableTaskMgr,NULL, NULL, (BYTE*)&val, &len)==ERROR_SUCCESS && val==1;}
這個類中的函數都是靜態,實際上CTaskKeyMgr完全就是一個名字空間。你可以在自己的程式中隨心所欲地使用它。例如,禁用任務轉換按鍵和工作列,但是不禁用Ctrl+Alt+Del:
CTaskKeyMgr::Disable(CTaskKeyMgr::TASKKEYS |CTaskKeyMgr::TASKBAR, TRUE);
此外,還有幾個函數是用來檢查當前禁用了哪些東西,甚至可以在使用者按下禁用鍵時發出蜂鳴聲……自己去享受Paul的原始碼吧!