1

Тема: AHK: Деактивация окон сторонних процессов

Если определить родительским окном, окно другого процесса, то при клике по дочернему, родительское деактивируется, чего не произошло бы, если бы родительское окно принадлежало процессу дочернего.
Можно конечно дочернему добавить WS_EX_NOACTIVATE, но возникает много разных проблем взаимодействия с большинством контролов.

Также интересует как можно использовать стандартное меню не деактивируя окна сторонних процессов. Напомню, что окна одного с меню процесса не деактивируются.
По этому вопросу нашёл только одну не решённую тему https://autohotkey.com/board/topic/9071 … s-problem/.

Код демонстрирующий проблему.

#SingleInstance Off
#Persistent
#NoEnv

p = %1%
if p = 
{  
	Gui, Show, w444 h444, ______#######______
	Run %A_ScriptFullPath% 1
	Return
}
 
Gui, New
WS_EX_NOACTIVATE := 0x8000000
; Gui, +E%WS_EX_NOACTIVATE%  
Gui, +HwndhGui -Caption
Gui, Color, 00ff00 
DllCall("SetParent", "Ptr", hGui, "Ptr", WinExist("______#######______"))
Gui, Show, x5 y5 w111 h111
OnMessage(0x204, "WM_RBUTTONDOWN")  
Menu, TestMenu, Add, 1, Return
Menu, TestMenu, Add, 2, Return
Return:
	Return

WM_RBUTTONDOWN(wp, lp, msg, hwnd) {  
    Menu, TestMenu, Show 
}

~Esc:: ExitApp
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

2 (изменено: teadrinker, 2020-05-26 23:47:19)

Re: AHK: Деактивация окон сторонних процессов

Это уже обсуждали когда-то.

SetParent пишет:

For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. ... if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style before calling SetParent.

Это всё автоматически делает GUI-опция +Parent%hwnd%.
По поводу меню — я лично просто создал меню изнутри другого процесса через инжект AutoHotkey.dll, по-другому не знаю как.

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

3

Re: AHK: Деактивация окон сторонних процессов

teadrinker пишет:

Это уже обсуждали когда-то.

Да, я про это уже раз третий забываю.

teadrinker пишет:

по-другому не знаю как.

Это https://docs.microsoft.com/ru-ru/window … er-setmenu по твоему может как то относится к вопросу?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

4

Re: AHK: Деактивация окон сторонних процессов

Так не работает.

