يتذكر مبرمجين ويندوز على لغة الفيجوال بيسك و السي++ طريقة كانوا يتجسسون بها على النوافذ الصغيرة مثل TextBox أو ComboBox للتغير في سلوكها و طريقة عملها، و كانت تسمى هذه الطريقة حسب اصطلاح مايكروسفت هوكينق Hooking، هذه الطريقة ما زالت ممكنة حتى في عالم الدوت نيت، فنستطيع التجسس على الأدوات في Windows.Forms مثل TextBox و ListView وغيرها، و الكود التالي عبارة عن فئتين Class تسهل العملية بشكل كبير.
using System; using System.Collections.Generic; using System.Text; namespace MaNa.Helper { using System; using System.Drawing; using System.Runtime.InteropServices; // Contains managed wrappers and implementations of Win32 // structures, delegates, constants and platform invokes // used by the GradientFill and Subclassing samples. public sealed class Win32 { public struct TRIVERTEX { public int x; public int y; public ushort Red; public ushort Green; public ushort Blue; public ushort Alpha; public TRIVERTEX(int x, int y, Color color) : this(x, y, color.R, color.G, color.B, color.A) { } public TRIVERTEX(int x, int y, ushort red, ushort green, ushort blue, ushort alpha) { this.x = x; this.y = y; this.Red = (ushort)(red << 8); this.Green = (ushort)(green << 8); this.Blue = (ushort)(blue << 8); this.Alpha = (ushort)(alpha << 8); } } public struct GRADIENT_RECT { public uint UpperLeft; public uint LowerRight; public GRADIENT_RECT(uint ul, uint lr) { this.UpperLeft = ul; this.LowerRight = lr; } } public struct GRADIENT_TRIANGLE { public uint Vertex1; public uint Vertex2; public uint Vertex3; public GRADIENT_TRIANGLE(uint v1, uint v2, uint v3) { this.Vertex1 = v1; this.Vertex2 = v2; this.Vertex3 = v3; } } // WM_NOTIFY notification message header. [System.Runtime.InteropServices.StructLayout (LayoutKind.Sequential)] public class NMHDR { private IntPtr hwndFrom; public uint idFrom; public uint code; } //[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)] public struct TVITEM { public int mask; private IntPtr hItem; public int state; public int stateMask; private IntPtr pszText; public int cchTextMax; public int iImage; public int iSelectedImage; public int cChildren; private IntPtr lParam; } // Native representation of a point. public struct POINT { public int X; public int Y; } public struct TVHITTESTINFO { public POINT pt; public uint flags; public IntPtr hItem; } // A callback to a Win32 window procedure (wndproc): // Parameters: // hwnd - The handle of the window receiving a message. // msg - The message // wParam - The message's parameters (part 1). // lParam - The message's parameters (part 2). // Returns an integer as described for the given message in MSDN. public delegate int WndProc(IntPtr hwnd, uint msg, uint wParam, int lParam); [DllImport ("user32.dll", SetLastError = true, EntryPoint = "GradientFill")] public static extern bool GradientFill(IntPtr hdc, TRIVERTEX[] pVertex, uint dwNumVertex, GRADIENT_RECT[] pMesh, uint dwNumMesh, uint dwMode); public const int GRADIENT_FILL_RECT_H = 0x00000000; public const int GRADIENT_FILL_RECT_V = 0x00000001; // Not supported on Windows CE: public const int GRADIENT_FILL_TRIANGLE = 0x00000002; [DllImport ("user32.dll")] public static extern IntPtr SetWindowLong(IntPtr hwnd, int nIndex, IntPtr dwNewLong); public const int GWL_WNDPROC = -4; [DllImport ("user32.dll")] public static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, uint wParam, int lParam); [DllImport ("user32.dll")] public static extern int DefWindowProc(IntPtr hwnd, uint msg, uint wParam, int lParam); [DllImport ("user32.dll")] public static extern int SendMessage(IntPtr hwnd, uint msg, uint wParam, ref TVHITTESTINFO lParam); [DllImport ("user32.dll", SetLastError = true)] public static extern int SendMessage(IntPtr hwnd, uint msg, uint wParam, ref TVITEM lParam); [DllImport ("user32.dll")] public static extern uint GetMessagePos(); [DllImport ("user32.dll")] public static extern IntPtr BeginPaint(IntPtr hwnd, ref PAINTSTRUCT ps); [DllImport ("user32.dll")] public static extern bool EndPaint(IntPtr hwnd, ref PAINTSTRUCT ps); public struct PAINTSTRUCT { private IntPtr hdc; public bool fErase; public Rectangle rcPaint; public bool fRestore; public bool fIncUpdate; [MarshalAs (UnmanagedType.ByValArray, SizeConst = 32)] public byte[] rgbReserved; } [DllImport ("user32.dll")] public static extern IntPtr GetDC(IntPtr hwnd); [DllImport ("user32.dll")] public static extern bool ReleaseDC(IntPtr hwnd, IntPtr hdc); // Helper function to convert a Windows lParam into a Point. // lParam - The parameter to convert. // Returns a Point where X is the low 16 bits and Y is the // high 16 bits of the value passed in. public static Point LParamToPoint(int lParam) { uint ulParam = (uint)lParam; return new Point((int)(ulParam & 0x0000ffff), (int)((ulParam & 0xffff0000) >> 16)); } // Windows messages public const uint WM_PAINT = 0x000F; public const uint WM_ERASEBKGND = 0x0014; public const uint WM_KEYDOWN = 0x0100; public const uint WM_KEYUP = 0x0101; public const uint WM_MOUSEMOVE = 0x0200; public const uint WM_LBUTTONDOWN = 0x0201; public const uint WM_LBUTTONUP = 0x0202; public const uint WM_NOTIFY = 0x4E; public const uint WM_SETFOCUS = 0x0007; public const uint WM_ACTIVATE = 0x0006; public const uint WM_SETCURSOR = 0x0020; public const uint WM_RBUTTONDOWN = 0x0204; public const uint WM_RBUTTONUP = 0x0205; public const uint WM_NCHITTEST = 0x0084; /* WM_NCHITTEST codes*/ public const int HTERROR = (-2); public const int HTTRANSPARENT = (-1); public const uint HTNOWHERE = 0; public const uint HTCLIENT = 1; public const uint HTCAPTION = 2; public const uint HTSYSMENU = 3; public const uint HTGROWBOX = 4; public const uint HTSIZE = HTGROWBOX; public const uint HTMENU = 5; public const uint HTHSCROLL = 6; public const uint HTVSCROLL = 7; public const uint HTMINBUTTON = 8; public const uint HTMAXBUTTON = 9; public const uint HTLEFT = 10; public const uint HTRIGHT = 11; public const uint HTTOP = 12; public const uint HTTOPLEFT = 13; public const uint HTTOPRIGHT = 14; public const uint HTBOTTOM = 15; public const uint HTBOTTOMLEFT = 16; public const uint HTBOTTOMRIGHT = 17; public const uint HTBORDER = 18; public const uint HTREDUCE = HTMINBUTTON; public const uint HTZOOM = HTMAXBUTTON; public const uint HTSIZEFIRST = HTLEFT; public const uint HTSIZELAST = HTBOTTOMRIGHT; public const uint HTOBJECT = 19; public const uint HTCLOSE = 20; public const uint HTHELP = 21; // Notifications public const uint NM_CLICK = 0xFFFFFFFE; public const uint NM_DBLCLK = 0xFFFFFFFD; public const uint NM_RCLICK = 0xFFFFFFFB; public const uint NM_RDBLCLK = 0xFFFFFFFA; // Key public const uint VK_SPACE = 0x20; public const uint VK_RETURN = 0x0D; // Treeview public const uint TV_FIRST = 0x1100; public const uint TVM_HITTEST = TV_FIRST + 17; public const uint TVHT_NOWHERE = 0x0001; public const uint TVHT_ONITEMICON = 0x0002; public const uint TVHT_ONITEMLABEL = 0x0004; public const uint TVHT_ONITEM = (TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON); public const uint TVHT_ONITEMINDENT = 0x0008; public const uint TVHT_ONITEMBUTTON = 0x0010; public const uint TVHT_ONITEMRIGHT = 0x0020; public const uint TVHT_ONITEMSTATEICON = 0x0040; public const uint TVHT_ABOVE = 0x0100; public const uint TVHT_BELOW = 0x0200; public const uint TVHT_TORIGHT = 0x0400; public const uint TVHT_TOLEFT = 0x0800; public const uint TVM_GETITEM = TV_FIRST + 62; //TVM_GETITEMW public const uint TVIF_TEXT = 0x0001; public const uint TVIF_IMAGE = 0x0002; public const uint TVIF_PARAM = 0x0004; public const uint TVIF_STATE = 0x0008; public const uint TVIF_HANDLE = 0x0010; public const uint TVIF_SELECTEDIMAGE = 0x0020; public const uint TVIF_CHILDREN = 0x0040; public const uint TVIF_DI_SETITEM = 0x1000; } }
و هذه الفئة الثانية:
using System;using System.Windows.Forms;using System.Text;using System.Collections.Generic;using System.Runtime.InteropServices;namespace Manahil.Helper{public class WndProcHooker{// The WndProcCallback method is used when a hooked// window's message map contains the hooked message.// Parameters:// hwnd - The handle to the window for which the message// was received.// wParam - The message's parameters (part 1).// lParam - The message's parameters (part 2).// handled - The invoked function sets this to true if it// handled the message. If the value is false when the callback// returns, the next window procedure in the wndproc chain is// called.//// Returns a value specified for the given message.public delegate int WndProcCallback(IntPtr hwnd, uint msg, uint wParam, int lParam, ref bool handled);// This is the global list of all the window procedures we have// hooked. The key is an hwnd. The value is a HookedProcInformation// object which contains a pointer to the old wndproc and a map of// message's callbacks for the window specified. Controls whose handles// have been created go into this dictionary.private static Dictionary<IntPtr, HookedProcInformation> hwndDict =new Dictionary<IntPtr, HookedProcInformation>();// The key for this dictionary is a control and the value is a// HookedProcInformation. Controls whose handles have not been created// go into this dictionary. When the HandleCreated event for the// control is fired the control is moved into hwndDict.private static Dictionary<Control, HookedProcInformation> ctlDict =new Dictionary<Control, HookedProcInformation>();// Makes a connection between a message on a specified window handle// and the callback to be called when that message is received. If the// window was not previously hooked it is added to the global list of// all the window procedures hooked.// Parameters:// ctl - The control whose wndproc we are hooking.// callback - The method to call when the specified.// message is received for the specified window.// msg - The message being hooked.public static void HookWndProc(Control ctl, WndProcCallback callback, uint msg){HookedProcInformation hpi = null;if (ctlDict.ContainsKey(ctl))hpi = ctlDict[ctl];else if (hwndDict.ContainsKey(ctl.Handle))hpi = hwndDict[ctl.Handle];if (hpi == null){// If new control, create a new// HookedProcInformation for it.hpi = new HookedProcInformation(ctl,new Win32.WndProc(WndProcHooker.WindowProc));ctl.HandleCreated += new EventHandler(ctl_HandleCreated);ctl.HandleDestroyed += new EventHandler(ctl_HandleDestroyed);ctl.Disposed += new EventHandler(ctl_Disposed);// If the handle has already been created set the hook. If it// hasn't been created yet, the hook will get set in the// ctl_HandleCreated event handler.if (ctl.Handle != IntPtr.Zero)hpi.SetHook();}// Stick hpi into the correct dictionary.if (ctl.Handle == IntPtr.Zero)ctlDict[ctl] = hpi;elsehwndDict[ctl.Handle] = hpi;// Add the message/callback into the message map.hpi.messageMap[msg] = callback;}// The event handler called when a control is disposed.static void ctl_Disposed(object sender, EventArgs e){Control ctl = sender as Control;if (ctlDict.ContainsKey(ctl))ctlDict.Remove(ctl);elseSystem.Diagnostics.Debug.Assert(false);}// The event handler called when a control's handle is destroyed.// We remove the HookedProcInformation from hwndDict and// put it back into ctlDict in case the control get re-// created and we still want to hook its messages.static void ctl_HandleDestroyed(object sender, EventArgs e){// When the handle for a control is destroyed, we want to// unhook its wndproc and update our listsControl ctl = sender as Control;if (hwndDict.ContainsKey(ctl.Handle)){HookedProcInformation hpi = hwndDict[ctl.Handle];UnhookWndProc(ctl, false);}elseSystem.Diagnostics.Debug.Assert(false);}// The event handler called when a control's handle is created. We// call SetHook() on the associated HookedProcInformation object and// move it from ctlDict to hwndDict.static void ctl_HandleCreated(object sender, EventArgs e){Control ctl = sender as Control;if (ctlDict.ContainsKey(ctl)){HookedProcInformation hpi = ctlDict[ctl];hwndDict[ctl.Handle] = hpi;ctlDict.Remove(ctl);hpi.SetHook();}elseSystem.Diagnostics.Debug.Assert(false);}// This is a generic wndproc. It is the callback for all hooked// windows. If we get into this function, we look up the hwnd in the// global list of all hooked windows to get its message map. If the// message received is present in the message map, its callback is// invoked with the parameters listed here.// Parameters:// hwnd - The handle to the window that received the// message// msg - The message// wParam - The message's parameters (part 1)// lParam - The messages's parameters (part 2)// Returns the callback handled the message, the callback's return// value is returned form this function. If the callback didn't handle// the message, the message is forwarded on to the previous wndproc.private static int WindowProc(IntPtr hwnd, uint msg, uint wParam, int lParam){if (hwndDict.ContainsKey(hwnd)){HookedProcInformation hpi = hwndDict[hwnd];if (hpi.messageMap.ContainsKey(msg)){WndProcCallback callback = hpi.messageMap[msg];bool handled = false;int retval = callback(hwnd, msg, wParam, lParam, ref handled);if (handled)return retval;}// If the callback didn't set the handled property to true,// call the original window procedure.return hpi.CallOldWindowProc(hwnd, msg, wParam, lParam);}System.Diagnostics.Debug.Assert(false, "WindowProc called for hwnd we don't know about");return Win32.DefWindowProc(hwnd, msg, wParam, lParam);}// This method removes the specified message from the message map for// the specified hwnd.public static void UnhookWndProc(Control ctl, uint msg){// Look for the HookedProcInformation in the// ctrDict and hwndDict dictionaries.HookedProcInformation hpi = null;if (ctlDict.ContainsKey(ctl))hpi = ctlDict[ctl];else if (hwndDict.ContainsKey(ctl.Handle))hpi = hwndDict[ctl.Handle];// if we couldn't find a HookedProcInformation, throwif (hpi == null)throw new ArgumentException("No hook exists for this control");// look for the message we are removing in the messageMapif (hpi.messageMap.ContainsKey(msg))hpi.messageMap.Remove(msg);else// if we couldn't find the message, throwthrow new ArgumentException(string.Format("No hook exists for message ({0}) on this control",msg));}// Restores the previous wndproc for the specified window.// Parameters:// ctl - The control whose wndproc we no longer want to hook.// disposing - True if HookedProcInformation is not// read back into ctlDict.public static void UnhookWndProc(Control ctl, bool disposing){HookedProcInformation hpi = null;if (ctlDict.ContainsKey(ctl))hpi = ctlDict[ctl];else if (hwndDict.ContainsKey(ctl.Handle))hpi = hwndDict[ctl.Handle];if (hpi == null)throw new ArgumentException("No hook exists for this control");// If we found our HookedProcInformation in ctlDict and we are// disposing remove it from ctlDict.if (ctlDict.ContainsKey(ctl) && disposing)ctlDict.Remove(ctl);// If we found our HookedProcInformation in hwndDict, remove it// and if we are not disposing stick it in ctlDict.if (hwndDict.ContainsKey(ctl.Handle)){hpi.Unhook();hwndDict.Remove(ctl.Handle);if (!disposing)ctlDict[ctl] = hpi;}}// This class remembers the old window procedure for the specified// window handle and also provides the message map for the messages// hooked on that window.class HookedProcInformation{// The message map for the window.public Dictionary<uint, WndProcCallback> messageMap;// The old window procedure for the window.private IntPtr oldWndProc;// The delegate that gets called in place of this window's// wndproc.private Win32.WndProc newWndProc;// Control whose wndproc is being hooked.private Control control;// Constructs a new HookedProcInformation object// Parameters:// ctl - The handle to the window being hooked// wndproc - The window procedure to replace the// original one for the control.public HookedProcInformation(Control ctl, Win32.WndProc wndproc){control = ctl;newWndProc = wndproc;messageMap = new Dictionary<uint, WndProcCallback>();}// Replaces the windows procedure for control with the// one specified in the constructor.public void SetHook(){IntPtr hwnd = control.Handle;if (hwnd == IntPtr.Zero)throw new InvalidOperationException("Handle for control has not been created");oldWndProc = Win32.SetWindowLong(hwnd, Win32.GWL_WNDPROC,Marshal.GetFunctionPointerForDelegate(newWndProc));}// Restores the original window procedure for the control.public void Unhook(){IntPtr hwnd = control.Handle;if (hwnd == IntPtr.Zero)throw new InvalidOperationException("Handle for control has not been created");Win32.SetWindowLong(hwnd, Win32.GWL_WNDPROC, oldWndProc);}// Calls the original window procedure of the control with the// arguments provided.// Parameters:// hwnd - The handle of the window that received the// message// msg - The message// wParam - The message's arguments (part 1)// lParam - The message's arguments (part 2)// Returns the value returned by the control's original wndproc.public int CallOldWindowProc(IntPtr hwnd, uint msg, uint wParam, int lParam){return Win32.CallWindowProc(oldWndProc, hwnd, msg, wParam, lParam);}}}}
using
namespace
{
Control ctl, WndProcCallback callback,
HookedProcInformation hpi =
hpi = ctlDict[ctl];
hpi = hwndDict[ctl.Handle];
hpi =
ctl.HandleCreated +=
ctl.HandleDestroyed +=
ctl.Disposed +=
hpi.SetHook();
}
ctlDict[ctl] = hpi;
hwndDict[ctl.Handle] = hpi;
hpi.messageMap[msg] = callback;
Control ctl = sender
ctlDict.Remove(ctl);
System.Diagnostics.Debug.Assert(
HookedProcInformation hpi = hwndDict[ctl.Handle];
UnhookWndProc(ctl,
HookedProcInformation hpi = ctlDict[ctl];
HookedProcInformation hpi = hwndDict[hwnd];
WndProcCallback callback = hpi.messageMap[msg];
hpi.messageMap.Remove(msg);
msg));
hpi.Unhook();
hwndDict.Remove(ctl.Handle);
control = ctl;
newWndProc = wndproc;
messageMap =
oldWndProc = Win32.SetWindowLong(hwnd, Win32.GWL_WNDPROC,
Win32.SetWindowLong(hwnd, Win32.GWL_WNDPROC, oldWndProc);
oldWndProc, hwnd, msg, wParam, lParam);