我有很多脚本。我希望能够在脚本中将它们全部管理为 1。我想要的是主脚本会激活某个脚本,然后当辅助脚本完成后,它会向主脚本返回一个值。之后,主脚本调用另一个辅助脚本,等等......
有没有合适的方法来做到这一点?
更精确的问题:
是否可以从另一个脚本 AHK 激活 AHK 脚本?
目前,为了检测辅助脚本是否完成,我目前使用的方式是在辅助脚本结束之前,我按下主脚本将检测到的组合键。一旦检测到,它会将主脚本变量加一,这将触发下一个脚本的激活。有没有更好的方法来实现这一目标?
我有很多脚本。我希望能够在脚本中将它们全部管理为 1。我想要的是主脚本会激活某个脚本,然后当辅助脚本完成后,它会向主脚本返回一个值。之后,主脚本调用另一个辅助脚本,等等......
有没有合适的方法来做到这一点?
更精确的问题:
是否可以从另一个脚本 AHK 激活 AHK 脚本?
目前,为了检测辅助脚本是否完成,我目前使用的方式是在辅助脚本结束之前,我按下主脚本将检测到的组合键。一旦检测到,它会将主脚本变量加一,这将触发下一个脚本的激活。有没有更好的方法来实现这一目标?
主脚本可以使用RunWait
. 然后脚本可以在终止之前进行通信。
通信的最佳选择是使用OnMessage。
以下是文档中的一个工作示例:
; Example: Send a string of any length from one script to another. This is a working example.
; To use it, save and run both of the following scripts then press Win+Space to show an
; InputBox that will prompt you to type in a string.
; Save the following script as "Receiver.ahk" then launch it:
#SingleInstance
OnMessage(0x4a, "Receive_WM_COPYDATA") ; 0x4a is WM_COPYDATA
return
Receive_WM_COPYDATA(wParam, lParam)
{
StringAddress := NumGet(lParam + 2*A_PtrSize) ; Retrieves the CopyDataStruct's lpData member.
CopyOfData := StrGet(StringAddress) ; Copy the string out of the structure.
; Show it with ToolTip vs. MsgBox so we can return in a timely fashion:
ToolTip %A_ScriptName%`nReceived the following string:`n%CopyOfData%
return true ; Returning 1 (true) is the traditional way to acknowledge this message.
}
; Save the following script as "Sender.ahk" then launch it. After that, press the Win+Space hotkey.
TargetScriptTitle = Receiver.ahk ahk_class AutoHotkey
#space:: ; Win+Space hotkey. Press it to show an InputBox for entry of a message string.
InputBox, StringToSend, Send text via WM_COPYDATA, Enter some text to Send:
if ErrorLevel ; User pressed the Cancel button.
return
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 saves a little memory in this case.
; This function sends the specified string to the specified window and returns the reply.
; The reply is 1 if the target window processed the message, or 0 if it ignored it.
{
VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0) ; Set up the structure's memory area.
; First set the structure's cbData member to the size of the string, including its zero terminator:
SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
NumPut(SizeInBytes, CopyDataStruct, A_PtrSize) ; OS requires that this be done.
NumPut(&StringToSend, CopyDataStruct, 2*A_PtrSize) ; Set lpData to point to the string itself.
Prev_DetectHiddenWindows := A_DetectHiddenWindows
Prev_TitleMatchMode := A_TitleMatchMode
DetectHiddenWindows On
SetTitleMatchMode 2
SendMessage, 0x4a, 0, &CopyDataStruct,, %TargetScriptTitle% ; 0x4a is WM_COPYDATA. Must use Send not Post.
DetectHiddenWindows %Prev_DetectHiddenWindows% ; Restore original setting for the caller.
SetTitleMatchMode %Prev_TitleMatchMode% ; Same.
return ErrorLevel ; Return SendMessage's reply back to our caller.
}
好吧,我不确定您为什么要让一个脚本运行另一个脚本……但这里有一些其他方法:
在另一个脚本中包含一个脚本
但是,你知道你可以include
在另一个脚本里面写一个脚本,对吧?也就是说,您可以在主脚本中使用其他脚本功能。
确保加载了特定的脚本
“我也有很多剧本”。有时我需要确保包含一个特定的,然后才能使用它,所以我把它放在顶部:
;make sure core.ahk is loaded since it is required
#include c:\ahk\core.ahk
而且您不必担心它会被多次包含(除非您需要它),因为:
#Include 确保 FileName 仅包含一次,即使遇到多个包含。相比之下,#IncludeAgain 允许多个包含同一文件,而在所有其他方面与 #Include 相同。
现在,当我包含file.ahk
in时main.ahk
,我确信使用该core.ahk
file.ahk 所需的函数没有问题。即使我core.ahk
再次将其包含在内main.ahk
也不用担心(除非它包含子例程而不仅仅是函数 - 在这种情况下,它们会在包含它们的位置运行,因此最好不要将子例程放入您的 ahk 库中)。
在脚本上使用好的 ole' RUN
除此之外,您知道您始终可以使用该run
命令来启动 ahk 脚本。您不必做所有花哨的 WM_SENDMESSAGE 东西。
使用隐藏的 GUI 在脚本之间进行通信
两个脚本相互通信的另一种方式是让脚本#1 保持打开一个隐藏的 GUI 窗口,该窗口具有一个编辑框和一个提交按钮。这个窗口永远不会显示。现在,脚本#2 寻找那个消息框,用于send
在编辑框中放置一个字符串,然后按住 control 并单击以按下提交按钮。现在脚本#1 刚刚收到来自脚本#2 的输入。如果您将 windows 值放在两个脚本中,您甚至不必寻找窗口hwnd
(因此他们已经提前知道了)。这就像一个魅力。
判断脚本是否完成
如果您使用 ahk 的run
命令,则有一个参数可以返回该PID
进程的名称(PID = 进程 ID)。您可以使用它PID
来检查脚本是否正在运行,并且可以使用它来终止进程。
此外,如果您使用runwait
- 使用该命令的脚本将暂停并等待运行的进程完成并关闭,然后再继续。
从理论上讲,您还可以在脚本之间使用文件对象作为一种标准输入/标准输出方法,因为当使用文件对象打开文件时,您可以将其设置为共享。
您还可以设置一个环境变量并将变量的名称传递给脚本,假设您在目标脚本中有设置参数处理,然后在关闭时设置环境变量值。使用 RunWait ,您可以找出脚本运行后的返回结果。
最后,考虑使用函数,因为这可能是您尝试做的“最佳实践”。由于函数可以执行脚本可以执行的任何操作,并且您可以将数组传递给它以对其进行操作,或者在数组参数上使用 ByRef。这意味着您不必在编写函数时写入一堆参数,并且一旦函数完成,变量将自动释放内存。您甚至可以在单独的文件中编写函数并使用#Include 在脚本中使用它们。