2024-11-20 20:15:18 +01:00
|
|
|
#include "pch.h"
|
|
|
|
|
#include "PwaHelper.h"
|
2025-06-17 15:39:44 +08:00
|
|
|
#include "WindowUtils.h"
|
2024-12-05 18:24:05 +03:00
|
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
|
|
|
|
|
#include <appmodel.h>
|
|
|
|
|
#include <shellapi.h>
|
2024-11-20 20:15:18 +01:00
|
|
|
#include <ShlObj.h>
|
2024-12-05 18:24:05 +03:00
|
|
|
#include <shobjidl.h>
|
2024-11-20 20:15:18 +01:00
|
|
|
#include <tlhelp32.h>
|
2024-12-05 18:24:05 +03:00
|
|
|
#include <wrl.h>
|
|
|
|
|
#include <propkey.h>
|
|
|
|
|
|
|
|
|
|
#include <wil/com.h>
|
|
|
|
|
|
2024-11-20 20:15:18 +01:00
|
|
|
#include <common/logger/logger.h>
|
|
|
|
|
#include <common/utils/winapi_error.h>
|
2024-12-05 18:24:05 +03:00
|
|
|
|
|
|
|
|
#include <WorkspacesLib/AppUtils.h>
|
|
|
|
|
#include <WorkspacesLib/CommandLineArgsHelper.h>
|
|
|
|
|
#include <WorkspacesLib/StringUtils.h>
|
2024-11-20 20:15:18 +01:00
|
|
|
|
2024-12-04 18:17:54 +01:00
|
|
|
namespace Utils
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
|
|
|
|
namespace NonLocalizable
|
|
|
|
|
{
|
|
|
|
|
const std::wstring EdgeAppIdIdentifier = L"--app-id=";
|
|
|
|
|
const std::wstring ChromeAppIdIdentifier = L"Chrome._crx_";
|
|
|
|
|
const std::wstring ChromeBase = L"Google\\Chrome\\User Data\\Default\\Web Applications";
|
|
|
|
|
const std::wstring EdgeBase = L"Microsoft\\Edge\\User Data\\Default\\Web Applications";
|
|
|
|
|
const std::wstring ChromeDirPrefix = L"_crx_";
|
|
|
|
|
const std::wstring EdgeDirPrefix = L"_crx__";
|
2024-12-05 18:24:05 +03:00
|
|
|
const std::wstring IcoExtension = L".ico";
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
2024-12-04 18:17:54 +01:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
static const std::wstring& GetLocalAppDataFolder()
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
static std::wstring localFolder{};
|
2024-11-20 20:15:18 +01:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
if (localFolder.empty())
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
wil::unique_cotaskmem_string folderPath;
|
|
|
|
|
HRESULT hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &folderPath);
|
|
|
|
|
if (SUCCEEDED(hres))
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
localFolder = folderPath.get();
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
Logger::error(L"Failed to get the local app data folder path: {}", get_last_error_or_default(hres));
|
|
|
|
|
localFolder = L""; // Ensure it is explicitly set to empty on failure
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
2025-06-17 15:39:44 +08:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
return localFolder;
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Finds all PwaHelper.exe processes with the specified parent process ID
|
|
|
|
|
std::vector<DWORD> FindPwaHelperProcessIds()
|
|
|
|
|
{
|
|
|
|
|
std::vector<DWORD> pwaHelperProcessIds;
|
|
|
|
|
const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
|
|
if (hSnapshot == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
Logger::info(L"Invalid handle when creating snapshot for the search for PwaHelper processes");
|
|
|
|
|
return pwaHelperProcessIds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PROCESSENTRY32 pe;
|
|
|
|
|
pe.dwSize = sizeof(PROCESSENTRY32);
|
|
|
|
|
|
|
|
|
|
if (Process32First(hSnapshot, &pe))
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (_wcsicmp(pe.szExeFile, L"PwaHelper.exe") == 0)
|
|
|
|
|
{
|
|
|
|
|
Logger::info(L"Found a PWA process with id {}", pe.th32ProcessID);
|
|
|
|
|
pwaHelperProcessIds.push_back(pe.th32ProcessID);
|
|
|
|
|
}
|
|
|
|
|
} while (Process32Next(hSnapshot, &pe));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CloseHandle(hSnapshot);
|
|
|
|
|
return pwaHelperProcessIds;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
PwaHelper::PwaHelper()
|
|
|
|
|
{
|
|
|
|
|
InitChromeAppIds();
|
|
|
|
|
InitEdgeAppIds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PwaHelper::InitAppIds(const std::wstring& browserDataFolder, const std::wstring& browserDirPrefix, const std::function<void(const std::wstring&)>& addingAppIdCallback)
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
std::filesystem::path folderPath(GetLocalAppDataFolder());
|
|
|
|
|
folderPath.append(browserDataFolder);
|
|
|
|
|
if (!std::filesystem::exists(folderPath))
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
Logger::info(L"Edge base path does not exist: {}", folderPath.wstring());
|
2024-11-20 20:15:18 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
try
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
for (const auto& directory : std::filesystem::directory_iterator(folderPath))
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
if (!directory.is_directory())
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
continue;
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
const std::wstring directoryName = directory.path().filename();
|
|
|
|
|
if (directoryName.find(browserDirPrefix) != 0)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::wstring appId = directoryName.substr(browserDirPrefix.length());
|
|
|
|
|
if (addingAppIdCallback)
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
addingAppIdCallback(appId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto& filename : std::filesystem::directory_iterator(directory))
|
|
|
|
|
{
|
|
|
|
|
if (!filename.is_directory())
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
const std::filesystem::path filenameString = filename.path().filename();
|
|
|
|
|
if (StringUtils::CaseInsensitiveEquals(filenameString.extension(), NonLocalizable::IcoExtension))
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
const auto stem = filenameString.stem().wstring();
|
|
|
|
|
m_pwaAppIdsToAppNames.insert({ appId, stem });
|
|
|
|
|
Logger::info(L"Found an installed Pwa app {} with PwaAppId {}", stem, appId);
|
|
|
|
|
break;
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-05 18:24:05 +03:00
|
|
|
catch (std::exception& ex)
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
Logger::error("Failed to iterate over the directory: {}", ex.what());
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
void PwaHelper::InitEdgeAppIds()
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
if (!m_edgeAppIds.empty())
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
// already initialized
|
|
|
|
|
return;
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
CommandLineArgsHelper commandLineArgsHelper{};
|
|
|
|
|
|
|
|
|
|
const auto pwaHelperProcessIds = FindPwaHelperProcessIds();
|
|
|
|
|
Logger::info(L"Found {} edge Pwa helper processes", pwaHelperProcessIds.size());
|
|
|
|
|
|
|
|
|
|
for (const auto subProcessID : pwaHelperProcessIds)
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
std::wstring aumidID = GetAUMIDFromProcessId(subProcessID);
|
|
|
|
|
std::wstring commandLineArg = commandLineArgsHelper.GetCommandLineArgs(subProcessID);
|
|
|
|
|
std::wstring appId = GetAppIdFromCommandLineArgs(commandLineArg);
|
|
|
|
|
|
|
|
|
|
m_edgeAppIds.insert({ aumidID, appId });
|
|
|
|
|
Logger::info(L"Found an edge Pwa helper process with AumidID {} and PwaAppId {}", aumidID, appId);
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
InitAppIds(NonLocalizable::EdgeBase, NonLocalizable::EdgeDirPrefix, [&](const std::wstring&) {});
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PwaHelper::InitChromeAppIds()
|
|
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
if (!m_chromeAppIds.empty())
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
// already initialized
|
2024-11-20 20:15:18 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
InitAppIds(NonLocalizable::ChromeBase, NonLocalizable::ChromeDirPrefix, [&](const std::wstring& appId) {
|
|
|
|
|
m_chromeAppIds.push_back(appId);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::wstring> PwaHelper::GetEdgeAppId(const std::wstring& windowAumid) const
|
|
|
|
|
{
|
|
|
|
|
const auto pwaIndex = m_edgeAppIds.find(windowAumid);
|
|
|
|
|
if (pwaIndex != m_edgeAppIds.end())
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
return pwaIndex->second;
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
2025-06-17 15:39:44 +08:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
std::optional<std::wstring> PwaHelper::GetChromeAppId(const std::wstring& windowAumid) const
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
|
|
|
|
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
|
|
|
|
|
if (appIdIndexStart != std::wstring::npos)
|
|
|
|
|
{
|
2024-12-04 18:17:54 +01:00
|
|
|
std::wstring windowAumidSub = windowAumid.substr(appIdIndexStart + NonLocalizable::ChromeAppIdIdentifier.size());
|
|
|
|
|
const auto appIdIndexEnd = windowAumidSub.find(L" ");
|
2024-11-20 20:15:18 +01:00
|
|
|
if (appIdIndexEnd != std::wstring::npos)
|
|
|
|
|
{
|
2024-12-04 18:17:54 +01:00
|
|
|
windowAumidSub = windowAumidSub.substr(0, appIdIndexEnd);
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-04 18:17:54 +01:00
|
|
|
const std::wstring windowAumidBegin = windowAumidSub.substr(0, 10);
|
|
|
|
|
for (const auto chromeAppId : m_chromeAppIds)
|
2024-11-20 20:15:18 +01:00
|
|
|
{
|
|
|
|
|
if (chromeAppId.find(windowAumidBegin) == 0)
|
|
|
|
|
{
|
2024-12-04 18:17:54 +01:00
|
|
|
return chromeAppId;
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-04 18:17:54 +01:00
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
std::wstring PwaHelper::SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const
|
2024-12-04 18:17:54 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
const auto index = m_pwaAppIdsToAppNames.find(pwaAppId);
|
|
|
|
|
if (index != m_pwaAppIdsToAppNames.end())
|
2024-12-04 18:17:54 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
return index->second;
|
|
|
|
|
}
|
2024-12-04 18:17:54 +01:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
std::wstring nameFromAumid{ windowAumid };
|
|
|
|
|
const std::size_t delimiterPos = nameFromAumid.find(L"-");
|
|
|
|
|
if (delimiterPos != std::string::npos)
|
|
|
|
|
{
|
|
|
|
|
return nameFromAumid.substr(0, delimiterPos);
|
|
|
|
|
}
|
2024-12-04 18:17:54 +01:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
return nameFromAumid;
|
|
|
|
|
}
|
2024-12-04 18:17:54 +01:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
std::wstring PwaHelper::GetAppIdFromCommandLineArgs(const std::wstring& commandLineArgs) const
|
|
|
|
|
{
|
|
|
|
|
auto result = commandLineArgs;
|
|
|
|
|
|
|
|
|
|
// remove the prefix
|
|
|
|
|
if (result.find(NonLocalizable::EdgeAppIdIdentifier) == 0)
|
|
|
|
|
{
|
|
|
|
|
result.erase(0, NonLocalizable::EdgeAppIdIdentifier.length());
|
2024-12-04 18:17:54 +01:00
|
|
|
}
|
2024-12-05 18:24:05 +03:00
|
|
|
|
|
|
|
|
// remove the suffix
|
|
|
|
|
auto appIdIndexEnd = result.find(L" ");
|
|
|
|
|
if (appIdIndexEnd != std::wstring::npos)
|
2024-12-04 18:17:54 +01:00
|
|
|
{
|
2024-12-05 18:24:05 +03:00
|
|
|
result = result.substr(0, appIdIndexEnd);
|
|
|
|
|
}
|
2024-12-04 18:17:54 +01:00
|
|
|
|
2024-12-05 18:24:05 +03:00
|
|
|
return result;
|
|
|
|
|
}
|
2024-11-20 20:15:18 +01:00
|
|
|
}
|