tested on AHK v1.1 U32/U64
tested on Notepad (Windows XP x32/Windows 7 x32/Windows 7 x64 versions)
Warning: use at your own risk, scripts that retrieve information from external programs can potentially crash them, save any files before testing.
[EDIT:][JEE_NotepadGetPath][updated: 2017-04-06]
Code: Select all
;e.g.
;q::
;WinGet, hWnd, ID, ahk_class Notepad
;WinGetTitle, vWinTitle, % "ahk_id " hWnd
;vPath := JEE_NotepadGetPath(hWnd)
;MsgBox, % "window title: " vWinTitle "`r`n" "file path: " vPath
;return
;JEE_NotepadGetFilename
JEE_NotepadGetPath(hWnd)
{
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "Notepad")
return
WinGet, vPID, PID, % "ahk_id " hWnd
WinGet, vPPath, ProcessPath, % "ahk_id " hWnd
FileGetVersion, vPVersion, % vPPath
MAX_PATH := 260
;PROCESS_QUERY_INFORMATION := 0x400 ;PROCESS_VM_READ := 0x10
if !hProc := DllCall("kernel32\OpenProcess", UInt,0x410, Int,0, UInt,vPID, Ptr)
return
if (vPVersion = "5.1.2600.5512") ;Notepad (Windows XP version)
vAddress := 0x100A900
if !vAddress
{
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")
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 (vMbiState & 0x1000) ;MEM_COMMIT := 0x1000
&& (vMbiType & 0x1000000) ;MEM_IMAGE := 0x1000000
&& InStr(vName, "notepad")
{
;get address where path starts
if A_Is64bitOS
DllCall("kernel32\IsWow64Process", Ptr,hProc, IntP,vIsWow64Process)
if !A_Is64bitOS || vIsWow64Process ;if process is 32-bit
vAddress := vMbiBaseAddress + 0xCAE0 ;(vMbiBaseAddress + 0xD378 also appears to work)
else
vAddress := vMbiBaseAddress + 0x10B40
break
}
vAddress += vMbiRegionSize
if (vAddress > 2**32-1) ;4 gigabytes
return
}
}
VarSetCapacity(vPath, MAX_PATH*2, 0)
DllCall("kernel32\ReadProcessMemory", Ptr,hProc, Ptr,vAddress, Str,vPath, UPtr,MAX_PATH*2, UPtr,0)
DllCall("kernel32\CloseHandle", Ptr,hProc)
return vPath
}
Code: Select all
;e.g.
;q::
;WinGet, hWnd, ID, ahk_class Notepad
;vPath := A_ScriptFullPath
;JEE_NotepadSetPath(hWnd, vPath)
;return
JEE_NotepadSetPath(hWnd, vPath)
{
PostMessage, 0x233, % JEE_DropCreate(vPath), 0, , % "ahk_id " hWnd ;WM_DROPFILES := 0x233
return
}
;==================================================
;e.g. hDrop := JEE_DropCreate(vPaths)
;where vPaths is an LF/CRLF-separated list
;JEE_HDropSetPaths
JEE_DropCreate(vPaths, vPosX=0, vPosY=0)
{
;GMEM_ZEROINIT := 0x40, GMEM_MOVEABLE := 0x2
vWidth := A_IsUnicode?2:1
hDrop := DllCall("GlobalAlloc", UInt,0x42, UPtr,20+(StrLen(vPaths)+2)*vWidth, Ptr)
pDrop := DllCall("GlobalLock", Ptr,hDrop)
;DROPFILES struct
NumPut(20, pDrop+0, 0, "UInt")
NumPut(vPosX, pDrop+4, 0, "UInt")
NumPut(vPosY, pDrop+8, 0, "UInt")
NumPut(A_IsUnicode?1:0, pDrop+16, 0, "UInt")
;e.g. CF_HDROP with 3 paths: 'path1 null path2 null path3 null null'
vOffset := 20
Loop, Parse, vPaths, `n, `r
if !(A_LoopField = "")
{
DllCall("RtlMoveMemory", UInt,pDrop+vOffset, Str,A_LoopField, UInt,StrLen(A_LoopField)*vWidth)
vOffset += (StrLen(A_LoopField)+1)*vWidth
}
DllCall("GlobalUnlock", Ptr,hDrop)
return hDrop
}
To get the path, find the base address for the notepad.exe region in the address space, and then add 0xCAE0 (32-bit) or 0x10B40 (64-bit), the path should be located there. It always seems to be consistent. If it were not consistent, one method would be to grab the window title from the title bar, to get the file name, prepend a backslash, and search for it in the address space.
SET PATH:
Create an hDrop containing the path you want, then send a WM_DROPFILES message to Notepad, via PostMessage, with the hDrop as a parameter. This is a useful general technique that works on many programs including Media Player Classic. It emulates dragging and dropping a file onto a window.
Note: using WM_DROPFILES and SendMessage, instead of PostMessage, didn't work, it just paused and nothing happened.
Note: You can use COM to set the path/url in Explorer/Internet Explorer. I had trouble finding a method to set the path in an Adobe Reader window programmatically, if anyone knows a way.
[EDIT:] If JEE_NotepadGetPath is compatible with Windows 8/Windows 10 or not, or is/isn't compatible with certain language versions, do let me know. Cheers.
==================================================
NOTE: FILE NAME RETRIEVED BUT DIRECTORY OMITTED
Code: Select all
;Let's say you have a folder containing 2 files:
;%A_Desktop%\New Folder\notepad.exe
;%A_Desktop%\New Folder\New Text Document.txt
;If you do this, it will retrieve the file name but no directory:
vDir = %A_Desktop%\New Folder
SetWorkingDir, % vDir
Run, notepad.exe "New Text Document.txt"
WinWait, New Text Document ahk_class Notepad
WinGet, hWnd, ID, New Text Document ahk_class Notepad
MsgBox, % JEE_NotepadGetPath(hWnd)
return