[Workspaces] Implement PWA recognition, launch. (#35913)

* [Workspaces] PWA: first steps: implement PWA app searcher, add basic controls to the editor

* spell checker

* Snapshot tool: adding command line args for edge

* PWA: add icon handling, add launch of PWA

* Impllement Aumid getters and comparison to connect PWA windows and processes. Update LauncherUI, Launcher

* Minor fixes, simplifications

* Spell checker

* Removing manual PWA selection, spell checker

* Fix merge conflict

* Trying to convince spell checker, that "PEB" is a correct word.

* XAML format fix

* Extending snapshot tool by logs for better testablility

* spell checker fix

* extending logs

* extending logs

* Removing some logs, modifying search criteria for pwa helper process search

* extending PWA detection for the case the directory with the app-id is missing

* Fix issue when pwaAppId is null

* fix missing pwa-app-id handling in the editor. Removed unused property (code cleaning) and updating json parser in Launcher

* Code cleaning: Moving duplicate code to a common project

* Fix issue: adding new Guid as app id if it is empty

* Code cleanup: moving Pwa related code from snapshotUtils to PwaHelper

* Code cleaning

* Code cleanup: Move common Application model to Csharp Library

* code cleanup

* modifying package name

* Ading project reference to Common.UI

* Code cleaning, fixing references

---------

Co-authored-by: donlaci <donlaci@yahoo.com>
This commit is contained in:
Laszlo Nemeth
2024-11-20 20:15:18 +01:00
committed by GitHub
parent f66450f6a8
commit 6b3bbf7e8f
26 changed files with 967 additions and 538 deletions

View File

@@ -0,0 +1,409 @@
#include "pch.h"
#include "PwaHelper.h"
#include <ShlObj.h>
#include <tlhelp32.h>
#include <winternl.h>
#include <initguid.h>
#include <filesystem>
#include <wil/result_macros.h>
#include <common/logger/logger.h>
#include <common/utils/winapi_error.h>
#include <wil\com.h>
#pragma comment(lib, "ntdll.lib")
namespace SnapshotUtils
{
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__";
}
// {c8900b66-a973-584b-8cae-355b7f55341b}
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:
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
{
public:
virtual HRESULT STDMETHODCALLTYPE GetAppIDForShortcut() = 0;
virtual HRESULT STDMETHODCALLTYPE GetAppIDForShortcutObject() = 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;
};
BOOL GetAppId_7(HWND hWnd, std::wstring* result)
{
HRESULT hr;
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 SUCCEEDED(hr);
}
BOOL GetAppId_8(HWND hWnd, std::wstring* result)
{
HRESULT hr;
*result = L"";
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 SUCCEEDED(hr);
}
BOOL PwaHelper::GetAppId(HWND hWnd, std::wstring* result)
{
HRESULT hr = GetAppId_8(hWnd, result);
if (!SUCCEEDED(hr))
{
hr = GetAppId_7(hWnd, result);
}
return SUCCEEDED(hr);
}
BOOL GetProcessId_7(DWORD dwProcessId, std::wstring* result)
{
HRESULT hr;
*result = L"";
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 SUCCEEDED(hr);
}
BOOL GetProcessId_8(DWORD dwProcessId, std::wstring* result)
{
HRESULT hr;
*result = L"";
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 SUCCEEDED(hr);
}
BOOL GetProcessId(DWORD dwProcessId, std::wstring* result)
{
HRESULT hr = GetProcessId_8(dwProcessId, result);
if (!SUCCEEDED(hr))
{
hr = GetProcessId_7(dwProcessId, result);
}
return SUCCEEDED(hr);
}
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
{
// Get the address of the ProcessEnvironmentBlock
PROCESS_BASIC_INFORMATION pbi = {};
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, &params, 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 commandLine;
}
// 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;
}
void PwaHelper::InitAumidToAppId()
{
if (pwaAumidToAppId.size() > 0)
{
return;
}
const auto pwaHelperProcessIds = FindPwaHelperProcessIds();
Logger::info(L"Found {} edge Pwa helper processes", pwaHelperProcessIds.size());
for (const auto subProcessID : pwaHelperProcessIds)
{
std::wstring aumidID;
GetProcessId(subProcessID, &aumidID);
std::wstring commandLineArg = GetProcCommandLine(subProcessID);
auto appIdIndexStart = commandLineArg.find(NonLocalizable::EdgeAppIdIdentifier);
if (appIdIndexStart != std::wstring::npos)
{
commandLineArg = commandLineArg.substr(appIdIndexStart + NonLocalizable::EdgeAppIdIdentifier.size());
auto appIdIndexEnd = commandLineArg.find(L" ");
if (appIdIndexEnd != std::wstring::npos)
{
commandLineArg = commandLineArg.substr(0, appIdIndexEnd);
}
}
std::wstring appId{ commandLineArg };
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;
HRESULT hres = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path);
if (SUCCEEDED(hres))
{
std::filesystem::path fsPath(path);
fsPath /= NonLocalizable::EdgeBase;
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::EdgeDirPrefix) == 0)
{
const std::wstring appIdDir = directoryName.wstring().substr(NonLocalizable::EdgeDirPrefix.size());
if (appIdDir == 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")
{
pwaAppIdsToAppNames.insert(std::map<std::wstring, std::wstring>::value_type(appId, filenameString.stem().wstring()));
Logger::info(L"Storing an edge Pwa app name {} for PwaAppId {}", filenameString.stem().wstring(), appId);
}
}
}
}
}
}
}
CoTaskMemFree(path);
}
}
}
BOOL PwaHelper::GetPwaAppId(std::wstring windowAumid, std::wstring* result)
{
const auto pwaIndex = pwaAumidToAppId.find(windowAumid);
if (pwaIndex != pwaAumidToAppId.end())
{
*result = pwaIndex->second;
return true;
}
return false;
}
BOOL PwaHelper::SearchPwaName(std::wstring pwaAppId, std::wstring windowAumid, std::wstring* pwaName)
{
const auto index = pwaAppIdsToAppNames.find(pwaAppId);
if (index != pwaAppIdsToAppNames.end())
{
*pwaName = index->second;
return true;
}
std::wstring nameFromAumid{ windowAumid };
const std::size_t delimiterPos = nameFromAumid.find(L"-");
if (delimiterPos != std::string::npos)
{
nameFromAumid = nameFromAumid.substr(0, delimiterPos);
}
*pwaName = nameFromAumid;
return false;
}
void PwaHelper::InitChromeAppIds()
{
if (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());
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")
{
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);
}
}
BOOL PwaHelper::SearchPwaAppId(std::wstring windowAumid, std::wstring* pwaAppId)
{
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
if (appIdIndexStart != std::wstring::npos)
{
windowAumid = windowAumid.substr(appIdIndexStart + NonLocalizable::ChromeAppIdIdentifier.size());
const auto appIdIndexEnd = windowAumid.find(L" ");
if (appIdIndexEnd != std::wstring::npos)
{
windowAumid = windowAumid.substr(0, appIdIndexEnd);
}
const std::wstring windowAumidBegin = windowAumid.substr(0, 10);
for (const auto chromeAppId : chromeAppIds)
{
if (chromeAppId.find(windowAumidBegin) == 0)
{
*pwaAppId = chromeAppId;
return true;
}
}
}
*pwaAppId = L"";
return false;
}
}

