26

Re: AHK: Самозакрытие при повторном запуске

Malcev пишет:

Так не сработает:

Это уже из области извращений. Понятно, что если изменить название скрипта, не сработает. serzh82saratov, всё равно тебя не понял. Давай сначала. В чём могут быть проблемы такого варианта?

#Persistent
#SingleInstance, Off
if CloseCopy() || RegExMatch(StrGet(DllCall("GetCommandLine", Ptr)), "i)\s/(restart|r)(\s|$)")
   ExitApp
Return

CloseCopy()  {
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinGet, List, List, % A_ScriptFullPath " ahk_class AutoHotkey"
   Loop % List
      if WinExist("ahk_id" List%A_Index%) != A_ScriptHwnd && res := true
         WinClose
   DetectHiddenWindows, % DHW_Prev
   Return res
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

27

Re: AHK: Самозакрытие при повторном запуске

По сабжу скрипт должен запускатся если нет другого запущенного экземпляра.
Даже если мы его запускаем из CMD или с ярлыка например с ключом restart.

По вопросам возмездной помощи пишите в личку
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.25.01 (Unicode 32-bit).

28

Re: AHK: Самозакрытие при повторном запуске

teadrinker, я ничего не менял.
Я имею в виду, что если скрипт зависнет на какой-либо операции, то он с твоим кодом закроется только после окончания этой операции.

29

Re: AHK: Самозакрытие при повторном запуске

А, теперь понял. Да кому в голову придёт запускать с ключом restart, если это не нужно, и тем более, если так не запускается?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

30 (изменено: teadrinker, 2017-01-06 19:41:09)

Re: AHK: Самозакрытие при повторном запуске

Malcev пишет:

то он с твоим кодом закроется только после окончания этой операции

А, ясно. Ну предложи обходной вариант. WinKill можно попробовать. Но сомневаюсь, что это входит в задачу.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

31

Re: AHK: Самозакрытие при повторном запуске

Да кому в голову придёт запускать с ключом restart, если это не нужно, и тем более, если так не запускается?

Если ты не допускаешь такую вероятность, то почему допускаешь то что в скрипте будет команда Reload?
Команда Reload менее вероятна, чем невероятное предположение того что её со стороны зачем то запустят с таким ключом.
Команды Reload не должно быть в принципе, потому как по задаче вместо неё ExitApp.
Зачем прописывать в самом скрипте Reload, а потом думать как их все закрыть?
Вот и вопрос - зачем проверять такой ключ, если ты сам не ждёшь его "со стороны"?

По вопросам возмездной помощи пишите в личку
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.25.01 (Unicode 32-bit).

32

Re: AHK: Самозакрытие при повторном запуске

и тем более, если так не запускается?

По ТЗ должен запускатся, если не запущен другой.

По вопросам возмездной помощи пишите в личку
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.25.01 (Unicode 32-bit).

33 (изменено: teadrinker, 2017-01-06 19:51:55)

Re: AHK: Самозакрытие при повторном запуске

serzh82saratov пишет:

то почему допускаешь то что в скрипте будет команда Reload?

Не пойму, где у меня в скрипте Reload? А в командной строке restart появится автоматически, если перезапускать через меню.

serzh82saratov пишет:

По ТЗ должен запускатся, если не запущен другой.

Ну и запускай обычным способом, в чём проблема. Зачем с ключом restart-то?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

34

Re: AHK: Самозакрытие при повторном запуске

Про меню не подумал, стандартное из трея убрать можно, а из главного окна геморойно. Тогда ок.

Кстати почему

StrGet(DllCall("GetCommandLine", Ptr))

а не

DllCall("GetCommandLine", Str)
По вопросам возмездной помощи пишите в личку
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.25.01 (Unicode 32-bit).

35

Re: AHK: Самозакрытие при повторном запуске

Ну предложи обходной вариант. WinKill можно попробовать

WinKill не сработает.

#Persistent
#SingleInstance, Off
OnExit, Exit
if CloseCopy() || RegExMatch(StrGet(DllCall("GetCommandLine", Ptr)), "i)\s/(restart|r|force|f)\s")
   ExitApp
Runwait, C:\Windows\System32\fsutil.exe file createnew D:\test.txt 10000000000
FileCopy D:\test.txt, D:\test1.txt, 1
Return

Exit:
	ExitApp

CloseCopy()  {
   DHW_Prev := A_DetectHiddenWindows
   DetectHiddenWindows, On
   WinGet, List, List, % A_ScriptFullPath " ahk_class AutoHotkey"
   Loop % List
   {
      if WinExist("ahk_id" List%A_Index%) != A_ScriptHwnd && res := true
      {
         WinClose
         WinWaitClose,,, 0
         if ErrorLevel
         {
            WinGet, PID, PID, % "ahk_id" List%A_Index%
            Process, Close, %PID%
            Process, WaitClose, %PID%
            NoTrayOrphans()     ; очистить трей от иконок закрытых приложений
         }
      }
   }
   DetectHiddenWindows, % DHW_Prev
   Return res
}


NoTrayOrphans()
{
    TrayInfo := TrayIcons("ahk_class Shell_TrayWnd", "ToolbarWindow32" . GetTrayBar())  
        . TrayIcons("ahk_class NotifyIconOverflowWindow", "ToolbarWindow321")
 
    Loop, Parse, TrayInfo, `n
    {  
        PID := StrX(A_Loopfield, "| PID: ", " |") 
        If !PID
            RemoveTrayIcon(StrX(A_Loopfield, "| hWnd: ", " |"), StrX(A_Loopfield, "| uID: ", " |"))   
    }
}

TrayIcons(traywindow, control)  
{
    DetectHiddenWindows, On
    WinGet, pidTaskbar, PID, %traywindow%
    hProc := DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
    pProc := DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0, "Uint", 32, "Uint", 0x1000, "Uint", 0x4)
    SendMessage, 0x418, 0, 0, %control%, %traywindow%
    Loop, %ErrorLevel%
    {
        SendMessage, 0x417, A_Index - 1, pProc, %control%, %traywindow%
        VarSetCapacity(btn, 32, 0), VarSetCapacity(nfo, 32, 0)
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pProc, "Uint", &btn, "Uint", 32, "Uint", 0)
        iBitmap := NumGet(btn, 0)
        idn := NumGet(btn, 4)
        Statyle := NumGet(btn, 8)
        If dwData := NumGet(btn, 12)
            iString := NumGet(btn, 16)
        Else
        {
            dwData := NumGet(btn, 16, "int64")
            iString := NumGet(btn, 24, "int64")
        }
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 32, "Uint", 0)
        If NumGet(btn,12)
        {
            hWnd := NumGet(nfo, 0)
            uID := NumGet(nfo, 4)
            nMsg := NumGet(nfo, 8)
            hIcon := NumGet(nfo, 20)
        }
        Else
        {
            hWnd := NumGet(nfo, 0, "int64")
            uID := NumGet(nfo, 8)
            nMsg := NumGet(nfo, 12)
            hIcon := NumGet(nfo, 24)
        }
        WinGet, pid, PID, ahk_id %hWnd%
        WinGet, sProcess, ProcessName, ahk_id %hWnd%
        WinGetClass, sClass, ahk_id %hWnd% 
        VarSetCapacity(sTooltip, 128)
        VarSetCapacity(wTooltip, 128*2)
        DllCall("ReadProcessMemory", "Uint", hProc, "Uint", iString, "Uint", &wTooltip, "Uint", 128*2, "Uint", 0)
        DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0)
        sTrayIcons .= "| Pid: " pid " | uID: " uID " | hWnd: " hWnd " |`n" 
    }
    DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pProc, "Uint", 0, "Uint", 0x8000)
    DllCall("CloseHandle", "Uint", hProc)
    Return sTrayIcons
}

