-
Notifications
You must be signed in to change notification settings - Fork 428
MSIX FindPackageFile*() API #6200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b57ac41
5996e25
10643e9
3e74652
d41dd14
9912d17
99bc5dd
7f25624
9fcfd8a
115ef4e
f93b30d
c70c361
4ffc762
4416815
67cf0f1
2d14aff
85716e8
16b7acf
e3004bb
9db4965
9f4fbc9
7f6c9af
1dfa5c1
f491637
110cda8
996118e
653d645
341aa90
f586727
919d295
d90ca7d
6d2de6a
572cfbc
31b010e
4a08b7c
f1cfa89
c302562
9d2b657
3459eac
be71808
475784c
94ae526
eefa063
a0363d5
50e998b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,12 @@ | |
|
|
||
| #include <appmodel.h> | ||
|
|
||
| #include <filesystem> | ||
| #include <string> | ||
|
|
||
| #include <AppModel.Identity.h> | ||
| #include <ExportLoader.h> | ||
| #include <IsWindowsVersion.h> | ||
|
|
||
| namespace AppModel::Package | ||
| { | ||
|
|
@@ -79,6 +84,211 @@ inline std::tuple<std::wstring, PACKAGE_VERSION, std::uint32_t, std::wstring, st | |
| { | ||
| return ParsePackageFullName(packageFullName.c_str()); | ||
| } | ||
|
|
||
| namespace details | ||
| { | ||
| // Helper: build the return type from PCWSTR | ||
| template <typename TString> | ||
| inline TString MakeFromPCWSTR(PCWSTR s) | ||
| { | ||
| if constexpr (std::is_same_v<TString, std::wstring>) | ||
| { | ||
| return s ? std::wstring{s} : std::wstring{}; | ||
| } | ||
| else | ||
| { | ||
| // For WIL unique string wrappers, use WIL's maker. | ||
| // WIL string maker functions accept PCWSTR and return a unique_*_string wrapper. [1](https://github-wiki-see.page/m/microsoft/wil/wiki/String-helpers) | ||
| return wil::make_unique_string<TString>(s); | ||
| } | ||
| } | ||
|
|
||
| // GetPackagePathByFullName2 requires >=19H1 | ||
| typedef LONG (WINAPI* GetPackagePathByFullName2Function)( | ||
| PCWSTR packageFullName, | ||
| PackagePathType packagePathType, | ||
| UINT32* pathLength, | ||
| PWSTR path); | ||
|
|
||
| inline wil::unique_hmodule g_dll_apiset_appmodel_runtime_1_3; | ||
| inline GetPackagePathByFullName2Function g_getPackagePathByFullName2{}; | ||
| inline std::once_flag g_onceFlag{}; | ||
|
|
||
| inline void initialize() | ||
| { | ||
| wil::unique_hmodule dll; | ||
| if (::ExportLoader::Load(L"api-ms-win-appmodel-runtime-l1-1-3.dll", wil::out_param(dll))) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| { | ||
| return; | ||
| } | ||
| if (dll) | ||
| { | ||
| GetPackagePathByFullName2Function getPackagePathByFullName2{}; | ||
| if (FAILED(::ExportLoader::GetFunctionIfExists<GetPackagePathByFullName2Function>(dll.get(), "GetPackagePathByFullName2", &getPackagePathByFullName2))) | ||
| { | ||
| return; | ||
| } | ||
| if (getPackagePathByFullName2) | ||
| { | ||
| g_dll_apiset_appmodel_runtime_1_3 = std::move(dll); | ||
| g_getPackagePathByFullName2 = std::move(getPackagePathByFullName2); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Get the path for a package, if GetPackagePathByFullName2() is available. | ||
| /// Return an empty path if the PackagePathType isn't supported on current platform (*pathLength=0, *path=""). | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/nf-appmodel-getpackagepathbyfullname2 | ||
| inline HRESULT GetPackagePathByFullName2IfSupported( | ||
| _In_ PCWSTR packageFullName, | ||
| PackagePathType packagePathType, | ||
| std::uint32_t* pathLength, | ||
| _Out_writes_opt_(*pathLength) PWSTR path) | ||
| { | ||
| // Availability is a matter of timeline: | ||
| // * PackagePathType_Install is available since Win8 | ||
| // * PackagePathType_Mutable is available since 19H1 | ||
| // * PackagePathType_Effective is available since 19H1 | ||
| // * PackagePathType_MachineExternalLocation is available since 20H1 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| // * PackagePathType_UserExternalLocation is available since 20H1 | ||
| // * PackagePathType_EffectiveExternalLocation is available since 20H1 | ||
| // GetPackagePathByFullName() is available since Win8 | ||
| // GetPackagePathByFullName2() is available since 19H1 (though not all PackagePathType values were supported that early) | ||
| // | ||
| // Treat asks for locations not supported by the current system the same as not-found | ||
|
|
||
| if (::WindowsVersion::IsWindows10_20H1OrGreater() || | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of checking by version number, wouldn't it be better to check by feature availability? |
||
| (::WindowsVersion::IsWindows10_19H1OrGreater() && | ||
| ((packagePathType == PackagePathType_Install) || (packagePathType == PackagePathType_Mutable) || (packagePathType == PackagePathType_Effective)))) | ||
| { | ||
| std::call_once(g_onceFlag, initialize); | ||
| RETURN_HR_IF_NULL(E_NOTIMPL, g_getPackagePathByFullName2); | ||
|
|
||
| RETURN_IF_FAILED(g_getPackagePathByFullName2(packageFullName, packagePathType, pathLength, path)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
| else if ((packagePathType == PackagePathType_Install) || (packagePathType == PackagePathType_Effective)) | ||
| { | ||
| // Only Install location is supported by the current system | ||
| // Effective is thus equivalent to Install | ||
| // Either way, rock it old school... | ||
| RETURN_IF_FAILED(::GetPackagePathByFullName(packageFullName, pathLength, path)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
| else | ||
| { | ||
| // The requested location isn't possible on the current system | ||
| if (path && (*pathLength > 0)) | ||
| { | ||
| *path = L'\0'; | ||
| } | ||
| *pathLength = 0; | ||
| } | ||
| return S_OK; | ||
| } | ||
| } | ||
|
|
||
| /// Get the path for a package. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/nf-appmodel-getcurrentpackagepath2 | ||
| template <typename Tstring> | ||
| inline Tstring GetPath(_In_ PCWSTR packageFullName, PackagePathType packagePathType) | ||
| { | ||
| // Paths can be long but typically short(ish). We can use a quick fixed buffer | ||
| // as an optimization and fallback to dynamic allocation if need be | ||
| WCHAR path[MAX_PATH]{}; | ||
| uint32_t pathLength{ ARRAYSIZE(path) }; | ||
| const auto hr{ details::GetPackagePathByFullName2IfSupported(packageFullName, packagePathType, &pathLength, path) }; | ||
| if (SUCCEEDED(hr)) | ||
| { | ||
| if (pathLength > 0) | ||
| { | ||
| return details::MakeFromPCWSTR<Tstring>(path); | ||
| } | ||
| else | ||
| { | ||
| return Tstring{}; | ||
| } | ||
| } | ||
| else if ((hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) || | ||
| (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_MUTABLE_DIRECTORY)) || | ||
| (hr == E_NOTIMPL)) | ||
| { | ||
| return Tstring{}; | ||
| } | ||
| else if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) | ||
| { | ||
| THROW_HR_MSG(hr, "PackageFullName=%ls PackagePathType=%d", packageFullName ? packageFullName : L"<null>", static_cast<int>(packagePathType)); | ||
| } | ||
|
|
||
| // It's bigger than a breadbox. Allocate memory | ||
| std::unique_ptr<WCHAR[]> pathBuffer{ std::make_unique<WCHAR[]>(pathLength) }; | ||
| THROW_IF_WIN32_ERROR_MSG(details::GetPackagePathByFullName2IfSupported(packageFullName, packagePathType, &pathLength, pathBuffer.get()), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| "PackageFullName=%ls PackagePathType=%d", packageFullName ? packageFullName : L"<null>", static_cast<int>(packagePathType)); | ||
| return details::MakeFromPCWSTR<Tstring>(pathBuffer.get()); | ||
| } | ||
|
|
||
| /// Get the install path for a package. | ||
| /// @return null or empty string if the package isn't visible. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/ne-appmodel-packagepathtype | ||
| template <typename Tstring> | ||
| inline Tstring GetInstallPath(_In_ PCWSTR packageFullName) | ||
| { | ||
| return GetPath<Tstring>(packageFullName, PackagePathType_Install); | ||
| } | ||
|
|
||
| /// Get the mutable path for a package. | ||
| /// @return null or empty string if the package isn't visible to the caller or has no mutable path. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/ne-appmodel-packagepathtype | ||
| template <typename Tstring> | ||
| inline Tstring GetMutablePath(_In_ PCWSTR packageFullName) | ||
| { | ||
| return GetPath<Tstring>(packageFullName, PackagePathType_Mutable); | ||
| } | ||
|
|
||
| /// Get the machine external path for a package. | ||
| /// @return null or empty string if the package isn't visible to the caller or has no machine external path. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/ne-appmodel-packagepathtype | ||
| template <typename Tstring> | ||
| inline Tstring GetMachineExternalPath(_In_ PCWSTR packageFullName) | ||
| { | ||
| return GetPath<Tstring>(packageFullName, PackagePathType_MachineExternal); | ||
| } | ||
|
|
||
| /// Get the user external path for a package. | ||
| /// @return null or empty string if the package isn't visible to the caller or has no user external path. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/ne-appmodel-packagepathtype | ||
| template <typename Tstring> | ||
| inline Tstring GetUserExternalPath(_In_ PCWSTR packageFullName) | ||
| { | ||
| return GetPath<Tstring>(packageFullName, PackagePathType_UserExternal); | ||
| } | ||
|
|
||
| /// Get the effective external path for a package. | ||
| /// @return null or empty string if the package isn't visible to the caller or has no effective external path. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/ne-appmodel-packagepathtype | ||
| template <typename Tstring> | ||
| inline Tstring GetEffectiveExternalPath(_In_ PCWSTR packageFullName) | ||
| { | ||
| return GetPath<Tstring>(packageFullName, PackagePathType_EffectiveExternal); | ||
| } | ||
|
|
||
| /// Get the effective path for a package. | ||
| /// @return null or empty string if the package isn't visible to the caller. | ||
| /// @see https://learn.microsoft.com/en-us/windows/win32/api/appmodel/ne-appmodel-packagepathtype | ||
| template <typename Tstring> | ||
| inline Tstring GetEffectivePath(_In_ PCWSTR packageFullName) | ||
| { | ||
| return GetPath<Tstring>(packageFullName, PackagePathType_Effective); | ||
| } | ||
|
|
||
| inline std::filesystem::path GetAbsoluteFilename( | ||
| PCWSTR packageFullName, | ||
| PCWSTR filename, | ||
| PackagePathType packageType) | ||
| { | ||
| const auto path{ ::AppModel::Package::GetPath<std::wstring>(packageFullName, packageType) }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| std::filesystem::path pathName{ path }; | ||
| pathName /= filename; | ||
| return std::filesystem::absolute(pathName); | ||
| } | ||
| } | ||
|
|
||
| #endif // __APPMODEL_PACKAGE_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,4 +59,4 @@ | |
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| </ItemGroup> | ||
| </Project> | ||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // Copyright (c) Microsoft Corporation and Contributors. | ||
| // Licensed under the MIT License. | ||
|
|
||
| // THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT IT | ||
|
|
||
| // INPUT FILE: dev\Common\TerminalVelocityFeatures-PackageRuntime.xml | ||
| // OPTIONS: -Channel Experimental -Language C++ -Namespace Microsoft.Windows.ApplicationModel -Path dev\Common\TerminalVelocityFeatures-PackageRuntime.xml -Output dev\Common\TerminalVelocityFeatures-PackageRuntime.h | ||
|
|
||
| #if defined(__midlrt) | ||
| namespace features | ||
| { | ||
| feature_name Feature_PackageRuntime = { DisabledByDefault, FALSE }; | ||
| } | ||
| #endif // defined(__midlrt) | ||
|
|
||
| // Feature constants | ||
| #define WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_APPLICATIONMODEL_FEATURE_PACKAGERUNTIME_ENABLED 1 | ||
|
|
||
| #if defined(__cplusplus) | ||
|
|
||
| namespace Microsoft::Windows::ApplicationModel | ||
| { | ||
|
|
||
| __pragma(detect_mismatch("ODR_violation_WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_APPLICATIONMODEL_FEATURE_PACKAGERUNTIME_ENABLED_mismatch", "AlwaysEnabled")) | ||
| struct Feature_PackageRuntime | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| { | ||
| static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_APPLICATIONMODEL_FEATURE_PACKAGERUNTIME_ENABLED == 1; } | ||
| }; | ||
|
|
||
| } // namespace Microsoft.Windows.ApplicationModel | ||
|
|
||
| #endif // defined(__cplusplus) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should PackageGraph also be added here?