Я не знаю стоит ли создавать для этого новую тему или писать сюда, но т.к. всё-таки проблема связана и с этой темой - то решил написать сюда.
Мой скрипт мутировал в такое:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, Force
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; #Include Hotstring.ahk
Global extractTo := A_Temp "\executor" ; Path where to extract archives' contents to.
Array := {}
Loop, Read, %A_ScriptDir%\Hotstrings.ini ; This files contents consist of lines that each consists of two parts separated with a pipe. Left part is the hotstring trigger text and the right part is the full path.
{
tmp := StrSplit(A_LoopReadLine, "|")
If (tmp[1] == "archiver") ; If the left part of a line is "archiver".
Global archiver := tmp[2] ; Then store the path from the right part of that line into a variable 'archiver' that will later be used for reaching files inside of archives.
Array.Insert(RegExReplace(tmp[1], "[\i\),`]"), tmp[2])
Hotstring(tmp[1], "subRoutine", 3)
}
Return
#IfWinActive, ahk_exe explorer.exe ahk_class #32770
subRoutine:
mainFunc(Array[$])
Return
mainFunc(input)
{
ControlGetFocus, activeControl, A
If (activeControl == "Edit1") ; Win+R window: "Execute" (or "Выполнить" in Ru OS locale).
{
WinClose ; Close the "Execute" (or "Выполнить" in Ru OS locale) window.
IfInString, input, ! ; Paths with "!" are the ones pointing to the files inside archives.
; Example path to an executable inside an archive: C:\Test.rar!subfolder\runme.exe
{
partialPath := StrSplit(input, "!") ; partialPath[1] contains the path to the archive. partialPath[2] contains the relative path to the executable withing the archive (where root is the archive itself).
archiveName := SubStr(partialPath[1], InStr(partialPath[1], "\",, 0), InStr(partialPath[1], ".",, 0) - InStr(partialPath[1], "\",, 0)) ; Archive's name (without extension) will be used to name the temporary folder where it will get unpacked to.
RunWait, % """" archiver """ x """ partialPath[1] """ -aoa -y -o""" extractTo archiveName """",, Hide ; Use the archiver to unpack the files.
RunWait, % extractTo archiveName "\" partialPath[2] ; Run the needed executable from the unpacked files.
FileRemoveDir, % extractTo archiveName, 1 ; Remove the unpacked stuff after it got closed.
}
Else ; The path points to a file outside archive.
Run, % Array[RegExReplace($, "`")]
}
}
Он позволяет запускать программы, в том числе программы внутри архивов по заранее заданным alias'ам для этих программ.
Alias'ы хранятся во внешнем файле %A_ScriptDir%\Hotstrings.ini
Содержимое этого файла должно выглядеть вот так:
archiver|C:\Program files\7-zip\7z.exe
7z`|C:\Program files\7-zip\7zFM.exe
7zip`|C:\Program files\7-zip\7zFM.exe
7-zip`|C:\Program files\7-zip\7zFM.exe
rar`|C:\Program files\WinRar\winrar.exe
unrar`|C:\Program files\WinRar\winrar.exe
winrar`|C:\Program files\WinRar\winrar.exe
ape`|C:\Soft\Utils\AppPathsEditor.zip!ape.exe
apppaths`|C:\Soft\Utils\AppPathsEditor.zip!ape.exe
junction`|C:\Soft\Utils\Junction.zip!Junction.exe
junctions`|C:\Soft\Utils\Junction.zip!Junction.exe
junc`|C:\Soft\Utils\Junction.zip!Junction.exe
junk`|C:\Soft\Utils\Junction.zip!Junction.exe
switcherx`|C:\Soft\Utils\Switcherx.rar!SwitcherX\SwitcherX.exe
Пользоваться скриптом так: запустить его, нажать Win+R (откроется окно "выполнить"), туда вбить "ape`" (без кавычек, но со штрихом) и откроется ape.exe из архива C:\Soft\Utils\AppPathsEditor.zip
Штука в том, что если была попытка запустить файл из архива - то архив сначала распаковывается (используя архиватор, путь к которому задаётся внутри hotstrings.ini в alias'е "archiver"), затем RunWait'ом открывается нужный исполняемый файл. RunWait нужен для того, чтобы по закрытии программы были удалены все распакованные из архива файлы. Т.е. реализована чистка за собой.
Но проблема в том, что не получается одновременно запустить 2 программы, если они обе заархивированы.
Не получается как раз из-за RunWait'а.
Как решить проблему через SetTimer?
Пробовал вот так
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, Force
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; #Include Hotstring.ahk
Global extractTo := A_Temp "\executor" ; Path where to extract archives' contents to.
Array := {}
Loop, Read, %A_ScriptDir%\Hotstrings.ini ; This files contents consist of lines that each consists of two parts separated with a pipe. Left part is the hotstring trigger text and the right part is the full path.
{
tmp := StrSplit(A_LoopReadLine, "|")
If (tmp[1] == "archiver") ; If the left part of a line is "archiver".
Global archiver := tmp[2] ; Then store the path from the right part of that line into a variable 'archiver' that will later be used for reaching files inside of archives.
Array.Insert(RegExReplace(tmp[1], "[\i\),`]"), tmp[2])
Hotstring(tmp[1], "subRoutine", 3)
}
Return
#IfWinActive, ahk_exe explorer.exe ahk_class #32770
subRoutine:
mainFunc(Array[$])
Return
timer:
waitAndRemove(runThis, removeThis)
Return
mainFunc(input)
{
ControlGetFocus, activeControl, A
If (activeControl == "Edit1") ; Win+R window: "Execute" (or "Выполнить" in Ru OS locale).
{
WinClose ; Close the "Execute" (or "Выполнить" in Ru OS locale) window.
IfInString, input, ! ; Paths with "!" are the ones pointing to the files inside archives.
; Example path to an executable inside an archive: C:\Test.rar!subfolder\runme.exe
{
partialPath := StrSplit(input, "!") ; partialPath[1] contains the path to the archive. partialPath[2] contains the relative path to the executable withing the archive (where root is the archive itself).
archiveName := SubStr(partialPath[1], InStr(partialPath[1], "\",, 0), InStr(partialPath[1], ".",, 0) - InStr(partialPath[1], "\",, 0)) ; Archive's name (without extension) will be used to name the temporary folder where it will get unpacked to.
RunWait, % """" archiver """ x """ partialPath[1] """ -aoa -y -o""" extractTo archiveName """",, Hide ; Use the archiver to unpack the files.
Global runThis := extractTo archiveName "\" partialPath[2]
Global removeThis := extractTo archiveName
SetTimer, timer, -1
; RunWait, % extractTo archiveName "\" partialPath[2] ; Run the needed executable from the unpacked files.
; FileRemoveDir, % extractTo archiveName, 1 ; Remove the unpacked stuff after it got closed.
}
Else ; The path points to a file outside archive.
Run, %input%
}
ListLines
}
waitAndRemove(runWait, fileRemoveDir)
{
msgbox runWait: '%runWait%'`nfileRemoveDir: '%fileRemoveDir%'`n
RunWait, %runWait%
FileRemoveDir, %fileRemoveDir%, 1 ; Remove the unpacked stuff after it got closed.
}
Но так почему-то не создаются новые псевдо-thread'ы и скрипт перестаёт реагировать на хотстринги когда висит на RunWait'е.
Второй вариант решения проблемы мне видится в том, чтобы создать массив PID'ов и сопоставленных им имён папок (куда были распакованы архивы), которые проверять settimer'ом на жизненность и удалять соответствующую папку, если PID умер.
Вариант с массивами пока не рассматривается как решение (хочется всё-таки получше с thread'ами разобраться).