WM_RBUTTONDOWN(wp, lp, msg, hwnd) {  
	hMenu := MenuGetHandle("TestMenu")
	DllCall("SetMenu", "Ptr", WinActive("A"), "Ptr", hMenu)
	Menu, TestMenu, Show 
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

5

Re: AHK: Деактивация окон сторонних процессов

SetMenu — это для оконного меню, в меню-баре.

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

6

Re: AHK: Деактивация окон сторонних процессов

А ты как инжектил, у меня всё равно деактивирует, но процесс меню от блокнота.


SetWorkingDir %A_ScriptDir%
#SingleInstance Force
#NoEnv
#Persistent  

code =
(LTrim

#NoEnv
#Persistent 
Menu, TestMenu, Add, 1, Return
Menu, TestMenu, Add, 2, Return
Return

f1::
Menu, TestMenu, Show 
Return

Return:
	Return
	
	
)

if (A_Is64bitOS && A_PtrSize = 4)
{
	Run, %A_AhkPath%\..\AutoHotkeyU64.exe "%A_ScriptFullPath%", %A_ScriptDir%
	ExitApp
}

Run, notepad,,, pid
WinWait, ahk_pid %pid%

dllFile := FileExist("AutoHotkey.dll") ? A_ScriptDir "\AutoHotkey.dll"
          : (A_PtrSize = 8)                  ? A_ScriptDir "\ahkDll\x64\AutoHotkey.dll"
          : A_ScriptDir "\ahkDll\x32\AutoHotkey.dll"
rThread := InjectAhkDll(pid, dllFile, "")
rThread.Exec(code)   
return



InjectAhkDll(PID,dll:="AutoHotkey64.dll",script:=0, deleteThread := false)
{
   static PROCESS_ALL_ACCESS:=0x1F0FFF,MEM_COMMIT := 0x1000,MEM_RELEASE:=0x8000,PAGE_EXECUTE_READWRITE:=64
   ,hKernel32:=DllCall("LoadLibrary","Str","kernel32.dll","PTR"),LoadLibraryA:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","LoadLibraryA","PTR")
   ,FreeLibrary:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","FreeLibrary","PTR")
   ,TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1
   ,MAX_PATH:=260,MAX_MODULE_NAME32:=255,ModuleName:="",init:=VarSetCapacity(ModuleName,MAX_PATH*(A_IsUnicode?2:1))
   base:= deleteThread ? {__Call:"InjectAhkDll",__Delete:"InjectAhkDll"} : {__Call:"InjectAhkDll"}

   if IsObject(PID)
   {
      if (dll!="Exec" && script)
         return "Only Exec method can be used here!"

      hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID.PID,"PTR")
      if !hProc
         return "Could not open process for PID: " PID.PID

      if (!script) ; Free Library in remote process (object is being deleted)
      {
         ; Terminate the thread in ahkdll
         hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", PID.ahkTerminate, "PTR", 0, "UInt", 0, "PTR", 0,"PTR")
         DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
         ,DllCall("CloseHandle", "PTR", hThread)

         ; Free library in remote process
         hThread := DllCall("CreateRemoteThread", "PTR", hProc, "UInt", 0, "UInt", 0, "PTR", FreeLibrary, "PTR", PID.hModule, "UInt", 0, "UInt", 0,"PTR")
         DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
         ,DllCall("CloseHandle", "PTR", hThread),DllCall("CloseHandle", "PTR", hProc)
         return
      }

      nScriptLength := VarSetCapacity(nScript, (StrLen(script)+1)*(A_IsUnicode?2:1), 0)
      ,StrPut(script,&nScript)

      ; Reserve memory in remote process where our script will be saved
      if !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nScriptLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
         return "Could not reseve memory for process"
      ,DllCall("CloseHandle", "PTR", hProc)

      ; Write script to remote process memory
      DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nScript, "PTR", nScriptLength, "Ptr", 0)

      ; Start execution of code
      hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", PID.ahkExec, "PTR", pBufferRemote, "UInt", 0, "PTR", 0,"PTR")
      if !hThread
      {
         DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nScriptLength,MEM_RELEASE)
         ,DllCall("CloseHandle", "PTR", hProc)
         return "Could not execute script in remote process"
      }

      ; Wait for thread to finish
      DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)

      ; Get Exit code returned by ahkExec (1 = script could be executed / 0 = script could not be executed)
      DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode)
      if !lpExitCode
         return "Could not execute script in remote process"

      DllCall("CloseHandle", "PTR", hThread)
      ,DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nScriptLength,MEM_RELEASE)
      ,DllCall("CloseHandle", "PTR", hProc)
      return
   }
   else if !hDll:=DllCall("LoadLibrary","Str",dll,"PTR")
      return "Could not find " dll " library", DllCall("CloseHandle", "PTR", hProc)
   else
   {
      hProc := DllCall("OpenProcess","UInt", PROCESS_ALL_ACCESS, "Int",0,"UInt", DllCall("GetCurrentProcessId"),"PTR")
      DllCall("GetModuleFileName","PTR",hDll,"PTR",&ModuleName,"UInt",MAX_PATH)
      DllCall("CloseHandle","PTR",hProc)
   }
   ; Open Process to PID
   hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID,"PTR")
   if !hProc
      return "Could not open process for PID: " PID
   
   Loop, Files, %dll%, F
      dll := A_LoopFileLongPath
   ; Reserve some memory and write dll path (ANSI)
   nDirLength := VarSetCapacity(nDir, StrLen(dll)+1, 0)
   ,StrPut(dll,&nDir,"CP0")

   ; Reserve memory in remote process
   if !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nDirLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
      return "Could not reseve memory for process", DllCall("CloseHandle", "PTR", hProc)

   ; Write dll path to remote process memory
   DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nDir, "PTR", nDirLength, "Ptr", 0)

   ; Start new thread loading our dll

   hThread:=DllCall("CreateRemoteThread","PTR",hProc,"PTR",0,"PTR",0,"PTR",LoadLibraryA,"PTR",pBufferRemote,"UInt",0,"PTR",0,"PTR")
   if !hThread
   {
      DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,"Uint",MEM_RELEASE)
      ,DllCall("CloseHandle", "PTR", hProc)
      return "Could not load " dll " in remote process"
   }
   ; Wait for thread to finish
   DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)

   ; Get Exit code returned by thread (HMODULE for our dll)
   DllCall("GetExitCodeThread", "PTR", hThread, "UInt*", hModule)

   ; Close Thread
   DllCall("CloseHandle", "PTR", hThread)

   if (A_PtrSize=8)
   { ; use different method to retrieve base address because GetExitCodeThread returns DWORD only
      hModule:=0,VarSetCapacity(me32, (A_PtrSize=8?48:32)+(A_IsUnicode?1032:516), 0) ;W:1080:1064, A:564:548
      ;  Take a snapshot of all modules in the specified process.
      hModuleSnap := DllCall("CreateToolhelp32Snapshot","UInt", TH32CS_SNAPMODULE,"UInt", PID, "PTR" )
      if ( hModuleSnap != INVALID_HANDLE_VALUE )
      {
         ; reset hModule and set the size of the structure before using it.
         NumPut((A_PtrSize=8?48:32)+(A_IsUnicode?1032:516), &me32, 0, "UInt") ;dwSize  ;W:1080:1064, A:564:548
         ;  Retrieve information about the first module,
         ;  and exit if unsuccessful
         if ( !DllCall("Module32First" (A_IsUnicode?"W":""),"PTR", hModuleSnap,"PTR", &me32 ) )
         {
            ; Free memory used for passing dll path to remote thread
            DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE)
            ,DllCall("CloseHandle","PTR", hModuleSnap ) ; Must clean up the snapshot object!
            return false
         }
         ;  Now walk the module list of the process,and display information about each module
         while(A_Index=1 || DllCall("Module32Next" (A_IsUnicode?"W":""),"PTR",hModuleSnap,"PTR", &me32 ) )
            if (StrGet(&me32+(A_PtrSize=8?48:32)+(A_IsUnicode?512:256))=dll) ;szExePath ;W:560:544, A:304:288
            {
               hModule := NumGet(me32, A_PtrSize=8?40:28, "Ptr") ;hModule
               break
            }
         DllCall("CloseHandle","PTR",hModuleSnap) ; clean up
      }
   }

   hDll:=DllCall("LoadLibrary","Str",dll,"PTR")

   ; Calculate pointer to ahkdll and ahkExec functions
   ahktextdll:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahktextdll","PTR")-hDll
   ahkExec:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahkExec","PTR")-hDll
   ahkTerminate:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahkTerminate","PTR")-hDll

   if script
   {
      nScriptLength := VarSetCapacity(nScript, (StrLen(script)+1)*(A_IsUnicode?2:1), 0)
      ,StrPut(script,&nScript)
      ; Reserve memory in remote process where our script will be saved
      if !pBufferScript := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nScriptLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr")
         return "Could not reseve memory for process"
      ,DllCall("CloseHandle", "PTR", hProc)

      ; Write script to remote process memory
      DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferScript, "Ptr", &nScript, "PTR", nScriptLength, "Ptr", 0)
   }
   else
      pBufferScript:=0

   ; Run ahkdll function in remote thread
   hThread := DllCall("CreateRemoteThread","PTR",hProc,"PTR",0,"PTR",0,"PTR",ahktextdll,"PTR",pBufferScript,"PTR",0,"UInt",0,"PTR")
   if !hThread
   { ; could not start ahkdll in remote process
      ; Free memory used for passing dll path to remote thread
      DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE)
      DllCall("CloseHandle", "PTR", hProc)
      return "Could not start ahkdll in remote process"
   }
   DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF)
   DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode)

   ; Release memory and handles
   DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE)
   DllCall("CloseHandle", "PTR", hThread)
   DllCall("CloseHandle", "PTR", hProc)

   if !lpExitCode ; thread could not be created.
      return "Could not create a thread in remote process"

   return {PID:PID,hModule:hModule,ahkExec:ahkExec,ahkTerminate:ahkTerminate,base:base}
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

