[ahk]关于AutoHotkey的调试技术

1、msgBox大法,累、泪。

2、TrayTip需要在任务栏上显示ahk的图标和通知。

3、toolTip、SplashTextOn显示输出,不能缩放移动。

5、outputDebug需要第三方程序DebugView.exe配合。

6、Scite4AutoHotkey ,按F7 在debug模式运行,F10逐步执行,点击variable list查看变量及对象的值。


我的最新玩具是利用OnMessage技术实现一个独立的脚本,来监视相关调试输出,就像玩硬件Arduino的串口监视器。


a、在你的脚本中#include debug.ahk

b、在脚本中用debug("变量名")调用输出功能

c、开启"调试器.ahk",可以看到相关的调试输出


;debug.ahk
;作者:sunwind
;时间:2016年1月11日21:47:52
debug(StringToSend,TargetScriptTitle= "调试器.ahk ahk_class AutoHotkey")
{
global
if (StringToSend="")
    return
	if IsObject(StringToSend)
	{
		For index, value in StringToSend
			StringToSend.= "Item " index " is '" value "'`n"
	}
	else{
	变量名=%StringToSend%
	变量值=% (%StringToSend%)
	StringToSend= %变量名%=%变量值%
	}
result := Send_WM_COPYDATA(StringToSend, TargetScriptTitle)
if result = FAIL
    MsgBox SendMessage failed. Does the following WinTitle exist?:`n%TargetScriptTitle%
else if result = 0
    MsgBox Message sent but the target window responded with 0, which may mean it ignored it.
return
}

Send_WM_COPYDATA(ByRef StringToSend, ByRef TargetScriptTitle)  ; 在这种情况中使用 ByRef 能节约一些内存.
; 此函数发送指定的字符串到指定的窗口然后返回收到的回复.
; 如果目标窗口处理了消息则回复为 1, 而消息被忽略了则为 0.
{
    VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0)  ; 分配结构的内存区域.
    ; 首先设置结构的 cbData 成员为字符串的大小, 包括它的零终止符:
    SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
    NumPut(SizeInBytes, CopyDataStruct, A_PtrSize)  ; 操作系统要求这个需要完成.
    NumPut(&StringToSend, CopyDataStruct, 2*A_PtrSize)  ; 设置 lpData 为到字符串自身的指针.
    Prev_DetectHiddenWindows := A_DetectHiddenWindows
    Prev_TitleMatchMode := A_TitleMatchMode
    DetectHiddenWindows On
    SetTitleMatchMode 2
    SendMessage, 0x4a, 0, &CopyDataStruct,, %TargetScriptTitle%  ; 0x4a 为 WM_COPYDATA. 必须使用发送而不是投递.
    DetectHiddenWindows %Prev_DetectHiddenWindows%  ; 恢复调用者原来的设置.
    SetTitleMatchMode %Prev_TitleMatchMode%         ; 同样.
    return ErrorLevel  ; 返回 SendMessage 的回复给我们的调用者.
}

;调试器.ahk 请不要改名
;作者:sunwind
;时间:2016年1月11日21:47:52

#SingleInstance
OnMessage(0x4a, "Receive_WM_COPYDATA")  ; 0x4a 为 WM_COPYDATA

; 示例: 含菜单栏的简单文本编辑器.

; 为菜单栏创建子菜单:
Menu, FileMenu, Add, &New, FileNew
Menu, FileMenu, Add, &Open, FileOpen
Menu, FileMenu, Add, &Save, FileSave
Menu, FileMenu, Add, Save &As, FileSaveAs
Menu, FileMenu, Add  ; 分隔线.
Menu, FileMenu, Add, E&xit, FileExit
Menu, HelpMenu, Add, &About, HelpAbout

; 创建用来附加子菜单的菜单栏:
Menu, MyMenuBar, Add, &File, :FileMenu
Menu, MyMenuBar, Add, &Help, :HelpMenu

; 添加菜单栏到窗口:
Gui, Menu, MyMenuBar

; 创建主编辑控件并显示窗口:
Gui, +Resize  ; 让用户可以调整窗口的大小.
Gui, Add, Edit, vMainEdit WantTab W600 R20
;~ Gui, Show,, Untitled
Gui, Show,, 调试器
CurrentFileName =  ; 表示当前没有文件.
return

FileNew:
GuiControl,, MainEdit  ; 清空编辑控件.
return

FileOpen:
Gui +OwnDialogs  ; 强制用户响应 FileSelectFile 对话框后才能返回到主窗口.
FileSelectFile, SelectedFileName, 3,, Open File, Text Documents (*.txt)
if SelectedFileName =  ; 没有选择文件.
    return
Gosub FileRead
return

FileRead:  ; 调用者已经设置了 SelectedFileName 变量.
FileRead, MainEdit, %SelectedFileName%  ; 读取文件的内容到变量中.
if ErrorLevel
{
    MsgBox Could not open "%SelectedFileName%".
    return
}
GuiControl,, MainEdit, %MainEdit%  ; 在控件中显示文本.
CurrentFileName = %SelectedFileName%
Gui, Show,, %CurrentFileName%   ; 在标题栏显示文件名.
return

FileSave:
if CurrentFileName =   ; 还没有选择文件, 所以执行另存为操作.
    Goto FileSaveAs
Gosub SaveCurrentFile
return

FileSaveAs:
Gui +OwnDialogs  ; 强制用户响应 FileSelectFile 对话框后才能返回到主窗口..
FileSelectFile, SelectedFileName, S16,, Save File, Text Documents (*.txt)
if SelectedFileName =  ; 没有选择文件.
    return
CurrentFileName = %SelectedFileName%
Gosub SaveCurrentFile
return

SaveCurrentFile:  ; 调用者已经确保了 CurrentFileName 不为空.
IfExist %CurrentFileName%
{
    FileDelete %CurrentFileName%
    if ErrorLevel
    {
        MsgBox The attempt to overwrite "%CurrentFileName%" failed.
        return
    }
}
GuiControlGet, MainEdit  ; 获取编辑控件的内容.
FileAppend, %MainEdit%, %CurrentFileName%  ; 保存内容到文件.
; 成功时在标题栏显示文件名 (以防 FileSaveAs 调用时的情况):
Gui, Show,, %CurrentFileName%
return

HelpAbout:
Gui, About:+owner1  ; 让主窗口 (Gui #1) 成为 "关于对话框" 的父窗口.
Gui +Disabled  ; 禁用主窗口.
Gui, About:Add, Text,, Text for about box.
Gui, About:Add, Button, Default, OK
Gui, About:Show
return

AboutButtonOK:  ; 上面的 "关于对话框" 需要使用这部分.
AboutGuiClose:
AboutGuiEscape:
Gui, 1:-Disabled  ; 重新启用主窗口 (必须在下一步之前进行).
Gui Destroy  ; 销毁关于对话框.
return

GuiDropFiles:  ; 对拖放提供支持.
Loop, Parse, A_GuiEvent, `n
{
    SelectedFileName = %A_LoopField%  ; 仅获取首个文件 (如果有多个文件的时候).
    break
}
Gosub FileRead
return

GuiSize:
if ErrorLevel = 1  ; 窗口被最小化了.  无需进行操作.
    return
; 否则, 窗口的大小被调整过或被最大化了. 调整编辑控件的大小以匹配窗口.
NewWidth := A_GuiWidth - 20
NewHeight := A_GuiHeight - 20
GuiControl, Move, MainEdit, W%NewWidth% H%NewHeight%
return

FileExit:     ; 用户在 File 菜单中选择了 "Exit".
GuiClose:  ; 用户关闭了窗口.
ExitApp

Receive_WM_COPYDATA(wParam, lParam)
{
    global
    StringAddress := NumGet(lParam + 2*A_PtrSize)  ; 获取 CopyDataStruct 的 lpData 成员.
    CopyOfData := StrGet(StringAddress)  ; 从结构中复制字符串.
    ; 比起 MsgBox, 应该用 ToolTip 显示, 这样我们可以及时返回:
    ;~ ToolTip %A_ScriptName%`nReceived the following string:`n%CopyOfData%
    ;~ SplashTextOn, 400,300 ,调试器, %CopyOfData%
    ;~ WinMove, 调试器, , A_ScreenWidth-200, A_ScreenHeight-200
    ;~ WinSetTitle, <insert title of splash window>, , NewTitle
	FormatTime, TimeString, %A_Now%, yyyy-MM-dd HH:mm:ss
	logTotal=%logTotal%`n%TimeString%`t%CopyOfData%
	GuiControl,,MainEdit,%logTotal%  ;主界面多行提醒,todo自动滚屏
    return true  ; 返回 1 (true) 是回复此消息的传统方式.
}

;测试用例如下:

#Include X:\oa公文\lib\debug.ahk
target=X:\oa公文\acc.accdb 
array := ["one", "two"]

thing := {}
thing.foo := "three"

debug("target")
debug(array)
debug(thing)

return


你可能感兴趣的:([ahk]关于AutoHotkey的调试技术)