C#屏蔽系统热键Ctrl+Alt+Delete的代码尝试。(已修改bug)

C#屏蔽系统热键Ctrl+Alt+Delete的代码尝试。

2011.08.05 (七夕前一天)

最近在做一款小软件,需要锁定用户的输入,包括系统热键(Ctrl+Alt+Delete),在网络中寻找良久,发现这些不错的代码。

经过仔细整理,现将这些代码公布,有兴趣的拿去用用。

搜集的过程有些艰辛,从VB6,到VB.NET,到我熟悉的C#。

 

一、思路分析。

1. 在窗体类Form中,重载消息循环WndProc来实现功能按键的屏蔽

protected override void WndProc(ref Message m)
{

  //ToDo:根据m.Msg来处理你要的按键

   base.WndProc(ref m);
}

优点:可以屏蔽大部分按键。使用简单。

缺点:不能注册全局热键,对系统级的热键无效,比如:a. Ctrl+Esc,  b. Ctrl+Shift+Esc,

c. Alt+Tab,  d. Alt+Esc,  e. Ctrl+Alt+Delete

类似的方法有System.Windows.Forms.Control的KeyPress,KeyDown事件,

2.利用钩子技术,这个可以捕获大多数键盘消息,但对Ctrl+Alt+Delete仍然无效。

3.最后发现一份VB6写的代码,提到这个方案:

锁定 Ctrl+Alt+Del 使用远程线程、代码注入及子类化技术。

普通键盘消息,使用普通钩子技术”

虽然这些我都还不太懂,但总算把代码移植到了.NET环境下,功能是实现了。

二、代码分析   

 第一步:包装Win32 API

User32.dll,

user32.dll
 1 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
2 public static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr pInstance, int threadId);
3
4 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
5 public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
6
7 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
8 public static extern int CallNextHookEx(IntPtr pHookHandle, int nCode, int wParam, IntPtr lParam);
9
10 [DllImport("user32.dll")]
11 public static extern bool BlockInput(bool fBlockIt);

Kernel32.dll,

View Code
 1 [DllImport("kernel32.dll")]