View File

@@ -0,0 +1,20 @@
#pragma once
namespace SnapshotUtils
{
class PwaHelper
{
public:
void InitAumidToAppId();
BOOL GetAppId(HWND hWnd, std::wstring* result);
BOOL GetPwaAppId(std::wstring windowAumid, std::wstring* result);
BOOL SearchPwaName(std::wstring pwaAppId, std::wstring windowAumid, std::wstring* pwaName);
void InitChromeAppIds();
BOOL SearchPwaAppId(std::wstring windowAumid, std::wstring* pwaAppId);
private:
std::map<std::wstring, std::wstring> pwaAumidToAppId;
std::vector<std::wstring> chromeAppIds;
std::map<std::wstring, std::wstring> pwaAppIdsToAppNames;
};
}

View File

@@ -1,9 +1,6 @@
#include "pch.h"
#include "SnapshotUtils.h"
#include <comdef.h>
#include <Wbemidl.h>
#include <common/utils/elevation.h>
#include <common/utils/process_path.h>
#include <common/notifications/NotificationUtil.h>
@@ -12,142 +9,17 @@
#include <workspaces-common/WindowFilter.h>
#include <WorkspacesLib/AppUtils.h>
#include <PwaHelper.h>
#pragma comment(lib, "ntdll.lib")
namespace SnapshotUtils
{
namespace NonLocalizable
{
const std::wstring ApplicationFrameHost = L"ApplicationFrameHost.exe";
}
class WbemHelper
{
public:
WbemHelper() = default;
~WbemHelper()
{
if (m_services)
{
m_services->Release();
}
if (m_locator)
{
m_locator->Release();
}
}
bool 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 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 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);
}
private:
std::wstring 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;
}
IWbemLocator* m_locator = NULL;
IWbemServices* m_services = NULL;
};
std::wstring GetCommandLineArgs(DWORD processID, const WbemHelper& wbemHelper)
{
std::wstring executablePath = wbemHelper.GetExecutablePath(processID);
std::wstring commandLineArgs = 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;
const std::wstring EdgeFilename = L"msedge.exe";
const std::wstring ChromeFilename = L"chrome.exe";
}
bool IsProcessElevated(DWORD processID)
@@ -168,16 +40,23 @@ namespace SnapshotUtils
return false;
}
bool IsEdge(Utils::Apps::AppData appData)
{
return appData.installPath.ends_with(NonLocalizable::EdgeFilename);
}
bool IsChrome(Utils::Apps::AppData appData)
{
return appData.installPath.ends_with(NonLocalizable::ChromeFilename);
}
std::vector<WorkspacesData::WorkspacesProject::Application> GetApps(const std::function<unsigned int(HWND)> getMonitorNumberFromWindowHandle, const std::function<WorkspacesData::WorkspacesProject::Monitor::MonitorRect(unsigned int)> getMonitorRect)
{
PwaHelper pwaHelper{};
std::vector<WorkspacesData::WorkspacesProject::Application> apps{};
auto installedApps = Utils::Apps::GetAppsList();
auto windows = WindowEnumerator::Enumerate(WindowFilter::Filter);
// for command line args detection
// WbemHelper wbemHelper;
// wbemHelper.Initialize();
for (const auto window : windows)
{
@@ -232,7 +111,7 @@ namespace SnapshotUtils
if (pid != otherPid && title == WindowUtils::GetWindowTitle(otherWindow))
{
processPath = get_process_path(otherPid);
break;
break;
}
}
}
@@ -249,6 +128,48 @@ namespace SnapshotUtils
continue;
}
std::wstring pwaAppId = L"";
std::wstring finalName = data.value().name;
std::wstring pwaName = L"";
if (IsEdge(data.value()))
{
pwaHelper.InitAumidToAppId();
std::wstring windowAumid;
pwaHelper.GetAppId(window, &windowAumid);
Logger::info(L"Found an edge window with aumid {}", windowAumid);
if (pwaHelper.GetPwaAppId(windowAumid, &pwaAppId))
{
Logger::info(L"The found edge window is a PWA app with appId {}", pwaAppId);
if (pwaHelper.SearchPwaName(pwaAppId, windowAumid ,& pwaName))
{
Logger::info(L"The found edge window is a PWA app with name {}", finalName);
}
finalName = pwaName + L" (" + finalName + L")";
}
else
{
Logger::info(L"The found edge window does not contain a PWA app", pwaAppId);
}
}
else if (IsChrome(data.value()))
{
pwaHelper.InitChromeAppIds();
std::wstring windowAumid;
pwaHelper.GetAppId(window, &windowAumid);
Logger::info(L"Found a chrome window with aumid {}", windowAumid);
if (pwaHelper.SearchPwaAppId(windowAumid, &pwaAppId))
{
if (pwaHelper.SearchPwaName(pwaAppId, windowAumid, &pwaName))
{
finalName = pwaName + L" (" + finalName + L")";
}
}
}
bool isMinimized = WindowUtils::IsMinimized(window);
unsigned int monitorNumber = getMonitorNumberFromWindowHandle(window);
@@ -263,12 +184,13 @@ namespace SnapshotUtils
}
WorkspacesData::WorkspacesProject::Application app{
.name = data.value().name,
.name = finalName,
.title = title,
.path = data.value().installPath,
.packageFullName = data.value().packageFullName,
.appUserModelId = data.value().appUserModelId,
.commandLineArgs = L"", // GetCommandLineArgs(pid, wbemHelper),
.pwaAppId = pwaAppId,
.commandLineArgs = L"",
.isElevated = IsProcessElevated(pid),
.canLaunchElevated = data.value().canLaunchElevated,
.isMinimized = isMinimized,

View File

@@ -104,7 +104,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shcore.lib;Shell32.lib;propsys.lib;DbgHelp.lib;wbemuuid.lib</AdditionalDependencies>
<AdditionalDependencies>shcore.lib;Shell32.lib;propsys.lib;DbgHelp.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
@@ -130,10 +130,12 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PwaHelper.cpp" />
<ClCompile Include="SnapshotUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="PwaHelper.h" />
<ClInclude Include="resource.base.h" />
<ClInclude Include="SnapshotUtils.h" />
</ItemGroup>

View File

@@ -24,6 +24,9 @@
<ClInclude Include="resource.base.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PwaHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -35,6 +38,9 @@
<ClCompile Include="SnapshotUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PwaHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />