How to Draw Lines with AutoHotkey Using Windows GDIPlus Graphics

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 :

  1. Create the GDIPlus object:
    Global GdipOBJ:={X: 0,Y: 0,W: A_ScreenWidth,H: A_ScreenWidth}
  2. Create the invisible GUI cover:
    Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
    Gui, 1:Show, Maximize
  3. Turn the GUI into a layered window:
    GdipOBJ := Layered_Window_SetUp(4,GdipOBJ.X,GdipOBJ.Y
    ,GdipOBJ.W,GdipOBJ.H,2,"-Caption -DPIScale +Parent1")
  4. Create the drawing pen:
    MyPen:=New_Pen("FF0000",,5)
  5. Capture the line start point:
    MouseGetPos,sx,sy
  6. Clear graphics from GUI window:
    Gdip_GraphicsClear(GdipOBJ.G)
  7. Capture the line endpoint:
    MouseGetPos,ex,ey
  8. Draw the line on the invisible GUI:
    Gdip_DrawLine(GdipOBJ.G, myPen, sx, sy, ex, ey)
  9. Update the layered window to show line:
    UpdateLayeredWindow(GdipOBJ.hwnd, GdipOBJ.hdc)
  10. Go to Step 6 and repeat to animate the moving line:
    SetTimer,DrawStuff,50
  11. Hit key to set the line and terminate the SetTimer loop:
    if(GETKEYSTATE("Shift"))
    if(GETKEYSTATE("Alt"))
Library Benefits

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.)

jack

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“!

4 thoughts on “How to Draw Lines with AutoHotkey Using Windows GDIPlus Graphics

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s