From 4d21e3bbfd4b050244d02cf8cf4f6c588d21c5e4 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Thu, 13 May 2021 00:48:29 -0700 Subject: [PATCH] [uwptool] Support lookup of full package name UWP apps must be launched using their package family name, but are uninstalled using their full package name. This patch updates the Application class to store both. Further, when launching UWP apps, we now do a lookup to verify the package exists before attempting to launch it. --- shell/platform/windows/uwptool_main.cc | 26 +++++++++------ shell/platform/windows/uwptool_utils.cc | 32 +++++++++++++++---- shell/platform/windows/uwptool_utils.h | 20 +++++++++--- .../windows/uwptool_utils_unittests.cc | 15 ++++++++- 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/shell/platform/windows/uwptool_main.cc b/shell/platform/windows/uwptool_main.cc index f58071088f4f7..24bc41981d4c7 100644 --- a/shell/platform/windows/uwptool_main.cc +++ b/shell/platform/windows/uwptool_main.cc @@ -21,7 +21,7 @@ namespace { void PrintInstalledApps() { flutter::ApplicationStore app_store; for (const flutter::Application& app : app_store.GetInstalledApplications()) { - std::wcout << app.GetPackageId() << std::endl; + std::wcout << app.GetPackageFamily() << std::endl; } } @@ -31,9 +31,15 @@ void PrintInstalledApps() { // Returns -1 if no matching app, or multiple matching apps are found, or if // the app fails to launch. Otherwise, the process ID of the launched app is // returned. -int LaunchApp(const std::wstring_view app_id, const std::wstring_view args) { - flutter::Application app(app_id); - return app.Launch(args); +int LaunchApp(const std::wstring_view package_family, + const std::wstring_view args) { + flutter::ApplicationStore app_store; + std::optional app = + app_store.GetInstalledApplication(package_family); + if (!app) { + return -1; + } + return app->Launch(args); } // Prints the command usage to stderr. @@ -66,8 +72,8 @@ int main(int argc, char** argv) { return 1; } - // Get the package ID. - std::string package_id = args[1]; + // Get the package family. + std::string package_family = args[1]; // Concatenate the remaining args, comma-separated. std::ostringstream app_args; @@ -77,16 +83,16 @@ int main(int argc, char** argv) { app_args << ","; } } - int process_id = LaunchApp(flutter::Utf16FromUtf8(package_id), + int process_id = LaunchApp(flutter::Utf16FromUtf8(package_family), flutter::Utf16FromUtf8(app_args.str())); if (process_id == -1) { - std::cerr << "error: Failed to launch app with package ID " << package_id - << std::endl; + std::cerr << "error: Failed to launch app with package family " + << package_family << std::endl; return 1; } // Write an informative message for the user to stderr. - std::cerr << "Launched app with package ID " << package_id + std::cerr << "Launched app with package family " << package_family << ". PID: " << std::endl; // Write the PID to stdout. The flutter tool reads this value in. std::cout << process_id << std::endl; diff --git a/shell/platform/windows/uwptool_utils.cc b/shell/platform/windows/uwptool_utils.cc index f3b8fefb00345..2fa58ed25e415 100644 --- a/shell/platform/windows/uwptool_utils.cc +++ b/shell/platform/windows/uwptool_utils.cc @@ -12,14 +12,16 @@ #include #include +#include #include #include #include namespace flutter { -Application::Application(const std::wstring_view package_id) - : package_id_(package_id) {} +Application::Application(const std::wstring_view package_family, + const std::wstring_view package_full_name) + : package_family_(package_family), package_full_name_(package_full_name) {} int Application::Launch(const std::wstring_view args) { // Create the ApplicationActivationManager. @@ -34,7 +36,7 @@ int Application::Launch(const std::wstring_view args) { // Launch the application. DWORD process_id; ACTIVATEOPTIONS options = AO_NONE; - std::wstring app_user_model_id = package_id_ + L"!App"; + std::wstring app_user_model_id = package_family_ + L"!App"; hresult = activation_manager->ActivateApplication( app_user_model_id.data(), args.data(), options, &process_id); if (FAILED(hresult)) { @@ -43,18 +45,34 @@ int Application::Launch(const std::wstring_view args) { return process_id; } -std::vector ApplicationStore::GetInstalledApplications() { +std::vector ApplicationStore::GetInstalledApplications() const { using winrt::Windows::ApplicationModel::Package; using winrt::Windows::Management::Deployment::PackageManager; // Find packages for the current user (default for empty string). PackageManager package_manager; - std::unordered_set package_ids; + std::vector apps; for (const Package& package : package_manager.FindPackagesForUser(L"")) { - package_ids.emplace(package.Id().FamilyName().c_str()); + apps.emplace_back(package.Id().FamilyName().c_str(), + package.Id().FullName().c_str()); } - std::vector apps(package_ids.begin(), package_ids.end()); return apps; } +std::optional ApplicationStore::GetInstalledApplication( + const std::wstring_view package_family) const { + using winrt::Windows::ApplicationModel::Package; + using winrt::Windows::Management::Deployment::PackageManager; + + // Find packages for the current user (default for empty string). + PackageManager package_manager; + std::vector apps; + for (const Package& package : + package_manager.FindPackagesForUser(L"", package_family)) { + return std::optional(Application(package.Id().FamilyName().c_str(), + package.Id().FullName().c_str())); + } + return std::nullopt; +} + } // namespace flutter diff --git a/shell/platform/windows/uwptool_utils.h b/shell/platform/windows/uwptool_utils.h index 9b6469aa5c08a..f2789871c1fc1 100644 --- a/shell/platform/windows/uwptool_utils.h +++ b/shell/platform/windows/uwptool_utils.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_UWPTOOL_UTILS_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_UWPTOOL_UTILS_H_ +#include #include #include @@ -13,12 +14,16 @@ namespace flutter { // A UWP application. class Application { public: - explicit Application(const std::wstring_view package_id); + explicit Application(const std::wstring_view package_family, + const std::wstring_view package_full_name); Application(const Application& other) = default; Application& operator=(const Application& other) = default; - // Returns the package ID. - std::wstring GetPackageId() const { return package_id_; } + // Returns the package family. + std::wstring GetPackageFamily() const { return package_family_; } + + // Returns the package full name. + std::wstring GetPackageFullName() const { return package_full_name_; } // Launches the application with the specified list of launch arguments. // @@ -26,7 +31,8 @@ class Application { int Launch(const std::wstring_view args); private: - std::wstring package_id_; + std::wstring package_family_; + std::wstring package_full_name_; }; // The machine-local store of installed applications. @@ -39,7 +45,11 @@ class ApplicationStore { ApplicationStore& operator=(const ApplicationStore& other) = delete; // Returns a list of all installed application user model IDs. - std::vector GetInstalledApplications(); + std::vector GetInstalledApplications() const; + + // Returns a list of all installed application user model IDs. + std::optional GetInstalledApplication( + const std::wstring_view package_family) const; }; } // namespace flutter diff --git a/shell/platform/windows/uwptool_utils_unittests.cc b/shell/platform/windows/uwptool_utils_unittests.cc index 6ede6b1b354d5..5589cdfd43c21 100644 --- a/shell/platform/windows/uwptool_utils_unittests.cc +++ b/shell/platform/windows/uwptool_utils_unittests.cc @@ -26,10 +26,23 @@ TEST(ApplicationStore, GetInstalledApplications) { EXPECT_FALSE(apps.empty()); auto ms_pos = std::find_if(apps.begin(), apps.end(), [](const auto& app) { - return app.GetPackageId().rfind(L"Microsoft.", 0); + return app.GetPackageFamily().rfind(L"Microsoft.", 0); }); EXPECT_TRUE(ms_pos != apps.end()); } +// Verify that we can look up an app by family name. +TEST(ApplicationStore, GetInstalledApplication) { + ApplicationStore app_store; + std::vector apps = app_store.GetInstalledApplications(); + EXPECT_FALSE(apps.empty()); + + std::optional found_app = + app_store.GetInstalledApplication(apps[0].GetPackageFamily()); + ASSERT_TRUE(found_app != std::nullopt); + EXPECT_EQ(found_app->GetPackageFamily(), apps[0].GetPackageFamily()); + EXPECT_EQ(found_app->GetPackageFullName(), apps[0].GetPackageFullName()); +} + } // namespace testing } // namespace flutter