MsgBox/InputBox gets hidden under another window (+ InputBox custom font) Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
GitHub: qwerty12

Re: MsgBox/InputBox gets hidden under another window (+ InputBox custom font)

15 Feb 2017, 08:45

For SHGetSetSettings, you can specify what setting you want it to tackle - SSF_HIDEICONS lets you change fHideIcons which you can set to
https://msdn.microsoft.com/en-us/library/windows/desktop/bb759788(v=vs.85).aspx wrote:TRUE to hide desktop icons, FALSE to show them.
I thought I was getting the bit manipulation wrong in AutoHotkey, but even in C I was having no luck. I guess there's a reason why it's listed as a deprecated function for Vista onwards...

I like your PostMessage solution - I wish I would've known you could do that when I was porting fragman's additions to call a menu item to Deo's 64-bit Unicode ShellContextMenu port. I wanted to bind #n to switch to the next desktop wallpaper in Windows 7, and it worked, but a ton of DLLs were loaded into the AutoHotkey process, bringing the RAM usage from about 4 MB to 24 MB... At least in Windows 8, IDesktopWallpaper provides a proper way to advance the slideshow.

Yeah, I remember SHCNE_ASSOCCHANGED, but it didn't work. It's of no matter anyway, your PostMessage solution is probably the best way to achieve the task IMHO.

Thanks, but with this post, it's hard for me to argue that I'm not :-p

EDIT:
jeeswg wrote:SHGetSetSettings seems to work fine on Windows 7, except that a refresh (e.g. F5) is required.
It might depend on the setting, but I guess it wouldn't surprise me to hear something went slightly askew there in Windows 10...
I just did some experiments regarding refresh Desktop/Explorer folder windows, so hopefully something will work for you there:
Refreshing the file explorer - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 93#p132093
Thanks. It's not personally a pressing problem, but I might need something like that in the future, so I'll make a note to remember that thread.
Last edited by qwerty12 on 15 Feb 2017, 09:43, edited 1 time in total.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: MsgBox/InputBox gets hidden under another window (+ InputBox custom font)

15 Feb 2017, 09:04

SHGetSetSettings seems to work fine on Windows 7, except that a refresh (e.g. F5) is required.

Omg @ RAM usage.

I just did some experiments regarding refresh Desktop/Explorer folder windows, so hopefully something will work for you there:
Refreshing the file explorer - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 93#p132093
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: MsgBox/InputBox gets hidden under another window (+ InputBox custom font)

21 Mar 2017, 16:06

Re. InputBox custom font (a way to resize the InputBox, but not resize the font):
- open *a copy of* AutoHotkey32.exe in Resource Hacker
- go to Dialog, 205
- right-click the GUI, choose Edit Dialog
- it has window style 0x80CC0A48

- open *a copy of* AutoHotkey32.exe in HxD
- search for '480ACC80' (Hex-values) in HxD
- find the first '0A' (10) after '480ACC80', replace it with '12' (18)
- the InputBox will now be bigger, although the font size won't change

I tried setting the window style to '0x80CC0A40' but this didn't help with the font size.

I tried overwriting the font 'MS Shell Dlg' with 'Arial' and got the error message 'The InputBox window could not be displayed.'

By editing the exe in this way, it would mean in the script above that you wouldn't have to resize the controls, although WM_SETFONT would still be necessary.

Anyway, if a custom InputBox font can be achieved just by binary editing the AutoHotkey exe or binary editing the address space, that would be great.

==================================================

