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!