mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 11:17:53 +01:00
launch packaged apps using names when possible
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
#include <winrt/Windows.ApplicationModel.Core.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <projects-common/AppUtils.h>
|
||||
#include <projects-common/MonitorEnumerator.h>
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <common/Display/dpi_aware.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
#include <RegistryUtils.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Management::Deployment;
|
||||
@@ -155,6 +157,30 @@ bool LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LaunchUsingUriProtocolName(const std::wstring& uriProtocolName, const std::wstring& commandLineArgs)
|
||||
{
|
||||
std::wstring command = std::wstring(uriProtocolName + (commandLineArgs.starts_with(L":") ? L"" : L":") + commandLineArgs);
|
||||
HINSTANCE result = ShellExecute(
|
||||
nullptr,
|
||||
L"open",
|
||||
command.c_str(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
SW_SHOWNORMAL
|
||||
);
|
||||
|
||||
// If the function succeeds, it returns a value greater than 32.
|
||||
if (result > reinterpret_cast<HINSTANCE>(32))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to launch process. {}", get_last_error_or_default(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LaunchPackagedApp(const std::wstring& packageFullName)
|
||||
{
|
||||
try
|
||||
@@ -190,16 +216,31 @@ bool LaunchPackagedApp(const std::wstring& packageFullName)
|
||||
|
||||
bool Launch(const Project::Application& app)
|
||||
{
|
||||
// TODO: verify app path is up to date.
|
||||
// Packaged apps have version in the path, it will be outdated after update.
|
||||
|
||||
bool launched;
|
||||
if (!app.packageFullName.empty() && app.commandLineArgs.empty())
|
||||
{
|
||||
Logger::trace(L"Launching packaged {}", app.name);
|
||||
Logger::trace(L"Launching packaged without command line args {}", app.name);
|
||||
launched = LaunchPackagedApp(app.packageFullName);
|
||||
}
|
||||
else
|
||||
else if (!app.packageFullName.empty() && !app.commandLineArgs.empty())
|
||||
{
|
||||
auto names = RegistryUtils::GetUriProtocolNames(app.packageFullName);
|
||||
if (!names.empty())
|
||||
{
|
||||
Logger::trace(L"Launching packaged by protocol with command line args {}", app.name);
|
||||
launched = LaunchUsingUriProtocolName(names[0], app.commandLineArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"Uri protocol names not found for {}", app.packageFullName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!launched)
|
||||
{
|
||||
// TODO: verify app path is up to date.
|
||||
// Packaged apps have version in the path, it will be outdated after update.
|
||||
Logger::trace(L"Launching {} at {}", app.name, app.path);
|
||||
|
||||
DWORD dwAttrib = GetFileAttributesW(app.path.c_str());
|
||||
|
||||
@@ -128,10 +128,12 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RegistryUtils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AppLauncher.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="RegistryUtils.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RegistryUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -35,6 +38,9 @@
|
||||
<ClCompile Include="AppLauncher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RegistryUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
84
src/modules/Projects/ProjectsLauncher/RegistryUtils.cpp
Normal file
84
src/modules/Projects/ProjectsLauncher/RegistryUtils.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "pch.h"
|
||||
#include "RegistryUtils.h"
|
||||
|
||||
#include <strsafe.h>
|
||||
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
namespace RegistryUtils
|
||||
{
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t RegKeyPackageId[] = L"Extensions\\ContractId\\Windows.Protocol\\PackageId\\";
|
||||
const wchar_t RegKeyPackageActivatableClassId[] = L"\\ActivatableClassId";
|
||||
const wchar_t RegKeyPackageCustomProperties[] = L"\\CustomProperties";
|
||||
const wchar_t RegValueName[] = L"Name";
|
||||
}
|
||||
|
||||
HKEY OpenRootRegKey(const wchar_t* key)
|
||||
{
|
||||
HKEY hKey{ nullptr };
|
||||
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, key, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
return hKey;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> GetUriProtocolNames(const std::wstring& packageFullPath)
|
||||
{
|
||||
std::vector<std::wstring> names{};
|
||||
|
||||
std::wstring keyPath = std::wstring(NonLocalizable::RegKeyPackageId) + packageFullPath + std::wstring(NonLocalizable::RegKeyPackageActivatableClassId);
|
||||
HKEY key = OpenRootRegKey(keyPath.c_str());
|
||||
if (key != nullptr)
|
||||
{
|
||||
LSTATUS result;
|
||||
|
||||
// iterate over all the subkeys to get the protocol names
|
||||
DWORD index = 0;
|
||||
wchar_t keyName[256];
|
||||
DWORD keyNameSize = sizeof(keyName) / sizeof(keyName[0]);
|
||||
FILETIME lastWriteTime;
|
||||
|
||||
while ((result = RegEnumKeyEx(key, index, keyName, &keyNameSize, NULL, NULL, NULL, &lastWriteTime)) != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
std::wstring subkeyPath = std::wstring(keyPath) + L"\\" + std::wstring(keyName, keyNameSize) + std::wstring(NonLocalizable::RegKeyPackageCustomProperties);
|
||||
HKEY subkey = OpenRootRegKey(subkeyPath.c_str());
|
||||
if (subkey != nullptr)
|
||||
{
|
||||
DWORD dataSize;
|
||||
wchar_t value[256];
|
||||
result = RegGetValueW(subkey, nullptr, NonLocalizable::RegValueName, RRF_RT_REG_SZ, nullptr, value, &dataSize);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
names.emplace_back(std::wstring(value, dataSize / sizeof(wchar_t) - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to query registry value. Error: {}", get_last_error_or_default(result));
|
||||
}
|
||||
|
||||
RegCloseKey(subkey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to enumerate subkey. Error: {}", get_last_error_or_default(result));
|
||||
break;
|
||||
}
|
||||
|
||||
keyNameSize = sizeof(keyName) / sizeof(keyName[0]); // Reset the buffer size
|
||||
++index;
|
||||
}
|
||||
|
||||
// Close the registry key
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
}
|
||||
6
src/modules/Projects/ProjectsLauncher/RegistryUtils.h
Normal file
6
src/modules/Projects/ProjectsLauncher/RegistryUtils.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace RegistryUtils
|
||||
{
|
||||
std::vector<std::wstring> GetUriProtocolNames(const std::wstring& packageFullPath);
|
||||
};
|
||||
Reference in New Issue
Block a user