7

Re: AHK: Деактивация окон сторонних процессов

teadrinker пишет:

SetMenu — это для оконного меню, в меню-баре.

Ты это по памяти? У меня ощущение что функции всех меню смешаны в одно описание.
https://docs.microsoft.com/ru-ru/window … -and-menus

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

8

Re: AHK: Деактивация окон сторонних процессов

serzh82saratov пишет:

А ты как инжектил

У меня это часть большого кода, я делал своё меню для SciTE:

 https://i.imgur.com/uL77CEf.png

Даже с иконками вышло.
Потом постараюсь какой-нибудь простой пример выложить.

serzh82saratov пишет:

Ты это по памяти?

Теперь уже да, приходилось использовать.

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

9

Re: AHK: Деактивация окон сторонних процессов

teadrinker пишет:

Потом постараюсь какой-нибудь простой пример выложить.

Интересно посмотреть, так как в моём тесте, в рабочем скрипте, заменён только код анк для инжекта.

TrackPopupMenu даже не стал пробовать:

There are three problems:

Clicking a menu item will still temporarily deactivate the active window.
The menu does not automatically disappear if you click elsewhere.
You cannot use the keyboard to select an item or cancel the menu, as it does not have keyboard focus.

Но оказалось что на Win10 это работает без отличий от обычным образом показанного, на семёрке насколько я помню всё так как пишет Lexikos.

