<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Серый форум &mdash; AHK: Tiny Master Script]]></title>
	<link rel="self" href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=15135&amp;type=atom" />
	<updated>2020-01-21T13:14:02Z</updated>
	<generator>PunBB</generator>
	<id>https://forum.script-coding.com/viewtopic.php?id=15135</id>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137408#p137408" />
			<content type="html"><![CDATA[<p><strong>teadrinker</strong>, спасибо! Потестирую.</p>]]></content>
			<author>
				<name><![CDATA[becauseim]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33149</uri>
			</author>
			<updated>2020-01-21T13:14:02Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137408#p137408</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137382#p137382" />
			<content type="html"><![CDATA[<p>Подредактировал основной скрипт.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2020-01-20T22:36:18Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137382#p137382</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137381#p137381" />
			<content type="html"><![CDATA[<p>Вот так можно удалить иконки AHK-скриптов из трея, но&nbsp; только на один раз, до перезагрузки:<br /></p><div class="codebox"><pre><code>exclude = 
( ; здесь скрипты, иконки которых не надо удалять
D:\AHK\My Programs\ScreenCatcher\ScreenCatcher.ahk
D:\AHK\My Programs\LinksMenu\LinksMenu.ahk
)

DeleteAhkIcons(exclude)

DeleteAhkIcons(exclude)
{
   static TB_GETBUTTON   := 0x417
        , TB_BUTTONCOUNT := 0x418
        , PtrSize := 4 &lt;&lt; A_Is64bitOS
        , szTBBUTTON := 8 + PtrSize*3
        , szTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinGet, PID, PID, ahk_exe explorer.exe
   RemoteBuff := new RemoteBuffer(PID, szTRAYDATA)
   DeleteIcon := []
   
   Loop 2 {
      if (A_Index = 2)
         ControlGet, hToolBar, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
      else {
         for k, v in [&quot;TrayNotifyWnd&quot;, &quot;SysPager&quot;, &quot;ToolbarWindow32&quot;]
            hToolBar := DllCall(&quot;FindWindowEx&quot;, &quot;Ptr&quot;, k = 1 ? WinExist(&quot;ahk_class Shell_TrayWnd&quot;) : hToolBar, &quot;Ptr&quot;, 0, &quot;Str&quot;, v, &quot;UInt&quot;, 0, &quot;Ptr&quot;)
      }
      SendMessage, TB_BUTTONCOUNT,,,, % &quot;ahk_id&quot; . hToolBar
      Loop % ErrorLevel {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr,, % &quot;ahk_id&quot; . hToolBar
         RemoteBuff.Read(TBBUTTON, szTBBUTTON)
         RemoteBuff.Read(TRAYDATA, szTRAYDATA, NumGet(&amp;TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr)
         hWnd := NumGet(TRAYDATA), uID := NumGet(&amp;TRAYDATA + PtrSize, &quot;UInt&quot;)
         WinGetClass, winClass, ahk_id %hWnd%
         if (winClass != &quot;AutoHotkey&quot;)
            continue
         WinGetTitle, title, ahk_id %hWnd%
         scriptPath := RegExReplace(title, &quot; - AutoHotkey v[\d\.]+&quot;)
         Loop, parse, % exclude, `n, `n
            if (scriptPath = A_LoopField)
               continue 2
         DeleteIcon.Insert({hWnd: hWnd, uID: uID})
      }
   }
   DetectHiddenWindows, %DHW_Prev%
   for k, v in DeleteIcon
      RemoveTrayIcon(v.hWnd, v.uID)
}

RemoveTrayIcon(hWnd, uID)
{
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   NumPut(size, NOTIFYICONDATA, &quot;UInt&quot;)
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID, NOTIFYICONDATA, 2*A_PtrSize, &quot;UInt&quot;)
   DllCall(&quot;shell32\Shell_NotifyIcon&quot;, &quot;UInt&quot;, NIM_DELETE := 2, Ptr, &amp;NOTIFYICONDATA)
   Return
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := [&quot;UInt&quot;, MEM_COMMIT := 0x1000, &quot;UInt&quot;, PAGE_READWRITE := 0x4, &quot;Ptr&quot;]
         
      if !this.hProc := DllCall(&quot;OpenProcess&quot;, &quot;UInt&quot;, flags, &quot;Int&quot;, 0, &quot;UInt&quot;, PID, &quot;Ptr&quot;)
         throw Exception(&quot;Can&#039;t open remote process PID = &quot; . PID . &quot;`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.__New&quot;)
      
      if !this.ptr := DllCall(&quot;VirtualAllocEx&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, 0, &quot;Ptr&quot;, size, Params*) {
         DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, this.hProc)
         throw Exception(&quot;Can&#039;t allocate memory in remote process PID = &quot; . PID . &quot;`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.__New&quot;)
      }
   }
   
   __Delete() {
      DllCall(&quot;VirtualFreeEx&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr, &quot;UInt&quot;, 0, &quot;UInt&quot;, MEM_RELEASE := 0x8000)
      DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, this.hProc)
   }
   
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall(&quot;ReadProcessMemory&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr + offset, &quot;Ptr&quot;, &amp;localBuff, &quot;Ptr&quot;, size, &quot;PtrP&quot;, bytesRead)
         throw Exception(&quot;Can&#039;t read data from remote buffer`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.Read&quot;)
      Return bytesRead
   }
   
   Write(pData, size, offset = 0) {
      if !res := DllCall(&quot;WriteProcessMemory&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr + offset, &quot;Ptr&quot;, pData, &quot;Ptr&quot;, size, &quot;PtrP&quot;, bytesWritten)
         throw Exception(&quot;Can&#039;t write data to remote buffer`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.Write&quot;)
      Return bytesWritten
   }
}</code></pre></div>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2020-01-20T22:28:42Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137381#p137381</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137380#p137380" />
			<content type="html"><![CDATA[<p><strong>teadrinker</strong>, круто! Спасибо! А чтобы &quot;вложить&quot; запущенные скрипты с исключением из трея, в любом случае необходимо прописывать в каждом <em>#NoTrayIcon</em>? По сути необходимость мини-мастера появилась в том, что различные сценарии у меня часто конфликтуют, т.к. прописаны и запускаются из одного файла. Была идея разделить один фактический скрипт на несколько процессов, но оставить единственную для всех иконку в трее.</p>]]></content>
			<author>
				<name><![CDATA[becauseim]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33149</uri>
			</author>
			<updated>2020-01-20T21:49:27Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137380#p137380</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137356#p137356" />
			<content type="html"><![CDATA[<p>Подобавлял всяких команд:<br /></p><div class="codebox"><pre><code>#NoEnv
SetBatchLines, -1
Menu, Tray, NoStandard
DetectHiddenWindows, On

scriptDirectory := &quot;D:\AHK\My Scripts&quot;
recurse := true
enumerateEXE := true
enumerateLNK := true

Scripts := EnumScriptsInDirectory(scriptDirectory, recurse, enumerateEXE, enumerateLNK)
OnMessage( 0x404, Func(&quot;AHK_NOTIFYICON&quot;).Bind(Scripts, scriptDirectory) )
Return

EnumScriptsInDirectory(scriptDirectory, recurse, exe, lnk) {
   if !InStr( FileExist(scriptDirectory), &quot;D&quot; ) {
      MsgBox, Folder &quot;%scriptDirectory%&quot; not found
      ExitApp
   }
   Scripts := [], Names := {}
   Loop, Files, % scriptDirectory . &quot;\*.*&quot;, % (recurse ? &quot;R&quot; : &quot;&quot;)
   {
      if (A_LoopFileExt ~= &quot;i)ahk&quot; . (exe ? &quot;|exe&quot; : &quot;&quot;) . (lnk ? &quot;|lnk&quot; : &quot;&quot;)) {
         if (A_LoopFileExt = &quot;lnk&quot;) {
            FileGetShortcut, % A_LoopFilePath, scriptPath
            if !(scriptPath ~= &quot;i)(ahk&quot; . (exe ? &quot;|exe&quot; : &quot;&quot;) . &quot;)$&quot;)
               continue
            SplitPath, scriptPath, name
         }
         else {
            name := A_LoopFileName
            scriptPath := A_LoopFilePath
         }
         if Names.HasKey(name) {
            if (scriptPath = Names[name].scriptPath)
               continue
            i := 0
            Loop
               newName := name . &quot; (&quot; . ++i . &quot;)&quot;
            until !Names.HasKey(newName)
            name := newName
         }
         Names[name] := {name: name, scriptPath: scriptPath}
      }
   }
   for k, v in Names
      Scripts.Push(v)
   Return Scripts
}

AHK_NOTIFYICON(Scripts, scriptDirectory, wp, lp) {
   static WM_MOUSEMOVE := 0x200, WM_RBUTTONUP := 0x205, info
        , IsData := [], timer := Func(&quot;IsDataClear&quot;).Bind(IsData)
   if (lp = WM_MOUSEMOVE) {
      if !IsData[1] {
         Critical
         Loop 3 {
            try info := GetAhkScriptsInfo()
            catch {
               Sleep, 100
               continue
            }
            break
         }
         IsData[1] := true
         SetTimer, % timer, -1000
         Critical Off
      }
   }
   if (lp = WM_RBUTTONUP) {
      handler := Func(&quot;RunFile&quot;).Bind(&quot;taskmgr&quot;)
      Menu, MyMenu, Add, Running Scripts, % handler
      Menu, MyMenu, Default, Running Scripts
      Menu, MyMenu, Add
      Names := {}
      for k, v in info {
         if Names.HasKey(v.name) {
            i := 0
            Loop
               name := v.name . &quot; (&quot; . ++i . &quot;)&quot;
            until !Names.HasKey(name)
            v.name := name
         }
         Names[v.name] := &quot;&quot;
      }
      for name in Names {
         for k, v in info {
            if (v.name = name) {
               CreateActionsSubMenu(k, v)
               item := v.name
               if v.suspended
                  item .= A_Tab . &quot;Suspended&quot;
               else if v.paused
                  item .= A_Tab . &quot;Paused&quot;
               Menu, MyMenu, Add, % item, :Actions%k%
               break
            }
         }
      }
      Menu, MyMenu, Add
      CreateScriptsSubmenu(Scripts, scriptDirectory, info)
      Menu, MyMenu, Add, My Scripts, :Scripts
      Menu, MyMenu, Add
      Menu, MyMenu, Add, Close this Script, ExitScript
      Menu, MyMenu, Show
      Loop % info.MaxIndex()
         Menu, Actions%A_Index%, DeleteAll
      Loop % Scripts.MaxIndex()
         Menu, ScriptFile%A_Index%, DeleteAll
      Menu, Scripts, DeleteAll
      Menu, MyMenu, DeleteAll
      IsData[1] := false
   }
}

IsDataClear(IsData) {
   IsData[1] := false
}

GetAhkScriptsInfo() {
   static Waiting := 5, Suspended := 5
        , MyPID := DllCall(&quot;GetCurrentProcessId&quot;)
   info := [], PIDs := {}
   WinGet, List, List, ahk_class AutoHotkey
   Loop % List {
      WinExist(&quot;ahk_id&quot; List%A_Index%)
      threadID := DllCall(&quot;GetWindowThreadProcessId&quot;, &quot;Ptr&quot;, List%A_Index%, &quot;UIntP&quot;, PID)
      if (PID = MyPID)
         continue
      PIDs[PID] := threadID
      WinGetTitle, title
      scriptPath := RegExReplace(title, &quot; - AutoHotkey v[\d\.]+&quot;)
      SplitPath, scriptPath, fileName
      
      info.Push({ scriptPath: scriptPath, name: fileName, PID: PID
                , hwnd: List%A_Index%, suspended: false, bitness: GetProcessBitness(PID) })
   }
   ThreadsInfo(PIDs)
   for k, v in info {
      v.threads := PIDs[ v.PID ]
      for k, j in PIDs[ v.PID ] {
         if !(j.ThreadState = Waiting &amp;&amp; j.WaitReason = Suspended)
            continue 2
         v.suspended := true
      }
   }
   for k, v in info
      if !v.suspended
         v.paused := IsPaused(v.hwnd)
   Return info
}

GetProcessBitness(PID) {
   if !A_Is64bitOS
      Return 32
   hProc := DllCall(&quot;OpenProcess&quot;, &quot;UInt&quot;, PROCESS_QUERY_INFORMATION := 0x400, &quot;UInt&quot;, 0, &quot;UInt&quot;, PID, &quot;Ptr&quot;)
   DllCall(&quot;IsWow64Process&quot;, &quot;Ptr&quot;, hProc, &quot;IntP&quot;, is32)
   DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, hProc)
   Return 32 &lt;&lt; !is32
}

ThreadsInfo(PIDs) {
   static SPI := SystemProcessInformation := 0x5, STATUS_SUCCESS := 0
        , szSPI := A_PtrSize = 4 ? 0xB8 : 0x100  ; size of SYSTEM_PROCESS_INFORMATION
        , szSTI := A_PtrSize = 4 ? 0x40 : 0x050  ; size of SYSTEM_THREAD_INFORMATION
        
   DllCall(&quot;Ntdll\NtQuerySystemInformation&quot;, &quot;Int&quot;, SPI, &quot;Ptr&quot;, 0, &quot;UInt&quot;, 0, &quot;UIntP&quot;, size, &quot;UInt&quot;)
   VarSetCapacity(buff, size, 0)
   addr := &amp;buff
   
   res := DllCall(&quot;Ntdll\NtQuerySystemInformation&quot;, &quot;Int&quot;, SPI, &quot;Ptr&quot;, addr, &quot;UInt&quot;, size, &quot;UIntP&quot;, 0, &quot;UInt&quot;)
   if (res != STATUS_SUCCESS)
      throw Exception( &quot;Could not get data from NtQuerySystemInformation. Error: &quot; . Format(&quot;{:#x}&quot;, res) )
   offset := 0
   Loop {
      addr += offset
      ProcessID := NumGet(addr + 4*14 + A_PtrSize*3)
      if !PIDs.HasKey(ProcessID)
         continue
      threadsCount := NumGet(addr + 4, &quot;UInt&quot;)
      mainThreadID := PIDs[ProcessID]
      PIDs[ProcessID] := []
      Loop % threadsCount {
         ThreadID := NumGet(addr + szSPI + 24 + A_PtrSize*3 + (A_Index - 1)*szSTI)
         if (ThreadID != mainThreadID)
            continue
         ThreadState := NumGet(addr + szSPI + 36 + A_PtrSize*4 + (A_Index - 1)*szSTI, &quot;UInt&quot;)
         WaitReason  := NumGet(addr + szSPI + 40 + A_PtrSize*4 + (A_Index - 1)*szSTI, &quot;UInt&quot;)
         PIDs[ProcessID].Push( {ThreadID: ThreadID, ThreadState: ThreadState, WaitReason: WaitReason} )
      }
   } until !offset := NumGet(addr + 0, &quot;UInt&quot;)
}

CreateScriptsSubmenu(Scripts, folder, info) {
   handler := Func(&quot;RunFile&quot;).Bind(folder)
   Menu, Scripts, Add, Files, % handler
   Menu, Scripts, Default, Files
   Menu, Scripts, Add
   for k, v in Scripts {
      isRunning := false
      for i, j in info {
         if (j.scriptPath = v.scriptPath &amp;&amp; isRunning := true)
            break
      }
      CreateScriptFileSubmenu(v.scriptPath, isRunning, k)
      Menu, Scripts, Add, % v.name, :ScriptFile%k%
      if isRunning
         Menu, Scripts, Check, % v.name
   }
}

CreateScriptFileSubmenu(scriptPath, isRunning, k) {
   if !isRunning {
      handler := Func(&quot;RunScript&quot;).Bind(scriptPath, k + 2)
      Menu, ScriptFile%k%, Add, Run, % handler
   }   
   if !(scriptPath ~= &quot;i)\.exe$&quot;) {
      handler := Func(&quot;RunFileContextMenuItem&quot;).Bind(scriptPath, &quot;Edit Script&quot;)
      Menu, ScriptFile%k%, Add, Edit Script, % handler
   }
   handler := Func(&quot;AddToStartup&quot;).Bind(scriptPath, k)
   Menu, ScriptFile%k%, Add, Add to Startup, % handler
   SplitPath, scriptPath, fileName
   if FileExist(A_Startup . &quot;\&quot; . fileName . &quot;.lnk&quot;)
      Menu, ScriptFile%k%, Check, Add to Startup
   
   handler := Func(&quot;OpenScriptFolder&quot;).Bind(scriptPath)
   Menu, ScriptFile%k%, Add, Open File Location, % handler
}

RunFileContextMenuItem(filePath, contextMenuItemName) {
   SplitPath, filePath, fileName, dir
   try Folder := ComObjCreate(&quot;Shell.Application&quot;).Namespace(dir)
   catch
      Return
   for Item in Folder.Items {
      if (Item.Name = fileName) {
         Loop % Item.Verbs.Count {
            Verb := Item.Verbs.Item(A_Index - 1)
            if (Verb.Name = contextMenuItemName) {
               Verb.DoIt()
               break 2
            }
         }
      }
   }
}

RunFile(filePath) {
   Run, % filePath
}

RunScript(scriptPath, ItemPos) {
   hMenu := MenuGetHandle(&quot;Scripts&quot;)
   if !IsMenuChecked(hMenu, ItemPos)
      Run, % scriptPath
}

IsMenuChecked(hMenu, itemNumber)  {
   static MIIM_STATE := 1, MFS_CHECKED := 0x8
   VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)
   NumPut(size, MENUITEMINFO)
   NumPut(MIIM_STATE, MENUITEMINFO, 4)
   DllCall(&quot;GetMenuItemInfo&quot;, Ptr, hMenu, UInt, itemNumber - 1, UInt, true, Ptr, &amp;MENUITEMINFO)
   Return !!(NumGet(MENUITEMINFO, 4*3, &quot;UInt&quot;) &amp; MFS_CHECKED)
}

CreateActionsSubMenu(k, info) {
   static MyBitness := GetProcessBitness( DllCall(&quot;GetCurrentProcessId&quot;) )
   if !(MyBitness = 32 &amp;&amp; info.bitness = 64) &amp;&amp; !(info.name ~= &quot;i)\.exe( \(\d+\))?$&quot;) {
      handler := Func(&quot;SuspendResumeThreads&quot;).Bind(info)
      Menu, Actions%k%, Add, Suspend Script, % handler
   }
   if info.suspended
      Menu, Actions%k%, Check, Suspend Script
   else {
      handler := Func(&quot;SelectMenuItem&quot;).Bind(info.hwnd, 5)
      Menu, Actions%k%, Add, Pause Script, % handler
      if info.paused
         Menu, Actions%k%, Check, Pause Script
   }
   Menu, Actions%k%, Add
   
   if !(info.name ~= &quot;i)\.exe$&quot;) {
      handler := Func(&quot;RunFileContextMenuItem&quot;).Bind(info.scriptPath, &quot;Edit Script&quot;)
      Menu, Actions%k%, Add, Edit Script, % handler
   }
   
   handler := Func(&quot;AddToStartup&quot;).Bind(info.scriptPath, k)
   Menu, Actions%k%, Add, Add to Startup, % handler
   if FileExist(A_Startup . &quot;\&quot; . info.name . &quot;.lnk&quot;)
      Menu, Actions%k%, Check, Add to Startup
   
   handler := Func(&quot;OpenScriptFolder&quot;).Bind(info.scriptPath)
   Menu, Actions%k%, Add, Open File Location, % handler
   
   Menu, Actions%k%, Add
   handler := Func(&quot;KillAndReload&quot;).Bind(info.PID, info.scriptPath)
   Menu, Actions%k%, Add, Kill And Reload, % handler
   handler := Func(&quot;KillScript&quot;).Bind(info.PID)
   Menu, Actions%k%, Add, Kill Script, % handler
   if !info.suspended {
      handler := Func(&quot;SelectMenuItem&quot;).Bind(info.hwnd, 1)
      Menu, Actions%k%, Add, Reload, % handler
      handler := Func(&quot;SelectMenuItem&quot;).Bind(info.hwnd, 8)
      Menu, Actions%k%, Add, Exit, % handler
   }
}

OpenScriptFolder(filePath) {
   SplitPath, filePath,, dir
   for window in ComObjCreate(&quot;Shell.Application&quot;).Windows {
      try ShellFolderView := window.Document
      try if ( (Folder := ShellFolderView.Folder).Self.Path = dir ) {
         for item in Folder.Items {
            if (item.Path = filePath &amp;&amp; found := true)
               break 2
         }
      }
   }
   if !found
      Run, explorer /select`, &quot;%filePath%&quot;
   else {
      WinActivate, % &quot;ahk_id&quot; window.hwnd
      ShellFolderView.SelectItem(item, 1|4|8|16)
    }
}

SelectMenuItem(hwnd, nMenu) {
   WinMenuSelectItem, ahk_id %hWnd%,, 1&amp;, % nMenu . &quot;&amp;&quot;
}

AddToStartup(scriptPath) {
   SplitPath, scriptPath, fileName
   lnk := A_Startup . &quot;\&quot; . fileName . &quot;.lnk&quot;
   if FileExist(lnk)
      FileDelete, % lnk
   else
      FileCreateShortcut, % scriptPath, % lnk
}

SuspendResumeThreads(info) {
   static MyBitness := GetProcessBitness( DllCall(&quot;GetCurrentProcessId&quot;) )
        , THREAD_SUSPEND_RESUME := 0x2
   for k, v in info.threads {
      hThread := DllCall(&quot;OpenThread&quot;, &quot;UInt&quot;, THREAD_SUSPEND_RESUME, &quot;UInt&quot;, false, &quot;UInt&quot;, v.ThreadID, &quot;Ptr&quot;)
      if info.suspended
         DllCall(&quot;ResumeThread&quot;, &quot;Ptr&quot;, hThread)
      else {
         if (MyBitness = info.bitness)
            DllCall(&quot;SuspendThread&quot;, &quot;Ptr&quot;, hThread)
         else
            DllCall(&quot;Wow64SuspendThread&quot;, &quot;Ptr&quot;, hThread)
      }
      DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, hThread)
   }
}

KillScript(PID) {
   Process, Close, % PID
   Process, WaitClose, % PID
   DeleteDummyIcons()
}

KillAndReload(PID, scriptPath) {
   KillScript(PID)
   Run, % scriptPath
}

IsPaused(hWnd) {
   static WM_ENTERMENULOOP := 0x211, WM_EXITMENULOOP := 0x212, MF_BYPOSITION := 0x400, MF_CHECKED := 8
        , Params := [&quot;Ptr&quot;, 0, &quot;Ptr&quot;, 0, &quot;UInt&quot;, SMTO_ABORTIFHUNG := 0x2|SMTO_ERRORONEXIT := 0x20, &quot;UInt&quot;, 500, &quot;Ptr&quot;, 0]
   Loop 2
      if !DllCall(&quot;SendMessageTimeout&quot;, Ptr, hWnd, UInt, A_Index = 1 ? WM_ENTERMENULOOP : WM_EXITMENULOOP, Params*)
         Return
   hWinMenu := DllCall(&quot;GetMenu&quot;, Ptr, hWnd, Ptr)
   hFileMenu := DllCall(&quot;GetSubMenu&quot;, Ptr, hWinMenu, Int, 0, Ptr)
   Return DllCall(&quot;GetMenuState&quot;, Ptr, hFileMenu, UInt, 4, UInt, MF_BYPOSITION) = MF_CHECKED   ; Pause state
}

ExitScript() {
   ExitApp
}

DeleteDummyIcons()
{
   static TB_GETBUTTON   := 0x417
        , TB_BUTTONCOUNT := 0x418
        , PtrSize := 4 &lt;&lt; A_Is64bitOS
        , szTBBUTTON := 8 + PtrSize*3
        , szTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinGet, PID, PID, ahk_exe explorer.exe
   RemoteBuff := new RemoteBuffer(PID, szTRAYDATA)
   Dummy := []
   
   Loop 2 {
      if (A_Index = 2)
         ControlGet, hToolBar, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
      else {
         for k, v in [&quot;TrayNotifyWnd&quot;, &quot;SysPager&quot;, &quot;ToolbarWindow32&quot;]
            hToolBar := DllCall(&quot;FindWindowEx&quot;, &quot;Ptr&quot;, k = 1 ? WinExist(&quot;ahk_class Shell_TrayWnd&quot;) : hToolBar, &quot;Ptr&quot;, 0, &quot;Str&quot;, v, &quot;UInt&quot;, 0, &quot;Ptr&quot;)
      }
      SendMessage, TB_BUTTONCOUNT,,,, % &quot;ahk_id&quot; . hToolBar
      Loop % ErrorLevel {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr,, % &quot;ahk_id&quot; . hToolBar
         RemoteBuff.Read(TBBUTTON, szTBBUTTON)
         RemoteBuff.Read(TRAYDATA, szTRAYDATA, NumGet(&amp;TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr)
         hWndIcon := NumGet(TRAYDATA), uID := NumGet(&amp;TRAYDATA + PtrSize, &quot;UInt&quot;)
         if !WinExist(&quot;ahk_id&quot; hWndIcon)
            Dummy.Insert({hWnd: hWndIcon, uID: uID})
      }
   }
   DetectHiddenWindows, %DHW_Prev%
   for k, v in Dummy
      RemoveTrayIcon(v.hWnd, v.uID)
}

RemoveTrayIcon(hWnd, uID)
{
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   NumPut(size, NOTIFYICONDATA, &quot;UInt&quot;)
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID, NOTIFYICONDATA, 2*A_PtrSize, &quot;UInt&quot;)
   DllCall(&quot;shell32\Shell_NotifyIcon&quot;, &quot;UInt&quot;, NIM_DELETE := 2, Ptr, &amp;NOTIFYICONDATA)
   Return
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := [&quot;UInt&quot;, MEM_COMMIT := 0x1000, &quot;UInt&quot;, PAGE_READWRITE := 0x4, &quot;Ptr&quot;]
         
      if !this.hProc := DllCall(&quot;OpenProcess&quot;, &quot;UInt&quot;, flags, &quot;Int&quot;, 0, &quot;UInt&quot;, PID, &quot;Ptr&quot;)
         throw Exception(&quot;Can&#039;t open remote process PID = &quot; . PID . &quot;`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.__New&quot;)
      
      if !this.ptr := DllCall(&quot;VirtualAllocEx&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, 0, &quot;Ptr&quot;, size, Params*) {
         DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, this.hProc)
         throw Exception(&quot;Can&#039;t allocate memory in remote process PID = &quot; . PID . &quot;`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.__New&quot;)
      }
   }
   
   __Delete() {
      DllCall(&quot;VirtualFreeEx&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr, &quot;UInt&quot;, 0, &quot;UInt&quot;, MEM_RELEASE := 0x8000)
      DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, this.hProc)
   }
   
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall(&quot;ReadProcessMemory&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr + offset, &quot;Ptr&quot;, &amp;localBuff, &quot;Ptr&quot;, size, &quot;PtrP&quot;, bytesRead)
         throw Exception(&quot;Can&#039;t read data from remote buffer`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.Read&quot;)
      Return bytesRead
   }
   
   Write(pData, size, offset = 0) {
      if !res := DllCall(&quot;WriteProcessMemory&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr + offset, &quot;Ptr&quot;, pData, &quot;Ptr&quot;, size, &quot;PtrP&quot;, bytesWritten)
         throw Exception(&quot;Can&#039;t write data to remote buffer`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.Write&quot;)
      Return bytesWritten
   }
}</code></pre></div><p>Папку, из которой будут показаны скрипты в подменю &quot;My Scripts&quot; нужно прописать в начале в переменной scriptDirectory.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2020-01-19T17:12:10Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137356#p137356</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137348#p137348" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>teadrinker пишет:</cite><blockquote><p>Там много чего не хватает</p></blockquote></div><p>думаю, для мини-менеджера этот набор функций был бы исчерпывающим.<br />Для остальных случаев можно скорректировать работу (отображение) <a href="https://github.com/Drugoy/Autohotkey-scripts-.ahk/blob/master/ScriptManager.ahk/MasterScript.ahk">MasterScript.ahk</a></p>]]></content>
			<author>
				<name><![CDATA[becauseim]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33149</uri>
			</author>
			<updated>2020-01-18T14:30:56Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137348#p137348</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137347#p137347" />
			<content type="html"><![CDATA[<p>Kill — это примерно как компьютер выключить выдёргиванием шнура из розетки.<br />Там много чего не хватает, это на данный момент скорее заготовка, чем рабочий скрипт.<br />Иконки можно, если знать пути к файлам, где они содержатся.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2020-01-18T14:21:46Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137347#p137347</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137346#p137346" />
			<content type="html"><![CDATA[<p><strong>teadrinker</strong>, круто! То, что нужно! Только не понял, в чем отличие <em>kill </em>от <em>exit</em>.</p><p>Понял, что не хватает пункта <em><strong>Edit</strong></em> и чекбокса для <em><strong>StartUp </strong></em>внутри управления на ряду с <em>Suspend, Pause</em>.., а так же некого <em><strong>watch folder</strong></em>, т.е. чтобы скрипты из директории рядом с мастер-скриптом автоматически отображались в списке трей-меню. А чтобы отличить, какие из списка запущены, а какие просто отображаются - добавить чекбоксы, т.е. его наличие отражает активность скрипта. Иными словами, получить <strong>возможность еще и быстро запускать скрипты из <em>watch folder</em></strong>.</p><p>Другой момент - не знаю, насколько это возможно - вкладывать иконки запущенных скриптов из трея, т.е. не отображать их отдельно, а только в списке мастер-скрипта. Понимаю, что это можно решить c помощью <em>#NoTrayIcon</em> для каждого скрипта, но часто в списке могут оказаться тестовые одноразовые скрипты, да и скрипты иногда можно запускать отдельно от мастер скрипта, и тогда ему уже нужна иконка в трее.</p>]]></content>
			<author>
				<name><![CDATA[becauseim]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33149</uri>
			</author>
			<updated>2020-01-18T14:09:17Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137346#p137346</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137343#p137343" />
			<content type="html"><![CDATA[<p>Вот, слепил из того, что было:<br /></p><div class="codebox"><pre><code>#NoEnv
SetBatchLines, -1
Menu, Tray, NoStandard
DetectHiddenWindows, On
OnMessage(0x404, &quot;AHK_NOTIFYICON&quot;)
Return

AHK_NOTIFYICON(wp, lp) {
   static WM_MOUSEMOVE := 0x200, WM_RBUTTONUP := 0x205, info
        , IsData := [], timer := Func(&quot;IsDataClear&quot;).Bind(IsData)
   if (lp = WM_MOUSEMOVE) {
      Critical
      if !IsData[1] {
         info := GetAhkScriptsInfo()
         IsData[1] := true
         SetTimer, % timer, -1000
      }
      Critical Off
   }
   if (lp = WM_RBUTTONUP) {
      names := {}
      for k, v in info {
         if names.HasKey(v.name) {
            i := 0
            Loop
               name := v.name . &quot; (&quot; . ++i . &quot;)&quot;
            until !names.HasKey(name)
            v.name := name
         }
         names[v.name] := &quot;&quot;
      }
      for name in names {
         for k, v in info {
            if (v.name != name)
               continue
            CreateSubMenu(k, v)
            item := v.name
            if v.suspended
               item .= A_Tab . &quot;Suspended&quot;
            else if v.paused
               item .= A_Tab . &quot;Paused&quot;
            Menu, MyMenu, Add, % item, :SubMenu%k%
         }
      }
      Menu, MyMenu, Add
      Menu, MyMenu, Add, Exit, ExitScript
      Menu, MyMenu, Show
      Loop % info.MaxIndex()
         Menu, SubMenu%A_Index%, DeleteAll
      Menu, MyMenu, DeleteAll
      IsData[1] := false
   }
}

IsDataClear(IsData) {
   IsData[1] := false
}

GetAhkScriptsInfo() {
   static Waiting := 5, Suspended := 5
        , MyPID := DllCall(&quot;GetCurrentProcessId&quot;)
   info := [], PIDs := {}
   WinGet, List, List, ahk_class AutoHotkey
   Loop % List {
      WinExist(&quot;ahk_id&quot; List%A_Index%)
      threadID := DllCall(&quot;GetWindowThreadProcessId&quot;, &quot;Ptr&quot;, List%A_Index%, &quot;UIntP&quot;, PID)
      if (PID = MyPID)
         continue
      PIDs[PID] := threadID
      WinGetTitle, title
      scriptPath := A_IsCompiled ? title : RegExReplace(title, &quot; - AutoHotkey v[\d\.]+&quot;)
      SplitPath, scriptPath, fileName
      info.Push({ scriptPath: scriptPath, name: fileName, PID: PID, hwnd: List%A_Index%, suspended: false, bitness: GetProcessBitness(PID) })
   }
   ThreadsInfo(PIDs)
   for k, v in info {
      v.threads := PIDs[ v.PID ]
      for k, j in PIDs[ v.PID ] {
         if !(j.ThreadState = Waiting &amp;&amp; j.WaitReason = Suspended)
            continue 2
         v.suspended := true
      }
   }
   for k, v in info
      if !v.suspended
         v.paused := IsPaused(v.hwnd)
   Return info
}

GetProcessBitness(PID) {
   if !A_Is64bitOS
      Return 32
   hProc := DllCall(&quot;OpenProcess&quot;, &quot;UInt&quot;, PROCESS_QUERY_INFORMATION := 0x400, &quot;UInt&quot;, 0, &quot;UInt&quot;, PID, &quot;Ptr&quot;)
   DllCall(&quot;IsWow64Process&quot;, &quot;Ptr&quot;, hProc, &quot;IntP&quot;, is32)
   DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, hProc)
   Return 32 &lt;&lt; !is32
}

ThreadsInfo(PIDs) {
   static SPI := SystemProcessInformation := 0x5, STATUS_SUCCESS := 0
        , szSPI := A_PtrSize = 4 ? 0xB8 : 0x100  ; size of SYSTEM_PROCESS_INFORMATION
        , szSTI := A_PtrSize = 4 ? 0x40 : 0x050  ; size of SYSTEM_THREAD_INFORMATION
        
   DllCall(&quot;Ntdll\NtQuerySystemInformation&quot;, &quot;Int&quot;, SPI, &quot;Ptr&quot;, 0, &quot;UInt&quot;, 0, &quot;UIntP&quot;, size, &quot;UInt&quot;)
   VarSetCapacity(buff, size, 0)
   addr := &amp;buff
   
   res := DllCall(&quot;Ntdll\NtQuerySystemInformation&quot;, &quot;Int&quot;, SPI, &quot;Ptr&quot;, addr, &quot;UInt&quot;, size, &quot;UIntP&quot;, 0, &quot;UInt&quot;)
   if (res != STATUS_SUCCESS)
      throw Exception( &quot;Could not get data from NtQuerySystemInformation. Error: &quot; . Format(&quot;{:#x}&quot;, res) )
   offset := 0
   Loop {
      addr += offset
      ProcessID := NumGet(addr + 4*14 + A_PtrSize*3)
      if !PIDs.HasKey(ProcessID)
         continue
      threadsCount := NumGet(addr + 4, &quot;UInt&quot;)
      mainThreadID := PIDs[ProcessID]
      PIDs[ProcessID] := []
      Loop % threadsCount {
         ThreadID := NumGet(addr + szSPI + 24 + A_PtrSize*3 + (A_Index - 1)*szSTI)
         if (ThreadID != mainThreadID)
            continue
         ThreadState := NumGet(addr + szSPI + 36 + A_PtrSize*4 + (A_Index - 1)*szSTI, &quot;UInt&quot;)
         WaitReason  := NumGet(addr + szSPI + 40 + A_PtrSize*4 + (A_Index - 1)*szSTI, &quot;UInt&quot;)
         PIDs[ProcessID].Push( {ThreadID: ThreadID, ThreadState: ThreadState, WaitReason: WaitReason} )
      }
   } until !offset := NumGet(addr + 0, &quot;UInt&quot;)
}

CreateSubMenu(k, info) {
   static MyBitness := GetProcessBitness( DllCall(&quot;GetCurrentProcessId&quot;) )
   if !(MyBitness = 32 &amp;&amp; info.bitness = 64) &amp;&amp; !(info.name ~= &quot;i)\.exe( \(\d+\))?$&quot;) {
      handler := Func(&quot;SuspendResumeThreads&quot;).Bind(info, k)
      Menu, SubMenu%k%, Add, Suspend Script, % handler
   }
   if info.suspended
      Menu, SubMenu%k%, Check, Suspend Script
   else {
      handler := Func(&quot;SelectMenuItem&quot;).Bind(info.hwnd, k, 5)
      Menu, SubMenu%k%, Add, Pause Script, % handler
      if info.paused
         Menu, SubMenu%k%, Check, Pause Script
      handler := Func(&quot;SelectMenuItem&quot;).Bind(info.hwnd, k, 8)
      Menu, SubMenu%k%, Add, Exit (Terminate Script), % handler
   }
   handler := Func(&quot;KillScript&quot;).Bind(info.PID)
   Menu, SubMenu%k%, Add, Kill Script, % handler
}

SelectMenuItem(hwnd, k, nMenu) {
   WinMenuSelectItem, ahk_id %hWnd%,, 1&amp;, % nMenu . &quot;&amp;&quot;
}

SuspendResumeThreads(info, k) {
   static MyBitness := GetProcessBitness( DllCall(&quot;GetCurrentProcessId&quot;) )
        , THREAD_SUSPEND_RESUME := 0x2
   for k, v in info.threads {
      hThread := DllCall(&quot;OpenThread&quot;, &quot;UInt&quot;, THREAD_SUSPEND_RESUME, &quot;UInt&quot;, false, &quot;UInt&quot;, v.ThreadID, &quot;Ptr&quot;)
      if info.suspended
         DllCall(&quot;ResumeThread&quot;, &quot;Ptr&quot;, hThread)
      else {
         if (MyBitness = info.bitness)
            DllCall(&quot;SuspendThread&quot;, &quot;Ptr&quot;, hThread)
         else
            DllCall(&quot;Wow64SuspendThread&quot;, &quot;Ptr&quot;, hThread)
      }
      DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, hThread)
   }
}

KillScript(PID) {
   Process, Close, % PID
   Process, WaitClose, % PID
   DeleteDummyIcons()
}

IsPaused(hWnd) {
   static WM_ENTERMENULOOP := 0x211, WM_EXITMENULOOP := 0x212, MF_BYPOSITION := 0x400, MF_CHECKED := 8
        , Params := [&quot;Ptr&quot;, 0, &quot;Ptr&quot;, 0, &quot;UInt&quot;, SMTO_ABORTIFHUNG := 0x2|SMTO_ERRORONEXIT := 0x20, &quot;UInt&quot;, 500, &quot;Ptr&quot;, 0]
   Loop 2
      if !DllCall(&quot;SendMessageTimeout&quot;, Ptr, hWnd, UInt, A_Index = 1 ? WM_ENTERMENULOOP : WM_EXITMENULOOP, Params*)
         Return
   hWinMenu := DllCall(&quot;GetMenu&quot;, Ptr, hWnd, Ptr)
   hFileMenu := DllCall(&quot;GetSubMenu&quot;, Ptr, hWinMenu, Int, 0, Ptr)
   Return DllCall(&quot;GetMenuState&quot;, Ptr, hFileMenu, UInt, 4, UInt, MF_BYPOSITION) = MF_CHECKED   ; Pause state
}

ExitScript() {
   ExitApp
}

DeleteDummyIcons()
{
   static PtrSize := A_Is64bitOS ? 8 : 4, WM_USER := 0x400
        , TB_BUTTONCOUNT := WM_USER + 24, TB_GETBUTTON := WM_USER + 23
        , szTBBUTTON := 8 + PtrSize*3, szTRAYDATA := 16 + PtrSize*2
   
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   ControlGet, hTray, hwnd,, ToolbarWindow321, ahk_class Shell_TrayWnd
   ControlGet, hOverflow, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
   WinGet, PID, PID, ahk_id %hTray%

   RemoteBuff := New RemoteBuffer(PID, szTRAYDATA)
   Dummy := []
   Loop 2
   {
      hwnd := A_Index = 1 ? hTray : hOverflow
      SendMessage, TB_BUTTONCOUNT,,,, ahk_id %hwnd%
      Loop % ErrorLevel
      {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr,, ahk_id %hwnd%
         RemoteBuff.Read(TBBUTTON, szTBBUTTON)
         
         RemoteBuff.Read(TRAYDATA, szTRAYDATA, NumGet(&amp;TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr)
         hWndIcon := NumGet(TRAYDATA), uID := NumGet(&amp;TRAYDATA + PtrSize, &quot;UInt&quot;)
         
         if !WinExist(&quot;ahk_id&quot; hWndIcon)
            Dummy.Insert({hWnd: hWndIcon, uID: uID})
      }
   }
   DetectHiddenWindows, %DHW_Prev%
   for k, v in Dummy
      RemoveTrayIcon(v.hWnd, v.uID)
}

RemoveTrayIcon(hWnd, uID)
{
   VarSetCapacity(NOTIFYICONDATA, size := A_PtrSize = 8 ? 848 : A_IsUnicode? 828 : 444, 0)
   NumPut(size, NOTIFYICONDATA, &quot;UInt&quot;)
   NumPut(hWnd, NOTIFYICONDATA, A_PtrSize)
   NumPut(uID, NOTIFYICONDATA, 2*A_PtrSize)
   DllCall(&quot;shell32\Shell_NotifyIcon&quot;, &quot;UInt&quot;, NIM_DELETE := 2, Ptr, &amp;NOTIFYICONDATA)
   Return
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := [&quot;UInt&quot;, MEM_COMMIT := 0x1000, &quot;UInt&quot;, PAGE_READWRITE := 0x4, &quot;Ptr&quot;]
         
      if !this.hProc := DllCall(&quot;OpenProcess&quot;, &quot;UInt&quot;, flags, &quot;Int&quot;, 0, &quot;UInt&quot;, PID, &quot;Ptr&quot;)
         throw Exception(&quot;Can&#039;t open remote process PID = &quot; . PID . &quot;`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.__New&quot;)
      
      if !this.ptr := DllCall(&quot;VirtualAllocEx&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, 0, &quot;Ptr&quot;, size, Params*) {
         DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, this.hProc)
         throw Exception(&quot;Can&#039;t allocate memory in remote process PID = &quot; . PID . &quot;`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.__New&quot;)
      }
   }
   
   __Delete() {
      DllCall(&quot;VirtualFreeEx&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr, &quot;UInt&quot;, 0, &quot;UInt&quot;, MEM_RELEASE := 0x8000)
      DllCall(&quot;CloseHandle&quot;, &quot;Ptr&quot;, this.hProc)
   }
   
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall(&quot;ReadProcessMemory&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr + offset, &quot;Ptr&quot;, &amp;localBuff, &quot;Ptr&quot;, size, &quot;PtrP&quot;, bytesRead)
         throw Exception(&quot;Can&#039;t read data from remote buffer`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.Read&quot;)
      Return bytesRead
   }
   
   Write(pData, size, offset = 0) {
      if !res := DllCall(&quot;WriteProcessMemory&quot;, &quot;Ptr&quot;, this.hProc, &quot;Ptr&quot;, this.ptr + offset, &quot;Ptr&quot;, pData, &quot;Ptr&quot;, size, &quot;PtrP&quot;, bytesWritten)
         throw Exception(&quot;Can&#039;t write data to remote buffer`nA_LastError: &quot; . A_LastError, &quot;RemoteBuffer.Write&quot;)
      Return bytesWritten
   }
}</code></pre></div><p>И для скомпилированных, и для обычных.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2020-01-18T11:16:37Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137343#p137343</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137342#p137342" />
			<content type="html"><![CDATA[<p>Наверное ещё стоит уточнить, требуется управление ahk-скриптами или скомпилированным exe-скриптами.</p>]]></content>
			<author>
				<name><![CDATA[ypppu]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=5974</uri>
			</author>
			<updated>2020-01-18T09:15:46Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137342#p137342</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[AHK: Tiny Master Script]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=137335#p137335" />
			<content type="html"><![CDATA[<p>Ищу мастер скрипт для управления запущенными скриптами. Перебрал найденные на форуме варианты - выходят ошибки о недостающих элементах и <a href="https://i.imgur.com/bgvEg6A.png">некорректно отображаются</a>. Вероятно, многие здесь имеют у себя отлаженные образцы менеджеров скриптов. Прошу поделиться. В идеале, это <strong>трей-меню</strong> с отображением всех запущенных скриптов с возможностью их завершения/заморозки без дополнительных окон с вкладками и подробной информацией. Ну или какой есть.</p>]]></content>
			<author>
				<name><![CDATA[becauseim]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33149</uri>
			</author>
			<updated>2020-01-18T01:42:16Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=137335#p137335</id>
		</entry>
</feed>
