【问题标题】:AHK: Manage multiple scriptsAHK:管理多个脚本
【发布时间】:2013-08-09 15:34:54
【问题描述】:

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

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

更精确的问题:

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

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

【问题讨论】:

    标签: automation autohotkey


    【解决方案1】:

    主脚本可以使用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.
    }
    

    【讨论】:

      【解决方案2】:

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

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

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

      确保已加载特定脚本

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

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

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

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

      现在,当我在 main.ahk 中包含 file.ahk 时,我确信使用 file.ahk 所需的 core.ahk 中的函数没有问题。即使我在main.ahk 中再次包含core.ahk,也不必担心(除非它包含子例程而不仅仅是函数——在这种情况下,它们会在包含它们的位置运行,所以最好不要将子例程放在你的ahk 图书馆)。

      在脚本上使用好的 ole' RUN

      除此之外,您知道您始终可以使用run 命令来启动 ahk 脚本。您不必做所有花哨的 WM_SENDMESSAGE 事情。

      使用隐藏的 GUI 在脚本之间进行通信

      两个脚本相互通信的另一种方式是让脚本 #1 保持打开一个隐藏的 GUI 窗口,该窗口具有一个编辑框和一个提交按钮。这个窗口永远不会显示。现在,脚本#2 搜索该消息框,使用send 将字符串放入编辑框中,然后按住Ctrl 并单击以按下提交按钮。现在脚本#1 刚刚收到来自脚本#2 的输入。如果您将 windows hwnd 值放在两个脚本中,您甚至不必寻找窗口(因此他们已经提前知道了)。这就像一个魅力。

      判断脚本是否完成

      如果你使用 ahk 的run 命令,有一个参数会返回那个进程的PID(PID = 进程 ID)。您可以使用此PID 来检查脚本是否正在运行,并且可以使用它来终止进程。

      此外,如果您使用 runwait - 使用该命令的脚本将暂停并等待运行的进程完成并关闭,然后再继续。

      【讨论】:

      • BGM Include docs 写道:#directives 不能属于 IF 语句。
      • 哦,我想你是对的(我什至没有意识到这一点)。感谢您指出。
      【解决方案3】:

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

      您还可以设置环境变量并将变量的名称传递给脚本,前提是您在目标脚本中有设置参数处理,然后在关闭时设置环境变量值。使用 RunWait 可以知道脚本运行后的返回结果是什么。

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

      【讨论】:

        猜你喜欢
        • 2021-01-01
        • 1970-01-01
        • 2016-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多