Gdip_All: https://github.com/buliasz/AHKv2-Gdip/blob/master/Gdip_All.ahk
ImagePut: https://github.com/iseahound/ImagePut/blob/master/ImagePut.ahk
Note: You can substitute the Gdip_All functions below, I'll use the raw DllCalls as an example.
GDI
A handle to a device context is a container that holds various objects. The exact objects can be retrieved with GetCurrentObject. To set a new object, use SelectObject, returning the previous object. The previous object must then be freed with DeleteObject. To summarize, an hdc always contains a stock OBJ_BITMAP, OBJ_BRUSH, OBJ_PEN, etc when it is created.
Let's take a look at the stock bitmap. It's a 1x1 tiny black pixel.
Code: Select all
#Include ImagePut.ahk
; Creates a handle to a device context compatible with the current screen.
hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr")
; Scale the tiny pixel 300x so we can see it.
ImageShow({scale: 300, image: hdc}) ; Right click to close.
Next we create a custom handle to a GDI bitmap hBitmap using CreateDIBSection.
Code: Select all
#Include ImagePut.ahk
; Creates a GDI hBitmap.
width := 300, height := 300
bi := Buffer(40, 0) ; sizeof(bi) = 40
NumPut( "uint", 40, bi, 0) ; Size
NumPut( "int", width, bi, 4) ; Width
NumPut( "int", -height, bi, 8) ; Height - Negative so (0, 0) is top-left.
NumPut("ushort", 1, bi, 12) ; Planes
NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel
hbm := DllCall("CreateDIBSection", "ptr", 0, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr")
ImagePutWindow(hbm)
Let's add a bit of color to show what I mean:
Code: Select all
#Include ImagePut.ahk
bi := Buffer(40, 0) ; sizeof(bi) = 40
NumPut( "uint", 40, bi, 0) ; Size
NumPut( "int", 10, bi, 4) ; Width
NumPut( "int", -10, bi, 8) ; Height - Negative so (0, 0) is top-left.
NumPut("ushort", 1, bi, 12) ; Planes
NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel
hbm := DllCall("CreateDIBSection", "ptr", 0, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr")
; Add some colors: Red Green and Blue
NumPut("uint", 0xFFFF0000, "uint", 0xFF00FF00, "uint", 0xFF0000FF, pBits)
; Zoom in 30x (sorry for blurry scaling)
ImagePutWindow({scale: 30, image: hbm})
Cool! Now let's finish up the typical GDI application which in order:
- Creates an hdc or a container that holds various GDI objects
- Creates a hbm or hBitmap or a handle to a GDI bitmap
- Selects the hbm onto the hdc
Code: Select all
#Include ImagePut.ahk
hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr")
bi := Buffer(40, 0) ; sizeof(bi) = 40
NumPut( "uint", 40, bi, 0) ; Size
NumPut( "int", 10, bi, 4) ; Width
NumPut( "int", -10, bi, 8) ; Height - Negative so (0, 0) is top-left.
NumPut("ushort", 1, bi, 12) ; Planes
NumPut("ushort", 32, bi, 14) ; BitCount / BitsPerPixel
hbm := DllCall("CreateDIBSection", "ptr", 0, "ptr", bi, "uint", 0, "ptr*", &pBits:=0, "ptr", 0, "uint", 0, "ptr")
obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr")
; Add some AliceBlue #9CD6E4 with some double d transparency.
loop 100
NumPut("uint", 0xDD9CD6E4, pBits, 4 * (A_Index-1))
ImagePutWindow({scale: 30, image: hdc})
Now what about obm? Well you can ignore and forget about it. But unlike the rest of the GDI stock objects that 1x1 black pixel can't be summoned via GetStockObject. Instead. you can do:
Code: Select all
obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr")
Hopefully you can now understand how GDI works with the help of ImagePut as a debugging tool.