Winform:再次记录钩子
之前有过一篇介绍钩子的,主要是写钩Mouse与KeyBoard ,最近特意再重看了一些资料,再次记录.这次参考了一个挂载钩子修改MESSAGEBOX的例子
先来段MSDN的介绍
In the Microsoft® Windows® operating system, a hook is a mechanism by which a function can intercept events (messages, mouse actions, keystrokes) before they reach an application. The function can act on events and, in some cases, modify or discard them. Functions that receive events are called filter functions and are classified according to the type of event they intercept.
大概意思也就是能截获事件在他们到达他们的应用程序之前.
To maintain and access filter functions, applications use the SetWindowsHookEx and the UnhookWindowsHookEx functions.
而主要操作即是在以上两个函数里面,提供了以下功能
Hooks provide powerful capabilities for Windows-based applications. These applications can use hooks to:
- Process or modify all messages meant for all the dialog boxes, message boxes, scroll bars, or menus for an application (WH_MSGFILTER).
- Process or modify all messages meant for all the dialog boxes, message boxes, scroll bars, or menus for the system (WH_SYSMSGFILTER).
- Process or modify all messages (of any type) for the system whenever a GetMessage or a PeekMessage function is called (WH_GETMESSAGE).
- Process or modify all messages (of any type) whenever a SendMessage function is called (WH_CALLWNDPROC).
- Record or play back keyboard and mouse events (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
- Process, modify, or remove keyboard events (WH_KEYBOARD).
- Process, modify, or discard mouse events (WH_MOUSE).
- Respond to certain system actions, making it possible to develop computer-based training (CBT) for applications (WH_CBT).
- Prevent another filter from being called (WH_DEBUG).
Applications have used hooks to:
- Provide F1 help key support to menus, dialog boxes, and message boxes (WH_MSGFILTER).
- Provide mouse and keystroke record and playback features, often referred to as macros. For example, the Windows Recorder accessory program uses hooks to supply record and playback functionality (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
- Monitor messages to determine which messages are being sent to a particular window or which actions a message generates (WH_GETMESSAGE, WH_CALLWNDPROC). The Spy utility program in the Platform SDK uses hooks to perform these tasks. The source for Spy is available in the SDK.
- Simulate mouse and keyboard input (WH_JOURNALPLAYBACK). Hooks provide the only reliable way to simulate these activities. If you try to simulate these events by sending or posting messages, Windows internals do not update the keyboard or mouse state, which can lead to unexpected behavior. If hooks are used to play back keyboard or mouse events, these events are processed exactly like real keyboard or mouse events. Microsoft Excel uses hooks to implement its SEND.KEYS macro function.
- Provide CBT for applications that run in the Windows environment (WH_CBT). The WH_CBT hook makes developing CBT applications much easier.
以下是一个从MSDN抄下来的HOOK WINDOWS的基类,很清楚地描述了那两个函数是怎么使用的
public class LocalWindowsHook
{
// Filter function delegate
public delegate int HookProc(int code, IntPtr wParam,
IntPtr lParam);
// Internal properties
protected IntPtr m_hhook = IntPtr.Zero;
//回调函数
protected HookProc m_filterFunc = null;
protected HookType m_hookType;
// Event delegate
public delegate void HookEventHandler(object sender,
HookEventArgs e);
// Event: HookInvoked
public event HookEventHandler HookInvoked;
protected void OnHookInvoked(HookEventArgs e)
{
if (HookInvoked != null)
HookInvoked(this, e);
}
// Class constructor(s)
public LocalWindowsHook(HookType hook)
{
m_hookType = hook;
m_filterFunc = new HookProc(this.CoreHookProc);
}
public LocalWindowsHook(HookType hook, HookProc func)
{
m_hookType = hook;
m_filterFunc = func;
}
// Default filter function
public int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
return CallNextHookEx(m_hhook, code, wParam, lParam);
// Let clients determine what to do
HookEventArgs e = new HookEventArgs();
e.HookCode = code;
e.wParam = wParam;
e.lParam = lParam;
OnHookInvoked(e);
// Yield to the next hook in the chain
return CallNextHookEx(m_hhook, code, wParam, lParam);
}
// Install the hook
public void Install()
{
m_hhook = SetWindowsHookEx(
m_hookType,
m_filterFunc,
IntPtr.Zero,
(int) AppDomain.GetCurrentThreadId());
}
// Uninstall the hook
public void Uninstall()
{
UnhookWindowsHookEx(m_hhook);
}
#region Win32 Imports
[DllImport("user32.dll")]
protected static extern IntPtr SetWindowsHookEx(HookType code,
HookProc func,
IntPtr hInstance,
int threadID);
// Win32: UnhookWindowsHookEx()
[DllImport("user32.dll")]
protected static extern int UnhookWindowsHookEx(IntPtr hhook);
// Win32: CallNextHookEx()
[DllImport("user32.dll")]
protected static extern int CallNextHookEx(IntPtr hhook,
int code, IntPtr wParam, IntPtr lParam);
#endregion
}
Hook的类型有以下几种:
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
这里着重介绍下CBT
The system calls a WH_CBT hook procedure before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event from the system message queue; before setting the input focus; or before synchronizing with the system message queue. The value the hook procedure returns determines whether the system allows or prevents one of these operations. The WH_CBT hook is intended primarily for computer-based training (CBT) applications.
HOOK CBT的话,能截获窗体创建时的消息,他可截获以下消息:
public enum CbtHookAction
{
HCBT_MOVESIZE,
HCBT_MINMAX,
HCBT_QS,
HCBT_CREATEWND,//创建
HCBT_DESTROYWND,//销毁
HCBT_ACTIVATE, //激活
HCBT_CLICKSKIPPED,
HCBT_KEYSKIPPED,
HCBT_SYSCOMMAND,
HCBT_SETFOCUS
}
以下也是从MSDN摘抄的
public class LocalCbtHook : LocalWindowsHook
{
// Fields
protected string m_class;
protected IntPtr m_hwnd;
protected bool m_isDialog;
protected string m_title;
// Events
public event CbtEventHandler WindowActivated;
public event CbtEventHandler WindowCreated;
public event CbtEventHandler WindowDestroyed;
// Methods
public LocalCbtHook()
: base(HookType.WH_CBT)
{
this.m_hwnd = IntPtr.Zero;
this.m_title = "";
this.m_class = "";
this.m_isDialog = false;
base.HookInvoked += new LocalWindowsHook.HookEventHandler(this.CbtHookInvoked);
}
public LocalCbtHook(LocalWindowsHook.HookProc func)
: base(HookType.WH_CBT, func)
{
this.m_hwnd = IntPtr.Zero;
this.m_title = "";
this.m_class = "";
this.m_isDialog = false;
base.HookInvoked += new LocalWindowsHook.HookEventHandler(this.CbtHookInvoked);
}
private void CbtHookInvoked(object sender, HookEventArgs e)
{
CbtHookAction code = (CbtHookAction)e.HookCode;
IntPtr wParam = e.wParam;//句柄
IntPtr lParam = e.lParam;
switch (code)
{
case CbtHookAction.HCBT_CREATEWND:
this.HandleCreateWndEvent(wParam, lParam);
break;
case CbtHookAction.HCBT_DESTROYWND:
this.HandleDestroyWndEvent(wParam, lParam);
break;
case CbtHookAction.HCBT_ACTIVATE:
this.HandleActivateEvent(wParam, lParam);
break;
}
}
[DllImport("user32.dll")]
protected static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
protected static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
private void HandleActivateEvent(IntPtr wParam, IntPtr lParam)
{
this.UpdateWindowData(wParam);
this.OnWindowActivated();
}
private void HandleCreateWndEvent(IntPtr wParam, IntPtr lParam)
{
this.UpdateWindowData(wParam);
this.OnWindowCreated();
}
private void HandleDestroyWndEvent(IntPtr wParam, IntPtr lParam)
{
this.UpdateWindowData(wParam);
this.OnWindowDestroyed();
}
protected virtual void OnWindowActivated()
{
if (this.WindowActivated != null)
{
CbtEventArgs e = new CbtEventArgs();
this.PrepareEventData(e);
this.WindowActivated(this, e);
}
}
protected virtual void OnWindowCreated()
{
if (this.WindowCreated != null)
{
CbtEventArgs e = new CbtEventArgs();
this.PrepareEventData(e);
this.WindowCreated(this, e);
}
}
protected virtual void OnWindowDestroyed()
{
if (this.WindowDestroyed != null)
{
CbtEventArgs e = new CbtEventArgs();
this.PrepareEventData(e);
this.WindowDestroyed(this, e);
}
}
private void PrepareEventData(CbtEventArgs e)
{
e.Handle = this.m_hwnd;
e.Title = this.m_title;
e.ClassName = this.m_class;
e.IsDialogWindow = this.m_isDialog;
}
private void UpdateWindowData(IntPtr wParam)
{
this.m_hwnd = wParam;
StringBuilder sb1 = new StringBuilder();
sb1.Capacity = 40;
GetClassName(this.m_hwnd, sb1, 40);
this.m_class = sb1.ToString();
StringBuilder sb2 = new StringBuilder();
sb2.Capacity = 0x100;
GetWindowText(this.m_hwnd, sb2, 0x100);
this.m_title = sb2.ToString();
this.m_isDialog = this.m_class == "#32770";
}
// Nested Types
public delegate void CbtEventHandler(object sender, CbtEventArgs e);
}
到此,我们已经做好了一个截获窗体消息的HOOK类了.下面看人家怎么使用来对MESSAGEBOX 挂载钩子.
我们大可定义一个Messagebox类并挂载钩子
public class MessageBox
{
// Properties
protected LocalCbtHook m_cbt;
public MessageBox()
{
m_cbt = new LocalCbtHook();
m_cbt.WindowCreated += new LocalCbtHook.CbtEventHandler(WndCreated);
m_cbt.WindowDestroyed += new LocalCbtHook.CbtEventHandler(WndDestroyed);
m_cbt.WindowActivated += new LocalCbtHook.CbtEventHandler(WndActivated);
}
}
此时我们就可以在WndActivated事件里做任何修改MESSAGEBOX类的事了
比如更换图标,改变字体大小,添加按钮(顶多四个),添加CHECKBOX,就有了上图的效果.
不过遗憾的是想改变背景颜色或图片,试了都不成功….郁闷……
使用SetBkColor一直没效果
Graphics g = Graphics.FromHwnd(m_handle);
IntPtr hdc = g.GetHdc();
SetBkColor(hdc, 0xff0000);
那位朋友知道的请相告一下
具体代码详见:
http://www.codeproject.com/KB/dialog/MessageBoxChk.aspx
http://msdn.microsoft.com/zh-cn/magazine/cc188966(en-us).aspx
http://msdn.microsoft.com/zh-cn/magazine/cc188920(en-us).aspx
http://msdn.microsoft.com/en-us/library/ms997537.aspx
http://msdn.microsoft.com/en-us/library/ms997511.aspx
http://msdn.microsoft.com/en-us/library/ms645505(VS.85).aspx
http://baike.baidu.com/view/1628482.htm