ScriptSock - Communication Between AutoHotkey Scripts

Post your working scripts, libraries and tools.
User avatar
AstraVista
Posts: 15
Joined: 16 Feb 2024, 03:14

ScriptSock - Communication Between AutoHotkey Scripts

20 Feb 2024, 05:22

ScriptSock
Communication Between AutoHotkey Scripts
AutoHotkey v2



Concept is:
Source.ahk - Set or Get Variables - Target.ahk



My first posting in AutoHotkey v2 forum.
I have developed it for my small project.

I am working on transforming code to more object-oriented implementing... :)

Originated from talk() class:
https://www.autohotkey.com/board/topic/94321-talk-interscript-communication-provider-and-more/
https://github.com/aviaryan/autohotkey-scripts/blob/master/Functions/talk.ahk


ScriptSock.ahk (Version: 2014.02.21)

Code: Select all

#Requires AutoHotkey v2

; ----------------------------------------------------------------------------------------------------------------------------------
; ScriptSock
; Communication Between AutoHotkey Scripts
;
; AutoHotkey V2 (2.0.11)
;
; Author: AstraVista
; Version: 2014.02.21
;
; Originated from talk class:
;	https://www.autohotkey.com/board/topic/94321-talk-interscript-communication-provider-and-more/
;	https://github.com/aviaryan/autohotkey-scripts/blob/master/Functions/talk.ahk
; ----------------------------------------------------------------------------------------------------------------------------------

;-----------------------------------------------------------------------------------------------------------------------------------
; ScriptSock Help
;
; - There are two ways to set variable in target script.
;
;	(1) SetVar()
;		: Replace target script's variable with sending data.
;
;	(2) PostVar()
;		: Send and save value to target script's message storage, which is awating fetched from the script.
;
; - There are two ways to get variable from target script.
;
;	(1) GetVar()
;		: Get value from target script directly.
;
;	(2) FetchVar()
;		: Fetch value from script's message storage saved by target script
;
; - Etc
;
; 	- PushVar()
;		: Change value in own's message storage, after data is set by other scripts.
;-----------------------------------------------------------------------------------------------------------------------------------

; ----------------------------------------------------------------------------------------------------------------------------------
; SendMessage() Help
;
; * When Sender() calls SendMessage()...
;
;		: SendMessage() always returns when a result is received or when an error such as timeout.
;		: Default waiting time is 5000ms.
;		: If there is no error, SendMessage() always returns after receiving and processing data in Receiver() which is OnMessage()'s callback.
;
;	- When SendMessage() returns normally...
;		: Then Sender() returns.
;		-> Since the results have already been saved, return immediately without any longer.
;
;	- When SendMessage() returns with an error
;		1. If an error occurs due to an abnormality such as an internal error or target window error...
;			: Sender() returns immediately.
;			: Result values cannot be received from Receiver() which is OnMessage()'s callback.
;			-> Therefore, return the error immediately.
;
;		2. In case of TimeoutError...
;			(1) There are two ways, when the result value is delayed due to MsgBox() in debugging...
;				- After Sender() returns, wait significant time for a message to come in and then return when time is out.
;				- Increase the default waiting time of SendMessage() significantly and return immediately when an error occurs.
;				: Both are similar method (The code adopts the later)
;
;			(2) OnMessage() cannot receive message due to lag or delays in the script.
;				: Since the default waiting time of SendMessage() is 5000ms, it is sufficient enough unless the script stops.
;				-> Therefore, if an error occurs, return immediately.
;
;			: In Receiver() which is OnMessage()'s callback, it is not possible to know whether data will be received or not.
;				- Wait longer after Sender() returns
;					: Even though, still may not receive message
;				- Wait longer before SendMessage() returns
;					: Even though, still may not receive message
; ----------------------------------------------------------------------------------------------------------------------------------

; **********************************************************************************************************************************
; ScriptSock Class
; **********************************************************************************************************************************

class ScriptSock
{
	; Variable storage
	static aVar := Map()

	static sTargetScript := ""
	static sSourceScript := ""

	; Error Message
	static sMsgError := "^Error^"

	; When put this sign to end of variable when querying, script automatically enters to debug mode!
	static sDebugSign := "#"
	static bDebug := false
	static bDebugBeep := true
	; Debug message when successful return of SendMessage()
	static bDebugSuccess := false

