Introduction
In the previous installment, “Creating a Magnifier in .NET, Part 1: Structure,” we created the structure for this project. We set up the Methods and Properties needed. If you have not read Part 1 yet, please do so before continuing.
All we need to do now is to make this work with a Form, so let’s not waste any more time and get started.
Practical
Open the code window for your Form, and add the next few fields to it.
private Form frmMag;
private Thread tBackground;
private System.Windows.Forms.Timer tmrMag;
private IntPtr iptrMag;
private float fMagVal;
private RECT rectMagWin = new RECT();
private bool blnInit;
private bool blnNormal = true;
private bool blnHidden = true;
Add the next few Enumerations:
private enum WStyle
{
ExStyle = -20
}
private enum WType
{
Transparent = 0x20,
Layered = 0x80000
}
private enum WCol
{
ColorKey = 0x1,
Alpha = 0x1
}
The Enumerations contain the settings for the Window style, its appearance, and its main color. Now, let’s add some more APIs:
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern int GetWindowLong(IntPtr hWnd,
WStyle nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong(IntPtr hWnd,
WStyle nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint =
"SetLayeredWindowAttributes")]
private static extern bool SetLayeredWindowAttributes(IntPtr
hWnd, int crKey, byte alpha, WCol dwFlags);
[DllImport("user32.dll")]
private static extern short GetAsyncKeyState(Keys vKey);
Add the Constructor to initialize the variables to default values:
public Form1()
{
InitializeComponent();
frmMag = this;
fMagVal = 2.0f;
CreateWindow();
frmMag.Resize += new EventHandler(Form_Resize);
frmMag.FormClosing += new
FormClosingEventHandler(Form_FormClosing);
tmrMag = new System.Windows.Forms.Timer();
tmrMag.Tick += new EventHandler(Timer_Tick);
blnInit = APIMethods.MagInitialize();
if (blnInit)
{
Setup();
tmrMag.Interval = APIMethods.USER_TIMER_MINIMUM;
tmrMag.Enabled = true;
}
DetermineKeysThread();
}
private void CreateWindow()
{
DoubleBuffered = true;
WindowState = FormWindowState.Normal;
StartPosition = FormStartPosition.CenterScreen;
ShowInTaskbar = false;
}
Determine which key is pressed with the next methods:
private void DetermineKeysThread()
{
tBackground = new Thread(() => DetermineKeys())
{
IsBackground = true,
Priority = ThreadPriority.Normal
};
tBackground.Start();
}
private void DetermineKeys()
{
BeginInvoke(new MethodInvoker(delegate
{
Hide();
}));
while (true)
{
Thread.Sleep(10);
foreach (Keys k in Enum.GetValues(typeof(Keys)))
{
if (((GetAsyncKeyState(k) & (1 << 15)) != 0))
{
if (k == Keys.MButton)
{
if (blnHidden)
{
BeginInvoke(new MethodInvoker(delegate
{
Show();
}));
Thread.Sleep(500);
blnHidden = false;
}
else
{
BeginInvoke(new MethodInvoker(delegate
{
Hide();
}));
Thread.Sleep(500);
blnHidden = true;
}
}
if (k == Keys.Add)
{
BeginInvoke(new MethodInvoker(delegate
{
Magnification++;
}));
Thread.Sleep(500);
}
if (k == Keys.Subtract)
{
BeginInvoke(new MethodInvoker(delegate
{
if (Magnification > 1f)
{
Magnification--;
}
}));
Thread.Sleep(500);
}
if (k == Keys.Multiply)
{
if (blnNormal)
{
blnNormal = false;
BeginInvoke(new MethodInvoker(delegate
{
WindowState = FormWindowState.Maximized;
}));
Thread.Sleep(500);
}
else
{
blnNormal = true;
BeginInvoke(new MethodInvoker(delegate
{
WindowState = FormWindowState.Normal;
}));
Thread.Sleep(500);
}
}
if (k == Keys.F10)
{
Application.Exit();
}
}
}
}
}
Add the next methods to override the Form’s Shown method, and the method to resize the form:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
int wl = GetWindowLong(Handle, WStyle.ExStyle);
wl = wl | 0x80000 | 0x20;
SetWindowLong(Handle, WStyle.ExStyle, wl);
SetLayeredWindowAttributes(Handle, 0, 128, WCol.Alpha);
}
protected virtual void ResizeMag()
{
if (blnInit && (iptrMag != IntPtr.Zero))
{
APIMethods.GetClientRect(frmMag.Handle, ref rectMagWin);
APIMethods.SetWindowPos(iptrMag, IntPtr.Zero,
rectMagWin.left, rectMagWin.top, rectMagWin.right,
rectMagWin.bottom, 0);
}
}
public virtual void UpdateMag()
{
if ((!blnInit) || (iptrMag == IntPtr.Zero))
{
return;
}
RECT rctSource = new RECT();
Point pPos = new Point(Screen.PrimaryScreen.Bounds.Width / 2,
Screen.PrimaryScreen.Bounds.Height / 2);
int iWidth = (int)((rectMagWin.right - rectMagWin.left) /
fMagVal);
int iHeight = (int)((rectMagWin.bottom - rectMagWin.top) /
fMagVal);
rctSource.left = pPos.X - iWidth / 2;
rctSource.top = pPos.Y - iHeight / 2;
if (rctSource.left < 0)
{
rctSource.left = 0;
}
if (rctSource.left > APIMethods.GetSystemMetrics
(APIMethods.SM_CXSCREEN) - iWidth)
{
rctSource.left = APIMethods.GetSystemMetrics
(APIMethods.SM_CXSCREEN) - iWidth;
}
rctSource.right = rctSource.left + iWidth;
if (rctSource.top < 0)
{
rctSource.top = 0;
}
if (rctSource.top > APIMethods.GetSystemMetrics
(APIMethods.SM_CYSCREEN) - iHeight)
{
rctSource.top = APIMethods.GetSystemMetrics
(APIMethods.SM_CYSCREEN) - iHeight;
}
rctSource.bottom = rctSource.top + iHeight;
if (frmMag == null)
{
tmrMag.Enabled = false;
return;
}
if (frmMag.IsDisposed)
{
tmrMag.Enabled = false;
return;
}
APIMethods.MagSetWindowSource(iptrMag, rctSource);
APIMethods.SetWindowPos(frmMag.Handle,
APIMethods.HWND_TOPMOST, 0, 0, 0, 0,
(int)SetWindowPosFlags.SWP_NOACTIVATE |
(int)SetWindowPosFlags.SWP_NOMOVE |
(int)SetWindowPosFlags.SWP_NOSIZE);
APIMethods.InvalidateRect(iptrMag, IntPtr.Zero, true);
}
private float Magnification
{
get { return fMagVal; }
set
{
if (fMagVal != value)
{
fMagVal = value;
Transform tMatrix = new Transform(fMagVal);
APIMethods.MagSetWindowTransform(iptrMag, ref
tMatrix);
}
}
}
protected void Setup()
{
if (!blnInit)
{
return;
}
IntPtr hInst;
hInst = APIMethods.GetModuleHandle(null);
frmMag.AllowTransparency = true;
frmMag.TransparencyKey = System.Drawing.Color.Empty;
frmMag.Opacity = 255;
APIMethods.GetClientRect(frmMag.Handle, ref rectMagWin);
iptrMag = APIMethods.CreateWindow((int)ExtendedWindowStyles
.WS_EX_TRANSPARENT, APIMethods.MAGNIFIER,
"Form1", (int)WindowStyles.WS_CHILD |
(int)WindowStyles.WS_VISIBLE,
rectMagWin.left, rectMagWin.top, rectMagWin.right,
rectMagWin.bottom, frmMag.Handle, IntPtr.Zero, hInst,
IntPtr.Zero);
if (iptrMag == IntPtr.Zero)
{
return;
}
Transform tMatrix = new Transform(fMagVal);
APIMethods.MagSetWindowTransform(iptrMag, ref tMatrix);
}
protected void RemoveMag()
{
if (blnInit)
{
APIMethods.MagUninitialize();
}
}
Finally, add the last few methods:
private void Form_FormClosing(object sender,
FormClosingEventArgs e)
{
tmrMag.Enabled = false;
}
private void Form_Resize(object sender, EventArgs e)
{
ResizeMag();
}
private void Timer_Tick(object sender, EventArgs e)
{
UpdateMag();
}
Conclusion
As developers, we are so fortunate to have Windows on our side, because making use of its built-in APIs can give us more power. I hope you have enjoyed this little series. Until next time, happy coding!