来源说明:本文参考 AutoHotkey 论坛 tic 发布的 GDI+ standard library 1.45 by tic 主题,并结合本站 GDI+系列教程目录 做补充整理。本站已有完整的 GDI+ 中文教程路线,这篇不重复讲画笔、画刷、图片绘制,而是专门说库版本、兼容性和常见坑。
很多 GDI+ 示例本身并不难,真正让新手卡住的往往是:下载了不合适的 Gdip 库、AHK 位数不匹配、Unicode/ANSI 不一致、反复启动关闭 GDI+、透明窗口在高 DPI 下显示异常。把这些基础问题排掉,后面的绘图、截图、保存图片、异型界面才会顺很多。
一、优先使用 Gdip_All.ahk
原帖里推荐的是 Gdip_All.ahk,它的意义不是名字更“全”,而是为了兼容不同 AHK 环境:ANSI、Unicode、x86、x64。很多老教程里可能引用的是较早版本的 Gdip.ahk,在旧环境能跑,但换到新版 AHK 或 64 位系统后就可能出现问题。
对现在的 AHKv1 用户来说,建议优先确认三件事:
- 脚本包含的是当前可用的
Gdip_All.ahk,不是很早以前下载的旧版。 - AHK 解释器位数和库的兼容性没有冲突,尤其是 x64 环境。
- 不要在多个目录里放不同版本的 Gdip 库,避免
#Include实际加载的不是你以为的那个文件。
#Requires AutoHotkey v1.1
#NoEnv
#SingleInstance Force
#Include <Gdip_All>
if !pToken := Gdip_Startup()
{
MsgBox, 48, GDI+错误, GDI+ 启动失败,请检查 Gdip_All.ahk 和系统环境。
ExitApp
}
; 这里写你的 GDI+ 绘图、截图、保存图片逻辑
Gdip_Shutdown(pToken)
ExitApp
如果你使用的是放在脚本同目录的库,也可以写成 #Include %A_ScriptDir%\Gdip_All.ahk,这样最清楚,不容易被全局 Lib 目录里的旧版本干扰。
二、Gdip_Startup 和 Gdip_Shutdown 不要乱放
一个很常见的错误是:把 Gdip_Startup() 和 Gdip_Shutdown() 写进每个函数里,用一次图片就启动一次,用完马上关闭一次。看起来很整洁,实际很容易造成重复关闭、句柄失效、脚本崩溃或者图片对象莫名失效。
更稳的写法是:脚本开始时启动一次,脚本退出前关闭一次。中间的函数只负责创建、使用和释放具体的 bitmap、graphics、brush、pen 等对象。
#NoEnv
#SingleInstance Force
#Include %A_ScriptDir%\Gdip_All.ahk
if !pToken := Gdip_Startup()
{
MsgBox, 48, GDI+错误, GDI+ 启动失败。
ExitApp
}
OnExit, HandleExit
; 主逻辑
Gosub, Demo
return
Demo:
; 在这里使用 GDI+,不要每次都重新 Startup / Shutdown
return
HandleExit:
Gdip_Shutdown(pToken)
ExitApp
如果你的脚本是常驻型工具,比如截图工具、放大镜、悬浮提示、动态 GUI,更应该保持这种结构。GDI+ 初始化属于脚本生命周期级别,不要当成普通函数内部的临时变量处理。
三、x64、Unicode 和参数类型问题
论坛回帖里多次提到旧版 Gdip 在 x64 或 Unicode 环境下的问题。根本原因通常不是绘图逻辑错了,而是底层 DllCall 参数类型不适配。例如指针相关参数在 32 位和 64 位下不能简单都写成 UInt,很多时候需要 Ptr 或 UPtr。
如果遇到下面这些情况,先怀疑库版本和位数兼容性:
- 同一份脚本在 32 位 AHK 能跑,64 位 AHK 不显示。
- 更新 AHK 后,原来的透明窗口、图层窗口突然不可见。
Gdip_Startup()能成功,但UpdateLayeredWindow、保存图片、加载图片异常。- 老示例里大量使用
UInt传窗口句柄、HDC、bitmap 指针。
排查时不要急着改业务代码,先换成兼容性更好的 Gdip_All.ahk,再确认运行的是 32 位还是 64 位 AHK。
MsgBox, % "A_PtrSize = " A_PtrSize "`n"
. "AHK位数 = " (A_PtrSize = 8 ? "64位" : "32位") "`n"
. "Unicode = " (A_IsUnicode ? "是" : "否")
四、透明窗口和高 DPI:UpdateLayeredWindow 要注意宽高
GDI+ 常用于透明悬浮窗、异型界面、无边框 GUI。论坛讨论里提到过一个高 DPI 相关问题:某些旧写法只调用 UpdateLayeredWindow(hwnd, hdc),在非标准 DPI 或某些系统环境下可能显示异常。
更稳的写法通常会把窗口宽高也传进去,例如:
UpdateLayeredWindow(hwnd1, hdc, 0, 0, WinWidth, WinHeight)
如果你做的是圆角窗口、透明贴图、悬浮按钮、放大镜、屏幕标注工具,遇到“脚本在运行但界面不显示”“换电脑后位置或大小不对”“缩放比例不是 100% 时异常”,就要把 DPI 和 UpdateLayeredWindow 参数一起检查。
五、对象释放比想象中重要
GDI+ 里很多东西都不是普通变量,而是系统资源句柄。比如 bitmap、graphics、brush、pen、font 等,用完后应该释放。短脚本可能看不出问题,常驻脚本或循环截图脚本就很容易内存上涨、句柄增加,最后卡顿或崩溃。
pBitmap := Gdip_CreateBitmap(400, 200) G := Gdip_GraphicsFromImage(pBitmap) pBrush := Gdip_BrushCreateSolid(0xffffcc00) Gdip_FillRectangle(G, pBrush, 20, 20, 160, 80) Gdip_SaveBitmapToFile(pBitmap, A_ScriptDir "\test.png") Gdip_DeleteBrush(pBrush) Gdip_DeleteGraphics(G) Gdip_DisposeImage(pBitmap)
记住一个简单原则:凡是 Create、From、Clone、Bitmap、Graphics 这类创建出来的对象,都要留意有没有对应的删除或释放函数。
六、AHKv2-Gdip 可以了解,但本站示例仍以 v1 为主
论坛后续讨论里提到了 AHKv2-Gdip,它主要面向 AHK v2,同时也兼容 v1.1。对于同时维护 v1/v2 脚本的人,这是一个值得了解的分支。
不过本站目前主要以 AHKv1 为主,如果你只是学习和运行本站 GDI+ 系列教程,优先跟着 v1 示例和 Gdip_All.ahk 走即可。不要一边看 v1 教程,一边混用 v2 风格库和 v2 语法,这样排错成本会明显增加。
七、官方示例和本站教程怎么对应
tic 原帖列出了 12 个官方示例,它们和本站 GDI+ 系列教程有不少对应关系。你可以把原帖示例当成“英文原版路线”,把本站教程当成“中文实战路线”。
- 绘制形状、轮廓:对应本站画笔、画刷基础。
- 从图片创建 GUI:对应异型界面、透明窗口。
- 创建 bitmap 并保存 PNG:对应画布内容保存为文件。
- 图片编辑:对应截图、缩放、裁剪、转换等应用。
- 可拖动圆角矩形、绘制文字:对应自定义 GUI 和控件美化。
- 进度条:对应模块化进度条。
- 旋转、翻转、镜像:对应图像旋转与镜像。
- BRA 动画、LockBits + MCode:属于更进阶的资源打包和高速像素处理。
如果你是新手,建议先按本站 GDI+系列教程目录 学;如果你已经会基本绘制,再回头看原帖官方示例,会更容易理解每个例子在练什么。
八、排错清单
遇到 GDI+ 示例跑不起来,可以按这个顺序检查:
- 确认脚本加载的是正确的
Gdip_All.ahk。 - 确认 AHK 位数:32 位还是 64 位。
- 确认是否 Unicode 版本。
- 确认
Gdip_Startup()是否成功。 - 确认没有重复或过早
Gdip_Shutdown()。 - 确认 bitmap、graphics、brush、pen 等对象没有提前释放。
- 透明窗口不显示时,检查
UpdateLayeredWindow参数和 DPI 缩放。 - 保存图片失败时,检查路径权限、文件扩展名和图片对象是否有效。
- 老代码迁移时,重点看
DllCall里的UInt、Ptr、UPtr。
GDI+ 的难点不只在“画什么”,还在“资源和环境是否正确”。库版本选对、启动关闭放对、对象释放做对,很多看似玄学的问题都会少一大半。
站内延伸
- GDI+系列教程目录
- 《GDI+系列教程》第0章 —— 什么是GDI+ 它能干啥?
- 《GDI+系列教程》第7章 —— 将画布内容保存为文件
- 《GDI+系列教程》第11章 —— 图像的旋转与镜像
- ImagePut 图片操作库
- ImageButton按钮样式库-优化版

评论(0)