GetTrayBar()
{
    ControlGet, hParent, hWnd,, TrayNotifyWnd1, ahk_class Shell_TrayWnd
    ControlGet, hChild, hWnd,, ToolbarWindow321, ahk_id %hParent%
    Loop
    {
        ControlGet, hWnd, hWnd,, ToolbarWindow32%A_Index%, ahk_class Shell_TrayWnd
        If (hWnd == hChild)
            idxTB := A_Index
        If !hWnd || (hWnd == hChild)
            Break
    }
    Return idxTB
}

StrX(H, BS = "", ES = "", Tr = 1, ByRef OS = 1)
{
    Return (SP := InStr(H, BS, 0, OS)) && (L := InStr(H, ES, 0, SP + StrLen(BS))) && (OS := L + StrLen(ES)) ? SubStr(H, SP := Tr ? SP + StrLen(BS) : SP, (Tr ? L : L + StrLen(ES)) -SP) : ""
}

RemoveTrayIcon(hWnd, uID, nMsg = 0, hIcon = 0, nRemove = 2)
{
    NumPut(VarSetCapacity(ni,444,0), ni)
    NumPut(hWnd, ni, 4)
    NumPut(uID, ni, 8)
    NumPut(1|2|4, ni, 12)
    NumPut(nMsg, ni, 16)
    NumPut(hIcon, ni, 20)
    Return DllCall("shell32\Shell_NotifyIconA", "Uint", nRemove, "Uint", &ni)
}