Links:
[DialogBox is used to create an InputBox based on a resource inside the AHK exe file]
DialogBox function (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
[window styles]
Dialog Box Styles (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
[DS_SHELLFONT is the '0x48' in the window style mentioned above]
Why does DS_SHELLFONT = DS_FIXEDSYS | DS_SETFONT? – The Old New Thing
https://blogs.msdn.microsoft.com/oldnew ... 0/?p=36513

#define DS_SETFONT 0x40L /* User specified font for Dlg controls */
#define DS_FIXEDSYS 0x0008L
#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS)

[btw the rebirth of Resource Hacker]
Resource Hacker - Wikipedia
https://en.wikipedia.org/wiki/Resource_Hacker

==================================================

[EDIT:]
If you open AutoHotkeyU32.exe with HxD (a hex editor), and search for 'Shell Dlg' (tick 'Unicode string'), the '0A' byte, 12 bytes before it, is the byte that determines the size of controls in the InputBox. Changing this will you give bigger controls. The controls are resized as if there was bigger font, but it doesn't actually change the font. Note: this number can be changed after AutoHotkey has loaded by editing it in the address space, or by editing (a copy of) the exe.

If you search for 'Consolas' (tick 'Unicode string'), and replace it, e.g. with 'Algerian', that will change the font for the main window.
Last edited by jeeswg on 22 Aug 2017, 22:33, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: MsgBox/InputBox gets hidden under another window (+ InputBox custom font)  Topic is solved

22 Aug 2017, 21:51

This is a script that allows InputBoxes to use a custom (e.g. bigger) font. You run the InputBox resizer script first. A script needs a small number of code lines at the start (see below) to make use of it. The script also activates MsgBoxes/InputBoxes when they are created, so that they don't get hidden under other windows.

x64/x32 ISSUES:
- At present this InputBox resizer script will resize InputBoxes from 64-bit scripts if run in AHK x64, and will resize InputBoxes from 32-bit scripts if run in AHK x32. I'm not sure what the problem is preventing cross compatibility.
- Also relating to x64/x32 I'm not sure what to add in to prevent a check for memory regions going on forever, or how to handle addresses in the top half of Int64, other than by perhaps storing such numbers in 2 separate variables, or in a binary struct.
- It may be possible to handle all x64 size addresses in x32 by using functions such as NtWow64QueryInformationProcess64 and NtWow64ReadVirtualMemory64.

TO ACHIEVE BIGGER INPUTBOXES WITHOUT ADDING CODE TO EXISTING SCRIPTS:
- It is feasible to write a script that will resize InputBoxes without having to add any code to existing scripts:
- Use dll injection to create an hFont in the AHK script.
- AHK scripts appear to contain 3 fonts on startup: Consolas for the main window, and fonts for the title bar and palette title (for tool windows with small title bars), so one could use the hFont for one of these scripts. It appears that the Consolas font size of 10 is specified in the source code, in theory, someone could recompile AHK changing that value, and then a binary edit could be made to the AHK exe before/after the script is loaded, (after by editing in the address space,) to achieve the same effect, or, the user could change the system-wide font settings for either title bars or palette titles, but this would affect all programs on the system.
- I use the approaches outlined here to retrieve a process's font handles, I plan to release a script soon.
get a process's GDI handles (e.g. get/set title bar font and apply WM_SETFONT to a control) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=31228

For a whole host of reasons, I think that AutoHotkey should implement a MsgBox command which makes use of a custom MsgBox dialog resource (perhaps a clone of the Winapi MessageBox function with additional features), and add window activation and custom font support for MsgBox and InputBox. I see this more as a necessity than a luxury.

Code: Select all

;InputBox resizer (it also activates MsgBox and InputBox dialogs created by AutoHotkey)

#SingleInstance force
DetectHiddenWindows, On

global oArray := {}
OnMessage(0x5555, "MsgMonitor")
return

MsgMonitor(wParam, lParam, uMsg, hWnd)
{
	DetectHiddenWindows, On
	WinGet, vPName, ProcessName, % "ahk_id " wParam
	if ((A_PtrSize = 8) && InStr(vPName, "32"))
	|| ((A_PtrSize != 8) && InStr(vPName, "64"))
		return
	WinGet, vPID, PID, % "ahk_id " wParam
	oArray[vPID] := lParam
	JEE_AhkInputBoxSetFontSize(vPID)
}

OnDialogStart(hWinEventHook, vEvent, hWnd)
{
	;EVENT_SYSTEM_DIALOGSTART := 0x10
	static _ := DllCall("SetWinEventHook", UInt,0x10, UInt,0x10, Ptr,0
	, Ptr,RegisterCallback("OnDialogStart"), UInt,0, UInt,0, UInt,0, Ptr)
	DetectHiddenWindows, On
	Critical
	WinGetClass, vWinClass, % "ahk_id " hWnd
	if !(vWinClass = "#32770")
		return
	WinGet, vPName, ProcessName, % "ahk_id " hWnd
	if !InStr(vPName, "AutoHotkey")
		return
	WinGet, vWinStyle, Style, % "ahk_id " hWnd
	if (vWinStyle = 0x94C803C5) ;MsgBox
		WinActivate, % "ahk_id " hWnd
	else if (vWinStyle = 0x94CC0A4C) ;InputBox
	{
		WinActivate, % "ahk_id " hWnd
		WinGet, vPID, PID, % "ahk_id " hWnd
		hFont := oArray[vPID]
		if !hFont
			return
		PostMessage, 0x30, % hFont, 1, Static1, % "ahk_id " hWnd ;WM_SETFONT := 0x30
		PostMessage, 0x30, % hFont, 1, Edit1, % "ahk_id " hWnd ;WM_SETFONT := 0x30
		PostMessage, 0x30, % hFont, 1, Button1, % "ahk_id " hWnd ;WM_SETFONT := 0x30
		PostMessage, 0x30, % hFont, 1, Button2, % "ahk_id " hWnd ;WM_SETFONT := 0x30
	}
}

;==================================================

;DetectHiddenWindows, On
;hWnd := A_ScriptHwnd
;WinGet, vPID, PID, % "ahk_id " hWnd
;SplitPath, A_AhkPath, vAhkName
;JEE_AhkInputBoxSetFontSize(vPID)
;InputBox, vInput,, % "hello world"
;return

JEE_AhkInputBoxSetFontSize(vPID, vFontSize:=18, vAhkName:="")
{
	if (vAhkName = "")
		SplitPath, A_AhkPath, vAhkName
	vRet := 0
	MAX_PATH := 260
	;PROCESS_QUERY_INFORMATION := 0x400 ;PROCESS_VM_WRITE := 0x20
	;PROCESS_VM_READ := 0x10 ;PROCESS_VM_OPERATION := 0x8
	if !hProc := DllCall("kernel32\OpenProcess", UInt,0x438, Int,0, UInt,vPID, Ptr)
		return 0
	VarSetCapacity(MEMORY_BASIC_INFORMATION, A_PtrSize=8?48:28, 0)
	vAddress := 0
	Loop
	{
		if !DllCall("kernel32\VirtualQueryEx", Ptr,hProc, Ptr,vAddress, Ptr,&MEMORY_BASIC_INFORMATION, UPtr,A_PtrSize=8?48:28, UPtr)
			break
		vMbiBaseAddress := NumGet(MEMORY_BASIC_INFORMATION, 0, "Ptr")
		vMbiRegionSize := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?24:12, "UPtr")
		vMbiState := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?32:16, "UInt")
		vMbiType := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?40:24, "UInt")

		vName := ""
		if (vMbiState & 0x1000) ;MEM_COMMIT := 0x1000
		&& (vMbiType & 0x1000000) ;MEM_IMAGE := 0x1000000
		{
			vPath := ""
			VarSetCapacity(vPath, MAX_PATH*2)
			DllCall("psapi\GetMappedFileName", Ptr,hProc, Ptr,vMbiBaseAddress, Str,vPath, UInt,MAX_PATH*2, UInt)
			if !(vPath = "")
				SplitPath, vPath, vName
		}
		if (vName = vAhkName)
		{
			VarSetCapacity(vData, vMbiRegionSize, 1)
			DllCall("kernel32\ReadProcessMemory", Ptr,hProc, Ptr,vMbiBaseAddress, Ptr,&vData, UPtr,vMbiRegionSize, UPtr,0)
			if vPos := RegExMatch(vData, "\x{0053}\x{0068}\x{0065}\x{006C}\x{006C}\x{0020}\x{0044}\x{006C}\x{0067}") ;Shell Dlg
			{
				vOffset := ((vPos-1)*2)-12
				;MsgBox, % NumGet(vData, vOffset, "UChar")
				VarSetCapacity(vDataNew, 1)
				NumPut(vFontSize, vDataNew, 0, "UChar")
				;PAGE_EXECUTE_READWRITE := 0x40
				;DllCall("kernel32\VirtualProtect", Ptr,vMbiBaseAddress+vOffset, UPtr,1, UInt,0x40, UIntP,0)
				DllCall("kernel32\VirtualProtectEx", Ptr,hProc, Ptr,vMbiBaseAddress+vOffset, UPtr,1, UInt,0x40, UIntP,0)
				if !DllCall("kernel32\WriteProcessMemory", Ptr,hProc, Ptr,vMbiBaseAddress+vOffset, Ptr,&vDataNew, UPtr,1, UPtr,0)
					vRet := 1
				break
			}
		}
		vAddress += vMbiRegionSize
		;if (vAddress > 2**32-1) ;4 gigabytes
		;	break
	}
	DllCall("kernel32\CloseHandle", Ptr,hProc)
	return vRet
}