	; Standard waiting time after return of static Sender() in normal runs (Not require)
	static iWaitTimeAfterReturn := 0
	; Default = 5000, 0 = Forever waiting
	static iWaitTimeNormalSend := 30 * 1000
	; Extended waiting time after return of SendMessage() in debug mode
	static iWaitTimeDebugSend := 600 * 1000

	static __New()
	{
		; WM_COPYDATA = 0x004A
		; Only static function can be callback function.
		; Class instances can register different names of callback function (%Callback Function Name%)
		; All registering callback functions of OnMessage() receive message at the same time.

		this.ReceiverProc := ObjBindMethod(ScriptSock, "Receiver")
		OnMessage(0x004A, this.ReceiverProc)
	}

	__New(sTargetScript)
	{
		; Target script to send
		; Add "\" in the head of script name for avoiding duplication of other windows.
		; If "\" is ommited, SendMessege() would send messages to active window of similar name like '???.ahk - SciTE4AutoHotkey'.
		ScriptSock.sTargetScript := (InStr(sTargetScript, "\")) ? sTargetScript : "\" sTargetScript

		; Source script to send
		ScriptSock.sSourceScript := "\" A_ScriptName

		try
		{
			iPrevDetectHiddenWindows := A_DetectHiddenWindows
			iPrevTitleMatchMode := A_TitleMatchMode
			DetectHiddenWindows(True)
			SetTitleMatchMode(2)

			sTitle := WinGetTitle("ahk_id " A_ScriptHwnd)
			sTitle := StrSplit(sTitle, " - AutoHotkey v")[1]
			if (InStr(sTitle, "\"))
			{
				ScriptSock.sSourceScript := "\" SubStr(sTitle, InStr(sTitle, "\", , -1) + 1)
			}
			else
			{
				ScriptSock.sSourceScript := "\" sTitle
			}

			DetectHiddenWindows(iPrevDetectHiddenWindows)
			SetTitleMatchMode(iPrevTitleMatchMode)
		}
	}

	Call(sTargetScript)
	{
		this.__New(sTargetScript)
		return (this)
	}

	__Item[sVarName := ""]
	{
		get
		{
			sVarName := StrReplace(sVarName, ScriptSock.sDebugSign)
			return (ScriptSock.aVar[sVarName])
		}
		set
		{
			sVarName := StrReplace(sVarName, ScriptSock.sDebugSign)
			ScriptSock.aVar[sVarName] := Value
		}
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; GetVar() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	GetVar(sVarName)
	{
		ScriptSock.aVar[sVarName] := ScriptVar(ScriptSock.sSourceScript, "GetVar", sVarName)
		oSendVar := ScriptSock.aVar[sVarName].Clone()

		if (InStr(sVarName, ScriptSock.sDebugSign))
		{
			sVarName := StrReplace(sVarName, ScriptSock.sDebugSign)
			oSendVar.sVarName := sVarName
			oSendVar.bDebug := true
			ScriptSock.bDebug := true
		}
		else
		{
			ScriptSock.bDebug := false
		}

		; Waiting until return of SendMessage()
		vResult := ScriptSock.Sender(ScriptSock.sTargetScript, oSendVar)

		; Return of Sender() - 0: Success, Others: Error
		iLoopMaxTime := (vResult) ? 0 : ScriptSock.iWaitTimeAfterReturn

		; SendMessage() always return after bReceive is set, if not an error.
		; Therefore, this routine would not be required.
		iLoopTiming := 10
		iLoopCount := iLoopMaxTime / iLoopTiming
		Loop (iLoopCount)
		{
			if (ScriptSock.aVar[sVarName].bReceive)
			{
				break
			}

			Sleep(iLoopTiming)
		}

		if (ScriptSock.aVar.Has(sVarName))
		{
			if (ScriptSock.bDebug)
			{
				MsgBox("ScriptSock GetVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" ScriptSock.aVar[sVarName].Packet() "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
			}

			if (ScriptSock.aVar[sVarName].bReceive)
			{
				vReturn := ScriptSock.aVar[sVarName].vData
				sMsgError := this.ExceptionStr("GetVar", sVarName, ScriptSock.sMsgError, ScriptSock.aVar[sVarName].vArg)
			}
			else
			{
				vReturn := ScriptSock.sMsgError
				sMsgError := this.ExceptionStr("GetVar", sVarName, ScriptSock.sMsgError, vResult)
			}

			ScriptSock.aVar[sVarName].bReceive := false
		}
		else
		{
			if (ScriptSock.bDebug)
			{
				MsgBox("ScriptSock GetVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
			}

			vReturn := ScriptSock.sMsgError
			sMsgError := this.ExceptionStr("GetVar", sVarName, ScriptSock.sMsgError, vResult)
		}

		ScriptSock.bDebug := false

		if (vReturn = ScriptSock.sMsgError)
		{
			throw(Error(sMsgError))
		}

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; SetVar() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	SetVar(sVarName, vSetValue)
	{
		ScriptSock.aVar[sVarName] := ScriptVar(ScriptSock.sSourceScript, "SetVar", sVarName, vSetValue)
		oSendVar := ScriptSock.aVar[sVarName].Clone()

		if (InStr(sVarName, ScriptSock.sDebugSign))
		{
			sVarName := StrReplace(sVarName, ScriptSock.sDebugSign)
			oSendVar.sVarName := sVarName
			oSendVar.bDebug := true
			ScriptSock.bDebug := true
		}
		else
		{
			ScriptSock.bDebug := false
		}

		; Waiting until return of SendMessage()
		vResult := ScriptSock.Sender(ScriptSock.sTargetScript, oSendVar)

		; Returns of ScriptSock.Sender() - 0: success, others: error
		iLoopMaxTime := (vResult) ? 0 : ScriptSock.iWaitTimeAfterReturn

		; SendMessage() always return after bReceive is set, if not an error.
		; Therefore, this routine would not be required.
		iLoopTiming := 10
		iLoopCount := iLoopMaxTime / iLoopTiming
		Loop (iLoopCount)
		{
			if (ScriptSock.aVar[sVarName].bReceive)
			{
				break
			}

			Sleep(iLoopTiming)
		}

		if (ScriptSock.aVar.Has(sVarName))
		{
			if (ScriptSock.bDebug)
			{
				MsgBox("ScriptSock SetVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" ScriptSock.aVar[sVarName].Packet() "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
			}

			if (ScriptSock.aVar[sVarName].bReceive)
			{
				vReturn := (ScriptSock.aVar[sVarName].vData = vSetValue) ? true : false
				sMsgError := this.ExceptionStr("SetVar", sVarName, ScriptSock.sMsgError, ScriptSock.aVar[sVarName].vArg)
			}
			else
			{
				vReturn := ScriptSock.sMsgError
				sMsgError := this.ExceptionStr("SetVar", sVarName, ScriptSock.sMsgError, vResult)
			}

			ScriptSock.aVar[sVarName].bReceive := false
		}
		else
		{
			if (ScriptSock.bDebug)
			{
				MsgBox("ScriptSock SetVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
			}

			vReturn := ScriptSock.sMsgError
			sMsgError := this.ExceptionStr("SetVar", sVarName, ScriptSock.sMsgError, vResult)
		}

		if (ScriptSock.bDebug)
		{
			MsgBox("ScriptSock SetVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" ScriptSock.aVar[sVarName].Packet() "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
		}

		ScriptSock.aVar[sVarName].bReceive := false
		ScriptSock.bDebug := false

		if (vReturn = ScriptSock.sMsgError)
		{
			throw(Error(sMsgError))
		}

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; FetchVar() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	FetchVar(sVarName, vDefault := ScriptSock.sMsgError)
	{
		if (ScriptSock.aVar.Has(sVarName))
		{
			if (ScriptSock.aVar[sVarName].bReceive)
			{
				ScriptSock.aVar[sVarName].bReceive := false
			}

			vReturn := ScriptSock.aVar[sVarName].vData
		}
		else
		{
			vReturn := vDefault
		}

		sMsgError := this.ExceptionStr("FetchVar", sVarName, vReturn, "Error: Variable not found.")

		if (vReturn = ScriptSock.sMsgError)
		{
			throw(Error(sMsgError))
		}

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; PushVar() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	PushVar(sVarName, vSetValue, vDefault := ScriptSock.sMsgError)
	{
		if (ScriptSock.aVar.Has(sVarName))
		{
			if (!ScriptSock.aVar[sVarName].bReceive)
			{
				ScriptSock.aVar[sVarName].vData := vSetValue
				vReturn := (!vDefault)
			}
			else
			{
				vReturn := vDefault
			}
		}
		else
		{
			vReturn := vDefault
		}

		sMsgError := this.ExceptionStr("PushVar", sVarName, vReturn, "Error: Variable not found.")

		if (vReturn = ScriptSock.sMsgError)
		{
			throw(Error(sMsgError))
		}

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; PostVar() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	PostVar(sVarName, vSetValue, vDefault := ScriptSock.sMsgError)
	{
		ScriptSock.aVar[sVarName] := ScriptVar(ScriptSock.sSourceScript, "PostVar", sVarName, vSetValue)
		oSendVar := ScriptSock.aVar[sVarName].Clone()

		if (InStr(sVarName, ScriptSock.sDebugSign))
		{
			sVarName := StrReplace(sVarName, ScriptSock.sDebugSign)
			oSendVar.sVarName := sVarName
			oSendVar.bDebug := true
			ScriptSock.bDebug := true
		}
		else
		{
			ScriptSock.bDebug := false
		}

		; Waiting until return of SendMessage()
		vResult := ScriptSock.Sender(ScriptSock.sTargetScript, oSendVar)

		; Returns of ScriptSock.Sender() - 0: success, others: error
		iLoopMaxTime := (vResult) ? 0 : ScriptSock.iWaitTimeAfterReturn

		; SendMessage() always will return after setting of .bReceive, if not error.
		; So, this routine would not be required.
		iLoopTiming := 10
		iLoopCount := iLoopMaxTime / iLoopTiming
		Loop (iLoopCount)
		{
			if (ScriptSock.aVar[sVarName].bReceive)
			{
				break
			}

			Sleep(iLoopTiming)
		}

		if (ScriptSock.aVar.Has(sVarName))
		{
			if (ScriptSock.bDebug)
			{
				MsgBox("ScriptSock PostVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" ScriptSock.aVar[sVarName].Packet() "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
			}

			if (ScriptSock.aVar[sVarName].bReceive)
			{
				vReturn := (ScriptSock.aVar[sVarName].vData = vSetValue) ? true : false
				sMsgError := this.ExceptionStr("PostVar", sVarName, ScriptSock.sMsgError, ScriptSock.aVar[sVarName].vArg)
			}
			else
			{
				vReturn := ScriptSock.sMsgError
				sMsgError := this.ExceptionStr("PostVar", sVarName, ScriptSock.sMsgError, vResult)
			}

			ScriptSock.aVar[sVarName].bReceive := false
		}
		else
		{
			if (ScriptSock.bDebug)
			{
				MsgBox("ScriptSock PostVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
			}

			vReturn := ScriptSock.sMsgError
			sMsgError := this.ExceptionStr("PostVar", sVarName, ScriptSock.sMsgError, vResult)
		}

		if (ScriptSock.bDebug)
		{
			MsgBox("ScriptSock PostVar() `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   Packet = [" ScriptSock.aVar[sVarName].Packet() "]`n`n← [" ScriptSock.sTargetScript "]", , "4096")
		}

		ScriptSock.aVar[sVarName].bReceive := false
		ScriptSock.bDebug := false

		if (vReturn = ScriptSock.sMsgError)
		{
			throw(Error(sMsgError))
		}

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; Suspend() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	Suspend(iSuspendTime)
	{
		vReturn := ScriptSock.Sender(ScriptSock.sTargetScript, ScriptVar(ScriptSock.sSourceScript, "Suspend", , iSuspendTime))

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; Terminate() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	Terminate()
	{
		vReturn := ScriptSock.Sender(ScriptSock.sTargetScript, ScriptVar(ScriptSock.sSourceScript, "Terminate"))

		return (vReturn)
	}

	; ------------------------------------------------------------------------------------------------------------------------------
	; ExceptionStr() Method
	; ------------------------------------------------------------------------------------------------------------------------------

	ExceptionStr(sFuncName, sVarName, vData, sErrorMessage)
	{
		sSeperator := "―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――"
		sMsgError := "ScriptSock " sFuncName "()`n" sSeperator "`n[" LTrim(ScriptSock.sSourceScript, "\") "] → [" ScriptSock.sTargetScript "]`n•    [" StrReplace(sVarName, ScriptSock.sDebugSign) "]`n•    [" vData "]`n" sErrorMessage "`n" sSeperator

		return (sMsgError)
	}

; **********************************************************************************************************************************
; Receiver() Method
; **********************************************************************************************************************************

	static Receiver(wParam, lParam, msg, hwnd)
	{
		global

		sReceivePacket := StrGet(NumGet(lParam + 2 * A_PtrSize, 0, "Ptr"))
		oReceiveVar := ScriptVar()
		oReceiveVar.Packet(sReceivePacket)

		ScriptSock.bDebug := oReceiveVar.bDebug

		if (ScriptSock.bDebug)
		{
			MsgBox("Receiver()`n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`nPacket :`n•    Script: [" oReceiveVar.sSenderScript "]`n•    Command: [" oReceiveVar.sCommand "]`n•    VarName:  [" oReceiveVar.sVarName "]`n•    ArgA: [" oReceiveVar.vData "]`n•    ArgB: [" oReceiveVar.vArg "]`n•    Process: [" oReceiveVar.bProcess "]`n•    Debug: [" oReceiveVar.bDebug "]`n`n← [" oReceiveVar.sSenderScript "]", , "4096")
		}

		; --------------------------------------------------------------------------------------------------------------------------
		; GetVar Receiver()
		; --------------------------------------------------------------------------------------------------------------------------
		if (oReceiveVar.sCommand = "GetVar")
		{
			oSendVar := ScriptVar(ScriptSock.sSourceScript, "Output")
			oSendVar.bDebug := oReceiveVar.bDebug ; Important !!

			try
			{
				if (ScriptSock.bDebug)
				{
					MsgBox("Receiver() GetVar `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    " oReceiveVar.sVarName " = [" %oReceiveVar.sVarName% "]`n•    → [" %oReceiveVar.sVarName% "]", , "4096")
				}

				oSendVar.sVarName := oReceiveVar.sVarName
				oSendVar.vData := %oReceiveVar.sVarName%
				oSendVar.vArg := ""
			}
			catch as oError
			{
				oSendVar.sVarName := oReceiveVar.sVarName
				oSendVar.vData := ScriptSock.sMsgError
				oSendVar.vArg := Type(oError) ": " oError.Message " (Line: " SubStr(oError.File, InStr(oError.File, "\", , -1) + 1) ", "  oError.Line ")"
			}

			if (oSendVar.sVarName = ScriptSock.sMsgError)
			{
				if (ScriptSock.bDebug)
				{
					MsgBox("Receiver() GetVar `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    " Type(oError) ": " oError.Message " (Line: " oError.Line ")", , "4096")
				}
			}

			ScriptSock.Sender(oReceiveVar.sSenderScript, oSendVar)

			return
		}

		; --------------------------------------------------------------------------------------------------------------------------
		; SetVar Receiver()
		; --------------------------------------------------------------------------------------------------------------------------
		if (oReceiveVar.sCommand = "SetVar")
		{
			oSendVar := ScriptVar(ScriptSock.sSourceScript, "Output")
			oSendVar.bDebug := oReceiveVar.bDebug ; Important !!

			try
			{
				if (ScriptSock.bDebug)
				{
					MsgBox("Receiver() SetVar `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    " oReceiveVar.sVarName " = [" %oReceiveVar.sVarName% "]`n•    ← " "[SetVar]" " ← [" oReceiveVar.vData "]", , "4096")
				}

				; Dymimic variable input needs to declare global in the top of function
				%oReceiveVar.sVarName% := oReceiveVar.vData

				oSendVar.sVarName := oReceiveVar.sVarName
				oSendVar.vData := %oReceiveVar.sVarName%
				oSendVar.vArg := ""
			}
			catch as oError
			{
				oSendVar.sVarName := oReceiveVar.sVarName
				oSendVar.vData := ScriptSock.sMsgError
				oSendVar.vArg := Type(oError) ": " oError.Message " (Line: " SubStr(oError.File, InStr(oError.File, "\", , -1) + 1) ", "  oError.Line ")"
			}

			if (oSendVar.vData = ScriptSock.sMsgError)
			{
				if (ScriptSock.bDebug)
				{
					MsgBox("Receiver() SetVar `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    " ((oReceiveVar.bProcess) ? "[Post]": "[Replace]") "`n•    " Type(oError) " : " oError.Message " (Line: " SubStr(oError.File, InStr(oError.File, "\", , -1) + 1) ", "  oError.Line ")", , "4096")
				}
			}

			ScriptSock.Sender(oReceiveVar.sSenderScript, oSendVar)

			return
		}

		; --------------------------------------------------------------------------------------------------------------------------
		; PostVar Receiver()
		; --------------------------------------------------------------------------------------------------------------------------
		if (oReceiveVar.sCommand = "PostVar")
		{
			oSendVar := ScriptVar(ScriptSock.sSourceScript, "Output")
			oSendVar.bDebug := oReceiveVar.bDebug ; Important !!

			try
			{
				if (!ScriptSock.aVar.Has(oReceiveVar.sVarName))
				{
					ScriptSock.aVar[oReceiveVar.sVarName] := ScriptVar()
				}

				if (ScriptSock.bDebug)
				{
					MsgBox("Receiver() PostVar `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    " oReceiveVar.sVarName " = [" ScriptSock.aVar[oReceiveVar.sVarName].vData "]`n•    ← " "[PostVar]" " [" oReceiveVar.vData "]", , "4096")
				}

				ScriptSock.aVar[oReceiveVar.sVarName].Packet(sReceivePacket)
				ScriptSock.aVar[oReceiveVar.sVarName].bReceive := true

				oSendVar.sVarName := oReceiveVar.sVarName
				oSendVar.vData := ScriptSock.aVar[oReceiveVar.sVarName].vData
				oSendVar.vArg := ""
			}
			catch as oError
			{
				oSendVar.sVarName := oReceiveVar.sVarName
				oSendVar.vData := ScriptSock.sMsgError
				oSendVar.vArg := Type(oError) ": " oError.Message " (Line: " SubStr(oError.File, InStr(oError.File, "\", , -1) + 1) ", "  oError.Line ")"
			}

			if (oSendVar.vData = ScriptSock.sMsgError)
			{
				if (ScriptSock.bDebug)
				{
					MsgBox("Receiver() PostVar `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    " "[PostVar]" "`n•    " Type(oError) ": " oError.Message " (Line: " SubStr(oError.File, InStr(oError.File, "\", , -1) + 1) ", "  oError.Line ")", , "4096")
				}
			}

			ScriptSock.Sender(oReceiveVar.sSenderScript, oSendVar)

			return
		}

		; --------------------------------------------------------------------------------------------------------------------------
		; Output Receiver()
		; --------------------------------------------------------------------------------------------------------------------------
		if (oReceiveVar.sCommand = "Output")
		{
			if (!ScriptSock.aVar.Has(oReceiveVar.sVarName))
			{
				ScriptSock.aVar[oReceiveVar.sVarName] := ScriptVar()
			}
			ScriptSock.aVar[oReceiveVar.sVarName].Packet(sReceivePacket)
			ScriptSock.aVar[oReceiveVar.sVarName].bReceive := true

			if (ScriptSock.bDebug)
			{
				MsgBox("Receiver() Output `n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•   sVarName = [" oReceiveVar.sVarName "]`n•   vData = [" oReceiveVar.vData "]`n•   vArg = [" oReceiveVar.vArg "]`n•   bReceive = [" ScriptSock.aVar[oReceiveVar.sVarName].bReceive "]`n•    → Save" , , "4096")
			}

			return
		}

		; --------------------------------------------------------------------------------------------------------------------------
		; Suspend Receiver()
		; --------------------------------------------------------------------------------------------------------------------------
		if (oReceiveVar.sCommand = "Suspend")
		{
			Suspend()
			Sleep(oReceiveVar.vData)
			Suspend()

			return
		}

		; --------------------------------------------------------------------------------------------------------------------------
		; Terminate Receiver()
		; --------------------------------------------------------------------------------------------------------------------------
		if (oReceiveVar.sCommand = "Terminate")
		{
			ExitApp
		}
	}

; **********************************************************************************************************************************
; Sender() Method
; **********************************************************************************************************************************

	static Sender(sReceiverScript, oSendVar)
	{
		sPacket := oSendVar.Packet()

		oCopyDataStruct := Buffer(3 * A_PtrSize)
		iSize := (StrLen(sPacket) + 1) * 2

		NumPut("Ptr", iSize, "Ptr", StrPtr(sPacket), oCopyDataStruct, A_PtrSize)

		iPrevDetectHiddenWindows := A_DetectHiddenWindows
		iPrevTitleMatchMode := A_TitleMatchMode
		DetectHiddenWindows(True)
		SetTitleMatchMode(2)

		; Make MsgBox() sub window of Receiver() script, otherwise SendMessage() will make OSError(0) error.
		if (ScriptSock.bDebug)
		{
			if (WinExist(sReceiverScript))
			{
				;  (0) = OSError test
				iOwnerID := (1) ? WinGetID(sReceiverScript) : ""
			}
			else
			{
				iOwnerID := 0
			}

			MsgBox("Sender()`n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`nPacket :`n•    Script: [" oSendVar.sSenderScript "]`n•    Command: [" oSendVar.sCommand "]`n•    VarName:  [" oSendVar.sVarName "]`n•    ArgA: [" oSendVar.vData "]`n•    ArgB: [" oSendVar.vArg "]`n•    Process: [" oSendVar.bProcess "]`n•    Debug: [" oSendVar.bDebug "]`n`n→ [" sReceiverScript "]", , "4096 Owner" iOwnerID)
		}

		iWaitTime := (ScriptSock.bDebug) ? ScriptSock.iWaitTimeDebugSend : ScriptSock.iWaitTimeNormalSend

		try
		{
			; WM_COPYDATA = 0x004A
			; SendMessage() returns after end of receiving and processing message of OnMessage() callback function of target script.
			; SendMessage() returns 0 if success.
			; SendMessage() does not send message and return immediately, when an error occurs.
			; Do not use PostMessage().
			vResultValue := SendMessage(0x004A, 0, oCopyDataStruct, , sReceiverScript, , , , iWaitTime)
			vReturn := 0
		}
		catch as oError
		{
			vResultValue := ScriptSock.sMsgError
			vReturn := Type(oError) ": " oError.Message
		}

		if (vResultValue = ScriptSock.sMsgError)
		{
			if (ScriptSock.bDebug)
			{
				if (ScriptSock.bDebugBeep)
				{
					SoundBeep(9000, 50)
					SoundBeep(9000, 50)
				}

				MsgBox("Sender() SendMessage()`n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    Return " Type(oError) ": " oError.Message "`n•    Target Win: [" sReceiverScript "]", , "4096")
			}
		}
		else
		{
			if (ScriptSock.bDebug)
			{
				if (ScriptSock.bDebugSuccess)
				{
					MsgBox("Sender() SendMessage()`n[" LTrim(ScriptSock.sSourceScript, "\") "]`n`n•    Return Success: [" vResultValue "]`n•    Target Win: [" sReceiverScript "]", , "4096")
				}
			}
		}

		DetectHiddenWindows(iPrevDetectHiddenWindows)
		SetTitleMatchMode(iPrevTitleMatchMode)

		return (vReturn)
	}
}

; **********************************************************************************************************************************
; ScriptVar Class
; **********************************************************************************************************************************

class ScriptVar
{
	__New(sSenderScript := "", sCommand := "", sVarName := "", vData := "", vArg := "", bProcess := false, bDebug := false, bReceive := false)
	{
		this.sSenderScript := sSenderScript ; Sender of Message
		this.sCommand := sCommand ; What to do in Receiver()
		this.sVarName := sVarName ; Variable name
		this.vData := vData ; Setting value or getting value
		this.vArg := vArg ; for message
		this.bProcess := bProcess ; for process
		this.bDebug := bDebug ; for debug script
		this.bReceive := bReceive ; for receiving packet

		this.sPacketSeperatorSign := ";" ; Packet seperator
		this.sReplaceSeperatorSign := "^Semicolon^" ; replace packet seperator found in data with this text.
	}

	Call(sPacket := "")
	{
		if (sPacket)
		{
			return(this.Packet(sPacket))
		}
		else
		{
			return (this)
		}
	}

	Packet(sPacket := "")
	{
		SS := this.sPacketSeperatorSign
		SR := this.sReplaceSeperatorSign

		if (sPacket)
		{
			aMessage := StrSplit(sPacket, SS)
			for sItem in aMessage
			{
				aMessage[A_Index] := StrReplace(sItem, SR, SS)
			}

			this.sSenderScript :=(aMessage.Has(1)) ? aMessage[1] : ""
			this.sCommand := (aMessage.Has(2)) ? aMessage[2] : ""
			this.sVarName := (aMessage.Has(3)) ? aMessage[3] : ""
			this.vData := (aMessage.Has(4)) ? aMessage[4] : ""
			this.vArg := (aMessage.Has(5)) ? aMessage[5] : ""
			this.bProcess := (aMessage.Has(6)) ? aMessage[6] : false
			this.bDebug := (aMessage.Has(7)) ? aMessage[7] : false
			this.bReceive := (aMessage.Has(8)) ? aMessage[8] : false

			return (this)
		}
		else
		{
			vNewVarName := StrReplace(this.sVarName, SS, SR)
			sNewArgA := StrReplace(this.vData, SS, SR)
			sNewArgB := StrReplace(this.vArg, SS, SR)

			Return(this.sSenderScript SS this.sCommand SS vNewVarName SS sNewArgA SS sNewArgB SS this.bProcess SS this.bDebug SS this.bReceive)
		}
	}
}


SourceWin.ahk (Example Usage)

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------------------
; SourceWin.ahk (Example Usage)
; ----------------------------------------------------------------------------------------------------------------------------------

#Requires AutoHotkey v2
#SingleInstance Force

#Warn All, StdOut
#Warn Unreachable, Off
#Warn LocalSameAsGlobal, Off
#Warn VarUnset, StdOut

DetectHiddenWindows(false)
DetectHiddenText(false)
SetTitleMatchMode(2)

#Include "ScriptSock.ahk"

; ----------------------------------------------------------------------------------------------------------------------------------
; Example 01
; ----------------------------------------------------------------------------------------------------------------------------------
if (1)
{
	; Make sure "TargetWin.ahk" is running.

	MsgBox("Get a variable from target script...")
	MsgBox("Result: " ScriptSock("TargetWin.ahk").GetVar("iGlobalTestVar")) ; 1111
}

; ----------------------------------------------------------------------------------------------------------------------------------
; Example 02
; ----------------------------------------------------------------------------------------------------------------------------------
else if (0)
{
	; Make sure "TargetWin.ahk" is running.

	oScriptSock := ScriptSock("")

	; Add "#" identifier to a variable's name for debugging
	MsgBox("Begin debugging...")
	MsgBox("Result: " oScriptSock("TargetWin.ahk").GetVar("iGlobalTestVar#")) ; 1111
}

; ----------------------------------------------------------------------------------------------------------------------------------
; Example 03
; ----------------------------------------------------------------------------------------------------------------------------------
else if (0)
{
	; Make sure "TargetWin.ahk" is running.

	MsgBox("Set a variable in target script...")
	ScriptSock("TargetWin.ahk").SetVar("iGlobalTestVar", 2222)
	MsgBox("Result: " ScriptSock("TargetWin.ahk").GetVar("iGlobalTestVar")) ; 2222
}


; ----------------------------------------------------------------------------------------------------------------------------------
; Example 04
; ----------------------------------------------------------------------------------------------------------------------------------
else if (0)
{
	; Make sure 'TargetWin.ahk' is running

	MsgBox("Set a variable in target script...")
	ScriptSock("TargetWin.ahk").SetVar("iGloblalTestVar", 3333)
	MsgBox("Result: " ScriptSock("TargetWin.ahk").GetVar("iGloblalTestVar")) ; 3333

	MsgBox("Post a variable and start fetching in target script...")
	ScriptSock("TargetWin.ahk").PostVar("bStartFirst", true)
	Sleep(300)
	MsgBox("Result: " ScriptSock("TargetWin.ahk").GetVar("iGloblalTestVar")) ; 9999
}

; ----------------------------------------------------------------------------------------------------------------------------------
; Example 05
; ----------------------------------------------------------------------------------------------------------------------------------
else if (0)
{
	; Make sure 'TargetWin.ahk' is running

	MsgBox("Post multiple variables to target script...")

	ScriptSock("TargetWin.ahk").PostVar("bBooleanVar", true)
	ScriptSock("TargetWin.ahk").PostVar("iIntegerVar", 5555)
	ScriptSock("TargetWin.ahk").PostVar("sStringVar", "Hello, world!")

	MsgBox("Start fetching in target script...")

	ScriptSock("TargetWin.ahk").PostVar("bStartSecond", true, 0)
}

return



TargetWin.ahk (Example Usage)

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------------------
; TargetWin.ahk (Example Usage)
; ----------------------------------------------------------------------------------------------------------------------------------

#Requires AutoHotkey v2
#SingleInstance Force

#Warn All, StdOut
#Warn Unreachable, Off
#Warn LocalSameAsGlobal, Off
#Warn VarUnset, StdOut

DetectHiddenWindows(false)
DetectHiddenText(false)
SetTitleMatchMode(2)

#Include "ScriptSock.ahk"

oScriptSock := ScriptSock("")

iGlobalTestVar := 1111

SetTimer(fMainFunc, 100)

fMainFunc()
{
	if (oScriptSock.FetchVar("bStartFirst", 0))
	{
		global iGloblalTestVar := 9999

		oScriptSock.PushVar("bStartFirst", false, 0)
	}

	if (oScriptSock.FetchVar("bStartSecond", 0))
	{
		MsgBox("Result: " oScriptSock.FetchVar("bBooleanVar", false), , "T2")
		MsgBox("Result: " oScriptSock.FetchVar("iIntegerVar", 0), , "T2")
		MsgBox("Result: " oScriptSock.FetchVar("sStringVar", ""), , "T2")

		oScriptSock.PushVar("bStartSecond", false, 0)
	}
}

return

AstraVista

Return to “Scripts and Functions (v2)”

Who is online

Users browsing this forum: No registered users and 22 guests