mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
[Workspaces] PWA follow-up (#36217)
This commit is contained in:
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@@ -59,6 +59,7 @@ Appium
|
|||||||
Applicationcan
|
Applicationcan
|
||||||
APPLICATIONFRAMEHOST
|
APPLICATIONFRAMEHOST
|
||||||
appmanifest
|
appmanifest
|
||||||
|
appmodel
|
||||||
APPNAME
|
APPNAME
|
||||||
appref
|
appref
|
||||||
appsettings
|
appsettings
|
||||||
@@ -1135,7 +1136,7 @@ pdo
|
|||||||
pdto
|
pdto
|
||||||
pdtobj
|
pdtobj
|
||||||
pdw
|
pdw
|
||||||
peb
|
Peb
|
||||||
pef
|
pef
|
||||||
PElems
|
PElems
|
||||||
Pels
|
Pels
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "CommandLineArgsHelper.h"
|
||||||
|
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
|
||||||
|
CommandLineArgsHelper::CommandLineArgsHelper() :
|
||||||
|
m_wbemHelper(WbemHelper::Create())
|
||||||
|
{
|
||||||
|
if (!m_wbemHelper)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to create WbemHelper");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring CommandLineArgsHelper::GetCommandLineArgs(DWORD processID) const
|
||||||
|
{
|
||||||
|
if (!m_wbemHelper)
|
||||||
|
{
|
||||||
|
Logger::error(L"WbemHelper not initialized");
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring executablePath = m_wbemHelper->GetExecutablePath(processID);
|
||||||
|
std::wstring commandLineArgs = m_wbemHelper->GetCommandLineArgs(processID);
|
||||||
|
|
||||||
|
if (!commandLineArgs.empty())
|
||||||
|
{
|
||||||
|
auto pos = commandLineArgs.find(executablePath);
|
||||||
|
if (pos != std::wstring::npos)
|
||||||
|
{
|
||||||
|
commandLineArgs = commandLineArgs.substr(pos + executablePath.size());
|
||||||
|
auto spacePos = commandLineArgs.find_first_of(' ');
|
||||||
|
if (spacePos != std::wstring::npos)
|
||||||
|
{
|
||||||
|
commandLineArgs = commandLineArgs.substr(spacePos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commandLineArgs;
|
||||||
|
}
|
||||||
15
src/modules/Workspaces/WorkspacesLib/CommandLineArgsHelper.h
Normal file
15
src/modules/Workspaces/WorkspacesLib/CommandLineArgsHelper.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <WorkspacesLib/WbemHelper.h>
|
||||||
|
|
||||||
|
class CommandLineArgsHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommandLineArgsHelper();
|
||||||
|
~CommandLineArgsHelper() = default;
|
||||||
|
|
||||||
|
std::wstring GetCommandLineArgs(DWORD processID) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<WbemHelper> m_wbemHelper;
|
||||||
|
};
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "PwaHelper.h"
|
#include "PwaHelper.h"
|
||||||
#include "AppUtils.h"
|
|
||||||
#include <ShlObj.h>
|
|
||||||
#include <tlhelp32.h>
|
|
||||||
#include <winternl.h>
|
|
||||||
#include <initguid.h>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <wil/result_macros.h>
|
|
||||||
|
#include <appmodel.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <ShlObj.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <propkey.h>
|
||||||
|
|
||||||
|
#include <wil/com.h>
|
||||||
|
|
||||||
#include <common/logger/logger.h>
|
#include <common/logger/logger.h>
|
||||||
#include <common/utils/winapi_error.h>
|
#include <common/utils/winapi_error.h>
|
||||||
#include <wil\com.h>
|
|
||||||
#pragma comment(lib, "ntdll.lib")
|
#include <WorkspacesLib/AppUtils.h>
|
||||||
|
#include <WorkspacesLib/CommandLineArgsHelper.h>
|
||||||
|
#include <WorkspacesLib/StringUtils.h>
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
@@ -22,197 +30,29 @@ namespace Utils
|
|||||||
const std::wstring EdgeBase = L"Microsoft\\Edge\\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 ChromeDirPrefix = L"_crx_";
|
||||||
const std::wstring EdgeDirPrefix = L"_crx__";
|
const std::wstring EdgeDirPrefix = L"_crx__";
|
||||||
|
const std::wstring IcoExtension = L".ico";
|
||||||
}
|
}
|
||||||
|
|
||||||
// {c8900b66-a973-584b-8cae-355b7f55341b}
|
static const std::wstring& GetLocalAppDataFolder()
|
||||||
DEFINE_GUID(CLSID_StartMenuCacheAndAppResolver, 0x660b90c8, 0x73a9, 0x4b58, 0x8c, 0xae, 0x35, 0x5b, 0x7f, 0x55, 0x34, 0x1b);
|
|
||||||
|
|
||||||
// {46a6eeff-908e-4dc6-92a6-64be9177b41c}
|
|
||||||
DEFINE_GUID(IID_IAppResolver_7, 0x46a6eeff, 0x908e, 0x4dc6, 0x92, 0xa6, 0x64, 0xbe, 0x91, 0x77, 0xb4, 0x1c);
|
|
||||||
|
|
||||||
// {de25675a-72de-44b4-9373-05170450c140}
|
|
||||||
DEFINE_GUID(IID_IAppResolver_8, 0xde25675a, 0x72de, 0x44b4, 0x93, 0x73, 0x05, 0x17, 0x04, 0x50, 0xc1, 0x40);
|
|
||||||
|
|
||||||
struct IAppResolver_7 : public IUnknown
|
|
||||||
{
|
{
|
||||||
public:
|
static std::wstring localFolder{};
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForShortcut() = 0;
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForWindow(HWND hWnd, WCHAR** pszAppId, void* pUnknown1, void* pUnknown2, void* pUnknown3) = 0;
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForProcess(DWORD dwProcessId, WCHAR** pszAppId, void* pUnknown1, void* pUnknown2, void* pUnknown3) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IAppResolver_8 : public IUnknown
|
if (localFolder.empty())
|
||||||
{
|
{
|
||||||
public:
|
wil::unique_cotaskmem_string folderPath;
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForShortcut() = 0;
|
HRESULT hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &folderPath);
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForShortcutObject() = 0;
|
if (SUCCEEDED(hres))
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForWindow(HWND hWnd, WCHAR** pszAppId, void* pUnknown1, void* pUnknown2, void* pUnknown3) = 0;
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetAppIDForProcess(DWORD dwProcessId, WCHAR** pszAppId, void* pUnknown1, void* pUnknown2, void* pUnknown3) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::GetAppId_7(HWND hWnd) const
|
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
localFolder = folderPath.get();
|
||||||
std::optional<std::wstring> result = std::nullopt;
|
|
||||||
|
|
||||||
wil::com_ptr<IAppResolver_7> appResolver;
|
|
||||||
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_7, reinterpret_cast<void**>(appResolver.put()));
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
wil::unique_cotaskmem_string pszAppId;
|
|
||||||
hr = appResolver->GetAppIDForWindow(hWnd, &pszAppId, NULL, NULL, NULL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
result = std::wstring(pszAppId.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
appResolver->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::GetAppId_8(HWND hWnd) const
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
std::optional<std::wstring> result = std::nullopt;
|
|
||||||
|
|
||||||
wil::com_ptr<IAppResolver_8> appResolver;
|
|
||||||
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_8, reinterpret_cast<void**>(appResolver.put()));
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
wil::unique_cotaskmem_string pszAppId;
|
|
||||||
hr = appResolver->GetAppIDForWindow(hWnd, &pszAppId, NULL, NULL, NULL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
result = std::wstring(pszAppId.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
appResolver->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring PwaHelper::GetAppId(HWND hWnd) const
|
|
||||||
{
|
|
||||||
std::optional<std::wstring> result = GetAppId_8(hWnd);
|
|
||||||
if (result == std::nullopt)
|
|
||||||
{
|
|
||||||
result = GetAppId_7(hWnd);
|
|
||||||
}
|
|
||||||
return result.has_value() ? result.value() : L"";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::GetProcessId_7(DWORD dwProcessId) const
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
std::optional<std::wstring> result = std::nullopt;
|
|
||||||
|
|
||||||
wil::com_ptr<IAppResolver_7> appResolver;
|
|
||||||
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_7, reinterpret_cast<void**>(appResolver.put()));
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
wil::unique_cotaskmem_string pszAppId;
|
|
||||||
hr = appResolver->GetAppIDForProcess(dwProcessId, &pszAppId, NULL, NULL, NULL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
result = std::wstring(pszAppId.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
appResolver->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::GetProcessId_8(DWORD dwProcessId) const
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
std::optional<std::wstring> result = std::nullopt;
|
|
||||||
|
|
||||||
wil::com_ptr<IAppResolver_8> appResolver;
|
|
||||||
hr = CoCreateInstance(CLSID_StartMenuCacheAndAppResolver, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IAppResolver_8, reinterpret_cast<void**>(appResolver.put()));
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
wil::unique_cotaskmem_string pszAppId;
|
|
||||||
hr = appResolver->GetAppIDForProcess(dwProcessId, &pszAppId, NULL, NULL, NULL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
result = std::wstring(pszAppId.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
appResolver->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring PwaHelper::GetProcessId(DWORD dwProcessId) const
|
|
||||||
{
|
|
||||||
std::optional<std::wstring> result = GetProcessId_8(dwProcessId);
|
|
||||||
if (result == std::nullopt)
|
|
||||||
{
|
|
||||||
result = GetProcessId_7(dwProcessId);
|
|
||||||
}
|
|
||||||
return result.has_value() ? result.value() : L"";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring GetProcCommandLine(DWORD pid)
|
|
||||||
{
|
|
||||||
std::wstring commandLine;
|
|
||||||
|
|
||||||
// Open a handle to the process
|
|
||||||
const HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
|
|
||||||
if (process == NULL)
|
|
||||||
{
|
|
||||||
Logger::error(L"Failed to open the process, error: {}", get_last_error_or_default(GetLastError()));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get the address of the ProcessEnvironmentBlock
|
Logger::error(L"Failed to get the local app data folder path: {}", get_last_error_or_default(hres));
|
||||||
PROCESS_BASIC_INFORMATION pbi = {};
|
localFolder = L""; // Ensure it is explicitly set to empty on failure
|
||||||
NTSTATUS status = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
Logger::error(L"Failed to query the process, error: {}", status);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get the address of the process parameters in the ProcessEnvironmentBlock
|
|
||||||
PEB processEnvironmentBlock = {};
|
|
||||||
if (!ReadProcessMemory(process, pbi.PebBaseAddress, &processEnvironmentBlock, sizeof(processEnvironmentBlock), NULL))
|
|
||||||
{
|
|
||||||
Logger::error(L"Failed to read the process ProcessEnvironmentBlock, error: {}", get_last_error_or_default(GetLastError()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get the command line arguments from the process parameters
|
|
||||||
RTL_USER_PROCESS_PARAMETERS params = {};
|
|
||||||
if (!ReadProcessMemory(process, processEnvironmentBlock.ProcessParameters, ¶ms, sizeof(params), NULL))
|
|
||||||
{
|
|
||||||
Logger::error(L"Failed to read the process params, error: {}", get_last_error_or_default(GetLastError()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UNICODE_STRING& commandLineArgs = params.CommandLine;
|
|
||||||
std::vector<WCHAR> buffer(commandLineArgs.Length / sizeof(WCHAR));
|
|
||||||
if (!ReadProcessMemory(process, commandLineArgs.Buffer, buffer.data(), commandLineArgs.Length, NULL))
|
|
||||||
{
|
|
||||||
Logger::error(L"Failed to read the process command line, error: {}", get_last_error_or_default(GetLastError()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
commandLine.assign(buffer.data(), buffer.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(process);
|
return localFolder;
|
||||||
}
|
|
||||||
|
|
||||||
return commandLine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds all PwaHelper.exe processes with the specified parent process ID
|
// Finds all PwaHelper.exe processes with the specified parent process ID
|
||||||
@@ -245,143 +85,116 @@ namespace Utils
|
|||||||
return pwaHelperProcessIds;
|
return pwaHelperProcessIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PwaHelper::InitAumidToAppId()
|
PwaHelper::PwaHelper()
|
||||||
{
|
{
|
||||||
if (m_pwaAumidToAppId.size() > 0)
|
InitChromeAppIds();
|
||||||
|
InitEdgeAppIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PwaHelper::InitAppIds(const std::wstring& browserDataFolder, const std::wstring& browserDirPrefix, const std::function<void(const std::wstring&)>& addingAppIdCallback)
|
||||||
{
|
{
|
||||||
|
std::filesystem::path folderPath(GetLocalAppDataFolder());
|
||||||
|
folderPath.append(browserDataFolder);
|
||||||
|
if (!std::filesystem::exists(folderPath))
|
||||||
|
{
|
||||||
|
Logger::info(L"Edge base path does not exist: {}", folderPath.wstring());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto pwaHelperProcessIds = FindPwaHelperProcessIds();
|
try
|
||||||
Logger::info(L"Found {} edge Pwa helper processes", pwaHelperProcessIds.size());
|
|
||||||
for (const auto subProcessID : pwaHelperProcessIds)
|
|
||||||
{
|
{
|
||||||
std::wstring aumidID;
|
for (const auto& directory : std::filesystem::directory_iterator(folderPath))
|
||||||
aumidID = GetProcessId(subProcessID);
|
|
||||||
std::wstring commandLineArg = GetProcCommandLine(subProcessID);
|
|
||||||
auto appIdIndexStart = commandLineArg.find(NonLocalizable::EdgeAppIdIdentifier);
|
|
||||||
if (appIdIndexStart != std::wstring::npos)
|
|
||||||
{
|
{
|
||||||
commandLineArg = commandLineArg.substr(appIdIndexStart + NonLocalizable::EdgeAppIdIdentifier.size());
|
if (!directory.is_directory())
|
||||||
auto appIdIndexEnd = commandLineArg.find(L" ");
|
|
||||||
if (appIdIndexEnd != std::wstring::npos)
|
|
||||||
{
|
{
|
||||||
commandLineArg = commandLineArg.substr(0, appIdIndexEnd);
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
std::wstring appId{ commandLineArg };
|
|
||||||
m_pwaAumidToAppId.insert(std::map<std::wstring, std::wstring>::value_type(aumidID, appId));
|
|
||||||
Logger::info(L"Found an edge Pwa helper process with AumidID {} and PwaAppId {}", aumidID, appId);
|
|
||||||
|
|
||||||
PWSTR path = NULL;
|
const std::wstring directoryName = directory.path().filename();
|
||||||
HRESULT hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path);
|
if (directoryName.find(browserDirPrefix) != 0)
|
||||||
if (SUCCEEDED(hres))
|
|
||||||
{
|
{
|
||||||
std::filesystem::path fsPath(path);
|
continue;
|
||||||
fsPath /= NonLocalizable::EdgeBase;
|
}
|
||||||
for (const auto& directory : std::filesystem::directory_iterator(fsPath))
|
|
||||||
{
|
const std::wstring appId = directoryName.substr(browserDirPrefix.length());
|
||||||
if (directory.is_directory())
|
if (addingAppIdCallback)
|
||||||
{
|
|
||||||
const std::filesystem::path directoryName = directory.path().filename();
|
|
||||||
if (directoryName.wstring().find(NonLocalizable::EdgeDirPrefix) == 0)
|
|
||||||
{
|
|
||||||
const std::wstring appIdDir = directoryName.wstring().substr(NonLocalizable::EdgeDirPrefix.size());
|
|
||||||
if (appIdDir == appId)
|
|
||||||
{
|
{
|
||||||
|
addingAppIdCallback(appId);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& filename : std::filesystem::directory_iterator(directory))
|
for (const auto& filename : std::filesystem::directory_iterator(directory))
|
||||||
{
|
{
|
||||||
if (!filename.is_directory())
|
if (!filename.is_directory())
|
||||||
{
|
{
|
||||||
const std::filesystem::path filenameString = filename.path().filename();
|
const std::filesystem::path filenameString = filename.path().filename();
|
||||||
if (filenameString.extension().wstring() == L".ico")
|
if (StringUtils::CaseInsensitiveEquals(filenameString.extension(), NonLocalizable::IcoExtension))
|
||||||
{
|
{
|
||||||
m_pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
|
const auto stem = filenameString.stem().wstring();
|
||||||
Logger::info(L"Storing an edge Pwa app name {} for PwaAppId {}", filenameString.stem().wstring(), appId);
|
m_pwaAppIdsToAppNames.insert({ appId, stem });
|
||||||
|
Logger::info(L"Found an installed Pwa app {} with PwaAppId {}", stem, appId);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
catch (std::exception& ex)
|
||||||
}
|
{
|
||||||
CoTaskMemFree(path);
|
Logger::error("Failed to iterate over the directory: {}", ex.what());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::GetPwaAppId(const std::wstring& windowAumid) const
|
void PwaHelper::InitEdgeAppIds()
|
||||||
{
|
{
|
||||||
const auto pwaIndex = m_pwaAumidToAppId.find(windowAumid);
|
if (!m_edgeAppIds.empty())
|
||||||
if (pwaIndex != m_pwaAumidToAppId.end())
|
{
|
||||||
|
// already initialized
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandLineArgsHelper commandLineArgsHelper{};
|
||||||
|
|
||||||
|
const auto pwaHelperProcessIds = FindPwaHelperProcessIds();
|
||||||
|
Logger::info(L"Found {} edge Pwa helper processes", pwaHelperProcessIds.size());
|
||||||
|
|
||||||
|
for (const auto subProcessID : pwaHelperProcessIds)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
InitAppIds(NonLocalizable::EdgeBase, NonLocalizable::EdgeDirPrefix, [&](const std::wstring&) {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void PwaHelper::InitChromeAppIds()
|
||||||
|
{
|
||||||
|
if (!m_chromeAppIds.empty())
|
||||||
|
{
|
||||||
|
// already initialized
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
{
|
{
|
||||||
return pwaIndex->second;
|
return pwaIndex->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring PwaHelper::SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const
|
std::optional<std::wstring> PwaHelper::GetChromeAppId(const std::wstring& windowAumid) const
|
||||||
{
|
|
||||||
const auto index = m_pwaAppIdsToAppNames.find(pwaAppId);
|
|
||||||
if (index != m_pwaAppIdsToAppNames.end())
|
|
||||||
{
|
|
||||||
return index->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring nameFromAumid{ windowAumid };
|
|
||||||
const std::size_t delimiterPos = nameFromAumid.find(L"-");
|
|
||||||
if (delimiterPos != std::string::npos)
|
|
||||||
{
|
|
||||||
return nameFromAumid.substr(0, delimiterPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nameFromAumid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PwaHelper::InitChromeAppIds()
|
|
||||||
{
|
|
||||||
if (m_chromeAppIds.size() > 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PWSTR path = NULL;
|
|
||||||
HRESULT hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path);
|
|
||||||
if (SUCCEEDED(hres))
|
|
||||||
{
|
|
||||||
std::filesystem::path fsPath(path);
|
|
||||||
fsPath /= NonLocalizable::ChromeBase;
|
|
||||||
for (const auto& directory : std::filesystem::directory_iterator(fsPath))
|
|
||||||
{
|
|
||||||
if (directory.is_directory())
|
|
||||||
{
|
|
||||||
const std::filesystem::path directoryName = directory.path().filename();
|
|
||||||
if (directoryName.wstring().find(NonLocalizable::ChromeDirPrefix) == 0)
|
|
||||||
{
|
|
||||||
const std::wstring appId = directoryName.wstring().substr(NonLocalizable::ChromeDirPrefix.size());
|
|
||||||
m_chromeAppIds.push_back(appId);
|
|
||||||
for (const auto& filename : std::filesystem::directory_iterator(directory))
|
|
||||||
{
|
|
||||||
if (!filename.is_directory())
|
|
||||||
{
|
|
||||||
const std::filesystem::path filenameString = filename.path().filename();
|
|
||||||
if (filenameString.extension().wstring() == L".ico")
|
|
||||||
{
|
|
||||||
m_pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
|
|
||||||
Logger::info(L"Found an installed chrome Pwa app {} with PwaAppId {}", filenameString.stem().wstring(), appId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CoTaskMemFree(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::SearchPwaAppId(const std::wstring& windowAumid) const
|
|
||||||
{
|
{
|
||||||
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
|
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
|
||||||
if (appIdIndexStart != std::wstring::npos)
|
if (appIdIndexStart != std::wstring::npos)
|
||||||
@@ -406,48 +219,122 @@ namespace Utils
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PwaHelper::UpdatePwaApp(Utils::Apps::AppData* appData, HWND window)
|
std::wstring PwaHelper::SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const
|
||||||
{
|
{
|
||||||
std::optional<std::wstring> pwaAppId = std::nullopt;
|
const auto index = m_pwaAppIdsToAppNames.find(pwaAppId);
|
||||||
std::wstring finalName = appData->name;
|
if (index != m_pwaAppIdsToAppNames.end())
|
||||||
std::wstring pwaName = L"";
|
|
||||||
if (appData->IsEdge())
|
|
||||||
{
|
{
|
||||||
InitAumidToAppId();
|
return index->second;
|
||||||
|
|
||||||
std::wstring windowAumid = GetAppId(window);
|
|
||||||
|
|
||||||
Logger::info(L"Found an edge window with aumid {}", windowAumid);
|
|
||||||
|
|
||||||
pwaAppId = GetPwaAppId(windowAumid);
|
|
||||||
if (pwaAppId.has_value())
|
|
||||||
{
|
|
||||||
Logger::info(L"The found edge window is a PWA app with appId {}", pwaAppId.value());
|
|
||||||
pwaName = SearchPwaName(pwaAppId.value(), windowAumid);
|
|
||||||
Logger::info(L"The found edge window is a PWA app with name {}", pwaName);
|
|
||||||
finalName = pwaName + L" (" + finalName + L")";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::info(L"The found edge window does not contain a PWA app");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (appData->IsChrome())
|
|
||||||
{
|
|
||||||
InitChromeAppIds();
|
|
||||||
|
|
||||||
std::wstring windowAumid = GetAppId(window);
|
|
||||||
Logger::info(L"Found a chrome window with aumid {}", windowAumid);
|
|
||||||
|
|
||||||
pwaAppId = SearchPwaAppId(windowAumid);
|
|
||||||
if (pwaAppId.has_value())
|
|
||||||
{
|
|
||||||
pwaName = SearchPwaName(pwaAppId.value(), windowAumid);
|
|
||||||
finalName = pwaName + L" (" + finalName + L")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
appData->name = finalName;
|
std::wstring nameFromAumid{ windowAumid };
|
||||||
appData->pwaAppId = pwaAppId.has_value() ? pwaAppId.value() : L"";
|
const std::size_t delimiterPos = nameFromAumid.find(L"-");
|
||||||
|
if (delimiterPos != std::string::npos)
|
||||||
|
{
|
||||||
|
return nameFromAumid.substr(0, delimiterPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameFromAumid;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the suffix
|
||||||
|
auto appIdIndexEnd = result.find(L" ");
|
||||||
|
if (appIdIndexEnd != std::wstring::npos)
|
||||||
|
{
|
||||||
|
result = result.substr(0, appIdIndexEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring PwaHelper::GetAUMIDFromWindow(HWND hwnd) const
|
||||||
|
{
|
||||||
|
std::wstring result{};
|
||||||
|
if (hwnd == NULL)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IPropertyStore> propertyStore;
|
||||||
|
HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&propertyStore));
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROPVARIANT propVariant;
|
||||||
|
PropVariantInit(&propVariant);
|
||||||
|
|
||||||
|
hr = propertyStore->GetValue(PKEY_AppUserModel_ID, &propVariant);
|
||||||
|
if (SUCCEEDED(hr) && propVariant.vt == VT_LPWSTR && propVariant.pwszVal != nullptr)
|
||||||
|
{
|
||||||
|
result = propVariant.pwszVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropVariantClear(&propVariant);
|
||||||
|
|
||||||
|
Logger::info(L"Found a window with aumid {}", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring PwaHelper::GetAUMIDFromProcessId(DWORD processId) const
|
||||||
|
{
|
||||||
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId);
|
||||||
|
if (hProcess == NULL)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to open process handle. Error: {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the package full name for the process
|
||||||
|
UINT32 packageFullNameLength = 0;
|
||||||
|
LONG rc = GetPackageFullName(hProcess, &packageFullNameLength, nullptr);
|
||||||
|
if (rc != ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to get package full name length. Error code: {}", rc);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<wchar_t> packageFullName(packageFullNameLength);
|
||||||
|
rc = GetPackageFullName(hProcess, &packageFullNameLength, packageFullName.data());
|
||||||
|
if (rc != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to get package full name. Error code: {}", rc);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the AUMID for the package
|
||||||
|
UINT32 appModelIdLength = 0;
|
||||||
|
rc = GetApplicationUserModelId(hProcess, &appModelIdLength, nullptr);
|
||||||
|
if (rc != ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to get AppUserModelId length. Error code: {}", rc);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<wchar_t> appModelId(appModelIdLength);
|
||||||
|
rc = GetApplicationUserModelId(hProcess, &appModelIdLength, appModelId.data());
|
||||||
|
if (rc != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to get AppUserModelId. Error code: {}", rc);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return std::wstring(appModelId.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <WorkspacesLib/AppUtils.h>
|
#include <WorkspacesLib/AppUtils.h>
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
@@ -7,23 +9,25 @@ namespace Utils
|
|||||||
class PwaHelper
|
class PwaHelper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void UpdatePwaApp(Apps::AppData* appData, HWND window);
|
PwaHelper();
|
||||||
|
~PwaHelper() = default;
|
||||||
|
|
||||||
|
std::wstring GetAUMIDFromWindow(HWND hWnd) const;
|
||||||
|
|
||||||
|
std::optional<std::wstring> GetEdgeAppId(const std::wstring& windowAumid) const;
|
||||||
|
std::optional<std::wstring> GetChromeAppId(const std::wstring& windowAumid) const;
|
||||||
|
std::wstring SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::wstring, std::wstring> m_pwaAumidToAppId;
|
void InitAppIds(const std::wstring& browserDataFolder, const std::wstring& browserDirPrefix, const std::function<void(const std::wstring&)>& addingAppIdCallback);
|
||||||
|
void InitEdgeAppIds();
|
||||||
|
void InitChromeAppIds();
|
||||||
|
|
||||||
|
std::wstring GetAppIdFromCommandLineArgs(const std::wstring& commandLineArgs) const;
|
||||||
|
std::wstring GetAUMIDFromProcessId(DWORD processId) const;
|
||||||
|
|
||||||
|
std::map<std::wstring, std::wstring> m_edgeAppIds;
|
||||||
std::vector<std::wstring> m_chromeAppIds;
|
std::vector<std::wstring> m_chromeAppIds;
|
||||||
std::map<std::wstring, std::wstring> m_pwaAppIdsToAppNames;
|
std::map<std::wstring, std::wstring> m_pwaAppIdsToAppNames;
|
||||||
|
|
||||||
void InitAumidToAppId();
|
|
||||||
void InitChromeAppIds();
|
|
||||||
std::optional<std::wstring> GetAppId_7(HWND hWnd) const;
|
|
||||||
std::optional<std::wstring> GetAppId_8(HWND hWnd) const;
|
|
||||||
std::wstring GetAppId(HWND hWnd) const;
|
|
||||||
std::optional<std::wstring> GetProcessId_7(DWORD dwProcessId) const;
|
|
||||||
std::optional<std::wstring> GetProcessId_8(DWORD dwProcessId) const;
|
|
||||||
std::wstring GetProcessId(DWORD dwProcessId) const;
|
|
||||||
std::optional<std::wstring> GetPwaAppId(const std::wstring& windowAumid) const;
|
|
||||||
std::wstring SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const;
|
|
||||||
std::optional<std::wstring> SearchPwaAppId(const std::wstring& windowAumid) const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/modules/Workspaces/WorkspacesLib/StringUtils.h
Normal file
20
src/modules/Workspaces/WorkspacesLib/StringUtils.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cwctype>
|
||||||
|
|
||||||
|
namespace StringUtils
|
||||||
|
{
|
||||||
|
bool CaseInsensitiveEquals(const std::wstring& str1, const std::wstring& str2)
|
||||||
|
{
|
||||||
|
if (str1.size() != str2.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::equal(str1.begin(), str1.end(), str2.begin(), [](wchar_t ch1, wchar_t ch2) {
|
||||||
|
return towupper(ch1) == towupper(ch2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
120
src/modules/Workspaces/WorkspacesLib/WbemHelper.cpp
Normal file
120
src/modules/Workspaces/WorkspacesLib/WbemHelper.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "WbemHelper.h"
|
||||||
|
|
||||||
|
#include <comdef.h>
|
||||||
|
#include <Wbemidl.h>
|
||||||
|
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "wbemuuid.lib")
|
||||||
|
|
||||||
|
std::unique_ptr<WbemHelper> WbemHelper::Create()
|
||||||
|
{
|
||||||
|
auto instance = std::unique_ptr<WbemHelper>(new WbemHelper());
|
||||||
|
if (instance->Initialize())
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
WbemHelper::~WbemHelper()
|
||||||
|
{
|
||||||
|
if (m_services)
|
||||||
|
{
|
||||||
|
m_services->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_locator)
|
||||||
|
{
|
||||||
|
m_locator->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring WbemHelper::GetCommandLineArgs(DWORD processID) const
|
||||||
|
{
|
||||||
|
static std::wstring property = L"CommandLine";
|
||||||
|
std::wstring query = L"SELECT " + property + L" FROM Win32_Process WHERE ProcessId = " + std::to_wstring(processID);
|
||||||
|
return Query(query, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring WbemHelper::GetExecutablePath(DWORD processID) const
|
||||||
|
{
|
||||||
|
static std::wstring property = L"ExecutablePath";
|
||||||
|
std::wstring query = L"SELECT " + property + L" FROM Win32_Process WHERE ProcessId = " + std::to_wstring(processID);
|
||||||
|
return Query(query, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WbemHelper::Initialize()
|
||||||
|
{
|
||||||
|
// Obtain the initial locator to WMI.
|
||||||
|
HRESULT hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<LPVOID*>(&m_locator));
|
||||||
|
if (FAILED(hres))
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to create IWbemLocator object. Error: {}", get_last_error_or_default(hres));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to WMI through the IWbemLocator::ConnectServer method.
|
||||||
|
hres = m_locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &m_services);
|
||||||
|
if (FAILED(hres))
|
||||||
|
{
|
||||||
|
Logger::error(L"Could not connect to WMI. Error: {}", get_last_error_or_default(hres));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set security levels on the proxy.
|
||||||
|
hres = CoSetProxyBlanket(m_services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||||
|
if (FAILED(hres))
|
||||||
|
{
|
||||||
|
Logger::error(L"Could not set proxy blanket. Error: {}", get_last_error_or_default(hres));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring WbemHelper::Query(const std::wstring& query, const std::wstring& propertyName) const
|
||||||
|
{
|
||||||
|
if (!m_locator || !m_services)
|
||||||
|
{
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumWbemClassObject* pEnumerator = NULL;
|
||||||
|
|
||||||
|
HRESULT hres = m_services->ExecQuery(bstr_t("WQL"), bstr_t(query.c_str()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
|
||||||
|
if (FAILED(hres))
|
||||||
|
{
|
||||||
|
Logger::error(L"Query for process failed. Error: {}", get_last_error_or_default(hres));
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
IWbemClassObject* pClassObject = NULL;
|
||||||
|
ULONG uReturn = 0;
|
||||||
|
std::wstring result = L"";
|
||||||
|
while (pEnumerator)
|
||||||
|
{
|
||||||
|
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObject, &uReturn);
|
||||||
|
if (uReturn == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VARIANT vtProp;
|
||||||
|
hr = pClassObject->Get(propertyName.c_str(), 0, &vtProp, 0, 0);
|
||||||
|
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR)
|
||||||
|
{
|
||||||
|
result = vtProp.bstrVal;
|
||||||
|
}
|
||||||
|
VariantClear(&vtProp);
|
||||||
|
|
||||||
|
pClassObject->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
pEnumerator->Release();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
24
src/modules/Workspaces/WorkspacesLib/WbemHelper.h
Normal file
24
src/modules/Workspaces/WorkspacesLib/WbemHelper.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct IWbemLocator;
|
||||||
|
struct IWbemServices;
|
||||||
|
|
||||||
|
class WbemHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<WbemHelper> Create();
|
||||||
|
~WbemHelper();
|
||||||
|
|
||||||
|
std::wstring GetCommandLineArgs(DWORD processID) const;
|
||||||
|
std::wstring GetExecutablePath(DWORD processID) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WbemHelper() = default;
|
||||||
|
|
||||||
|
bool Initialize();
|
||||||
|
|
||||||
|
std::wstring Query(const std::wstring& query, const std::wstring& propertyName) const;
|
||||||
|
|
||||||
|
IWbemLocator* m_locator = NULL;
|
||||||
|
IWbemServices* m_services = NULL;
|
||||||
|
};
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="AppUtils.h" />
|
<ClInclude Include="AppUtils.h" />
|
||||||
|
<ClInclude Include="CommandLineArgsHelper.h" />
|
||||||
<ClInclude Include="IPCHelper.h" />
|
<ClInclude Include="IPCHelper.h" />
|
||||||
<ClInclude Include="JsonUtils.h" />
|
<ClInclude Include="JsonUtils.h" />
|
||||||
<ClInclude Include="LaunchingStateEnum.h" />
|
<ClInclude Include="LaunchingStateEnum.h" />
|
||||||
@@ -40,12 +41,15 @@
|
|||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="PwaHelper.h" />
|
<ClInclude Include="PwaHelper.h" />
|
||||||
<ClInclude Include="Result.h" />
|
<ClInclude Include="Result.h" />
|
||||||
|
<ClInclude Include="StringUtils.h" />
|
||||||
<ClInclude Include="utils.h" />
|
<ClInclude Include="utils.h" />
|
||||||
|
<ClInclude Include="WbemHelper.h" />
|
||||||
<ClInclude Include="WorkspacesData.h" />
|
<ClInclude Include="WorkspacesData.h" />
|
||||||
<ClInclude Include="trace.h" />
|
<ClInclude Include="trace.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="AppUtils.cpp" />
|
<ClCompile Include="AppUtils.cpp" />
|
||||||
|
<ClCompile Include="CommandLineArgsHelper.cpp" />
|
||||||
<ClCompile Include="IPCHelper.cpp" />
|
<ClCompile Include="IPCHelper.cpp" />
|
||||||
<ClCompile Include="JsonUtils.cpp" />
|
<ClCompile Include="JsonUtils.cpp" />
|
||||||
<ClCompile Include="LaunchingStatus.cpp" />
|
<ClCompile Include="LaunchingStatus.cpp" />
|
||||||
@@ -54,6 +58,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="PwaHelper.cpp" />
|
<ClCompile Include="PwaHelper.cpp" />
|
||||||
<ClCompile Include="two_way_pipe_message_ipc.cpp" />
|
<ClCompile Include="two_way_pipe_message_ipc.cpp" />
|
||||||
|
<ClCompile Include="WbemHelper.cpp" />
|
||||||
<ClCompile Include="WorkspacesData.cpp" />
|
<ClCompile Include="WorkspacesData.cpp" />
|
||||||
<ClCompile Include="trace.cpp" />
|
<ClCompile Include="trace.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -44,6 +44,15 @@
|
|||||||
<ClInclude Include="PwaHelper.h">
|
<ClInclude Include="PwaHelper.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="CommandLineArgsHelper.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="WbemHelper.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="StringUtils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
@@ -73,8 +82,17 @@
|
|||||||
<ClCompile Include="PwaHelper.cpp">
|
<ClCompile Include="PwaHelper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="CommandLineArgsHelper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="WbemHelper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -116,7 +116,33 @@ namespace SnapshotUtils
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pwaHelper.UpdatePwaApp(&data.value(), window);
|
auto appData = data.value();
|
||||||
|
|
||||||
|
bool isEdge = appData.IsEdge();
|
||||||
|
bool isChrome = appData.IsChrome();
|
||||||
|
if (isEdge || isChrome)
|
||||||
|
{
|
||||||
|
auto windowAumid = pwaHelper.GetAUMIDFromWindow(window);
|
||||||
|
std::optional<std::wstring> pwaAppId{};
|
||||||
|
|
||||||
|
if (isEdge)
|
||||||
|
{
|
||||||
|
pwaAppId = pwaHelper.GetEdgeAppId(windowAumid);
|
||||||
|
}
|
||||||
|
else if (isChrome)
|
||||||
|
{
|
||||||
|
pwaAppId = pwaHelper.GetChromeAppId(windowAumid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwaAppId.has_value())
|
||||||
|
{
|
||||||
|
auto pwaName = pwaHelper.SearchPwaName(pwaAppId.value(), windowAumid);
|
||||||
|
Logger::info(L"Found {} PWA app with name {}, appId: {}", (isEdge ? L"Edge" : (isChrome ? L"Chrome" : L"unknown")), pwaName, pwaAppId.value());
|
||||||
|
|
||||||
|
appData.pwaAppId = pwaAppId.value();
|
||||||
|
appData.name = pwaName + L" (" + appData.name + L")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isMinimized = WindowUtils::IsMinimized(window);
|
bool isMinimized = WindowUtils::IsMinimized(window);
|
||||||
unsigned int monitorNumber = getMonitorNumberFromWindowHandle(window);
|
unsigned int monitorNumber = getMonitorNumberFromWindowHandle(window);
|
||||||
@@ -132,15 +158,15 @@ namespace SnapshotUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
WorkspacesData::WorkspacesProject::Application app{
|
WorkspacesData::WorkspacesProject::Application app{
|
||||||
.name = data.value().name,
|
.name = appData.name,
|
||||||
.title = title,
|
.title = title,
|
||||||
.path = data.value().installPath,
|
.path = appData.installPath,
|
||||||
.packageFullName = data.value().packageFullName,
|
.packageFullName = appData.packageFullName,
|
||||||
.appUserModelId = data.value().appUserModelId,
|
.appUserModelId = appData.appUserModelId,
|
||||||
.pwaAppId = data.value().pwaAppId,
|
.pwaAppId = appData.pwaAppId,
|
||||||
.commandLineArgs = L"",
|
.commandLineArgs = L"",
|
||||||
.isElevated = IsProcessElevated(pid),
|
.isElevated = IsProcessElevated(pid),
|
||||||
.canLaunchElevated = data.value().canLaunchElevated,
|
.canLaunchElevated = appData.canLaunchElevated,
|
||||||
.isMinimized = isMinimized,
|
.isMinimized = isMinimized,
|
||||||
.isMaximized = WindowUtils::IsMaximized(window),
|
.isMaximized = WindowUtils::IsMaximized(window),
|
||||||
.position = WorkspacesData::WorkspacesProject::Application::Position{
|
.position = WorkspacesData::WorkspacesProject::Application::Position{
|
||||||
|
|||||||
@@ -178,9 +178,36 @@ std::optional<WindowWithDistance> WindowArranger::GetNearestWindow(const Workspa
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pwaHelper.UpdatePwaApp(&data.value(), window);
|
auto appData = data.value();
|
||||||
|
|
||||||
if ((app.name == data.value().name || app.path == data.value().installPath) && (app.pwaAppId == data.value().pwaAppId))
|
// PWA apps
|
||||||
|
bool isEdge = appData.IsEdge();
|
||||||
|
bool isChrome = appData.IsChrome();
|
||||||
|
if (isEdge || isChrome)
|
||||||
|
{
|
||||||
|
auto windowAumid = pwaHelper.GetAUMIDFromWindow(window);
|
||||||
|
std::optional<std::wstring> pwaAppId{};
|
||||||
|
|
||||||
|
if (isEdge)
|
||||||
|
{
|
||||||
|
pwaAppId = pwaHelper.GetEdgeAppId(windowAumid);
|
||||||
|
}
|
||||||
|
else if (isChrome)
|
||||||
|
{
|
||||||
|
pwaAppId = pwaHelper.GetChromeAppId(windowAumid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwaAppId.has_value())
|
||||||
|
{
|
||||||
|
auto pwaName = pwaHelper.SearchPwaName(pwaAppId.value(), windowAumid);
|
||||||
|
Logger::info(L"Found {} PWA app with name {}, appId: {}", (isEdge ? L"Edge" : (isChrome ? L"Chrome" : L"unknown")), pwaName, pwaAppId.value());
|
||||||
|
|
||||||
|
appData.pwaAppId = pwaAppId.value();
|
||||||
|
appData.name = pwaName + L" (" + appData.name + L")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((app.name == appData.name || app.path == appData.installPath) && (app.pwaAppId == appData.pwaAppId))
|
||||||
{
|
{
|
||||||
if (!appDataNearest.has_value())
|
if (!appDataNearest.has_value())
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user