36

Re: AHK: Самозакрытие при повторном запуске

Ну, если сильно заморачиваться, можно и так. Проверку ключей лучше делать, как тут, а предыдущий вариант не сработает, если скрипт будет скомпилирован.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

37

Re: AHK: Самозакрытие при повторном запуске

Не, народ, мне нужно что-то полегче для процессорной накачки. Иконки в трее можно опустить, их скорее не будет.
Не нравится, что в скриптах, где, скажем, выполняется быстрый хоткей постоянно будет крутиться функция с циклом поиска окон, почему я и хочу проверять по A_ExitReason или какому-то иному событию.

38

Re: AHK: Самозакрытие при повторном запуске

Flasher пишет:

постоянно будет крутиться функция с циклом поиска окон

А с чего ей постоянно крутиться? Поиск окон идёт только один раз при запуске.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

39

Re: AHK: Самозакрытие при повторном запуске

А как же Return?

40

Re: AHK: Самозакрытие при повторном запуске

Который? У меня всё вроде на месте. В цикле столько итераций, сколько есть окон с путём скрипта в заголовке.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

41 (изменено: Flasher, 2017-01-06 21:26:16)

Re: AHK: Самозакрытие при повторном запуске

Поспешил с выводами. Ладно, пойдёт.

Но с #SingleInstance, Force было бы лучше.

42

Re: AHK: Самозакрытие при повторном запуске

Если без WMI, то так можно:

#Persistent
#SingleInstance, force
OnExit(Func("Exit"))
Return

Exit(ExitReason)  {
   if ExitReason not in Single,Reload
      Return
   
   MyPID := DllCall("GetCurrentProcessId")
   VarSetCapacity(buff, buffSize := 4096, 0)
   DllCall("Psapi\EnumProcesses", Ptr, &buff, UInt, buffSize, UIntP, bytes)
   Loop % bytes//4  {
      PID := NumGet(buff, A_Index * 4, "UInt")
      if (MyPID != PID && InStr(GetCommandLine(PID), A_ScriptFullPath))
         Process, Close, % PID
   }
}