В общем на Win10 это работает как надо.


#SingleInstance Off
#Persistent
#NoEnv

p = %1%
if p = 
{  
	Gui, Show, w444 h444, ______#######______
	Run %A_ScriptFullPath% 1
	Return
}

; Gui, +HwndhGui1
; Gui, Show, w444 h444, ______#######______
Gui, New

WS_EX_NOACTIVATE := 0x8000000
WS_POPUP := 0x80000000
WS_CHILD := 0x40000000

; Gui, +E%WS_EX_NOACTIVATE%  
Gui, +%WS_CHILD% -%WS_POPUP%
Gui, +HwndhGui -Caption
Gui, Color, 00ff00 
DllCall("SetParent", "Ptr", hGui, "Ptr", WinExist("______#######______"))
Gui, Show, x5 y5 w111 h111
OnMessage(0x204, "WM_RBUTTONDOWN")  
Menu, TestMenu, Add, Item 1, Return
Menu, TestMenu, Add, Item 2, Return
Return:
	ToolTip % A_ThisMenuItem
	Return

WM_RBUTTONDOWN(wp, lp, msg, hwnd) {  
	hMenu := MenuGetHandle("TestMenu") 
	CoordMode, Mouse 
	MouseGetPos, mX, mY
	DllCall("TrackPopupMenu", "ptr", hMenu, "uint", 0, "int", mx, "int", my
                        , "int", 0, "ptr", A_ScriptHwnd, "ptr", 0)
						
	; Menu, TestMenu, Show 
}

~Esc:: ExitApp
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

10

Re: AHK: Деактивация окон сторонних процессов

У меня на семёрке вроде нормально работает, только иногда дочернее окно не появляется.

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

11 (изменено: serzh82saratov, 2020-05-27 02:29:57)

Re: AHK: Деактивация окон сторонних процессов

Значит это было исправлено в AutoHotkey.

teadrinker пишет:

только иногда дочернее окно не появляется

У меня такого не было, баг AutoHotkey?
Может с WinExist("______#######______") что то.
Так тоже?

Gui, +HwndhGui -Caption +AlwaysOnTop
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

12 (изменено: teadrinker, 2020-05-27 05:10:09)

Re: AHK: Деактивация окон сторонних процессов

Надо так:


#SingleInstance Off
#Persistent
#NoEnv

p = %1%
if p = 
{  
   Gui, Show, w444 h444, ______#######______
   Run %A_ScriptFullPath% 1
   Return
}
WinWait, ______#######______
WinSet, Style, +0x2000000 ; WS_CLIPCHILDREN

Gui, New, % "+hwndhGui -Caption +ToolWindow +Parent" . WinExist()
Gui, Color, 00ff00
Gui, Show, NA x5 y5 w111 h111
OnMessage(0x204, "WM_RBUTTONDOWN")  
Menu, TestMenu, Add, Item 1, Label
Menu, TestMenu, Add, Item 2, Label
Return

Label() {
   ToolTip % A_ThisMenuItem
}

WM_RBUTTONDOWN(wp, lp, msg, hwnd) {  
   hMenu := MenuGetHandle("TestMenu") 
   CoordMode, Mouse 
   MouseGetPos, mX, mY
   DllCall("TrackPopupMenu", "ptr", hMenu, "uint", 0, "int", mx, "int", my
                        , "int", 0, "ptr", A_ScriptHwnd, "ptr", 0)
                  
   ; Menu, TestMenu, Show 
}

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

13

Re: AHK: Деактивация окон сторонних процессов

WS_CLIPCHILDREN

Понял, спасибо.

А с SciTE у тебя не так?

+Parent" . WinExist()


Invalid or nonexistent owner or parent window

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

14

Re: AHK: Деактивация окон сторонних процессов

Попробовал со SciTE, ошибки не возникает, но и окно не показывается.

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

15

Re: AHK: Деактивация окон сторонних процессов

То есть правильнее и универсальнее с SetParent?
И TrackPopupMenu может отменить так сказать "необходимость инжекта" в твоём случае со сторонним меню?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru
Win10x64 v2004, AutoHotkey_L v1.1.33.02 (Unicode 32-bit). AhkSpy, Hotkey, ClockGui

16

Re: AHK: Деактивация окон сторонних процессов

Похоже, с SetParent лучше.
Если не использовать инжект, то для попап-меню этого достаточно, но у меня модифицируется оконное меню. Тоже можно, конечно, попап-меню присобачить, но придётся как-то отслеживать клик по оконному меню.

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