;==================================================

Code: Select all

;an example script that initialises itself for use with InputBox resizer

#SingleInstance force

;==============================
;for use with InputBox resizer
DetectHiddenWindows, On
SetTitleMatchMode, 2
if hWnd := WinExist("InputBox resizer ahk_class AutoHotkey")
{
	vFontName := "Arial"
	vFontSize := 20
	vFontWeight := 400
	vFontHeight := -Round(vFontSize*A_ScreenDPI/72)
	hFont := DllCall("gdi32\CreateFont", Int,vFontHeight, Int,0, Int,0, Int,0
	, Int,vFontWeight, UInt,0, UInt,0 ,UInt,0
	, UInt,0, UInt,0, UInt,0, UInt,0
	, UInt,0, Str,vFontName, Ptr)
	SendMessage, 0x5555, % A_ScriptHwnd, % hFont,, % "ahk_id " hWnd
}
;==============================

InputBox, vInput,, % "hello world"
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: MsgBox/InputBox gets hidden under another window (+ InputBox custom font)

07 Oct 2017, 19:10

OK, I have stand-alone script working for the first time:

Although you would need a dll from here:
[get x64 and x32 versions of AutoHotkeyMini.dll]
GitHub - HotKeyIt/ahkdll-v1-release: AutoHotkey_H v1 release
https://github.com/HotKeyIt/ahkdll-v1-release

