1

Тема: AHK: Возвращение пути к PDF-файлу

Следующий код по клавише F11 выводит путь к файлу, открытому в PDF-просмотрщике. Но в случае, когда открыто несколько окон, путь определяется неверно. Как правильно получить путь для активного окна?

#SingleInstance Force

F11:: 
   WinGet, PID, PID, A
   obj := GetCommandLine2(PID, true, true)
   ;MsgBox, % "CommandLine = " obj.cmd "`nImagePath = " obj.path
   MsgBox, % obj.cmd
   Return

GetCommandLine2(PID, SetDebugPrivilege := false, GetImagePath := false)  {
   static SetDebug := 0, PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0
   
   if (SetDebugPrivilege && !SetDebug)  {
      if !res := SeDebugPrivilege()
         SetDebug := 1
      else  {
         MsgBox, 4, Ошибка SeDebugPrivilege(), Не удалось установить привилегии.`nОшибка %res%`nПродолжить?
         IfMsgBox, No
            Return
      }
   }
   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, PtrType := "UInt", pPtr := "UIntP", offsetCMD := 0x40
   else
      PtrSize := 8, PtrType := "Int64", pPtr := "Int64P", offsetCMD := 0x70

   hModule := DllCall("GetModuleHandle", "str", "Ntdll", Ptr)
   if (A_PtrSize < PtrSize)  {            ; скрипт 32, целевой процесс 64
      if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64QueryInformationProcess64", Ptr)
         failed := "NtWow64QueryInformationProcess64"
      if !ReadProcessMemory := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64ReadVirtualMemory64", Ptr)
         failed := "NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else  {
      if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtQueryInformationProcess", Ptr)
         failed := "NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)            ; скрипт 64, целевой процесс 32
         info := 26, szPBI := 8, offsetPEB := 0
      else                                ; скрипт и целевой процесс одной битности
         info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
   }
   if failed  {
      DllCall("CloseHandle", Ptr, hProc)
      MsgBox, Не удалось получить указатель на функцию %failed%
      Return
   }
   VarSetCapacity(PBI, 48, 0)
   if DllCall(QueryInformationProcess, Ptr, hProc, UInt, info, Ptr, &PBI, UInt, szPBI, UIntP, bytes) != STATUS_SUCCESS  {
      DllCall("CloseHandle", Ptr, hProc)
      Return
   }
   pPEB := NumGet(&PBI + offsetPEB, PtrType)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, UIntP, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD, UShortP, szCMD, PtrType, 2, UIntP, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD + PtrSize, pPtr, pCMD, PtrType, PtrSize, UIntP, bytes)
   
   VarSetCapacity(buff, szCMD, 0)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pCMD, Ptr, &buff, PtrType, szCMD, UIntP, bytes)
   obj := { cmd: StrGet(&buff, "UTF-16") }
   
   if (GetImagePath && obj.cmd)  {
      DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD - PtrSize*2, UShortP, szPATH, PtrType, 2, UIntP, bytes)
      DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCMD - PtrSize, pPtr, pPATH, PtrType, PtrSize, UIntP, bytes)
      
      VarSetCapacity(buff, szPATH, 0)
      DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pPATH, Ptr, &buff, PtrType, szPATH, UIntP, bytes)
      obj.path := StrGet(&buff, "UTF-16") . (IsWow64 ? " *32" : "")
   }
   DllCall("CloseHandle", Ptr, hProc)
   Return obj
}

SeDebugPrivilege()  {
   static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2
   
   hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, Int, false, UInt, DllCall("GetCurrentProcessId"), Ptr)
   DllCall("Advapi32\OpenProcessToken", Ptr, hProc, UInt, TOKEN_ADJUST_PRIVILEGES, PtrP, token)
   
   DllCall("Advapi32\LookupPrivilegeValue", Ptr, 0, Str, "SeDebugPrivilege", Int64P, luid)
   VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
   NumPut(1, TOKEN_PRIVILEGES, "UInt")
   NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
   NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
   DllCall("Advapi32\AdjustTokenPrivileges", Ptr, token, Int, false, Ptr, &TOKEN_PRIVILEGES, UInt, 0, Ptr, 0, Ptr, 0)
   res := A_LastError
   DllCall("CloseHandle", Ptr, token)
   DllCall("CloseHandle", Ptr, hProc)
   Return res  ; в случае удачи 0
}

2

Re: AHK: Возвращение пути к PDF-файлу

peterverhovensky пишет:

Следующий код по клавише F11 выводит путь к файлу, открытому в PDF-просмотрщике.

Нет, он выводит, судя по коду, командную строку процесса.

peterverhovensky пишет:

Как правильно получить путь для активного окна?

Думаю, это зависит от того, как устроен «PDF-просмотрщик».

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

3

Re: AHK: Возвращение пути к PDF-файлу

teadrinker

А если он выводит командную строку процесса, не относящуюся к данному окну — где искать валидную инфу? Или эта инфа замещается самим просмотрщиком и она не доступна? Кстати говоря, пробовал я это в "Adobe Reader", и в "STDU Viewer".

4

Re: AHK: Возвращение пути к PDF-файлу

Командная строка не относится к окну, она относится к процессу.

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

5

Re: AHK: Возвращение пути к PDF-файлу

Попробую путём обхода всех окон и сбора ком. строк, с сравнением с заголовками окон.

6 (изменено: peterverhovensky, 2022-12-15 16:10:47)

Re: AHK: Возвращение пути к PDF-файлу

Судя по всему, процесс при запуске имеет ком. строку первого окна, которая для последующих окон не меняется, поэтому получить ее для следующих окон невозможно.

7

Re: AHK: Возвращение пути к PDF-файлу

peterverhovensky пишет:

процесс при запуске имеет ком. строку первого окна

Просто в первом окне открывается файл, указанный в командной строке. Можно в том же окне открыть потом другой файл, командная строка от этого, конечно, не изменится.

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