1

我有很多脚本。我希望能够在脚本中将它们全部管理为 1。我想要的是主脚本会激活某个脚本,然后当辅助脚本完成后,它会向主脚本返回一个值。之后,主脚本调用另一个辅助脚本,等等......

有没有合适的方法来做到这一点?

更精确的问题:

  • 是否可以从另一个脚本 AHK 激活 AHK 脚本?

  • 目前,为了检测辅助脚本是否完成,我目前使用的方式是在辅助脚本结束之前,我按下主脚本将检测到的组合键。一旦检测到,它会将主脚本变量加一,这将触发下一个脚本的激活。有没有更好的方法来实现这一目标?

4

3 回答 3

4

主脚本可以使用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.
}
于 2013-08-09T17:53:20.247 回答
2

好吧,我不确定您为什么要让一个脚本运行另一个脚本……但这里有一些其他方法:

在另一个脚本中包含一个脚本

但是,你知道你可以include在另一个脚本里面写一个脚本,对吧?也就是说,您可以在主脚本中使用其他脚本功能。

确保加载了特定的脚本

“我也有很多剧本”。有时我需要确保包含一个特定的,然后才能使用它,所以我把它放在顶部:

;make sure core.ahk is loaded since it is required
#include c:\ahk\core.ahk

而且您不必担心它会被多次包含(除非您需要它),因为:

#Include 确保 FileName 仅包含一次,即使遇到多个包含。相比之下,#IncludeAgain 允许多个包含同一文件,而在所有其他方面与 #Include 相同。

现在,当我包含file.ahkin时main.ahk,我确信使用该core.ahkfile.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- 使用该命令的脚本将暂停并等待运行的进程完成并关闭,然后再继续。

于 2013-08-10T02:34:34.167 回答
0

从理论上讲,您还可以在脚本之间使用文件对象作为一种标准输入/标准输出方法,因为当使用文件对象打开文件时,您可以将其设置为共享。

您还可以设置一个环境变量并将变量的名称传递给脚本,假设您在目标脚本中有设置参数处理,然后在关闭时设置环境变量值。使用 RunWait ,您可以找出脚本运行后的返回结果。

最后,考虑使用函数,因为这可能是您尝试做的“最佳实践”。由于函数可以执行脚本可以执行的任何操作,并且您可以将数组传递给它以对其进行操作,或者在数组参数上使用 ByRef。这意味着您不必在编写函数时写入一堆参数,并且一旦函数完成,变量将自动释放内存。您甚至可以在单独的文件中编写函数并使用#Include 在脚本中使用它们。

于 2015-06-21T09:15:41.400 回答