And the script will only work on scripts of the same type, e.g. U32/U64.

Code: Select all

;InputBox resizer (also activates MsgBox and InputBox dialogs created by AutoHotkey)

;[get x64 and x32 versions of AutoHotkeyMini.dll]
;GitHub - HotKeyIt/ahkdll-v1-release: AutoHotkey_H v1 release
;https://github.com/HotKeyIt/ahkdll-v1-release

#SingleInstance force
#Persistent
DetectHiddenWindows, On

global vFontName := "Arial"
global vFontSize := 20
global vFontWeight := 400
global oArray := {}
global vPathDll

;vDir := A_ScriptDir
vDir := "C:\Program Files\AutoHotkey"
if (A_PtrSize = 8)
	vPathDll := vDir "\AutoHotkeyMiniU64.dll"
else
	vPathDll := vDir "\AutoHotkeyMiniU32.dll"

OnMessage(0x5555, "MsgMonitor")

oWMI := ComObjGet("winmgmts:")
ComObjConnect(oSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessCreate_")
vInterval := 1
oWMI.ExecNotificationQueryAsync(oSink, "Select * from __InstanceCreationEvent within " vInterval " where TargetInstance isa 'Win32_Process'")
return

;==================================================

;New Process Notifier - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/56984-new-process-notifier/

ProcessCreate_OnObjectReady(obj)
{
	oProc := obj.TargetInstance
	vPID := oProc.ProcessID
	vPName := oProc.Name
	;vPPath := oProc.ExecutablePath

	if !InStr(oProc.Name, "AutoHotkey")
		return
	if !((A_PtrSize=8) = JEE_ProcessIs64Bit(vPID))
		return
	vFontHeight := -Round(vFontSize*A_ScreenDPI/72)
	JEE_AhkInputBoxSetFontSize(vPID, vFontSize)
	vScript = ;continuation section
	(LTrim
	DetectHiddenWindows, On
	hFont := DllCall("gdi32\CreateFont", Int,%vFontHeight%, Int,0, Int,0, Int,0
	, Int,%vFontWeight%, UInt,0, UInt,0, UInt,0
	, UInt,0, UInt,0, UInt,0, UInt,0
	, UInt,0, Str,"%vFontName%", Ptr)
	PostMessage, 0x5555, `% hFont, %vPID%, Edit1, `% "ahk_id " %A_ScriptHwnd%
	)
	rThread := InjectAhkDll(vPID, vPathDll)
	rThread.Exec(vScript)
	rThread := ""
}

;==================================================

MsgMonitor(wParam, lParam, uMsg, hWnd)
{
	;oArray[vPID] := hFont
	oArray[lParam] := wParam
	;MsgBox, % Format("{} {} {} {}", wParam, lParam, uMsg, hWnd)
	;ToolTip, % Format("{} {} {} {}", wParam, lParam, uMsg, hWnd)
}

;==================================================

OnDialogStart(hWinEventHook, vEvent, hWnd)
{
	;EVENT_SYSTEM_DIALOGSTART := 0x10
	static _ := DllCall("SetWinEventHook", UInt,0x10, UInt,0x10, Ptr,0
	, Ptr,RegisterCallback("OnDialogStart"), UInt,0, UInt,0, UInt,0, Ptr)
	global vPathDll
	DetectHiddenWindows, On
	Critical

	WinGetClass, vWinClass, % "ahk_id " hWnd
	if !(vWinClass = "#32770")
		return
	WinGet, vPName, ProcessName, % "ahk_id " hWnd
	if !InStr(vPName, "AutoHotkey")
		return
	WinGet, vPID, PID, % "ahk_id " hWnd
	WinGet, vWinStyle, Style, % "ahk_id " hWnd
	if (vWinStyle = 0x94C803C5) ;MsgBox
		WinActivate, % "ahk_id " hWnd
	else if (vWinStyle = 0x94CC0A4C) ;InputBox
	{
		WinActivate, % "ahk_id " hWnd
		if !hFont := oArray[vPID]
			return
		PostMessage, 0x30, % hFont, 1, Static1, % "ahk_id " hWnd ;WM_SETFONT := 0x30
		PostMessage, 0x30, % hFont, 1, Edit1, % "ahk_id " hWnd ;WM_SETFONT := 0x30
		PostMessage, 0x30, % hFont, 1, Button1, % "ahk_id " hWnd ;WM_SETFONT := 0x30
		PostMessage, 0x30, % hFont, 1, Button2, % "ahk_id " hWnd ;WM_SETFONT := 0x30
	}
}

;==================================================

JEE_AhkInputBoxSetFontSize(vPID, vFontSize:=18, vAhkName:="")
{
	if (vAhkName = "")
		SplitPath, A_AhkPath, vAhkName
	vRet := 0
	MAX_PATH := 260
	;PROCESS_QUERY_INFORMATION := 0x400 ;PROCESS_VM_WRITE := 0x20
	;PROCESS_VM_READ := 0x10 ;PROCESS_VM_OPERATION := 0x8
	if !hProc := DllCall("kernel32\OpenProcess", UInt,0x438, Int,0, UInt,vPID, Ptr)
		return 0
	VarSetCapacity(MEMORY_BASIC_INFORMATION, A_PtrSize=8?48:28, 0)
	vAddress := 0
	Loop
	{
		if !DllCall("kernel32\VirtualQueryEx", Ptr,hProc, Ptr,vAddress, Ptr,&MEMORY_BASIC_INFORMATION, UPtr,A_PtrSize=8?48:28, UPtr)
			break
		vMbiBaseAddress := NumGet(MEMORY_BASIC_INFORMATION, 0, "Ptr")
		vMbiRegionSize := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?24:12, "UPtr")
		vMbiState := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?32:16, "UInt")
		vMbiType := NumGet(MEMORY_BASIC_INFORMATION, A_PtrSize=8?40:24, "UInt")

		vName := ""
		if (vMbiState & 0x1000) ;MEM_COMMIT := 0x1000
		&& (vMbiType & 0x1000000) ;MEM_IMAGE := 0x1000000
		{
			vPath := ""
			VarSetCapacity(vPath, MAX_PATH*2)
			DllCall("psapi\GetMappedFileName", Ptr,hProc, Ptr,vMbiBaseAddress, Str,vPath, UInt,MAX_PATH*2, UInt)
			if !(vPath = "")
				SplitPath, vPath, vName
		}
		if (vName = vAhkName)
		{
			VarSetCapacity(vData, vMbiRegionSize, 1)
			DllCall("kernel32\ReadProcessMemory", Ptr,hProc, Ptr,vMbiBaseAddress, Ptr,&vData, UPtr,vMbiRegionSize, UPtr,0)
			if vPos := RegExMatch(vData, "\x{0053}\x{0068}\x{0065}\x{006C}\x{006C}\x{0020}\x{0044}\x{006C}\x{0067}") ;Shell Dlg
			{
				vOffset := ((vPos-1)*2)-12
				;MsgBox, % NumGet(vData, vOffset, "UChar")
				VarSetCapacity(vDataNew, 1)
				NumPut(vFontSize, vDataNew, 0, "UChar")
				;PAGE_EXECUTE_READWRITE := 0x40
				;DllCall("kernel32\VirtualProtect", Ptr,vMbiBaseAddress+vOffset, UPtr,1, UInt,0x40, UIntP,0)
				DllCall("kernel32\VirtualProtectEx", Ptr,hProc, Ptr,vMbiBaseAddress+vOffset, UPtr,1, UInt,0x40, UIntP,0)
				if !DllCall("kernel32\WriteProcessMemory", Ptr,hProc, Ptr,vMbiBaseAddress+vOffset, Ptr,&vDataNew, UPtr,1, UPtr,0)
					vRet := 1
				break
			}
		}
		vAddress += vMbiRegionSize
		;if (vAddress > 2**32-1) ;4 gigabytes
		;	break
	}
	DllCall("kernel32\CloseHandle", Ptr,hProc)
	return vRet
}