2 public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess,
3 [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
4 int dwProcessId);
5 [DllImport("kernel32.dll", SetLastError = true)]
6 public static extern bool ReadProcessMemory(
7 IntPtr hProcess,
8 IntPtr lpBaseAddress,
9 [Out] byte[] lpBuffer,
10 int dwSize,
11 out int lpNumberOfBytesRead
12 );
13 [DllImport("kernel32.dll", SetLastError = true)]
14 public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, uint[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
15
16
17 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
18 public static extern ushort GlobalAddAtom(string lpString);
19 [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
20 public static extern ushort GlobalDeleteAtom(ushort nAtom);
21 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "GlobalFindAtomW")]
22 public static extern ushort GlobalFindAtom(string lpString);
23
24
25 [DllImport("kernel32.dll", SetLastError = true)]
26 public static extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags dwFlags, uint th32ProcessID);
27 [DllImport("kernel32.dll", EntryPoint = "Process32FirstW")]
28 public static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
29 [DllImport("kernel32.dll", EntryPoint = "Process32NextW")]
30 public static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
31
32
33 [DllImport("kernel32.dll", SetLastError = true)]
34 [return: MarshalAs(UnmanagedType.Bool)]
35 public static extern bool CloseHandle(IntPtr hObject);
36 [DllImport("kernel32.dll")]
37 public static extern IntPtr GetCurrentProcess();
38
39
40 [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
41 public static extern IntPtr GetModuleHandle(string lpModuleName);
42 [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
43 public static extern UIntPtr GetProcAddress(IntPtr hModule, string procName);
44 [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
45 public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
46 [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
47 public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, FreeType dwFreeType);
48
49
50 [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
51 public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, int lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId);
52 [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
53 public static extern UInt32 WaitForSingleObject(IntPtr hHandle, Int32 dwMilliseconds);
54 [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
55 public static extern bool GetExitCodeThread(IntPtr hThread, out int lpExitCode);
56
57 [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
58 public static extern void MoveMemory(object dest, IntPtr src, int size);

advapi32.dll

View Code
 1 [DllImport("advapi32.dll", SetLastError = true)]
2 [return: MarshalAs(UnmanagedType.Bool)]
3 public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
4
5 [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
6 [return: MarshalAs(UnmanagedType.Bool)]
7 public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);
8
9 // Use this signature if you want the previous state information returned
10 [DllImport("advapi32.dll", SetLastError = true)]
11 [return: MarshalAs(UnmanagedType.Bool)]
12 public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
13 [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
14 ref TOKEN_PRIVILEGES NewState,
15 UInt32 BufferLengthInBytes,
16 ref TOKEN_PRIVILEGES PreviousState,
17 out UInt32 ReturnLengthInBytes);

第二步,创建一个辅助类,HookHelper

以下是两个公开的方法:

View Code
  /// <summary>
/// 锁定一些功能键
/// </summary>
/// <param name="isLock"></param>
/// <returns></returns>
public bool Lock_SomeKey(bool isLock)
{
if (isLock)
{
if (this.m_lHookID == IntPtr.Zero)
{
IntPtr pInstance
= Win32Lib.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

//安装钩子
m_lHookID = Win32Lib.SetWindowsHookEx(
(
int)HookType.WH_KEYBOARD_LL,
new HookProc(LowLevelKeyboardProc),
pInstance,
0);

if (m_lHookID == IntPtr.Zero)
{
this.Lock_SomeKey(false);
return false;
}
}
return true;
}
else
{
bool result = true;
if (this.m_lHookID != IntPtr.Zero)
{
result
= Win32Lib.UnhookWindowsHookEx(m_lHookID);
this.m_lHookID = IntPtr.Zero;
}
return result;
}
}

/// <summary>
/// 锁定Ctrl+Alt+Delete,Ctrl+Shift+Esc这两组系统热键
/// </summary>
/// <param name="isLock"></param>
/// <returns></returns>
public bool Lock_SysKey(bool isLock)
{
ushort iAtom = Win32Lib.GlobalFindAtom(Win32Lib.SHELL_FALG);
if (iAtom == 0)
{
long lResult = InsertAsmCode();
if (lResult > 0)
{
return false;
}
}

iAtom
= Win32Lib.GlobalFindAtom(Win32Lib.ATOM_FLAG);
if (isLock)
{
//插入热键
if (iAtom == 0)
{
iAtom
= Win32Lib.GlobalAddAtom(Win32Lib.ATOM_FLAG);
}
}
else
{
//删除热键
if (iAtom != 0)
{
Win32Lib.GlobalDeleteAtom(iAtom);
}
}

return true;
}

第三,提供一下源码的地址

http://ishare.iask.sina.com.cn/f/17782020.html

总结:第一次发博客,希望大家支持。

------------------------------《《《《《《《《《

2011年08月09日,程序出错的BUG修正,感谢朋友的指出。

------------------------------《《《《《《《《《

 

 

错误描述:

在多次切换锁定和解锁功能,并狂按Alt键时程序会关闭,经调试,出现如下错误:

检测到 CallbackOnCollectedDelegate
  Message: 对“Demo!SomeNamespace.SomeClass+SomeDelegate::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。

错误原因:

如果非托管代码需要多次调用托管代码中的回调,请将委托的引用保存为成员变量。否则会出现类似上面的异常: 

  。。。。

  如果不用成员变量,而用局部变量引用被new出来的委托,那么非托管代码可能刚开始的几次回调是OK的,但是接下来就会出现上面所说的异常,

原因就在于GC将局部变量和局部变量引用的委托对象都销毁了,非托管代码再去访问那个函数指针时发现指针指向的地址已经无效。

 

解决办法:

//1.把委托拿到外面定义
private HookProc m_HookProc;

//2.在构造函数里赋值这个委托
{
m_HookProc
= new HookProc(LowLevelKeyboardProc);
}


//3.在调用方法中使用这个定义过的委托。
{
//安装钩子
m_lHookID = Win32Lib.SetWindowsHookEx(
(
int)HookType.WH_KEYBOARD_LL,
m_HookProc,
pInstance,
0);

//这里注释掉的是以前的代码
//m_lHookID = Win32Lib.SetWindowsHookEx(
// (int)HookType.WH_KEYBOARD_LL,
// new HookProc(LowLevelKeyboardProc),
// pInstance,
// 0);
}


再次感谢大家的支持。

posted @ 2011-08-05 16:58  robnetcn  阅读(7452)  评论(15编辑  收藏  举报