GetCommandLine(PID)  {
   static SYNCHRONIZE := 0x100000, STANDARD_RIGHTS_REQUIRED := 0xF0000, offsetSize := A_IsUnicode ? 2 : 1
        , PROCESS_ALL_ACCESS := STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xFFF, INFINITE := 0xFFFFFFFF
        
   hProc := DllCall("OpenProcess", UInt, PROCESS_ALL_ACCESS, Int, 0, UInt, PID, Ptr)
   if A_Is64bitOS  {
      DllCall("IsWow64Process", Ptr, hProc, UIntP, bool)
      if (bool && A_PtrSize = 8) || (!bool && A_PtrSize = 4)  {
         DllCall("CloseHandle", Ptr, hProc)
         ; MsgBox, Скрипт и целевой процесс разных битностей, функция не будет работать!
         Return
      }
   }
   hModule := DllCall("GetModuleHandle", "str", "Kernel32.dll", Ptr)
   pFunc := DllCall("GetProcAddress", Ptr, hModule, AStr, "GetCommandLine" . (A_IsUnicode ? "W" : "A"), Ptr)
   if !hThrd := DllCall("CreateRemoteThread", Ptr, hProc, Ptr, 0, Ptr, 0, Ptr, pFunc, Ptr, 0, UInt, 0, UInt, 0)  {
      DllCall("CloseHandle", Ptr, hProc)
      Return
   }
   DllCall("WaitForSingleObject", Ptr, hThrd, UInt, INFINITE)
   DllCall("GetExitCodeThread", Ptr, hThrd, UIntP, pPtr)
   DllCall("CloseHandle", Ptr, hThrd)

   VarSetCapacity(buff, 2048, 0)
   Loop  {
      offset := (A_Index - 1) * offsetSize
      DllCall("ReadProcessMemory", Ptr, hProc, Ptr, pPtr + offset, Ptr, &buff + offset, Ptr, offsetSize, Ptr, 0)
   } until !NumGet(&buff + offset, A_IsUnicode ? "UShort" : "UChar")

   DllCall("CloseHandle", Ptr, hProc)
   Return StrGet(&buff)
}

Или так:

#Persistent
#SingleInstance, force
OnExit(Func("Exit"))
Return

Exit(ExitReason)  {
   if ExitReason not in Single,Reload
      Return
   
   MyPID := DllCall("GetCurrentProcessId")
   VarSetCapacity(buff, buffSize := 4096, 0)
   DllCall("Psapi\EnumProcesses", Ptr, &buff, UInt, buffSize, UIntP, bytes)
   Loop % bytes//4  {
      PID := NumGet(buff, A_Index * 4, "UInt")
      if (MyPID != PID && InStr(GetCommandLine(PID), A_ScriptFullPath))
         Process, Close, % PID
   }
}

GetCommandLine(PID)  {
   static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10
   
   VarSetCapacity(PBI, 48)
   hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, Int, 0, UInt, PID, Ptr)

   (A_Is64bitOS && DllCall("IsWow64Process", Ptr, hProc, UIntP, IsWow64))
   if (!A_Is64bitOS || IsWow64)
      PtrSize := 4, szPtr := "UInt", pPtr := "UIntP", offsetCMD := 0x44
   else
      PtrSize := 8, szPtr := "UInt64", pPtr := "UInt64P", offsetCMD := 0x78

   if (A_PtrSize < PtrSize)  {    ; скрипт 32, процесс 64
      QueryInformationProcess := "Ntdll\NtWow64QueryInformationProcess64"
      ReadProcessMemory := "Ntdll\NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else  {
      QueryInformationProcess := "Ntdll\NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)    ; скрипт 64, процесс 32
         info := 26, szPBI := 8, offsetPEB := 0
      else
         info := 0, szPBI := PtrSize * 6, OffsetPEB := PtrSize
   }
   DllCall(QueryInformationProcess, Ptr, hProc, UInt, info, Ptr, &PBI, UInt, szPBI, pPtr, bytes)
   pPEB := NumGet(&PBI + OffsetPEB, szPtr)
   DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pPEB + PtrSize * 4, pPtr, pRUPP, szPtr, PtrSize, pPtr, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pRUPP + offsetCMD, pPtr, pCMD, szPtr, PtrSize, pPtr, bytes)

   VarSetCapacity(buff, 1024, 0)
   Loop  {
      offset := (A_Index - 1) * 2
      DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pCMD + offset, Ptr, &buff + offset, szPtr, 2, pPtr, bytes)
   } until !NumGet(&buff + offset, "UShort")

   DllCall("CloseHandle", Ptr, hProc)
   Return StrGet(&buff, "UTF-16")
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