;==================================================

JEE_ProcessIs64Bit(vPID)
{
	if !A_Is64bitOS
		return 0
	hProc := DllCall("kernel32\OpenProcess", UInt,0x400, Int,0, UInt,vPID, Ptr)
	DllCall("kernel32\IsWow64Process", Ptr,hProc, IntP,vIsWow64Process)
	DllCall("kernel32\CloseHandle", Ptr,hProc)
	return !vIsWow64Process
}

;==================================================

;[original version of InjectAhkDll]
;[SOLVED]get other process's working dir - Page 3 - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/85304-solvedget-other-processs-working-dir/page-3#entry544650

;[get x64 and x32 versions of AutoHotkeyMini.dll]
;GitHub - HotKeyIt/ahkdll-v1-release: AutoHotkey_H v1 release
;https://github.com/HotKeyIt/ahkdll-v1-release

;by HotKeyIt (modified version by jeeswg to not require _Struct.ahk)
InjectAhkDll(PID,dll="AutoHotkey.dll",script=0)
{
	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")
	,base:={__Call:"InjectAhkDll",__Delete:"InjectAhkDll"},FreeLibrary:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","FreeLibrary","PTR")
	static TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1
	,MAX_PATH:=260,MAX_MODULE_NAME32:=255,ModuleName:="",init:=VarSetCapacity(ModuleName,MAX_PATH*(A_IsUnicode?2:1))

	if IsObject(PID)
	{
		if (dll!="Exec" && script)
			return DllCall("MessageBox","PTR",0,"Str","Only Exec method can be used here!","STR","Error","UInt",0)

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

		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 DllCall("MessageBox","PTR",0,"Str","Could not reseve memory for process.","STR","Error","UInt",0)
		,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 DllCall("MessageBox","PTR",0,"Str","Could not execute script in remote process.","STR","Error","UInt",0)
		}

		; 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 DllCall("MessageBox","PTR",0,"Str","Could not execute script in remote process.","STR","Error","UInt",0)

		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 DllCall("MessageBox","PTR",0,"Str","Could not find " dll " library.","STR","Error","UInt",0),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 DllCall("MessageBox","PTR",0,"Str","Could not open process for PID: " PID,"STR","Error","UInt",0)

	; 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 DllCall("MessageBox","PTR",0,"Str","Could not reseve memory for process.","STR","Error","UInt",0),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 DllCall("MessageBox","PTR",0,"Str","Could not load " dll " in remote process.","STR","Error","UInt",0)
	}
	; 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 DllCall("MessageBox","PTR",0,"Str","Could not reseve memory for process.","STR","Error","UInt",0)
		,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 DllCall("MessageBox","PTR",0,"Str","Could not start ahkdll in remote process","STR","Error","UInt",0)
	}
	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 DllCall("MessageBox","PTR",0,"Str","Could not create a thread in remote process","STR","Error","UInt",0)

	return {PID:PID,hModule:hModule,ahkExec:ahkExec,ahkTerminate:ahkTerminate,base:base}
}

;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask For Help”

Who is online

Users browsing this forum: ahketype, Bing [Bot], boiler, cainxabel and 221 guests