這篇開始,我開始講解一下我的界面開發的全部過程,一步一步的講解開發界面的過程,這 篇主要講解的是Hook編程,Hook所有的窗體。
Hook,對於大多數程序員來說,這個詞並不陌生。對於Windows系統來說,消息Message的傳 遞貫穿了整個系統,Message簡單來說就是一個整數,它具有相應的意義。在C++的winuser.h中 可以看到我們常用的很多的Message。Hook與Message是密不可分的,它的中文解釋就是“鉤子 ”,就是監控系統中Message的傳遞,就是在Message傳遞到最終的Message處理前,對特定的消 息進行處理。
對於Hook來說,開發主要的有3個API函數,均放在User32.dll文件中,這三個函數是:
Hook
1 /// <summary>
2 /// SetWindowsHookEx
3 /// </summary>
4 /// <param name="idHook"></param>
5 /// <param name="lpfn"></param>
6 /// <param name="hMod"></param>
7 /// <param name="dwThreadId"></param>
8 /// <returns></returns>
9 [DllImport("User32.dll", CharSet = CharSet.Auto)]
10 public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, int hMod, int dwThreadId);
11
12 /// <summary>
13 /// CallNextHookEx
14 /// </summary>
15 /// <param name="hhk"></param>
16 /// <param name="nCode"></param>
17 /// <param name="wParam"></param>
18 /// <param name="lParam"></param>
19 /// <returns></returns>
20 [DllImport("User32.dll", CharSet = CharSet.Auto)]
21 public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
22
23 /// <summary>
24 /// UnhookWindowsHookEx
25 /// </summary>
26 /// <param name="hhk"></param>
27 /// <returns></returns>
28 [DllImport("User32.dll", CharSet = CharSet.Auto)]
29 public static extern bool UnhookWindowsHookEx(IntPtr hhk);
這三個方法分別就是添加Hook,釋放Hook和執行下一個Hook。其中的參數就不必介紹了,網 上有很多這方面的資料。
接下來就是對Windows窗體的消息截取。
我創建一個項目名稱叫做SkinEngines,然後再NativeMethod中添加了這三個方法。其中 SetWindowsHookEx中需要一個參數就是一個方面的名稱,在C#中使用委托實現,所以也創建了 一個專門保存委托的地點,放在 Delegates.cs文件中。
HookProc
/// <summary>
/// HookProc -- HookProc
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
然後創建一個名為SkinEngine的Component。在SkinEngine的構造函數中添加了自己的一些 操作,對窗體的Hook。代碼如下:
1 /// <summary>
2 /// SkinEngine -- Skin All Form,Dialog,Control
3 /// </summary>
4 public partial class SkinEngine : Component
5 {
6 #region Field
7 /// <summary>
8 /// CBTHook -- Hook WH_CBT
9 /// </summary>
10 private static HookProc _cbtHook;
11
12 /// <summary>
13 /// Hook
14 /// </summary>
15 private static IntPtr Hook;
16
17 /// <summary>
18 /// Current SkinEngine
19 /// </summary>
20 internal static SkinEngine Engine;
21
22 /// <summary>
23 /// Skinned handled
24 /// </summary>
25 internal static ArrayList SkinHandleList = new ArrayList();
26 #endregion
27
28 #region Constructor
29 /// <summary>
30 /// Constructor
31 /// </summary>
32 public SkinEngine()
33 {
34 InitializeComponent();
35 // Internal Constructor
36 this.InternalConstructor();
37 }
38
39 /// <summary>
40 /// Constructor With container
41 /// </summary>
42 /// <param name="container"></param>
43 public SkinEngine(IContainer container)
44 {
45 container.Add(this);
46
47 InitializeComponent();
48
49 // Internal Constructor
50 this.InternalConstructor();
51 }
52 #endregion
53
54 #region InternalConstructor
55 /// <summary>
56 /// the Internal Constructor to Create Hook and Get List of all control to skin.
57 /// </summary>
58 private void InternalConstructor()
59 {
60 // IsDesignMode == false
61 if (!IsDesignMode)
62 {
63 // Check Engine
64 if (Engine == null)
65 {
66 // Set Engine
67 Engine = this;
68
69 // Hook Process
70 if (Hook == IntPtr.Zero)
71 {
72 _cbtHook = new HookProc(SkinEngine.FnHookProc);
73 Hook = NativeMethod.SetWindowsHookEx(5, _cbtHook, 0, AppDomain.GetCurrentThreadId ());
74 Application.ApplicationExit += new EventHandler (Application_ApplicationExit);
75 }
76 }
77 }
78 }
79 #endregion
80
81 #region FnHookProc
82 /// <summary>
83 /// FnHookProc
84 /// </summary>
85 /// <param name="nCode"></param>
86 /// <param name="wParam"></param>
87 /// <param name="lParam"></param>
88 /// <returns></returns>
89 private static unsafe IntPtr FnHookProc(int nCode, IntPtr wParam, IntPtr lParam)
90 {
91 if (Engine != null)
92 {
93 switch (nCode)
94 {
95 case 5:
96 // Get Skin Control
97 Control control = Control.FromHandle(wParam);
98 // Control is null it Can be Dialog
99 if (control == null)
100 {
101 StringBuilder builder = new StringBuilder(260);
102 NativeMethod.GetClassName(wParam, builder, 260);
103 // #32770 is Dialog
104 if (builder.Length == 6 && builder.ToString() == "#32770")
105 {
106 // Add to SkinHandleList
107 SkinHandleList.Add (wParam);
108 // Print
109 Debug.WriteLine(builder.ToString());
110 }
111 break;
112 }
113 if (!SkinHandleList.Contains(wParam) && (control is Form))
114 {
115 // Add to SkinHandleList
116 SkinHandleList.Add(wParam);
117 // Print all control's Name
118 Debug.WriteLine(control.Name);
119 }
120 break;
121 default:
122 break;
123 }
124 }
125 return NativeMethod.CallNextHookEx(Hook, nCode, wParam, lParam);
126 }
127 #endregion
128
129 #region Application_ApplicationExit
130 /// <summary>
131 /// Application_ApplicationExit
132 /// </summary>
133 /// <param name="sender"></param>
134 /// <param name="e"></param>
135 private void Application_ApplicationExit(object sender, EventArgs e)
136 {
137 Engine.Dispose(false);
138 }
139 #endregion
140
141 #region Property
142 /// <summary>
143 /// Gets or sets a value indicating whether we are currently in design mode.
144 /// </summary>
145 /// <value>
146 /// <c>true</c> if this we are in design mode; otherwise, <c>false</c>.
147 /// </value>
148 internal static bool IsDesignMode { get; set; }
149 #endregion
150 }
這樣整個窗體就可以進行Hook,其中NativeMethod.SetWindowsHookEx設置了WM_CBT的消息 ,這個消息用來對 Windows窗體的激活,顯示。這樣,窗體就會被我們記錄下來,現在僅僅是 將記錄下來的窗體顯示出來,寫出了窗體的名稱。結果如下:
這篇就暫時寫道這裡,下一篇將對Form的消息進行Hook並繪制。