43

Re: AHK: Самозакрытие при повторном запуске

На 32-бит оба не срабатывают.

44

Re: AHK: Самозакрытие при повторном запуске

У меня оба срабатывают. А какая ОС?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

45

Re: AHK: Самозакрытие при повторном запуске

Вот я про неё как раз.

46

Re: AHK: Самозакрытие при повторном запуске

Только что специально в XP x86 перезагрузился, попробовал — всё работает, так что не знаю, в чём проблема. Проверяй версию AHK.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

47

Re: AHK: Самозакрытие при повторном запуске

Win 7 SP1 Max x86, AutoHotkey(A|U)32.exe 1.1.24.04.
Процесс остаётся на месте. После второго вызова часто выскакивает окно:

[Window Title]
AutoHotkey Unicode 32-bit

[Main Instruction]
Прекращена работа программы "AutoHotkey Unicode 32-bit"

[Content]
Возникшая проблема привела к прекращению работы программы. Закройте эту программу.

[Закрыть программу]

48

Re: AHK: Самозакрытие при повторном запуске

Также.

По вопросам возмездной помощи пишите в личку
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.25.01 (Unicode 32-bit).

49 (изменено: teadrinker, 2017-01-08 23:32:43)

Re: AHK: Самозакрытие при повторном запуске

Подправленный второй вариант:

#Persistent
#SingleInstance, force
OnExit(Func("Exit"))
Return

Exit(ExitReason)  {
   if ExitReason not in Single,Reload
      Return
   
   MyPID := DllCall("GetCurrentProcessId")
   VarSetCapacity(buff, buffSize := 4096, 0)
   DllCall("Psapi\EnumProcesses", Ptr, &buff, UInt, buffSize, UIntP, bytes)
   Loop % bytes//4  {
      PID := NumGet(buff, A_Index * 4, "UInt")
      if (MyPID != PID && InStr(GetCommandLine(PID), A_ScriptFullPath))
         Process, Close, % PID
   }
}

GetCommandLine(PID)  {
   static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10
   
   VarSetCapacity(PBI, 48)
   hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, Int, 0, UInt, PID, Ptr)

   (A_Is64bitOS && DllCall("IsWow64Process", Ptr, hProc, UIntP, IsWow64))
   if (!A_Is64bitOS || IsWow64)
      PtrSize := 4, szPtr := "UInt", pPtr := "UIntP", offsetCMD := 0x44
   else
      PtrSize := 8, szPtr := "Int64", pPtr := "Int64P", offsetCMD := 0x78

   if (A_PtrSize < PtrSize)  {    ; скрипт 32, процесс 64
      QueryInformationProcess := "Ntdll\NtWow64QueryInformationProcess64"
      ReadProcessMemory := "Ntdll\NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else  {
      QueryInformationProcess := "Ntdll\NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)    ; скрипт 64, процесс 32
         info := 26, szPBI := 8, offsetPEB := 0
      else
         info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
   }
   DllCall(QueryInformationProcess, Ptr, hProc, UInt, info, Ptr, &PBI, UInt, szPBI, pPtr, bytes)
   pPEB := NumGet(&PBI + offsetPEB, szPtr)
   DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pPEB + PtrSize * 4, pPtr, pRUPP, szPtr, PtrSize, pPtr, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pRUPP + offsetCMD, pPtr, pCMD, szPtr, PtrSize, pPtr, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pRUPP + offsetCMD - PtrSize, UShortP, szCMD, szPtr, 2, pPtr, bytes)
   
   VarSetCapacity(buff, szCMD, 0)
   DllCall(ReadProcessMemory, Ptr, hProc, szPtr, pCMD, Ptr, &buff, szPtr, szCMD, pPtr, bytes)
   DllCall("CloseHandle", Ptr, hProc)
   Return StrGet(&buff, "UTF-16")
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

50

Re: AHK: Самозакрытие при повторном запуске

Ещё немного подправил размерность в связи с

Unsigned 64-bit integers produced by a function are not supported.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg