After Laying an Invisible Graphical User Interface (GUI) over Your Computer Screen, You Can Use Windows GDIPlus to Draw Smooth Lines and Shapes
In my last blog (“Replace Hotkeys with the AutoHotkey GetKeyState() Function“), I explained a Hotstring replacement trick as well as introducing GDIPlus graphics drawing functions from an AutoHotkey post by Hellbent. After comparing the functions in the GDIP_All.ahk library with those from Hellbent, I noted that while many were identical, Hellbent added a few more functions which seemed to make the process easier. Although, I haven’t analyzed the details of each function, I have made them work in the MouseMeasure.ahk script. Here I offer an overview to guide you in how to add an invisible GDIPlus graphics drawing overlay to your computer screen.

Since these GDIPlus functions (included in the script) contain the individual DLLCall() functions, they make it easier to implement on-screen graphics without understanding each enigmatic DLL call. A general understanding of how the MouseMeasure.ahk script works with GDIPlus will help you to implement your own AutoHotkey graphics.
The GDIPlus functions use Object Oriented Programming (OOP) syntax—a topic for another time (see here for an OOP tutorial). As long as you use the same notation as shown, you should have no problem. Copy the functions into your script and take the following steps to add an invisible line drawing cover to your script :
- Create the GDIPlus object:
Global GdipOBJ:={X: 0,Y: 0,W: A_ScreenWidth,H: A_ScreenWidth}
- Create the invisible GUI cover:
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
Gui, 1:Show, Maximize
- Turn the GUI into a layered window:
GdipOBJ := Layered_Window_SetUp(4,GdipOBJ.X,GdipOBJ.Y
,GdipOBJ.W,GdipOBJ.H,2,"-Caption -DPIScale +Parent1")
- Create the drawing pen:
MyPen:=New_Pen("FF0000",,5)
- Capture the line start point:
MouseGetPos,sx,sy
- Clear graphics from GUI window:
Gdip_GraphicsClear(GdipOBJ.G)
- Capture the line endpoint:
MouseGetPos,ex,ey
- Draw the line on the invisible GUI:
Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
- Update the layered window to show line:
UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
- Go to Step 6 and repeat to animate the moving line:
SetTimer,DrawStuff,50
- Hit key to set the line and terminate the SetTimer loop:
if(GETKEYSTATE("Shift"))
if(GETKEYSTATE("Alt"))
1. Create the GDIPlus Object
This first step creates the object GdipOBJ used throughout the script. It tracks the object properties needed to set up the graphics and draw the line.
Global GdipOBJ:={X: 0 ,Y: 0 ,W: A_ScreenWidth, H: A_ScreenHeight}
While initially GdipOBJ only assigns origin coordinates along with the screen width and height, other properties comes into play as a result of internally called functions.
2. Create the Invisible GUI Cover
In Hellbent’s original script, he used a visible GUI for line drawing. I took the following code from another script to turn GUI, 1:
into an invisible, always-on-top, transparent (click-through) window:
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
Gui, 1:Show, Maximize
Since I wanted to cover the entire screen, I used the option Maximize
to expand the GUI with the same effect as A_ScreenWidth
and A_ScreenHeight
.
I also adjusted the Coordinate Mode to accurately grab the mouse cursor location from the screen:
CoordMode, Mouse, Screen
3.Turn the GUI into a Layered Window
A Layered Window makes smooth advanced graphics possible:
Using a layered window can significantly improve performance and visual effects for a window that has a complex shape, animates its shape, or wishes to use alpha blending effects. The system automatically composes and repaints layered windows and the windows of underlying applications.
docs.microsoft.com
The following function turns the active GUI window into a layered window using GdipOBJ:
GdipOBJ := Layered_Window_SetUp(4,GdipOBJ.X,GdipOBJ.Y
,GdipOBJ.W,GdipOBJ.H,2,"-Caption -DPIScale +Parent1")
I’m not clear on the inner workings of all of the parameters but it acts on the invisible GUI cover to create the GDIPlus drawing surface creating all the needed object properties. (I didn’t mess with this one.)
Note: This function also loads the GDIPlus graphics drivers. In other scripts, I saw that they loaded the drivers upfront with a warning for missing DLLs:
If !pToken := Gdip_Startup()
{
MsgBox, 48, gdiplus error!
, Gdiplus failed to start
. Please ensure you have gdiplus on your system.
ExitApp
}
4. Create the Drawing Pen
Everybody needs a pen to do any drawing. Specify the color and line width:
MyPen:=New_Pen("FF0000",,5)
While this function also appears inside another subroutine in the MouseMeasure.ahk script, we only need it at the startup of the script as long as I remove the correspond delete function in the terminating subroutine:
Gdip_DeletePen(myPen)
5. Capture the Line Starting Point
Before we can begin drawing the line we need the starting coordinates:
MouseGetPos,sx,sy
6. Clear Graphics from Window
Initially, no graphic appears on the invisible cover GUI. However, once the drawing starts, the script must clear the screen before each update:
Gdip_GraphicsClear(GdipOBJ.G)
GdipOBJ.g is assigned the layered window itself. This clear operation occurs before each update.
7. Capture Line Endpoint
A line needs an endpoint:
MouseGetPos,ex,ey
8. Draw the Line on the Invisible GUI
Using the layered window and the pen, the script draws a line:
Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
Each time the SetTimer command launches the subroutine, this function redraws the line.
9. Update the Layered Window
The line doesn’t appear until after updating the layered window:
UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
Note that the object now contains values for GdipOBJ.hwnd
and GdipOBJ.hdc
—obtained when first setting up the layered window.
10. Go to Step 6 and Repeat to Animate the Moving Line
To make the line track with the movement of the mouse, the script must clear the screen, redraw the line and update the cover GUI:
SetTimer,DrawStuff,50
The SetTimer command forces this GUI update every 50 milliseconds.
11. Hit Key to Set the Line and Terminate the SetTimer Loop
The line continues to move with the mouse cursor until terminating the SetTimer subroutine using either the Shift
or Alt
key:
if(GETKEYSTATE("Shift"))
if(GETKEYSTATE("Alt"))
These steps layout how the MouseMeasure.ahk script draws lines. You can use these functions without knowing exactly how they work by including them in your script. (Be sure to include all of the functions found in the script since some call other functions available in the list.) Plus, you’ll find more functions for drawing other shapes. The basic steps do not change—although, the order of the GDIPlus functions may change accordingly for different purposes.
Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

This post was proofread by Grammarly
(Any other mistakes are all mine.)
(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)
Find my AutoHotkey books at ComputorEdge E-Books!
Find quick-start AutoHotkey classes at “Robotic Desktop Automation with AutoHotkey“!
AWESOME explanation. Do you mind if I post your updated ahk file on the AHK forum thread?
LikeLike
No problem.
LikeLike
[…] GetKeyState() Function” for an introduction to the GDIPlus version of the script. See “How to Draw Lines with AutoHotkey Using Windows GDIPlus Graphics” for information on the GDIPlus functions used in the […]
LikeLike
[…] discussed in “How to Draw Lines with AutoHotkey Using Windows GDIPlus Graphics“, this AutoHotkey script formulates lines between the start point (sx,sy) and the endpoint […]
LikeLike
Hi Jack,
Been using this mouse measurement tool quite a bit. I was wondering how I can add more function. For example how would I approach using this to make patterns that would be recognizable for the script to output a sentence based on the drawing made. Similar to the pattern pin code you use to bypass a locked Samsung phone?
LikeLike
That’s an intriguing question. I’ve never attempted any type of pattern matching. I’ll have to give that one some thought.
LikeLike