Introduction
You never know when you may need something. This is the lesson I have learned recently. I am not talking about physical things. I mean, everyone needs money, but this is not what I am talking about. I am talking about a small thing we can take for granted. Eyesight.
Due to an injury, I have been forced to type everything out with mostly one hand, and because of that, the screen and keyboard are farther away than usual. To properly see what I type, I need to make use of the built-in magnifier feature that Windows supplies as an accessibility feature, or I have to set the zoom level or font size higher.
Hence this article.
This article will show you how to make a magnifier with the use of the built-in magnification functions of Windows.
Practical
Open Visual Studio and create a new C# Windows Forms project. Ensure that the form is displayed as Maximized by setting its WindowStyle property.
Add a new class and name it APIMethods. Add the following code into it:
using System; using System.Runtime.InteropServices; namespace HTG_Magnify_C { internal static class APIMethods { public static IntPtr HWND_TOPMOST = new IntPtr(-1); public const int USER_TIMER_MINIMUM = 0x0000000A; public const int SM_ARRANGE = 0x38; public const int SM_CLEANBOOT = 0x43; public const int SM_CMONITORS = 80; public const int SM_CMOUSEBUTTONS = 0x2b; public const int SM_CXBORDER = 5; public const int SM_CXCURSOR = 13; public const int SM_CXDOUBLECLK = 0x24; public const int SM_CXDRAG = 0x44; public const int SM_CXEDGE = 0x2d; public const int SM_CXFIXEDFRAME = 7; public const int SM_CXFOCUSBORDER = 0x53; public const int SM_CXFRAME = 0x20; public const int SM_CXHSCROLL = 0x15; public const int SM_CXHTHUMB = 10; public const int SM_CXICON = 11; public const int SM_CXICONSPACING = 0x26; public const int SM_CXMAXIMIZED = 0x3d; public const int SM_CXMAXTRACK = 0x3b; public const int SM_CXMENUCHECK = 0x47; public const int SM_CXMENUSIZE = 0x36; public const int SM_CXMIN = 0x1c; public const int SM_CXMINIMIZED = 0x39; public const int SM_CXMINSPACING = 0x2f; public const int SM_CXMINTRACK = 0x22; public const int SM_CXSCREEN = 0; public const int SM_CXSIZE = 30; public const int SM_CXSIZEFRAME = 0x20; public const int SM_CXSMICON = 0x31; public const int SM_CXSMSIZE = 0x34; public const int SM_CXVIRTUALSCREEN = 0x4e; public const int SM_CXVSCROLL = 2; public const int SM_CYBORDER = 6; public const int SM_CYCAPTION = 4; public const int SM_CYCURSOR = 14; public const int SM_CYDOUBLECLK = 0x25; public const int SM_CYDRAG = 0x45; public const int SM_CYEDGE = 0x2e; public const int SM_CYFIXEDFRAME = 8; public const int SM_CYFOCUSBORDER = 0x54; public const int SM_CYFRAME = 0x21; public const int SM_CYHSCROLL = 3; public const int SM_CYICON = 12; public const int SM_CYICONSPACING = 0x27; public const int SM_CYKANJIWINDOW = 0x12; public const int SM_CYMAXIMIZED = 0x3e; public const int SM_CYMAXTRACK = 60; public const int SM_CYMENU = 15; public const int SM_CYMENUCHECK = 0x48; public const int SM_CYMENUSIZE = 0x37; public const int SM_CYMIN = 0x1d; public const int SM_CYMINIMIZED = 0x3a; public const int SM_CYMINSPACING = 0x30; public const int SM_CYMINTRACK = 0x23; public const int SM_CYSCREEN = 1; public const int SM_CYSIZE = 0x1f; public const int SM_CYSIZEFRAME = 0x21; public const int SM_CYSMCAPTION = 0x33; public const int SM_CYSMICON = 50; public const int SM_CYSMSIZE = 0x35; public const int SM_CYVIRTUALSCREEN = 0x4f; public const int SM_CYVSCROLL = 20; public const int SM_CYVTHUMB = 9; public const int SM_DBCSENABLED = 0x2a; public const int SM_DEBUG = 0x16; public const int SM_MENUDROPALIGNMENT = 40; public const int SM_MIDEASTENABLED = 0x4a; public const int SM_MOUSEPRESENT = 0x13; public const int SM_MOUSEWHEELPRESENT = 0x4b; public const int SM_NETWORK = 0x3f; public const int SM_PENWINDOWS = 0x29; public const int SM_REMOTESESSION = 0x1000; public const int SM_SAMEDISPLAYFORMAT = 0x51; public const int SM_SECURE = 0x2c; public const int SM_SHOWSOUNDS = 70; public const int SM_SWAPBUTTON = 0x17; public const int SM_XVIRTUALSCREEN = 0x4c; public const int SM_YVIRTUALSCREEN = 0x4d; public const string MAGNIFIER = "Magnifier"; [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern int GetSystemMetrics(int nIndex); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern IntPtr SetTimer(IntPtr hWnd, int nIDEvent, int uElapse, IntPtr lpTimerFunc); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool KillTimer(IntPtr hwnd, int idEvent); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetClientRect(IntPtr hWnd, [In, Out] ref RECT rect); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags); [DllImport("user32.dll", EntryPoint = "CreateWindowExW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public extern static IntPtr CreateWindow(int dwExStyle, string lpClassName, string lpWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, LayeredWindowAttributeFlags dwFlags); [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr GetModuleHandle([MarshalAs (UnmanagedType.LPWStr)] string modName); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetCursorPos(ref POINT pt); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetCursorPos(int X, int Y); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool InvalidateRect(IntPtr hWnd, IntPtr rect, [MarshalAs(UnmanagedType.Bool)] bool erase); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagInitialize(); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagUninitialize(); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagSetWindowSource(IntPtr hwnd, RECT rect); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagGetWindowSource(IntPtr hwnd, ref RECT pRect); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagSetWindowTransform(IntPtr hwnd, ref Transform pTransform); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagGetWindowTransform(IntPtr hwnd, ref Transform pTransform); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagSetWindowFilterList(IntPtr hwnd, int dwFilterMode, int count, IntPtr pHWND); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] public static extern int MagGetWindowFilterList(IntPtr hwnd, IntPtr pdwFilterMode, int count, IntPtr pHWND); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagSetColorEffect(IntPtr hwnd, ref Color pEffect); [DllImport("Magnification.dll", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MagGetColorEffect(IntPtr hwnd, ref Color pEffect); } }
This class contains definitions and declarations from the Windows Magnification.dll. We import their abilities into our program, so that we can make use of them.
Add a new class and name it APIStructures. Add the following code:
namespace HTG_Magnify_C { internal enum Style : int { MS_SHOWMAGNIFIEDCURSOR = 0x0001, MS_CLIPAROUNDCURSOR = 0x0002, MS_INVERTCOLORS = 0x0004 } internal enum Filter { MW_FILTERMODE_EXCLUDE = 0, MW_FILTERMODE_INCLUDE = 1 } internal struct Transform { public float m00; public float m10; public float m20; public float m01; public float m11; public float m21; public float m02; public float m12; public float m22; public Transform(float Factor) : this() { m00 = Factor; m11 = Factor; m22 = 1.0f; } } internal struct Color { public float transform00; public float transform10; public float transform20; public float transform30; public float transform40; public float transform01; public float transform02; public float transform03; public float transform04; public float transform11; public float transform12; public float transform13; public float transform14; public float transform21; public float transform22; public float transform23; public float transform24; public float transform31; public float transform32; public float transform33; public float transform34; public float transform41; public float transform42; public float transform43; public float transform44; } internal struct POINT { public int x; public int y; public POINT(int x, int y) { this.x = x; this.y = y; } } internal struct RECT { public int left; public int top; public int right; public int bottom; public RECT(int left, int top, int right, int bottom) { this.left = left; this.right = right; this.top = top; this.bottom = bottom; } public RECT(int width, int height) { this.left = 0; this.top = 0; this.right = width; this.bottom = height; } public override bool Equals(object obj) { RECT r = (RECT)obj; return (r.left == left && r.right == right && r.top == top && r.bottom == bottom); } public override int GetHashCode() { return ((left ^ top) ^ right) ^ bottom; } public static bool operator ==(RECT a, RECT b) { return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); } public static bool operator !=(RECT a, RECT b) { return !(a == b); } } internal enum WindowStyles : int { WS_OVERLAPPED = 0x00000000, WS_POPUP = -2147483648, WS_CHILD = 0x40000000, WS_MINIMIZE = 0x20000000, WS_VISIBLE = 0x10000000, WS_DISABLED = 0x08000000, WS_CLIPSIBLINGS = 0x04000000, WS_CLIPCHILDREN = 0x02000000, WS_MAXIMIZE = 0x01000000, WS_CAPTION = 0x00C00000, WS_BORDER = 0x00800000, WS_DLGFRAME = 0x00400000, WS_VSCROLL = 0x00200000, WS_HSCROLL = 0x00100000, WS_SYSMENU = 0x00080000, WS_THICKFRAME = 0x00040000, WS_GROUP = 0x00020000, WS_TABSTOP = 0x00010000, WS_MINIMIZEBOX = 0x00020000, WS_MAXIMIZEBOX = 0x00010000 } internal enum CommonWindowStyles : int { WS_TILED = WindowStyles.WS_OVERLAPPED, WS_ICONIC = WindowStyles.WS_MINIMIZE, WS_SIZEBOX = WindowStyles.WS_THICKFRAME, WS_OVERLAPPEDWINDOW = (WindowStyles.WS_OVERLAPPED | WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU | WindowStyles.WS_THICKFRAME | WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_MAXIMIZEBOX), WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW, WS_POPUPWINDOW = (WindowStyles.WS_POPUP | WindowStyles.WS_BORDER | WindowStyles.WS_SYSMENU), WS_CHILDWINDOW = (WindowStyles.WS_CHILD) } internal enum SetWindowPosFlags : int { SWP_NOSIZE = 1, SWP_NOMOVE = 2, SWP_NOZORDER = 4, SWP_NOREDRAW = 8, SWP_NOACTIVATE = 0x10, SWP_FRAMECHANGED = 0x20, SWP_SHOWWINDOW = 0x40, SWP_HIDEWINDOW = 0x80, SWP_NOCOPYBITS = 0x100, SWP_NOOWNERZORDER = 0x200, SWP_NOSENDCHANGING = 0x400 } internal enum ExtendedWindowStyles : int { WS_EX_DLGMODALFRAME = 0x00000001, WS_EX_NOPARENTNOTIFY = 0x00000004, WS_EX_TOPMOST = 0x00000008, WS_EX_ACCEPTFILES = 0x00000010, WS_EX_TRANSPARENT = 0x00000020, WS_EX_MDICHILD = 0x00000040, WS_EX_TOOLWINDOW = 0x00000080, WS_EX_WINDOWEDGE = 0x00000100, WS_EX_CLIENTEDGE = 0x00000200, WS_EX_CONTEXTHELP = 0x00000400, WS_EX_RIGHT = 0x00001000, WS_EX_LEFT = 0x00000000, WS_EX_RTLREADING = 0x00002000, WS_EX_LTRREADING = 0x00000000, WS_EX_LEFTSCROLLBAR = 0x00004000, WS_EX_RIGHTSCROLLBAR = 0x00000000, WS_EX_CONTROLPARENT = 0x00010000, WS_EX_STATICEDGE = 0x00020000, WS_EX_APPWINDOW = 0x00040000, WS_EX_LAYERED = 0x00080000, WS_EX_NOINHERITLAYOUT = 0x00100000, WS_EX_LAYOUTRTL = 0x00400000, WS_EX_COMPOSITED = 0x02000000, WS_EX_NOACTIVATE = 0x08000000 } internal enum CommonExtendedWindowStyles : int { WS_EX_OVERLAPPEDWINDOW = (ExtendedWindowStyles.WS_EX_WINDOWEDGE | ExtendedWindowStyles.WS_EX_CLIENTEDGE), WS_EX_PALETTEWINDOW = (ExtendedWindowStyles.WS_EX_WINDOWEDGE | ExtendedWindowStyles.WS_EX_TOOLWINDOW | ExtendedWindowStyles.WS_EX_TOPMOST) } internal enum LayeredWindowAttributeFlags : int { LWA_COLORKEY = 0x00000001, LWA_ALPHA = 0x00000002 } internal enum LayeredWindowUpdateFlags : int { ULW_COLORKEY = 0x00000001, ULW_ALPHA = 0x00000002, ULW_OPAQUE = 0x00000004 } internal enum BlendOperations : byte { AC_SRC_OVER = 0x00, AC_SRC_ALPHA = 0x01 } internal enum ShowWindowStyles : short { SW_HIDE = 0, SW_SHOWNORMAL = 1, SW_NORMAL = 1, SW_SHOWMINIMIZED = 2, SW_SHOWMAXIMIZED = 3, SW_MAXIMIZE = 3, SW_SHOWNOACTIVATE = 4, SW_SHOW = 5, SW_MINIMIZE = 6, SW_SHOWMINNOACTIVE = 7, SW_SHOWNA = 8, SW_RESTORE = 9, SW_SHOWDEFAULT = 10, SW_FORCEMINIMIZE = 11, SW_MAX = 11 } internal enum WindowMessage : int { WM_CREATE = 0x0001, WM_DESTROY = 0x0002, WM_PAINT = 0x000F, WM_CLOSE = 0x0010, WM_QUERYENDSESSION = 0x0011, WM_QUIT = 0x0012, WM_ENDSESSION = 0x0016, WM_SETCURSOR = 0x0020, WM_MOVE = 0x0003, WM_SIZE = 0x0005, WM_MOUSEMOVE = 0x0200, WM_NCMOUSEMOVE = 0x00A0, WM_KEYDOWN = 0x0100, WM_SYSKEYDOWN = 0x0104, WM_KEYUP = 0x0101, WM_CHAR = 0x0102, WM_SYSCHAR = 0x0106, WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x0202, WM_LBUTTONDBLCLK = 0x0203, WM_RBUTTONDOWN = 0x0204, WM_RBUTTONUP = 0x0205, WM_RBUTTONDBLCLK = 0x0206, WM_MBUTTONDOWN = 0x0207, WM_MBUTTONUP = 0x0208, WM_MBUTTONDBLCLK = 0x0209, WM_MOUSEWHEEL = 0x020A, WM_MOUSEHOVER = 0x02A1, WM_MOUSELEAVE = 0x02A3, WM_NCLBUTTONDOWN = 0x00A1, WM_NCLBUTTONUP = 0x00A2, WM_NCLBUTTONDBLCLK = 0x00A3, WM_NCRBUTTONDOWN = 0x00A4, WM_NCRBUTTONUP = 0x00A5, WM_NCRBUTTONDBLCLK = 0x00A6, WM_NCMBUTTONDOWN = 0x00A7, WM_NCMBUTTONUP = 0x00A8, WM_NCMBUTTONDBLCLK = 0x00A9, WM_NCXBUTTONDOWN = 0x00AB, WM_NCXBUTTONUP = 0x00AC, WM_GETDLGCODE = 0x0087, WM_NCHITTEST = 0x0084, WM_WINDOWPOSCHANGING = 0x0046, WM_WINDOWPOSCHANGED = 0x0047, WM_KILLTIMER = 0x402, WM_TIMER = 0x113, WM_NCPAINT = 0x85, WM_ERASEBKGND = 20, WM_DROPFILES = 0x233, WM_MOUSEACTIVATE = 0x0021, WM_ACTIVATE = 0x0006, WM_ACTIVATEAPP = 0x001C, WM_KILLFOCUS = 8 } }
Conclusion
In Part 2, we will put everything together and use it. Until then, happy coding!