/ src / common / utils / process_path.h
process_path.h
  1  #pragma once
  2  #define WIN32_LEAN_AND_MEAN
  3  #include <windows.h>
  4  #include <shlwapi.h>
  5  
  6  #include <string>
  7  #include <thread>
  8  
  9  // Get the executable path or module name for modern apps
 10  inline std::wstring get_process_path(DWORD pid) noexcept
 11  {
 12      auto process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, TRUE, pid);
 13      std::wstring name;
 14      if (process != INVALID_HANDLE_VALUE)
 15      {
 16          name.resize(MAX_PATH);
 17          DWORD name_length = static_cast<DWORD>(name.length());
 18          if (QueryFullProcessImageNameW(process, 0, name.data(), &name_length) == 0)
 19          {
 20              name_length = 0;
 21          }
 22          name.resize(name_length);
 23          CloseHandle(process);
 24      }
 25      return name;
 26  }
 27  
 28  // Get the executable path or module name for modern apps
 29  inline std::wstring get_process_path(HWND window) noexcept
 30  {
 31      const static std::wstring app_frame_host = L"ApplicationFrameHost.exe";
 32  
 33      DWORD pid{};
 34      GetWindowThreadProcessId(window, &pid);
 35      auto name = get_process_path(pid);
 36  
 37      if (name.length() >= app_frame_host.length() &&
 38          name.compare(name.length() - app_frame_host.length(), app_frame_host.length(), app_frame_host) == 0)
 39      {
 40          // It is a UWP app. We will enumerate the windows and look for one created
 41          // by something with a different PID
 42          DWORD new_pid = pid;
 43  
 44          EnumChildWindows(
 45              window, [](HWND hwnd, LPARAM param) -> BOOL {
 46                  auto new_pid_ptr = reinterpret_cast<DWORD*>(param);
 47                  DWORD pid;
 48                  GetWindowThreadProcessId(hwnd, &pid);
 49                  if (pid != *new_pid_ptr)
 50                  {
 51                      *new_pid_ptr = pid;
 52                      return FALSE;
 53                  }
 54                  else
 55                  {
 56                      return TRUE;
 57                  }
 58              },
 59              reinterpret_cast<LPARAM>(&new_pid));
 60  
 61          // If we have a new pid, get the new name.
 62          if (new_pid != pid)
 63          {
 64              return get_process_path(new_pid);
 65          }
 66      }
 67  
 68      return name;
 69  }
 70  
 71  inline std::wstring get_process_path_waiting_uwp(HWND window)
 72  {
 73      const static std::wstring appFrameHost = L"ApplicationFrameHost.exe";
 74  
 75      int attempt = 0;
 76      auto processPath = get_process_path(window);
 77  
 78      while (++attempt < 30 && processPath.length() >= appFrameHost.length() &&
 79             processPath.compare(processPath.length() - appFrameHost.length(), appFrameHost.length(), appFrameHost) == 0)
 80      {
 81          std::this_thread::sleep_for(std::chrono::milliseconds(5));
 82          processPath = get_process_path(window);
 83      }
 84  
 85      return processPath;
 86  }
 87  
 88  inline std::wstring get_module_filename(HMODULE mod = nullptr)
 89  {
 90      wchar_t buffer[MAX_PATH + 1];
 91      DWORD actual_length = GetModuleFileNameW(mod, buffer, MAX_PATH);
 92      if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
 93      {
 94          const DWORD long_path_length = 0xFFFF; // should be always enough
 95          std::wstring long_filename(long_path_length, L'\0');
 96          actual_length = GetModuleFileNameW(mod, long_filename.data(), long_path_length);
 97          return long_filename.substr(0, actual_length);
 98      }
 99      return { buffer, actual_length };
100  }
101  
102  inline std::wstring get_module_folderpath(HMODULE mod = nullptr, const bool removeFilename = true)
103  {
104      wchar_t buffer[MAX_PATH + 1];
105      DWORD actual_length = GetModuleFileNameW(mod, buffer, MAX_PATH);
106      if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
107      {
108          const DWORD long_path_length = 0xFFFF; // should be always enough
109          std::wstring long_filename(long_path_length, L'\0');
110          actual_length = GetModuleFileNameW(mod, long_filename.data(), long_path_length);
111          PathRemoveFileSpecW(long_filename.data());
112          long_filename.resize(std::wcslen(long_filename.data()));
113          long_filename.shrink_to_fit();
114          return long_filename;
115      }
116  
117      if (removeFilename)
118      {
119          PathRemoveFileSpecW(buffer);
120      }
121      return { buffer, static_cast<uint64_t>(lstrlenW(buffer))};
122  }