如何在AutoHotkey中通过SendMessage设置SysMonthCal控件选中指定日期
问题排查与修正方案
核心错误点
- 参数传递逻辑错误:你自定义的
ConvertNormalDateToSystemTime函数返回的已经是SystemTime结构体的内存地址,在调用SendMessage时额外加&取地址,相当于传入了存储地址的变量本身的指针,目标控件读取到的不是正确的日期结构体内容。 - 跨进程内存隔离限制:如果你的操作目标是其他程序的月历控件,直接传递当前脚本进程的内存地址会失效,因为不同进程的虚拟地址空间相互独立,目标进程无法访问你脚本进程内的结构体数据。
- 语法冗余:函数内
return % &SystemTime的%属于多余写法,AHK v1中直接写return &SystemTime即可。
最简修正(适用目标为同脚本AHK GUI的月历控件)
直接移除SendMessage参数里的&即可,修改后对应代码行如下:
SendMessage MCM_SETCURSEL , , dateASelectionnerDansCalendrier, SysMonthCal321, ahk_class AutoHotkeyGUI
修改后ErrorLevel返回非0值代表操作成功,返回0代表操作失败。
跨进程操作通用方案(适用第三方程序的月历控件)
需要先在目标进程内申请可读写内存,把SystemTime结构体写入目标进程内存后再传地址发消息,参考实现逻辑:
ConvertNormalDateToSystemTime(YYYYMMDD, ByRef SystemTime) { YYYYMMDD.=000000 YYYYMMDDHHMISS:=YYYYMMDD VarSetCapacity(SystemTime, 16, 0) NumPut(SubStr(YYYYMMDDHHMISS, 1, 4), SystemTime, 0, "UShort") NumPut(SubStr(YYYYMMDDHHMISS, 5, 2), SystemTime, 2, "UShort") NumPut(SubStr(YYYYMMDDHHMISS, 7, 2), SystemTime, 6, "UShort") NumPut(SubStr(YYYYMMDDHHMISS, 9, 2), SystemTime, 8, "UShort") NumPut(SubStr(YYYYMMDDHHMISS, 11, 2), SystemTime, 10, "UShort") NumPut(SubStr(YYYYMMDDHHMISS, 13, 2), SystemTime, 12, "UShort") } MCM_FIRST:= 0x1000 MCM_SETCURSEL:= MCM_FIRST + 2 MyDate:= 20211115 WinGet, pid, PID, ahk_class AutoHotkeyGUI ; 获取目标进程ID ; 打开目标进程,申请内存权限 hProcess := DllCall("OpenProcess", "UInt", 0x1F0FFF, "Int", 0, "UInt", pid, "Ptr") ; 在目标进程内申请16字节内存 pRemoteMem := DllCall("VirtualAllocEx", "Ptr", hProcess, "Ptr", 0, "UPtr", 16, "UInt", 0x1000|0x2000, "UInt", 0x4, "Ptr") ; 生成本地SystemTime结构体 ConvertNormalDateToSystemTime(MyDate, stLocal) ; 把本地结构体写入目标进程内存 DllCall("WriteProcessMemory", "Ptr", hProcess, "Ptr", pRemoteMem, "Ptr", &stLocal, "UPtr", 16, "Ptr", 0) ; 发送消息,传入目标进程内的结构体地址 SendMessage MCM_SETCURSEL , , pRemoteMem, SysMonthCal321, ahk_class AutoHotkeyGUI MsgBox 操作结果:%ErrorLevel% ; 释放申请的内存和进程句柄 DllCall("VirtualFreeEx", "Ptr", hProcess, "Ptr", pRemoteMem, "UPtr", 0, "UInt", 0x8000) DllCall("CloseHandle", "Ptr", hProcess)
额外验证项
- 用系统自带的Window Spy工具确认目标月历控件的类名确实为
SysMonthCal321,控件序号不对也会导致操作失败 - 确认目标月历控件没有开启多选模式,
MCM_SETCURSEL仅适用于单选模式的月历控件
内容的提问来源于stack exchange,提问作者Gilles Gruwez
相关产品推荐
相关产品推荐

