XP系統(tǒng)中屏蔽Ctrl+Esc鍵序列的方法
發(fā)布時間:2013-11-11 10:04:57 作者:佚名
我要評論

在Windows XP中如何實現(xiàn)屏蔽CTRL+ALT+DEL組合鍵,也就是任務(wù)管理器,任務(wù)切換組合鍵(Alt+Tab),任務(wù)欄和“開始”菜單Ctrl+Esc,VK_LWIN,VK_RWIN
對于用過Windows的人,幾乎沒有人不知道Ctrl+Alt+Del組合鍵,尤其是在使用經(jīng)常死機的Windows9x時,使用它的頻率更高,這一組合鍵是專門為了系統(tǒng)安全起見提供的緊急出口。VC知識庫在線雜志第11期,ac952_z_cn在他的個人專欄中寫過一篇關(guān)于這方面的文章:“WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL”。因此本文側(cè)重于介紹在Windows XP中如何實現(xiàn)屏蔽CTRL+ALT+DEL組合鍵,也就是任務(wù)管理器,任務(wù)切換組合鍵(Alt+Tab),任務(wù)欄和“開始”菜單(Ctrl+Esc,VK_LWIN,VK_RWIN)。這個方法也能應(yīng)用于Windows 2000環(huán)境。
在Windows 9x/Me系統(tǒng)中,屏蔽Ctrl+Alt+Del和各種任務(wù)開關(guān)鍵的方法是通過下面的方法實現(xiàn)的:
BOOL bOldState;
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &bOldState, 0);
MS大佬認(rèn)為這種方法很業(yè)余,所以在Windows NT/2000/XP中對此進(jìn)行了修改。在這些較新的Windows版本中用戶登陸使用Winlogon和GINA——Graphical Identification and Authentication,意思是圖形化的身份認(rèn)證,挺嚇唬人的是不是!其實就那么回事。Winlogon是Windows系統(tǒng)的一部分,它專門提供交互式登陸支持,而GINA則是Winlogon用來實現(xiàn)認(rèn)證的一個DLL——這個DLL就是msgina.dll。WlxInitialize、WlxActivateUserShell便是其中輸出,當(dāng)然不知這兩個,還有別的。前者進(jìn)行自身的初始化,后者激活用戶的外殼程序。Windows就是用這個DLL來實現(xiàn)用戶名+口令的身份認(rèn)證的,但是開發(fā)人員可以用自己的GINA代替msgina.dll。例如,實現(xiàn)智能卡、視網(wǎng)膜掃描儀、DNA檢查等等認(rèn)證機制來代替輸入用戶名+口令形式的身份檢查。 下面的表格中列出了與GINA有關(guān)的全部函數(shù)。其中有一個是WlxLoggedOnSAS,當(dāng)按下Ctrl+Alt+Del 鍵時,Winlogon便調(diào)用這個函數(shù)。
(表一)GINA 函數(shù)一覽表 函數(shù) 描述
WlxActivateUserShell激活用戶外殼程序
WlxDisplayLockedNotice允許GINA DLL 顯示鎖定信息
WlxDisplaySASNotice 當(dāng)沒有用戶登陸時,Winlogon調(diào)用此函數(shù)
WlxDisplayStatusMessageWinlogon 用一個狀態(tài)信息調(diào)用此函數(shù)進(jìn)行顯示
WlxGetConsoleSwitchCredentials Winlogon調(diào)用此函數(shù)讀取當(dāng)前登陸用戶的信任信息,并透明地將它們傳到目標(biāo)會話
WlxGetStatusMessage Winlogon 調(diào)用此函數(shù)獲取當(dāng)前狀態(tài)信息
WlxInitialize 針對指定的窗口位置進(jìn)行GINA DLL初始化
WlxIsLockOk 驗證工作站正常鎖定
WlxIslogoffOk 驗證注銷正常
WlxLoggedOnSAS 用戶已登陸并且工作站沒有被加鎖,如果此時接收到SAS事件,則Winlogon 調(diào)用此函數(shù)
WlxLoggedOutSAS 沒有用戶登陸,如果此時收到SAS事件,則Winlogon 調(diào)用此函數(shù)
WlxLogoff 請求注銷操作時通知GINA DLL
WlxNegotiate 表示當(dāng)前的Winlogon版本是否能使用GINA DLL
WlxNetworkProviderLoad 在加載網(wǎng)絡(luò)服務(wù)提供程序收集了身份和認(rèn)證信息后,Winlogon 調(diào)用此函數(shù)
WlxRemoveStatusMessage Winlogon 調(diào)用此函數(shù)告訴GINA DLL 停止顯示狀態(tài)信息
WlxScreensaverNotify 允許GINA與屏幕保護(hù)操作交互
WlxShutdown 在關(guān)閉之前Winlogon 調(diào)用此函數(shù),允許GINA實現(xiàn)任何關(guān)閉任務(wù),例如從讀卡器中退出智能卡
WlxStartApplication 當(dāng)系統(tǒng)需要在用戶的上下文中啟動應(yīng)用程序時調(diào)用此函數(shù)
WlxWkstaLockedSAS當(dāng)工作站被鎖定,如果接收到一個SAS,則Winlogon 調(diào)用此函數(shù)
在默認(rèn)情況下,GINA顯示登陸對話框,用戶輸入用戶名及口令。所以要想屏蔽掉Ctrl+Alt+Del,則可以寫一個新的MyGina.dll,其中提供接口調(diào)用msgina.dll的函數(shù)WlxLoggedOnSAS,從而實現(xiàn)Ctrl+Alt+Del屏蔽?;蛘呔帉懸粋€鍵盤驅(qū)動程序來實現(xiàn)。
難道屏蔽Ctrl+Alt+Del真的象上述所說的那么麻煩嗎?有沒有更好的方法呢?答案是肯定的。所以忘掉GINA吧,使用操作系統(tǒng)的策略設(shè)置完全可以搞掂這個問題。方法是進(jìn)入"開始"菜單,選擇"運行",然后在運行對話框中輸入"gpedit.msc",啟動Windows系統(tǒng)的組策略編輯器。在左邊窗格查看"用戶配置|管理模板|系統(tǒng)|登錄/注銷",則在右邊窗格策略里不難發(fā)現(xiàn)"禁用任務(wù)管理器"一項。
組策略編輯器
通過對這個策略的設(shè)置可以屏蔽掉Ctrl+Alt+Del。如果要通過編寫代碼來實現(xiàn),則必須操作下面的注冊表項:
HKCU\
Software\
Microsoft\
Windows\
CurrentVersion\
Policies\
System\DisableTaskMgr = dword:1
如此設(shè)置之后,則在Windows XP中,如果用戶按下Ctrl+Alt+Del,則會彈出一個出錯對話框,
注意這里假設(shè)在控制面板中“用戶帳號”管理的“選擇登錄和注銷選項”設(shè)置啟用了“使用歡迎屏幕”一項。
否則,XP將使用Windows的傳統(tǒng)登錄模式,要求用戶輸入帳戶名。并且Ctrl+Alt+Del組合鍵的 行為也和傳統(tǒng)的行為一樣,注冊表中DisableTaskMgr的設(shè)置也只是將登錄/注銷對話框中的任務(wù)管理器按鈕屏蔽或置灰。 有人可能會問,有關(guān)任務(wù)管理器的文檔又沒有明確說明,那你是怎么知道DisableTaskMgr是用來禁用任務(wù)管理器的呢?告訴你吧, 我是在使用GPEDIT時發(fā)現(xiàn)的。GPEDIT是一個非常有用的工具,不僅可以用它來編輯策略,還可以用它來發(fā)現(xiàn)策略。利用這個工具可以輕松控制Windows的許多東西,從許可權(quán)限的存取到是否使用IE的傳統(tǒng)外觀,從是否顯示對話框中的Places Bar到是否用Ctrl+Alt+Del 啟動任務(wù)管理器。總之用它可以配置上百個界面行為,因此它是一個足以讓系統(tǒng)管理員垂延三尺的工具。一旦找到了感興趣的策略,那如何知道相應(yīng)的注冊表位置呢?有兩種方法。第一種是比較粗魯?shù)霓k法:在修改策略的前后將注冊表輸出到一個.reg文件,然后比較它們有什么不同。所有的策略無外乎以下的四個注冊表鍵:
// 用戶指定
HKEY_CURRENT_USER\Software\Policies
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies
// 機器指定
HKEY_LOCAL_MACHINE\Software\Policies
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies
第二種方法是直搗信息源頭--檢查描述策略的管理模板文件(.adm)。下面是Windows XP的system.adm文件對 DisableTaskMgr的描述:(Windows 2000對此的描述稍有不同,其細(xì)節(jié)請參考Windows 2000的資源開發(fā)包)
CATEGORY !!CADOptions
#if version >= 4
EXPLAIN !!CADOptions_Help
#endif
KEYNAME "Software\Microsoft\Windows\CurrentVersion\Policies\System"
POLICY !!DisableTaskMgr
#if version >= 4
SUPPORTED !!SUPPORTED_Win2k
#endif
EXPLAIN !!DisableTaskMgr_Help
VALUENAME "DisableTaskMgr"
END POLICY
;
; More Ctrl+Alt+Del policies here...
;
END CATEGORY ; Ctrl+Alt+Del options
……
……
DisableTaskMgr_Help="防止用戶啟動''任務(wù)管理器''(Taskmgr.exe)。\n\n如果該設(shè)置被啟用,并且用戶試圖啟動任務(wù)管理器,系統(tǒng)
會顯示消息,解釋是一個策略禁止了這個操作。\n\n任務(wù)管理器讓用戶啟動或終止程序,監(jiān)視計算機性能,查看及監(jiān)視計算機上所有運行
中的程序 (包含系統(tǒng)服務(wù)), 搜索程序的執(zhí)行文件名,及更改程序運行的優(yōu)先順序。"
DisableTaskMgr="刪除任務(wù)管理器"
以上是DisableTaskMgr的描述片斷
正是在這段描述中KEYNAME 和VALUENAME指定了注冊表的鍵值對。利用這種方法,你可以為自己的應(yīng)用程序創(chuàng)建管理模板和策略,但編輯和瀏覽.adm模板文件的編輯器必須支持Unicode字符。如Notepad或者WordPad等都可以。此外,使用管理模板文件,系統(tǒng)管理員可以用它為整個組織配置需要的策略——由此可以看出,此文件在系統(tǒng)中的地位舉足輕重!有關(guān)模板管理文件格式的詳細(xì)信息請參考平臺SDK。最后需要強調(diào)的是DisableTaskMgr只是禁用Ctrl+Alt+Del的功能。下面我們來討論如何捕獲它的按鍵序列。要想截獲Ctrl+Alt+Del,有三種可選擇的方法:
1、 編寫一個GINA代理;此方法我們在以后的文章中介紹。實際上,ac952_z_cn的個人專欄文章:“WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL”使用的就是這種方法。
2、 編寫一個鍵盤驅(qū)動程序;本文例子程序使用的方法。
3、 用自己的程序代替任務(wù)管理器程序TaskMgr.exe。
屏蔽Ctrl+Alt+Del解決方案的具體實現(xiàn)細(xì)節(jié)請參考本文的例子代碼。
下面讓我們來解決屏蔽任務(wù)切換鍵序列的問題,這些鍵序列包括Alt+Tab、Ctrl+Esc、Alt+Esc、VK_LWIN/VK_RWIN以及任務(wù)欄。在很早以前的Window 3.1年代,處理這個問題的方法是通過WM_SYSKEYDOWN實現(xiàn)。到了Windows 9x時期,本文前面提到過對這個問題的處理方法,使用SPI_SETSCREENSAVERRUNNING。但是進(jìn)入Windows NT 4.0 (SP3 +),Windows 2000以及Windows XP時代,對這個問題的處理已經(jīng)有所不同,必須寫一個低級的鍵盤驅(qū)動鉤子。不要怕,因為要實現(xiàn)這個鉤子并不是很難。本文下面會介紹如何實現(xiàn)這個鍵盤鉤子。一般來講,系統(tǒng)級鉤子必須是一個DLL。下面是本文提供的一個鍵盤鉤子DLL的源代碼片斷(TaskKeyHook.dll):
頭文件
////////////////////////////////////////////////////////////////
//TaskKeyHook.h
//
#define DLLIMPORT __declspec(dllimport)
DLLIMPORT BOOL DisableTaskKeys(BOOL bEnable, BOOL bBeep);
DLLIMPORT BOOL AreTaskKeysDisabled();
實現(xiàn)文件
////////////////////////////////////////////////////////////////
// TaskKeyHook.cpp
//
#define _WIN32_WINNT 0x0500 // for KBDLLHOOKSTRUCT
#include // MFC core and standard components
#define DLLEXPORT __declspec(dllexport)
//////////////////
// App (DLL) object
//
class CTaskKeyHookDll : public CWinApp {
public:
CTaskKeyHookDll() { }
~CTaskKeyHookDll() { }
} MyDll;
////////////////////////////////////////////////
// 下面的代碼表示這一部分在此DLL所有實例之間共享
// 低級鍵盤鉤子一定是系統(tǒng)級的鉤子
//
#pragma data_seg (".mydata")
HHOOK g_hHookKbdLL = NULL; // 鉤子句柄
BOOL g_bBeep = FALSE; // 按下非法鍵時蜂鳴響鈴
#pragma data_seg ()
#pragma comment(linker, "/SECTION:.mydata,RWS") // 告訴鏈接器:建立數(shù)據(jù)共享段
//////////////////////////////////
// 低級鍵盤鉤子
// 截獲任務(wù)轉(zhuǎn)換鍵:不傳遞直接返回
//
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);
}
////////////////////////////////////////////////
// 是否屏蔽任務(wù)鍵序列——也就是說鍵盤鉤子是否安裝?
// 注:這里假設(shè)沒有其它鉤子做同樣的事情
//
DLLEXPORT BOOL AreTaskKeysDisabled()
{
return g_hHookKbdLL != NULL;
}
////////////////////////////////////////////////
// 屏蔽任務(wù)鍵:安裝低級鍵盤構(gòu)
// 返回當(dāng)前是否屏蔽標(biāo)志(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 輸出兩個函數(shù):DisableTaskKeys 和 AreTaskKeysDisabled。前者安裝WH_KEYBOARD_LL 鉤子;后者判斷這個鉤子是否安裝。此鍵盤鉤子的處理思路是截獲Alt+Tab,Ctrl+Esc,Alt+Esc以及Windows 鍵VK_LWIN/VK_RWIN,關(guān)于這兩個鍵,稍候會有詳細(xì)描述。當(dāng)鉤子碰到這些鍵時,它直接返回到調(diào)用者,而不是將處理傳遞給CallNextHookEx 。
LRESULT CALLBACK MyTaskKeyHookLL(...)
{
if (/* 任務(wù)鍵*)
return 1; // 立即返回
return CallNextHookEx(...);
}
TaskKeyHook的大部分實現(xiàn)都很簡單。只有一個地方用到了一點小技巧:既使用#pragma data_seg 命名包含全程數(shù)據(jù)的數(shù)據(jù)段,并且用#pragma comment (linker...)告訴鏈接器讓這個數(shù)據(jù)段為共享段。實現(xiàn)細(xì)節(jié)請參考源代碼。本文附帶的例子程序(TrapKeys.exe)匯集了上述幾個有關(guān)屏蔽鍵盤按鍵序列的功能,除此之外,它還有一個功能就是禁用任務(wù)欄。因為既然禁用了任務(wù)轉(zhuǎn)換鍵,那么一般來說,也必然要禁用任務(wù)欄,否則禁用任務(wù)轉(zhuǎn)換鍵就沒有意義了。禁用任務(wù)欄的具體方法如下:
HWND hwnd = FindWindow("Shell_traywnd", NULL);//找到任務(wù)欄
EnableWindow(hwnd, FALSE); // 禁用任務(wù)欄
如圖四是例子程序運行畫面:
圖四 TrapKeys程序運行畫面
以下是TrapKeys程序的實現(xiàn)代碼:
/////////////////////////////////////////////////
// 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()
};
///////////////////////////////////////////////////////
// 標(biāo)準(zhǔn)的MFC 對話框應(yīng)用類代碼。
//
class CMyApp : public CWinApp {
public:
virtual BOOL InitInstance() {
// 初始化app:運行對話框
CMyDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
return FALSE;
}
virtual int ExitInstance() {
// 為了按全起見,在退出程序的時候,將所有禁用的項目復(fù)原
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()
///////////////////////////////////////////////
// 初始化對話框:子類化超鏈接柄加栽圖標(biāo)
//
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// 初始化超鏈接
m_wndLink1.SubclassDlgItem(IDC_EMAIL,this);
m_wndLink2.SubclassDlgItem(IDC_VCKBASEURL,this);
m_wndLink3.SubclassDlgItem(IDC_VCKBASELINK,this);
// 自己設(shè)置對話框圖標(biāo)。MFC不會為對話框應(yīng)用程序設(shè)置它
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
SetIcon(m_hIcon, TRUE); // 打圖標(biāo)
SetIcon(m_hIcon, FALSE); // 小圖標(biāo)
return TRUE;
}
////////////////////////////////////////////////////////
// 命令/UI 更新處理:寫這些東西應(yīng)該很輕松。
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;
}
按上述方法盡管禁用了任務(wù)欄,但是還有一個機關(guān)沒有處理,那就是按下Windows鍵仍然可以彈出“開始”菜單。顯然在處理VK_LWIN之前,任務(wù)欄不會檢查是否被啟用。一般來講,如果某個窗口被屏蔽掉,那么它就不再會處理用戶在這個窗口的輸入——這就是所謂的禁用(Disable)的含義。通常調(diào)用EnableWindow(FALSE)后自然就達(dá)到了這個目的。但是處理VK_LWIN/VK_RWIN按鍵的代碼決不會去檢查任務(wù)欄啟用/禁用狀態(tài)。對此,本文的處理辦法仍然是利用鍵盤鉤子。修改一下TaskKeyHook實現(xiàn),增加對Windows鍵的捕獲。這樣按下“開始”菜單鍵之后什么也不會發(fā)生。希望沒有漏掉其它的按鍵。如果哪位讀者發(fā)現(xiàn)漏掉了什么鍵,請和我聯(lián)系,以便把它加到鍵盤鉤子中去。為了簡單起見,我在類CTaskKeyMgr中封裝了所有禁用的函數(shù)。下面是這個類的定義擊實現(xiàn)文件:
TaskKeyMgr
////////////////////////////////////////
// TaskKeyMgr.h
//
#pragma once
#include "TaskKeyHook.h"
/////////////////////////////////////////////////////////////////////
// 使用這個類禁用任務(wù)鍵,任務(wù)管理器或任務(wù)欄。
// 用相應(yīng)的標(biāo)志調(diào)用Disable,如:CTaskMgrKeys::Disable(CTaskMgrKeys::ALL);
//
class CTaskKeyMgr {
public:
enum {
TASKMGR = 0x01, // 禁用任務(wù)管理器(Ctrl+Alt+Del)
TASKKEYS = 0x02, //禁用任務(wù)轉(zhuǎn)換鍵(Alt-TAB, etc)
TASKBAR = 0x04, //禁用任務(wù)欄
ALL=0xFFFF //禁用所有東西L
};
static void Disable(DWORD dwItem,BOOL bDisable,BOOL bBeep=FALSE);
static BOOL IsTaskMgrDisabled();
static BOOL IsTaskBarDisabled();
static BOOL AreTaskKeysDisabled() {
return ::AreTaskKeysDisabled(); // 調(diào)用 DLL
}
};
CPP實現(xiàn)
////////////////////////////////////////////////////////////////
// TaskKeyMgr.cpp
//
#include "StdAfx.h"
#include "TaskKeyMgr.h"
#define HKCU HKEY_CURRENT_USER
// 用于禁用任務(wù)管理器策略的注冊表鍵值對
LPCTSTR KEY_DisableTaskMgr =
"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
LPCTSTR VAL_DisableTaskMgr = "DisableTaskMgr";
///////////////////////////////////////////
// 禁用相關(guān)的任務(wù)鍵
//
// dwFlags = 表示禁用什么
// bDisable = 禁用為 (TRUE) ,否則為啟用 (FALSE)
// bBeep = 按下非法鍵是否蜂鳴(指針對任務(wù)鍵)
//
void CTaskKeyMgr::Disable(DWORD dwFlags, BOOL bDisable, BOOL bBeep)
{
// 任務(wù)管理器 (Ctrl+Alt+Del)
if (dwFlags & TASKMGR) {
HKEY hk;
if (RegOpenKey(HKCU, KEY_DisableTaskMgr,&hk)!=ERROR_SUCCESS)
RegCreateKey(HKCU, KEY_DisableTaskMgr, &hk);
if (bDisable) { // 禁用任務(wù)管理器(disable TM): set policy = 1
DWORD val=1;
RegSetValueEx(hk, VAL_DisableTaskMgr, NULL,
REG_DWORD, (BYTE*)&val, sizeof(val));
} else { // 啟用任務(wù)管理器(enable TM)
RegDeleteValue(hk,VAL_DisableTaskMgr);
}
}
// 任務(wù)鍵 (Alt-TAB etc)
if (dwFlags & TASKKEYS)
::DisableTaskKeys(bDisable,bBeep); // 安裝鍵盤鉤
// 任務(wù)欄
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;
}
這個類中的函數(shù)都是靜態(tài)的,實際上CTaskKeyMgr完全就是一個名字空間。你可以在自己的程序中隨心所欲地使用它。例如,禁用任務(wù)轉(zhuǎn)換按鍵和任務(wù)欄,但是不禁用Ctrl+Alt+Del:
CTaskKeyMgr::Disable(CTaskKeyMgr::TASKKEYS |
CTaskKeyMgr::TASKBAR, TRUE);
此外,還有幾個函數(shù)是用來檢查當(dāng)前禁用了哪些東西,甚至可以在用戶按下禁用鍵時發(fā)出蜂鳴聲……自己去享受Paul的源代碼吧!
在Windows 9x/Me系統(tǒng)中,屏蔽Ctrl+Alt+Del和各種任務(wù)開關(guān)鍵的方法是通過下面的方法實現(xiàn)的:
BOOL bOldState;
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &bOldState, 0);
MS大佬認(rèn)為這種方法很業(yè)余,所以在Windows NT/2000/XP中對此進(jìn)行了修改。在這些較新的Windows版本中用戶登陸使用Winlogon和GINA——Graphical Identification and Authentication,意思是圖形化的身份認(rèn)證,挺嚇唬人的是不是!其實就那么回事。Winlogon是Windows系統(tǒng)的一部分,它專門提供交互式登陸支持,而GINA則是Winlogon用來實現(xiàn)認(rèn)證的一個DLL——這個DLL就是msgina.dll。WlxInitialize、WlxActivateUserShell便是其中輸出,當(dāng)然不知這兩個,還有別的。前者進(jìn)行自身的初始化,后者激活用戶的外殼程序。Windows就是用這個DLL來實現(xiàn)用戶名+口令的身份認(rèn)證的,但是開發(fā)人員可以用自己的GINA代替msgina.dll。例如,實現(xiàn)智能卡、視網(wǎng)膜掃描儀、DNA檢查等等認(rèn)證機制來代替輸入用戶名+口令形式的身份檢查。 下面的表格中列出了與GINA有關(guān)的全部函數(shù)。其中有一個是WlxLoggedOnSAS,當(dāng)按下Ctrl+Alt+Del 鍵時,Winlogon便調(diào)用這個函數(shù)。
(表一)GINA 函數(shù)一覽表 函數(shù) 描述
WlxActivateUserShell激活用戶外殼程序
WlxDisplayLockedNotice允許GINA DLL 顯示鎖定信息
WlxDisplaySASNotice 當(dāng)沒有用戶登陸時,Winlogon調(diào)用此函數(shù)
WlxDisplayStatusMessageWinlogon 用一個狀態(tài)信息調(diào)用此函數(shù)進(jìn)行顯示
WlxGetConsoleSwitchCredentials Winlogon調(diào)用此函數(shù)讀取當(dāng)前登陸用戶的信任信息,并透明地將它們傳到目標(biāo)會話
WlxGetStatusMessage Winlogon 調(diào)用此函數(shù)獲取當(dāng)前狀態(tài)信息
WlxInitialize 針對指定的窗口位置進(jìn)行GINA DLL初始化
WlxIsLockOk 驗證工作站正常鎖定
WlxIslogoffOk 驗證注銷正常
WlxLoggedOnSAS 用戶已登陸并且工作站沒有被加鎖,如果此時接收到SAS事件,則Winlogon 調(diào)用此函數(shù)
WlxLoggedOutSAS 沒有用戶登陸,如果此時收到SAS事件,則Winlogon 調(diào)用此函數(shù)
WlxLogoff 請求注銷操作時通知GINA DLL
WlxNegotiate 表示當(dāng)前的Winlogon版本是否能使用GINA DLL
WlxNetworkProviderLoad 在加載網(wǎng)絡(luò)服務(wù)提供程序收集了身份和認(rèn)證信息后,Winlogon 調(diào)用此函數(shù)
WlxRemoveStatusMessage Winlogon 調(diào)用此函數(shù)告訴GINA DLL 停止顯示狀態(tài)信息
WlxScreensaverNotify 允許GINA與屏幕保護(hù)操作交互
WlxShutdown 在關(guān)閉之前Winlogon 調(diào)用此函數(shù),允許GINA實現(xiàn)任何關(guān)閉任務(wù),例如從讀卡器中退出智能卡
WlxStartApplication 當(dāng)系統(tǒng)需要在用戶的上下文中啟動應(yīng)用程序時調(diào)用此函數(shù)
WlxWkstaLockedSAS當(dāng)工作站被鎖定,如果接收到一個SAS,則Winlogon 調(diào)用此函數(shù)
在默認(rèn)情況下,GINA顯示登陸對話框,用戶輸入用戶名及口令。所以要想屏蔽掉Ctrl+Alt+Del,則可以寫一個新的MyGina.dll,其中提供接口調(diào)用msgina.dll的函數(shù)WlxLoggedOnSAS,從而實現(xiàn)Ctrl+Alt+Del屏蔽?;蛘呔帉懸粋€鍵盤驅(qū)動程序來實現(xiàn)。
難道屏蔽Ctrl+Alt+Del真的象上述所說的那么麻煩嗎?有沒有更好的方法呢?答案是肯定的。所以忘掉GINA吧,使用操作系統(tǒng)的策略設(shè)置完全可以搞掂這個問題。方法是進(jìn)入"開始"菜單,選擇"運行",然后在運行對話框中輸入"gpedit.msc",啟動Windows系統(tǒng)的組策略編輯器。在左邊窗格查看"用戶配置|管理模板|系統(tǒng)|登錄/注銷",則在右邊窗格策略里不難發(fā)現(xiàn)"禁用任務(wù)管理器"一項。
組策略編輯器
通過對這個策略的設(shè)置可以屏蔽掉Ctrl+Alt+Del。如果要通過編寫代碼來實現(xiàn),則必須操作下面的注冊表項:
HKCU\
Software\
Microsoft\
Windows\
CurrentVersion\
Policies\
System\DisableTaskMgr = dword:1
如此設(shè)置之后,則在Windows XP中,如果用戶按下Ctrl+Alt+Del,則會彈出一個出錯對話框,
注意這里假設(shè)在控制面板中“用戶帳號”管理的“選擇登錄和注銷選項”設(shè)置啟用了“使用歡迎屏幕”一項。
否則,XP將使用Windows的傳統(tǒng)登錄模式,要求用戶輸入帳戶名。并且Ctrl+Alt+Del組合鍵的 行為也和傳統(tǒng)的行為一樣,注冊表中DisableTaskMgr的設(shè)置也只是將登錄/注銷對話框中的任務(wù)管理器按鈕屏蔽或置灰。 有人可能會問,有關(guān)任務(wù)管理器的文檔又沒有明確說明,那你是怎么知道DisableTaskMgr是用來禁用任務(wù)管理器的呢?告訴你吧, 我是在使用GPEDIT時發(fā)現(xiàn)的。GPEDIT是一個非常有用的工具,不僅可以用它來編輯策略,還可以用它來發(fā)現(xiàn)策略。利用這個工具可以輕松控制Windows的許多東西,從許可權(quán)限的存取到是否使用IE的傳統(tǒng)外觀,從是否顯示對話框中的Places Bar到是否用Ctrl+Alt+Del 啟動任務(wù)管理器。總之用它可以配置上百個界面行為,因此它是一個足以讓系統(tǒng)管理員垂延三尺的工具。一旦找到了感興趣的策略,那如何知道相應(yīng)的注冊表位置呢?有兩種方法。第一種是比較粗魯?shù)霓k法:在修改策略的前后將注冊表輸出到一個.reg文件,然后比較它們有什么不同。所有的策略無外乎以下的四個注冊表鍵:
// 用戶指定
HKEY_CURRENT_USER\Software\Policies
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies
// 機器指定
HKEY_LOCAL_MACHINE\Software\Policies
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies
第二種方法是直搗信息源頭--檢查描述策略的管理模板文件(.adm)。下面是Windows XP的system.adm文件對 DisableTaskMgr的描述:(Windows 2000對此的描述稍有不同,其細(xì)節(jié)請參考Windows 2000的資源開發(fā)包)
CATEGORY !!CADOptions
#if version >= 4
EXPLAIN !!CADOptions_Help
#endif
KEYNAME "Software\Microsoft\Windows\CurrentVersion\Policies\System"
POLICY !!DisableTaskMgr
#if version >= 4
SUPPORTED !!SUPPORTED_Win2k
#endif
EXPLAIN !!DisableTaskMgr_Help
VALUENAME "DisableTaskMgr"
END POLICY
;
; More Ctrl+Alt+Del policies here...
;
END CATEGORY ; Ctrl+Alt+Del options
……
……
DisableTaskMgr_Help="防止用戶啟動''任務(wù)管理器''(Taskmgr.exe)。\n\n如果該設(shè)置被啟用,并且用戶試圖啟動任務(wù)管理器,系統(tǒng)
會顯示消息,解釋是一個策略禁止了這個操作。\n\n任務(wù)管理器讓用戶啟動或終止程序,監(jiān)視計算機性能,查看及監(jiān)視計算機上所有運行
中的程序 (包含系統(tǒng)服務(wù)), 搜索程序的執(zhí)行文件名,及更改程序運行的優(yōu)先順序。"
DisableTaskMgr="刪除任務(wù)管理器"
以上是DisableTaskMgr的描述片斷
正是在這段描述中KEYNAME 和VALUENAME指定了注冊表的鍵值對。利用這種方法,你可以為自己的應(yīng)用程序創(chuàng)建管理模板和策略,但編輯和瀏覽.adm模板文件的編輯器必須支持Unicode字符。如Notepad或者WordPad等都可以。此外,使用管理模板文件,系統(tǒng)管理員可以用它為整個組織配置需要的策略——由此可以看出,此文件在系統(tǒng)中的地位舉足輕重!有關(guān)模板管理文件格式的詳細(xì)信息請參考平臺SDK。最后需要強調(diào)的是DisableTaskMgr只是禁用Ctrl+Alt+Del的功能。下面我們來討論如何捕獲它的按鍵序列。要想截獲Ctrl+Alt+Del,有三種可選擇的方法:
1、 編寫一個GINA代理;此方法我們在以后的文章中介紹。實際上,ac952_z_cn的個人專欄文章:“WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL”使用的就是這種方法。
2、 編寫一個鍵盤驅(qū)動程序;本文例子程序使用的方法。
3、 用自己的程序代替任務(wù)管理器程序TaskMgr.exe。
屏蔽Ctrl+Alt+Del解決方案的具體實現(xiàn)細(xì)節(jié)請參考本文的例子代碼。
下面讓我們來解決屏蔽任務(wù)切換鍵序列的問題,這些鍵序列包括Alt+Tab、Ctrl+Esc、Alt+Esc、VK_LWIN/VK_RWIN以及任務(wù)欄。在很早以前的Window 3.1年代,處理這個問題的方法是通過WM_SYSKEYDOWN實現(xiàn)。到了Windows 9x時期,本文前面提到過對這個問題的處理方法,使用SPI_SETSCREENSAVERRUNNING。但是進(jìn)入Windows NT 4.0 (SP3 +),Windows 2000以及Windows XP時代,對這個問題的處理已經(jīng)有所不同,必須寫一個低級的鍵盤驅(qū)動鉤子。不要怕,因為要實現(xiàn)這個鉤子并不是很難。本文下面會介紹如何實現(xiàn)這個鍵盤鉤子。一般來講,系統(tǒng)級鉤子必須是一個DLL。下面是本文提供的一個鍵盤鉤子DLL的源代碼片斷(TaskKeyHook.dll):
頭文件
////////////////////////////////////////////////////////////////
//TaskKeyHook.h
//
#define DLLIMPORT __declspec(dllimport)
DLLIMPORT BOOL DisableTaskKeys(BOOL bEnable, BOOL bBeep);
DLLIMPORT BOOL AreTaskKeysDisabled();
實現(xiàn)文件
////////////////////////////////////////////////////////////////
// TaskKeyHook.cpp
//
#define _WIN32_WINNT 0x0500 // for KBDLLHOOKSTRUCT
#include // MFC core and standard components
#define DLLEXPORT __declspec(dllexport)
//////////////////
// App (DLL) object
//
class CTaskKeyHookDll : public CWinApp {
public:
CTaskKeyHookDll() { }
~CTaskKeyHookDll() { }
} MyDll;
////////////////////////////////////////////////
// 下面的代碼表示這一部分在此DLL所有實例之間共享
// 低級鍵盤鉤子一定是系統(tǒng)級的鉤子
//
#pragma data_seg (".mydata")
HHOOK g_hHookKbdLL = NULL; // 鉤子句柄
BOOL g_bBeep = FALSE; // 按下非法鍵時蜂鳴響鈴
#pragma data_seg ()
#pragma comment(linker, "/SECTION:.mydata,RWS") // 告訴鏈接器:建立數(shù)據(jù)共享段
//////////////////////////////////
// 低級鍵盤鉤子
// 截獲任務(wù)轉(zhuǎn)換鍵:不傳遞直接返回
//
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);
}
////////////////////////////////////////////////
// 是否屏蔽任務(wù)鍵序列——也就是說鍵盤鉤子是否安裝?
// 注:這里假設(shè)沒有其它鉤子做同樣的事情
//
DLLEXPORT BOOL AreTaskKeysDisabled()
{
return g_hHookKbdLL != NULL;
}
////////////////////////////////////////////////
// 屏蔽任務(wù)鍵:安裝低級鍵盤構(gòu)
// 返回當(dāng)前是否屏蔽標(biāo)志(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 輸出兩個函數(shù):DisableTaskKeys 和 AreTaskKeysDisabled。前者安裝WH_KEYBOARD_LL 鉤子;后者判斷這個鉤子是否安裝。此鍵盤鉤子的處理思路是截獲Alt+Tab,Ctrl+Esc,Alt+Esc以及Windows 鍵VK_LWIN/VK_RWIN,關(guān)于這兩個鍵,稍候會有詳細(xì)描述。當(dāng)鉤子碰到這些鍵時,它直接返回到調(diào)用者,而不是將處理傳遞給CallNextHookEx 。
LRESULT CALLBACK MyTaskKeyHookLL(...)
{
if (/* 任務(wù)鍵*)
return 1; // 立即返回
return CallNextHookEx(...);
}
TaskKeyHook的大部分實現(xiàn)都很簡單。只有一個地方用到了一點小技巧:既使用#pragma data_seg 命名包含全程數(shù)據(jù)的數(shù)據(jù)段,并且用#pragma comment (linker...)告訴鏈接器讓這個數(shù)據(jù)段為共享段。實現(xiàn)細(xì)節(jié)請參考源代碼。本文附帶的例子程序(TrapKeys.exe)匯集了上述幾個有關(guān)屏蔽鍵盤按鍵序列的功能,除此之外,它還有一個功能就是禁用任務(wù)欄。因為既然禁用了任務(wù)轉(zhuǎn)換鍵,那么一般來說,也必然要禁用任務(wù)欄,否則禁用任務(wù)轉(zhuǎn)換鍵就沒有意義了。禁用任務(wù)欄的具體方法如下:
HWND hwnd = FindWindow("Shell_traywnd", NULL);//找到任務(wù)欄
EnableWindow(hwnd, FALSE); // 禁用任務(wù)欄
如圖四是例子程序運行畫面:
圖四 TrapKeys程序運行畫面
以下是TrapKeys程序的實現(xiàn)代碼:
/////////////////////////////////////////////////
// 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()
};
///////////////////////////////////////////////////////
// 標(biāo)準(zhǔn)的MFC 對話框應(yīng)用類代碼。
//
class CMyApp : public CWinApp {
public:
virtual BOOL InitInstance() {
// 初始化app:運行對話框
CMyDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
return FALSE;
}
virtual int ExitInstance() {
// 為了按全起見,在退出程序的時候,將所有禁用的項目復(fù)原
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()
///////////////////////////////////////////////
// 初始化對話框:子類化超鏈接柄加栽圖標(biāo)
//
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// 初始化超鏈接
m_wndLink1.SubclassDlgItem(IDC_EMAIL,this);
m_wndLink2.SubclassDlgItem(IDC_VCKBASEURL,this);
m_wndLink3.SubclassDlgItem(IDC_VCKBASELINK,this);
// 自己設(shè)置對話框圖標(biāo)。MFC不會為對話框應(yīng)用程序設(shè)置它
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
SetIcon(m_hIcon, TRUE); // 打圖標(biāo)
SetIcon(m_hIcon, FALSE); // 小圖標(biāo)
return TRUE;
}
////////////////////////////////////////////////////////
// 命令/UI 更新處理:寫這些東西應(yīng)該很輕松。
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;
}
按上述方法盡管禁用了任務(wù)欄,但是還有一個機關(guān)沒有處理,那就是按下Windows鍵仍然可以彈出“開始”菜單。顯然在處理VK_LWIN之前,任務(wù)欄不會檢查是否被啟用。一般來講,如果某個窗口被屏蔽掉,那么它就不再會處理用戶在這個窗口的輸入——這就是所謂的禁用(Disable)的含義。通常調(diào)用EnableWindow(FALSE)后自然就達(dá)到了這個目的。但是處理VK_LWIN/VK_RWIN按鍵的代碼決不會去檢查任務(wù)欄啟用/禁用狀態(tài)。對此,本文的處理辦法仍然是利用鍵盤鉤子。修改一下TaskKeyHook實現(xiàn),增加對Windows鍵的捕獲。這樣按下“開始”菜單鍵之后什么也不會發(fā)生。希望沒有漏掉其它的按鍵。如果哪位讀者發(fā)現(xiàn)漏掉了什么鍵,請和我聯(lián)系,以便把它加到鍵盤鉤子中去。為了簡單起見,我在類CTaskKeyMgr中封裝了所有禁用的函數(shù)。下面是這個類的定義擊實現(xiàn)文件:
TaskKeyMgr
////////////////////////////////////////
// TaskKeyMgr.h
//
#pragma once
#include "TaskKeyHook.h"
/////////////////////////////////////////////////////////////////////
// 使用這個類禁用任務(wù)鍵,任務(wù)管理器或任務(wù)欄。
// 用相應(yīng)的標(biāo)志調(diào)用Disable,如:CTaskMgrKeys::Disable(CTaskMgrKeys::ALL);
//
class CTaskKeyMgr {
public:
enum {
TASKMGR = 0x01, // 禁用任務(wù)管理器(Ctrl+Alt+Del)
TASKKEYS = 0x02, //禁用任務(wù)轉(zhuǎn)換鍵(Alt-TAB, etc)
TASKBAR = 0x04, //禁用任務(wù)欄
ALL=0xFFFF //禁用所有東西L
};
static void Disable(DWORD dwItem,BOOL bDisable,BOOL bBeep=FALSE);
static BOOL IsTaskMgrDisabled();
static BOOL IsTaskBarDisabled();
static BOOL AreTaskKeysDisabled() {
return ::AreTaskKeysDisabled(); // 調(diào)用 DLL
}
};
CPP實現(xiàn)
////////////////////////////////////////////////////////////////
// TaskKeyMgr.cpp
//
#include "StdAfx.h"
#include "TaskKeyMgr.h"
#define HKCU HKEY_CURRENT_USER
// 用于禁用任務(wù)管理器策略的注冊表鍵值對
LPCTSTR KEY_DisableTaskMgr =
"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
LPCTSTR VAL_DisableTaskMgr = "DisableTaskMgr";
///////////////////////////////////////////
// 禁用相關(guān)的任務(wù)鍵
//
// dwFlags = 表示禁用什么
// bDisable = 禁用為 (TRUE) ,否則為啟用 (FALSE)
// bBeep = 按下非法鍵是否蜂鳴(指針對任務(wù)鍵)
//
void CTaskKeyMgr::Disable(DWORD dwFlags, BOOL bDisable, BOOL bBeep)
{
// 任務(wù)管理器 (Ctrl+Alt+Del)
if (dwFlags & TASKMGR) {
HKEY hk;
if (RegOpenKey(HKCU, KEY_DisableTaskMgr,&hk)!=ERROR_SUCCESS)
RegCreateKey(HKCU, KEY_DisableTaskMgr, &hk);
if (bDisable) { // 禁用任務(wù)管理器(disable TM): set policy = 1
DWORD val=1;
RegSetValueEx(hk, VAL_DisableTaskMgr, NULL,
REG_DWORD, (BYTE*)&val, sizeof(val));
} else { // 啟用任務(wù)管理器(enable TM)
RegDeleteValue(hk,VAL_DisableTaskMgr);
}
}
// 任務(wù)鍵 (Alt-TAB etc)
if (dwFlags & TASKKEYS)
::DisableTaskKeys(bDisable,bBeep); // 安裝鍵盤鉤
// 任務(wù)欄
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;
}
這個類中的函數(shù)都是靜態(tài)的,實際上CTaskKeyMgr完全就是一個名字空間。你可以在自己的程序中隨心所欲地使用它。例如,禁用任務(wù)轉(zhuǎn)換按鍵和任務(wù)欄,但是不禁用Ctrl+Alt+Del:
CTaskKeyMgr::Disable(CTaskKeyMgr::TASKKEYS |
CTaskKeyMgr::TASKBAR, TRUE);
此外,還有幾個函數(shù)是用來檢查當(dāng)前禁用了哪些東西,甚至可以在用戶按下禁用鍵時發(fā)出蜂鳴聲……自己去享受Paul的源代碼吧!
相關(guān)文章
WinXP登錄失敗提示:未授予用戶在此計算機上的請求登陸類型怎么辦?
WinXP登錄失敗提示:“未授予用戶在此計算機上的請求登陸類型”怎么辦?今天我們就來看看詳細(xì)的解決過程2023-08-16xp系統(tǒng)我的文檔在哪? WinXP系統(tǒng)下我的文檔打不開怎么辦?
xp系統(tǒng)我的文檔在哪?winxp系統(tǒng)中的我的文檔打不開,可能是權(quán)限出現(xiàn)了變化,下面我們就來看看WinXP系統(tǒng)下我的文檔打不開怎么辦?2023-08-16winXP系統(tǒng)如何快速升級到Windows8系統(tǒng)?
XP系統(tǒng)如何快速升級到Win8系統(tǒng)?當(dāng)我們使用XP系統(tǒng)的電腦時,想要升級到Win8系統(tǒng),這時我們該怎么做呢,讓我們一起看下文尋找解決的方法吧2020-12-24- 如何解決WinXP系統(tǒng)LOL安全證書不可用?最近有不少XP系統(tǒng)的用戶,向小編反應(yīng)LOL安全證書不可用該怎么解決,下面就由小編帶領(lǐng)大家來解決問題2020-12-22
- 如何恢復(fù)XP系統(tǒng)本地連接?最近有不少XP系統(tǒng)的用戶,在使用電腦的時候遇到了這樣的問題本地連接不見了,那么如何恢復(fù)呢。下面就由小編為大家解決問題2020-12-11
如何解決WinXP系統(tǒng)記事本亂碼?解決WinXP系統(tǒng)記事本亂碼的教程
如何解決WinXP系統(tǒng)記事本亂碼?相信很多WinXP系統(tǒng)用戶都有因為設(shè)置不當(dāng)導(dǎo)致記事本亂碼而煩惱過,那么如何解決這一問題呢,讓我們一起來看看吧2020-12-08WinXP系統(tǒng)網(wǎng)頁不能復(fù)制粘貼的教程
怎么解決WinXP系統(tǒng)網(wǎng)頁不能復(fù)制粘貼?windows xp系統(tǒng),在使用電腦的時需要復(fù)制粘貼這個功能,但是有時候我們在WinXP系統(tǒng)網(wǎng)頁不能完成復(fù)制粘貼,該如何解決這一問題,下面小編2020-12-07- 如何解決winxp系統(tǒng)oracle無法使用?很多電腦用戶不知道oracle的話,就需要開啟oracle服務(wù),但是如何開啟oracle服務(wù)呢,下面小編帶領(lǐng)大家學(xué)習(xí)一下2020-12-07
怎么解決winXP出現(xiàn)“數(shù)據(jù)執(zhí)行保護(hù)”?
怎么解決XP出現(xiàn)"數(shù)據(jù)執(zhí)行保護(hù)"?最近有很多小伙伴向小編反應(yīng)使用xp系統(tǒng)過程中,總是會彈出"數(shù)據(jù)執(zhí)行保護(hù)",那么我們該如何解決這一問題呢,下面小編為2020-12-07winxp超級管理員賬戶消失了怎么辦? winxp管理員賬戶恢復(fù)的技巧
winxp超級管理員賬戶消失了怎么辦?最近遇到一個問題,winxp創(chuàng)建新賬戶后超級管理員賬戶消失了,該怎么辦呢?下面我們就來看看winxp管理員賬戶恢復(fù)的技巧,需要的朋友可以2020-08-19