Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
*.userosscache
*.sln.docstates

# Backup files
*.[Bb][Aa][Kk]

# full nuget directory
[Bb]uild/FullNuget

Expand Down
163 changes: 163 additions & 0 deletions WindowsAppRuntime.sln

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions build/NuSpecs/AppxManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
<ActivatableClass ActivatableClassId="Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyContext" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyRank" ThreadingModel="both" />

<!-- Package -->
<ActivatableClass ActivatableClassId="Microsoft.Windows.ApplicationModel.Package" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.ApplicationModel.PackageGraph" ThreadingModel="both" />

<!-- WinAppSDK Deployment -->
<ActivatableClass ActivatableClassId="Microsoft.Windows.ApplicationModel.WindowsAppRuntime.DeploymentManager" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Windows.ApplicationModel.WindowsAppRuntime.DeploymentResult" ThreadingModel="both" />
Expand Down
206 changes: 206 additions & 0 deletions dev/Common/AppModel.Package.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

#include <appmodel.h>

#include <filesystem>
#include <string>

#include <AppModel.Identity.h>
#include <ExportLoader.h>
#include <IsWindowsVersion.h>

namespace AppModel::Package
{
Expand Down Expand Up @@ -79,6 +84,207 @@ 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{ ::ExportLoader::Load(L"api-ms-win-appmodel-runtime-l1-1-3.dll") };
if (dll)
{
auto getPackagePathByFullName2{ ::ExportLoader::GetFunctionIfExists<GetPackagePathByFullName2Function>(dll.get(), "GetPackagePathByFullName2") };
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_MachineExternal is available since 20H1
// * PackagePathType_UserExternal is available since 20H1
// * PackagePathType_EffectiveExternal 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() ||
(::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_WIN32_ERROR(g_getPackagePathByFullName2(packageFullName, packagePathType, pathLength, path));
}
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_WIN32_ERROR(::GetPackagePathByFullName(packageFullName, pathLength, path));
}
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_FAILED_MSG(details::GetPackagePathByFullName2IfSupported(packageFullName, packagePathType, &pathLength, pathBuffer.get()),
"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) };
if (path.empty())
{
return path;
}
std::filesystem::path pathName{ path };
pathName /= filename;
return std::filesystem::absolute(pathName);
}
}

#endif // __APPMODEL_PACKAGE_H
6 changes: 3 additions & 3 deletions dev/Common/AppModel.PackageGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ namespace AppModel::PackageGraph
{
inline HRESULT GetCurrentPackageGraph(
const UINT32 flags,
uint32_t& packageInfoCount,
std::uint32_t& packageInfoCount,
const PACKAGE_INFO*& packageInfo,
wil::unique_cotaskmem_ptr<BYTE[]>& buffer)
{
packageInfoCount = 0;
packageInfo = nullptr;

uint32_t bufferLength{};
std::uint32_t bufferLength{};
LONG rc{ ::GetCurrentPackageInfo(flags, &bufferLength, nullptr, &packageInfoCount) };
if ((rc == APPMODEL_ERROR_NO_PACKAGE) || (packageInfoCount == 0))
{
// No packages. Were done
// No packages. We're done
return S_OK;
}
RETURN_HR_IF(HRESULT_FROM_WIN32(rc), rc != ERROR_INSUFFICIENT_BUFFER);
Expand Down
2 changes: 1 addition & 1 deletion dev/Common/Common.vcxitems.filters
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
</Project>
43 changes: 40 additions & 3 deletions dev/Common/ExportLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@

namespace ExportLoader
{
inline HRESULT Load(PCWSTR moduleName, _Out_ HMODULE* module)
{
auto hmodule{ ::LoadLibraryExW(moduleName, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) };
if (!hmodule)
{
const auto rc{ GetLastError() };
RETURN_HR_IF_MSG(HRESULT_FROM_WIN32(rc), rc != ERROR_MOD_NOT_FOUND, "%ls", moduleName);
RETURN_HR(E_NOTIMPL);
}
*module = hmodule;
return S_OK;
}

inline HMODULE Load(PCWSTR moduleName)
{
auto hmodule{ ::LoadLibraryExW(moduleName, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) };
Expand All @@ -19,17 +32,41 @@ inline HMODULE Load(PCWSTR moduleName)
}

template <typename T>
inline T GetFunction(HMODULE module, PCSTR functionName)
inline HRESULT GetFunctionIfExists(HMODULE module, PCSTR functionName, _Out_ T* function)
{
auto fn{ reinterpret_cast<T>(::GetProcAddress(module, functionName)) };
if (!fn)
{
const auto rc{ GetLastError() };
RETURN_HR_IF_MSG(HRESULT_FROM_WIN32(rc), rc != ERROR_PROC_NOT_FOUND, "%hs", functionName);
}
*function = fn;
return S_OK;
}

template <typename T>
inline T GetFunctionIfExists(HMODULE module, PCSTR functionName)
{
auto function{ reinterpret_cast<T>(::GetProcAddress(module, functionName)) };
if (!function)
{
const auto rc{ GetLastError() };
THROW_HR_IF_MSG(HRESULT_FROM_WIN32(rc), rc != ERROR_PROC_NOT_FOUND, "%hs", functionName);
THROW_HR(E_NOTIMPL);
if (rc == ERROR_PROC_NOT_FOUND)
{
return nullptr;
}
THROW_WIN32_MSG(rc, "%hs", functionName);
}
return function;
}

template <typename T>
inline T GetFunction(HMODULE module, PCSTR functionName)
{
auto function{ GetFunctionIfExists<T>(module, functionName) };
THROW_HR_IF_NULL_MSG(E_NOTIMPL, function, "%hs", functionName);
return function;
}
}

#endif // defined(__EXPORTLOADER_H)
4 changes: 3 additions & 1 deletion dev/Common/IsWindowsVersion.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// Copyright (c) Microsoft Corporation and Contributors.
// Copyright (c) Microsoft Corporation and Contributors.
// Licensed under the MIT License.

#ifndef __ISWINDOWSVERSION_H
#define __ISWINDOWSVERSION_H

#include <VersionHelpers.h>

#include <wil/resource.h>

namespace WindowsVersion
{
inline bool IsExportPresent(
Expand Down
32 changes: 32 additions & 0 deletions dev/Common/TerminalVelocityFeatures-PackageRuntime.h
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
{
static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_APPLICATIONMODEL_FEATURE_PACKAGERUNTIME_ENABLED == 1; }
};

} // namespace Microsoft.Windows.ApplicationModel

#endif // defined(__cplusplus)
Loading
Loading