Почитал ещё по ссылкам и удалось сделать скрипт универсальным. Теперь работает при любых сочетаниях битностей скрипта и процесса. Попутно выяснилось, что обрезание через "& 0xFFFFFFFFFFFFF000" в АНК не работает, т.к. он ведь поддерживает целые только до 0x7FFFFFFFFFFFFFFF. И никакого предупреждения не выводится, что интересно. Убил из-за этого кучу времени, наблюдая непонятные глюки NtWow64QueryVirtualMemory64. Так что решил эту задачу сдвигом.
MsgBox, % PsGetEnv("AutoHotkey.exe", "Temp") ; Переменная.
MsgBox, % PsGetEnv("AutoHotkey.exe") ; Весь список.
; Переменная активного окна.
F10::
WinGet, PID, PID, A
MsgBox, % PsGetEnv(PID, "Path")
Return
; ============================= Функция ===================================
PsGetEnv(Process, Var = 0)
{
Static PBI ; PROCESS_BASIC_INFORMATION
Static MBI, pMBI, cbMBI := 48 ; MEMORY_BASIC_INFORMATION
Static PROCESS_VM_READ := 0x10, PROCESS_QUERY_INFORMATION := 0x400
Static STATUS_SUCCESS := 0, cbPES_max := 0x4000 ; Макс. размер блока переменных.
If (!PBI) {
VarSetCapacity(PBI, 48), VarSetCapacity(MBI, cbMBI + 16)
; Выравнять по границе 16 байт для NtWow64QueryVirtualMemory64.
pMBI := ((&MBI + 16) >> 4) << 4
}
Process, Exist, %Process%
If !(PID := ErrorLevel)
Return Error("Процесс не найден")
If !(hProcess := DllCall("OpenProcess", "uint", PROCESS_VM_READ | PROCESS_QUERY_INFORMATION
, "int", 0, "uint", PID, "ptr"))
Return Error("Ошибка OpenProcess")
If (A_Is64bitOS)
DllCall("IsWow64Process", "ptr", hProcess, "int *", Wow64Process)
If (!A_Is64bitOS || Wow64Process) ; Процесс 32-битный.
PsPtrSize := 4, pptr := "uint *", OffsetRUPP := 16, OffsetPES := 0x48
Else ; Процесс 64-битный.
PsPtrSize := 8, pptr := "int64 *", OffsetRUPP := 32, OffsetPES := 0x80
If (A_PtrSize < PsPtrSize) { ; Скрипт х32, процесс х64.
InfoClass := 0, cbPBI := 48, OffsetPEB := 8
;;; PROCESS_BASIC_INFORMATION (PBI)
If (DllCall("ntdll.dll\NtWow64QueryInformationProcess64"
, "ptr", hProcess, "int", InfoClass, "ptr", &PBI, "uint", cbPBI
, "int64 *", ReturnLength) <> STATUS_SUCCESS)
Return Error("Ошибка NtWow64QueryInformationProcess64", hProcess)
;;; Process Environment Block (PEB)
pPEB := NumGet(PBI, OffsetPEB, "int64")
;;; RTL_USER_PROCESS_PARAMETERS (RUPP)
If (DllCall("ntdll.dll\NtWow64ReadVirtualMemory64"
, "ptr", hProcess, "int64", pPEB + OffsetRUPP, "int64 *", pRUPP
, "int64", 8, "int64 *", BytesRead) <> STATUS_SUCCESS)
Return Error("Ошибка NtWow64ReadVirtualMemory64: pRUPP", hProcess)
;;; Process Environment Strings (PES)
If (DllCall("ntdll.dll\NtWow64ReadVirtualMemory64"
, "ptr", hProcess, "int64", pRUPP + OffsetPES, "int64 *", pPES
, "int64", 8, "int64 *", BytesRead) <> STATUS_SUCCESS)
Return Error("Ошибка NtWow64ReadVirtualMemory64: pPES", hProcess)
;;; Размер региона памяти, где находится PES.
If (DllCall("ntdll.dll\NtWow64QueryVirtualMemory64"
, "ptr", hProcess, "int64", pPES, "uint", 0, "ptr", pMBI
, "int64", cbMBI, "int64 *", ReturnLength) <> STATUS_SUCCESS)
Return Error("Ошибка NtWow64QueryVirtualMemory64", hProcess)
cbRegion := NumGet(pMBI+0, 24, "int64")
}
Else {
If (A_PtrSize > PsPtrSize) ; Скрипт х64, процесс х32.
InfoClass := 26, cbPBI := 8, OffsetPEB := 0
Else
InfoClass := 0, cbPBI := A_PtrSize * 6, OffsetPEB := A_PtrSize
;;; PROCESS_BASIC_INFORMATION (PEB)
If (DllCall("ntdll.dll\NtQueryInformationProcess"
, "ptr", hProcess, "int", InfoClass, "ptr", &PBI, "uint", cbPBI
, "uint *", ReturnLength) <> STATUS_SUCCESS)
Return Error("Ошибка NtQueryInformationProcess", hProcess)
;;; Process Environment Block (PEB)
pPEB := NumGet(PBI, OffsetPEB, "ptr")
;;; RTL_USER_PROCESS_PARAMETERS (RUPP)
If !DllCall("ReadProcessMemory", "ptr", hProcess, "ptr", pPEB + OffsetRUPP
, pptr, pRUPP, "ptr", PsPtrSize, "ptr *", BytesRead)
Return Error("Ошибка ReadProcessMemory: pRUPP", hProcess)
;;; Process Environment Strings (PES)
If !DllCall("ReadProcessMemory", "ptr", hProcess, "ptr", pRUPP + OffsetPES
, pptr, pPES, "ptr", PsPtrSize, "ptr *", BytesRead)
Return Error("Ошибка ReadProcessMemory: pPES", hProcess)
;;; Размер региона памяти, где находится PES.
If !DllCall("VirtualQueryEx", "ptr", hProcess, "ptr", pPES, "ptr", pMBI
, "ptr", cbMBI, "int64")
Return Error("Ошибка VirtualQueryEx", hProcess)
cbRegion := NumGet(pMBI+0, A_PtrSize * 3, "ptr")
}
;;; Размер от начала блока PES до конца региона.
cbPES := (((pPES + cbRegion) >> 12) << 12) - pPES
If (cbPES > cbPES_max) ; Если размер большой, ограничить разумной величиной.
cbPES := cbPES_max
VarSetCapacity(PES, cbPES, 0)
If (A_PtrSize < PsPtrSize) {
If (DllCall("ntdll.dll\NtWow64ReadVirtualMemory64"
, "ptr", hProcess, "int64", pPES, "ptr", &PES
, "int64", cbPES, "int64 *", ReturnLength, "uint") <> STATUS_SUCCESS)
Return Error("Ошибка NtWow64ReadVirtualMemory64: PES", hProcess)
}
Else {
If !DllCall("ReadProcessMemory"
, "ptr", hProcess, "ptr", pPES, "ptr", &PES
, "ptr", cbPES, "ptr *", BytesRead)
Return Error("Ошибка ReadProcessMemory: PES", hProcess)
}
DllCall("CloseHandle", "ptr", hProcess)
Loop, % cbPES // 2 ; Строки в блоке разделены нулями, на конце два нуля.
{ ; Заменяем нули на переводы строки, кроме последних.
If ((char := NumGet(PES, (A_Index - 1) * 2, "uchar")) = 0) {
If (prev = 0)
Break
NumPut(0xA, PES, (A_Index - 1) * 2, "uchar")
}
prev := char
}
EnvList := StrGet(&PES, "utf-16")
If (!Var)
Return EnvList
RegExMatch(EnvList, "im`n)^" Var "=([^\n]+)$", Found)
Return Found1
}
Error(Msg, hProcess = 0)
{
If (hProcess)
DllCall("CloseHandle", "ptr", hProcess)
MsgBox, %Msg%
Return False
}