mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
Workspaces: PWA apps should not necessarily configure profile to launch. (#39971)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Workspace support for pwa is now limited, it is tight to specific Profile launch. If you create a pwa app with a profile other than "Default", launch will fail. Then you have to manually configure that profile to launch. This pr fix it by launching with shell:appsfolder\appusermodelId <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [X] **Closes:** #36384 - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed - [X] Create a new workspace with a pwa app(Other than default profile) should be no problem. - [X] Existing workspace with a pwa(default profile and other profile) should launch successfully without problem 1. with pt version 91.1, create a loop pwa with "Profile 1" instead of "Default" in edge. 2. capture and launch actually launch the edge instead of loop 3. Create profile with this impl and launch 4. Launch pwa successfully --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -49,6 +49,8 @@ namespace WorkspacesEditor.Data
|
|||||||
public WindowPositionWrapper Position { get; set; }
|
public WindowPositionWrapper Position { get; set; }
|
||||||
|
|
||||||
public int Monitor { get; set; }
|
public int Monitor { get; set; }
|
||||||
|
|
||||||
|
public string Version { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct MonitorConfigurationWrapper
|
public struct MonitorConfigurationWrapper
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace WorkspacesEditor.Models
|
|||||||
Maximized = other.Maximized;
|
Maximized = other.Maximized;
|
||||||
Position = other.Position;
|
Position = other.Position;
|
||||||
MonitorNumber = other.MonitorNumber;
|
MonitorNumber = other.MonitorNumber;
|
||||||
|
Version = other.Version;
|
||||||
|
|
||||||
Parent = other.Parent;
|
Parent = other.Parent;
|
||||||
IsNotFound = other.IsNotFound;
|
IsNotFound = other.IsNotFound;
|
||||||
@@ -274,5 +275,7 @@ namespace WorkspacesEditor.Models
|
|||||||
CommandLineArguments = newCommandLineValue;
|
CommandLineArguments = newCommandLineValue;
|
||||||
OnPropertyChanged(new PropertyChangedEventArgs(nameof(AppMainParams)));
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(AppMainParams)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Version { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ namespace WorkspacesEditor.Models
|
|||||||
AppPath = app.ApplicationPath,
|
AppPath = app.ApplicationPath,
|
||||||
AppTitle = app.Title,
|
AppTitle = app.Title,
|
||||||
PwaAppId = string.IsNullOrEmpty(app.PwaAppId) ? string.Empty : app.PwaAppId,
|
PwaAppId = string.IsNullOrEmpty(app.PwaAppId) ? string.Empty : app.PwaAppId,
|
||||||
|
Version = string.IsNullOrEmpty(app.Version) ? string.Empty : app.Version,
|
||||||
PackageFullName = app.PackageFullName,
|
PackageFullName = app.PackageFullName,
|
||||||
AppUserModelId = app.AppUserModelId,
|
AppUserModelId = app.AppUserModelId,
|
||||||
Parent = this,
|
Parent = this,
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ namespace WorkspacesEditor.Utils
|
|||||||
CommandLineArguments = app.CommandLineArguments,
|
CommandLineArguments = app.CommandLineArguments,
|
||||||
IsElevated = app.IsElevated,
|
IsElevated = app.IsElevated,
|
||||||
CanLaunchElevated = app.CanLaunchElevated,
|
CanLaunchElevated = app.CanLaunchElevated,
|
||||||
|
Version = app.Version,
|
||||||
Maximized = app.Maximized,
|
Maximized = app.Maximized,
|
||||||
Minimized = app.Minimized,
|
Minimized = app.Minimized,
|
||||||
Position = new ProjectData.ApplicationWrapper.WindowPositionWrapper
|
Position = new ProjectData.ApplicationWrapper.WindowPositionWrapper
|
||||||
|
|||||||
@@ -165,16 +165,52 @@ namespace AppLauncher
|
|||||||
|
|
||||||
if (!launched && !app.pwaAppId.empty())
|
if (!launched && !app.pwaAppId.empty())
|
||||||
{
|
{
|
||||||
std::filesystem::path appPath(app.path);
|
int version = 0;
|
||||||
if (appPath.filename() == NonLocalizable::EdgeFilename)
|
|
||||||
|
if (app.version != L"")
|
||||||
{
|
{
|
||||||
appPathFinal = appPath.parent_path() / NonLocalizable::EdgePwaFilename;
|
try
|
||||||
commandLineArgsFinal = NonLocalizable::PwaCommandLineAddition + app.pwaAppId + L" " + app.commandLineArgs;
|
{
|
||||||
|
version = std::stoi(app.version);
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&)
|
||||||
|
{
|
||||||
|
Logger::error(L"Invalid version format: {}", app.version);
|
||||||
|
version = 0;
|
||||||
|
}
|
||||||
|
catch (const std::out_of_range&)
|
||||||
|
{
|
||||||
|
Logger::error(L"Version out of range: {}", app.version);
|
||||||
|
version = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (appPath.filename() == NonLocalizable::ChromeFilename)
|
|
||||||
|
if (version >= 1)
|
||||||
{
|
{
|
||||||
appPathFinal = appPath.parent_path() / NonLocalizable::ChromePwaFilename;
|
auto res = LaunchApp(L"shell:AppsFolder\\" + app.appUserModelId, app.commandLineArgs, app.isElevated);
|
||||||
commandLineArgsFinal = NonLocalizable::PwaCommandLineAddition + app.pwaAppId + L" " + app.commandLineArgs;
|
if (res.isOk())
|
||||||
|
{
|
||||||
|
launched = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
launchErrors.push_back({ app.appUserModelId, res.error() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!launched)
|
||||||
|
{
|
||||||
|
std::filesystem::path appPath(app.path);
|
||||||
|
if (appPath.filename() == NonLocalizable::EdgeFilename)
|
||||||
|
{
|
||||||
|
appPathFinal = appPath.parent_path() / NonLocalizable::EdgePwaFilename;
|
||||||
|
commandLineArgsFinal = NonLocalizable::PwaCommandLineAddition + app.pwaAppId + L" " + app.commandLineArgs;
|
||||||
|
}
|
||||||
|
if (appPath.filename() == NonLocalizable::ChromeFilename)
|
||||||
|
{
|
||||||
|
appPathFinal = appPath.parent_path() / NonLocalizable::ChromePwaFilename;
|
||||||
|
commandLineArgsFinal = NonLocalizable::PwaCommandLineAddition + app.pwaAppId + L" " + app.commandLineArgs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,19 +76,6 @@ namespace WorkspacesLibUnitTests
|
|||||||
Assert::IsTrue(result == nonExistentWindowAumid);
|
Assert::IsTrue(result == nonExistentWindowAumid);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (PwaHelper_GetAUMIDFromWindow_InvalidWindow_ReturnsEmpty)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
Utils::PwaHelper helper;
|
|
||||||
HWND invalidWindow = nullptr;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
std::wstring result = helper.GetAUMIDFromWindow(invalidWindow);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert::IsTrue(result.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (PwaHelper_GetEdgeAppId_ValidConstruction_DoesNotCrash)
|
TEST_METHOD (PwaHelper_GetEdgeAppId_ValidConstruction_DoesNotCrash)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "PwaHelper.h"
|
#include "PwaHelper.h"
|
||||||
|
#include "WindowUtils.h"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ namespace Utils
|
|||||||
localFolder = L""; // Ensure it is explicitly set to empty on failure
|
localFolder = L""; // Ensure it is explicitly set to empty on failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return localFolder;
|
return localFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +194,7 @@ namespace Utils
|
|||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::wstring> PwaHelper::GetChromeAppId(const std::wstring& windowAumid) const
|
std::optional<std::wstring> PwaHelper::GetChromeAppId(const std::wstring& windowAumid) const
|
||||||
{
|
{
|
||||||
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
|
const auto appIdIndexStart = windowAumid.find(NonLocalizable::ChromeAppIdIdentifier);
|
||||||
@@ -256,85 +257,4 @@ namespace Utils
|
|||||||
|
|
||||||
return result;
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -12,19 +12,16 @@ namespace Utils
|
|||||||
PwaHelper();
|
PwaHelper();
|
||||||
~PwaHelper() = default;
|
~PwaHelper() = default;
|
||||||
|
|
||||||
std::wstring GetAUMIDFromWindow(HWND hWnd) const;
|
|
||||||
|
|
||||||
std::optional<std::wstring> GetEdgeAppId(const std::wstring& windowAumid) const;
|
std::optional<std::wstring> GetEdgeAppId(const std::wstring& windowAumid) const;
|
||||||
std::optional<std::wstring> GetChromeAppId(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;
|
std::wstring SearchPwaName(const std::wstring& pwaAppId, const std::wstring& windowAumid) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitAppIds(const std::wstring& browserDataFolder, const std::wstring& browserDirPrefix, const std::function<void(const std::wstring&)>& addingAppIdCallback);
|
void InitAppIds(const std::wstring& browserDataFolder, const std::wstring& browserDirPrefix, const std::function<void(const std::wstring&)>& addingAppIdCallback);
|
||||||
void InitEdgeAppIds();
|
void InitEdgeAppIds();
|
||||||
void InitChromeAppIds();
|
void InitChromeAppIds();
|
||||||
|
|
||||||
std::wstring GetAppIdFromCommandLineArgs(const std::wstring& commandLineArgs) const;
|
std::wstring GetAppIdFromCommandLineArgs(const std::wstring& commandLineArgs) const;
|
||||||
std::wstring GetAUMIDFromProcessId(DWORD processId) const;
|
|
||||||
|
|
||||||
std::map<std::wstring, std::wstring> m_edgeAppIds;
|
std::map<std::wstring, std::wstring> m_edgeAppIds;
|
||||||
std::vector<std::wstring> m_chromeAppIds;
|
std::vector<std::wstring> m_chromeAppIds;
|
||||||
|
|||||||
18
src/modules/Workspaces/WorkspacesLib/StringUtils.cpp
Normal file
18
src/modules/Workspaces/WorkspacesLib/StringUtils.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,15 +6,5 @@
|
|||||||
|
|
||||||
namespace StringUtils
|
namespace StringUtils
|
||||||
{
|
{
|
||||||
inline bool CaseInsensitiveEquals(const std::wstring& str1, const std::wstring& str2)
|
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
105
src/modules/Workspaces/WorkspacesLib/WindowUtils.cpp
Normal file
105
src/modules/Workspaces/WorkspacesLib/WindowUtils.cpp
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "WindowUtils.h"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#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/utils/winapi_error.h>
|
||||||
|
|
||||||
|
#include <WorkspacesLib/AppUtils.h>
|
||||||
|
#include <WorkspacesLib/CommandLineArgsHelper.h>
|
||||||
|
#include <WorkspacesLib/StringUtils.h>
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
std::wstring GetAUMIDFromProcessId(DWORD processId)
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring GetAUMIDFromWindow(HWND hwnd)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/modules/Workspaces/WorkspacesLib/WindowUtils.h
Normal file
12
src/modules/Workspaces/WorkspacesLib/WindowUtils.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <WorkspacesLib/AppUtils.h>
|
||||||
|
#include <wtypes.h>
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
std::wstring GetAUMIDFromWindow(HWND hWnd);
|
||||||
|
std::wstring GetAUMIDFromProcessId(DWORD processId);
|
||||||
|
};
|
||||||
@@ -87,6 +87,7 @@ namespace WorkspacesData
|
|||||||
const static wchar_t* MaximizedID = L"maximized";
|
const static wchar_t* MaximizedID = L"maximized";
|
||||||
const static wchar_t* PositionID = L"position";
|
const static wchar_t* PositionID = L"position";
|
||||||
const static wchar_t* MonitorID = L"monitor";
|
const static wchar_t* MonitorID = L"monitor";
|
||||||
|
const static wchar_t* VersionID = L"version";
|
||||||
}
|
}
|
||||||
|
|
||||||
json::JsonObject ToJson(const WorkspacesProject::Application& data)
|
json::JsonObject ToJson(const WorkspacesProject::Application& data)
|
||||||
@@ -106,6 +107,7 @@ namespace WorkspacesData
|
|||||||
json.SetNamedValue(NonLocalizable::MaximizedID, json::value(data.isMaximized));
|
json.SetNamedValue(NonLocalizable::MaximizedID, json::value(data.isMaximized));
|
||||||
json.SetNamedValue(NonLocalizable::PositionID, PositionJSON::ToJson(data.position));
|
json.SetNamedValue(NonLocalizable::PositionID, PositionJSON::ToJson(data.position));
|
||||||
json.SetNamedValue(NonLocalizable::MonitorID, json::value(data.monitor));
|
json.SetNamedValue(NonLocalizable::MonitorID, json::value(data.monitor));
|
||||||
|
json.SetNamedValue(NonLocalizable::VersionID, json::value(data.version));
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@@ -168,6 +170,11 @@ namespace WorkspacesData
|
|||||||
|
|
||||||
result.position = position.value();
|
result.position = position.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json.HasKey(NonLocalizable::VersionID))
|
||||||
|
{
|
||||||
|
result.version = json.GetNamedString(NonLocalizable::VersionID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const winrt::hresult_error&)
|
catch (const winrt::hresult_error&)
|
||||||
{
|
{
|
||||||
@@ -286,6 +293,7 @@ namespace WorkspacesData
|
|||||||
const static wchar_t* MoveExistingWindowsID = L"move-existing-windows";
|
const static wchar_t* MoveExistingWindowsID = L"move-existing-windows";
|
||||||
const static wchar_t* MonitorConfigurationID = L"monitor-configuration";
|
const static wchar_t* MonitorConfigurationID = L"monitor-configuration";
|
||||||
const static wchar_t* AppsID = L"applications";
|
const static wchar_t* AppsID = L"applications";
|
||||||
|
const static wchar_t* Version = L"version";
|
||||||
}
|
}
|
||||||
|
|
||||||
json::JsonObject ToJson(const WorkspacesProject& data)
|
json::JsonObject ToJson(const WorkspacesProject& data)
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ namespace WorkspacesData
|
|||||||
std::wstring appUserModelId;
|
std::wstring appUserModelId;
|
||||||
std::wstring pwaAppId;
|
std::wstring pwaAppId;
|
||||||
std::wstring commandLineArgs;
|
std::wstring commandLineArgs;
|
||||||
|
|
||||||
|
// empty to 1,
|
||||||
|
std::wstring version;
|
||||||
bool isElevated{};
|
bool isElevated{};
|
||||||
bool canLaunchElevated{};
|
bool canLaunchElevated{};
|
||||||
bool isMinimized{};
|
bool isMinimized{};
|
||||||
@@ -86,7 +89,7 @@ namespace WorkspacesData
|
|||||||
{
|
{
|
||||||
WorkspacesData::WorkspacesProject::Application application;
|
WorkspacesData::WorkspacesProject::Application application;
|
||||||
HWND window{};
|
HWND window{};
|
||||||
LaunchingState state { LaunchingState::Waiting };
|
LaunchingState state{ LaunchingState::Waiting };
|
||||||
};
|
};
|
||||||
|
|
||||||
using LaunchingAppStateMap = std::map<WorkspacesData::WorkspacesProject::Application, LaunchingAppState>;
|
using LaunchingAppStateMap = std::map<WorkspacesData::WorkspacesProject::Application, LaunchingAppState>;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<ClInclude Include="StringUtils.h" />
|
<ClInclude Include="StringUtils.h" />
|
||||||
<ClInclude Include="utils.h" />
|
<ClInclude Include="utils.h" />
|
||||||
<ClInclude Include="WbemHelper.h" />
|
<ClInclude Include="WbemHelper.h" />
|
||||||
|
<ClInclude Include="WindowUtils.h" />
|
||||||
<ClInclude Include="WorkspacesData.h" />
|
<ClInclude Include="WorkspacesData.h" />
|
||||||
<ClInclude Include="trace.h" />
|
<ClInclude Include="trace.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -59,8 +60,10 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="PwaHelper.cpp" />
|
<ClCompile Include="PwaHelper.cpp" />
|
||||||
<ClCompile Include="SteamGameHelper.cpp" />
|
<ClCompile Include="SteamGameHelper.cpp" />
|
||||||
|
<ClCompile Include="StringUtils.cpp" />
|
||||||
<ClCompile Include="two_way_pipe_message_ipc.cpp" />
|
<ClCompile Include="two_way_pipe_message_ipc.cpp" />
|
||||||
<ClCompile Include="WbemHelper.cpp" />
|
<ClCompile Include="WbemHelper.cpp" />
|
||||||
|
<ClCompile Include="WindowUtils.cpp" />
|
||||||
<ClCompile Include="WorkspacesData.cpp" />
|
<ClCompile Include="WorkspacesData.cpp" />
|
||||||
<ClCompile Include="trace.cpp" />
|
<ClCompile Include="trace.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -56,6 +56,9 @@
|
|||||||
<ClInclude Include="SteamHelper.h">
|
<ClInclude Include="SteamHelper.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="WindowUtils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
@@ -94,6 +97,12 @@
|
|||||||
<ClCompile Include="SteamGameHelper.cpp">
|
<ClCompile Include="SteamGameHelper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="WindowUtils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="StringUtils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <WorkspacesLib/AppUtils.h>
|
#include <WorkspacesLib/AppUtils.h>
|
||||||
#include <WorkspacesLib/PwaHelper.h>
|
#include <WorkspacesLib/PwaHelper.h>
|
||||||
|
#include <WorkspacesLib/WindowUtils.h>
|
||||||
#include <WindowProperties/WorkspacesWindowPropertyUtils.h>
|
#include <WindowProperties/WorkspacesWindowPropertyUtils.h>
|
||||||
|
|
||||||
#include "Generated Files/resource.h"
|
#include "Generated Files/resource.h"
|
||||||
@@ -139,7 +140,7 @@ namespace SnapshotUtils
|
|||||||
bool isChrome = appData.IsChrome();
|
bool isChrome = appData.IsChrome();
|
||||||
if (isEdge || isChrome)
|
if (isEdge || isChrome)
|
||||||
{
|
{
|
||||||
auto windowAumid = pwaHelper.GetAUMIDFromWindow(window);
|
auto windowAumid = Utils::GetAUMIDFromWindow(window);
|
||||||
std::optional<std::wstring> pwaAppId{};
|
std::optional<std::wstring> pwaAppId{};
|
||||||
|
|
||||||
if (isEdge)
|
if (isEdge)
|
||||||
@@ -158,6 +159,8 @@ namespace SnapshotUtils
|
|||||||
|
|
||||||
appData.pwaAppId = pwaAppId.value();
|
appData.pwaAppId = pwaAppId.value();
|
||||||
appData.name = pwaName + L" (" + appData.name + L")";
|
appData.name = pwaName + L" (" + appData.name + L")";
|
||||||
|
// If it's pwa app, appUserModelId should be their own pwa id.
|
||||||
|
appData.appUserModelId = windowAumid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +188,7 @@ namespace SnapshotUtils
|
|||||||
.appUserModelId = appData.appUserModelId,
|
.appUserModelId = appData.appUserModelId,
|
||||||
.pwaAppId = appData.pwaAppId,
|
.pwaAppId = appData.pwaAppId,
|
||||||
.commandLineArgs = L"",
|
.commandLineArgs = L"",
|
||||||
|
.version = L"1",
|
||||||
.isElevated = IsProcessElevated(pid),
|
.isElevated = IsProcessElevated(pid),
|
||||||
.canLaunchElevated = appData.canLaunchElevated,
|
.canLaunchElevated = appData.canLaunchElevated,
|
||||||
.isMinimized = isMinimized,
|
.isMinimized = isMinimized,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <WindowProperties/WorkspacesWindowPropertyUtils.h>
|
#include <WindowProperties/WorkspacesWindowPropertyUtils.h>
|
||||||
#include <WorkspacesLib/PwaHelper.h>
|
#include <WorkspacesLib/PwaHelper.h>
|
||||||
|
#include <WorkspacesLib/WindowUtils.h>
|
||||||
|
|
||||||
namespace NonLocalizable
|
namespace NonLocalizable
|
||||||
{
|
{
|
||||||
@@ -203,7 +204,7 @@ std::optional<WindowWithDistance> WindowArranger::GetNearestWindow(const Workspa
|
|||||||
|
|
||||||
if (!data->IsSteamGame() && !WindowUtils::HasThickFrame(window))
|
if (!data->IsSteamGame() && !WindowUtils::HasThickFrame(window))
|
||||||
{
|
{
|
||||||
// Only care about steam games if it has no thick frame to remain consistent with
|
// Only care about steam games if it has no thick frame to remain consistent with
|
||||||
// the behavior as before.
|
// the behavior as before.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -220,7 +221,7 @@ std::optional<WindowWithDistance> WindowArranger::GetNearestWindow(const Workspa
|
|||||||
bool isChrome = appData.IsChrome();
|
bool isChrome = appData.IsChrome();
|
||||||
if (isEdge || isChrome)
|
if (isEdge || isChrome)
|
||||||
{
|
{
|
||||||
auto windowAumid = pwaHelper.GetAUMIDFromWindow(window);
|
auto windowAumid = Utils::GetAUMIDFromWindow(window);
|
||||||
std::optional<std::wstring> pwaAppId{};
|
std::optional<std::wstring> pwaAppId{};
|
||||||
|
|
||||||
if (isEdge)
|
if (isEdge)
|
||||||
|
|||||||
Reference in New Issue
Block a user