From 3b35a32007261ea3a4fa40d5757a06adde6c8b19 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Fri, 2 Sep 2022 12:32:55 -0700 Subject: [PATCH] Runtime query'able version information API spec (#2893) * 41026156: Add runtime query'able release information API spec * Incorporated feedback --- specs/VersionInfo/VersionInfo.md | 166 +++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 specs/VersionInfo/VersionInfo.md diff --git a/specs/VersionInfo/VersionInfo.md b/specs/VersionInfo/VersionInfo.md new file mode 100644 index 0000000000..64b2fd15da --- /dev/null +++ b/specs/VersionInfo/VersionInfo.md @@ -0,0 +1,166 @@ +# VersionInfo API + +# Background + +When using Windows App SDK via its framework-dependent runtime (aka MSIX packages) a developer +specifies at build-time a dependency _criteria_ which can match a range of possible packages. This +is resolved at runtime to a package meeting the criteria but it's not easy to determine the specific +package in use. + +This API shrinkwraps these complexities providing an easy and reliable mechanism to determine the +specific runtime in use. + +# Description + +Developers using the Windows App SDK runtime as MSIX packages (aka framework-dependent) specify a +criteria to resolve at runtime. The mechanism and syntax depends if the app is packaged or +unpackaged. + +Packaged apps declare a dependency in their `appxmanifest.xml e.g. for a dependency on WinAppSDK +1.1.0 + +```xml + + + +``` + +Unpackaged apps use the [Bootstrapper API](https://docs.microsoft.com/en-us/windows/windows-app-sdk/api/win32/_bootstrap/) specifying their dependency via parameters e.g. for a dependency on WinAppSDK 1.1.0 [using C](https://docs.microsoft.com/windows/windows-app-sdk/api/win32/mddbootstrap/nf-mddbootstrap-mddbootstrapinitialize) + +```c +#include +#include +// ... + +HRESULT hr = MddBootstrapInitialize(WINDOWSAPPSDK_RELEASE_MAJORMINOR, WINDOWSAPPSDK_RELEASE_VERSION_TAG_W, WINDOWSAPPSDK_RUNTIME_VERSION_UINT64); +if (FAILED(hr)) +{ + wprintf(L"Error 0x%X in Bootstrap initialization\n", hr); +} +``` + +where `WINDOWSAPPSDK_RELEASE_MAJORMINOR`, `WINDOWSAPPSDK_RELEASE_VERSION_TAG_W` and +`WINDOWSAPPSDK_RUNTIME_VERSION_UINT64` are build-time constants from `WindowsAppSDK-VersionInfo.h` +i.e. + +```c +MddBootstrapInitialize(WINDOWSAPPSDK_RELEASE_MAJORMINOR, WINDOWSAPPSDK_RELEASE_VERSION_TAG_W, WINDOWSAPPSDK_RUNTIME_VERSION_UINT64) +``` + +for 1.1.0 is equivalent to + +```c +MddBootstrapInitialize(0x00010001, L"", 0x03E80204086C0000u) +``` + +Developers using the Bootstrapper auto-initializer link a global constructor into their executable +which calls the Bootstrapper API with this build-time information. + +All these options share a common property: the developer specifies the WinAppSDK release, channel +and a _minimum_ acceptable package version. This resolves to a specific package at runtime that +satisfies the dependency which is >= MinVersion (not ==MinVersion). + +One can indirectly determine the actual runtime version in use by retrieving the package graph via +[GetCurrentPackageInfo()](https://docs.microsoft.com/windows/win32/api/appmodel/nf-appmodel-getcurrentpackageinfo) +and walking the result looking for a framework package in the runtime's family. This is cumbersome +(even more so for C# given the need for P/Invoke and the shape of the API for C# callers), can pose +performance overhead (searching across a deep copy of the package graph) and is potentially +ambiguous (e.g. advanced scenarios using Dynamic Dependencies can have multiple runtimes in the +package graph). + +This can be shrinkwrapped via an easy to use API where we (WinAppSDK) incur the burden of +implementation complexity, using a design to directly and efficiently yield the correct answer. + +This provides a simple but reliable and performant solution for applications, as well as class +libraries and other components using WinAppSDK. + +# Examples + +An example using the runtime version information API to display the actual version in use at runtime: + +```c# +using System; +using System.Windows.Forms; +using Microsoft.Windows.ApplicationModel.WindowsAppRuntime; + +public class MyInfo +{ + public static void About() + { + var build_release = Microsoft.WindowsAppSDK.Release; + var build_version = Microsoft.WindowsAppSDK.Runtime.Version; + var release = ReleaseInfo.Current(); + var runtime = RuntimeInfo.Current(); + var message = $"Built with Windows App SDK ${build_release.Major}.${build_release.Minor}.${build_release.Patch}${build_release.FormattedVersionTag}\n" + $"Minimum Windows App Runtime version ${build_version.Major}.${build_version.Minor}.${build_version.Build}.${build_version.Revision}\n" + "\n" + + $"Running with Windows App SDK ${release.Major}.${release.Minor}.${release.Patch}${release.FormattedVersionTag}\n" + + $"Windows App Runtime version ${runtime.version.Major}.${runtime.version.Minor}.${runtime.version.Build}.${runtime.version.Revision}"; + MessageBox.Show(message, "About MyApp", MessageBoxButtons.OK, MessageBoxIcon.Information); + } +} +``` + +# Remarks + +Version information is compiled into `Microsoft.WindowsAppRuntime.Insights.Resource.dll` as the +product is assembled (i.e. when the version is defined). The VersionInfo API retrieves this +information via an internal API. + +# 6. API Details + +```c# (but really MIDL3) +namespace Microsoft.Windows.ApplicationModel.WindowsAppRuntime +{ + [contractversion(1)] + apicontract VersionInfoContract{}; + + /// Version information for the Windows App SDK release. + [contract(VersionInfoContract, 1)] + static runtimeclass ReleaseInfo + { + /// The major version of the Windows App SDK release. + static UInt16 Major{ get; }; + + /// The minor version of the Windows App SDK release. + static UInt16 Minor{ get; }; + + /// The patch version of the Windows App SDK release. + static UInt16 Patch{ get; }; + + /// The Windows App SDK release's version tag; for example, "preview2", or empty string for stable. + static String VersionTag{ get; }; + + /// The version of the Windows App SDK runtime; for example, "1.1-preview2" or "1.2.3". + static String ToString{ get; }; + }; + + /// Version information for the Windows App SDK runtime. + [contract(VersionInfoContract, 1)] + static runtimeclass RuntimeInfo + { + /// The version of the Windows App SDK runtime; for example, { Major=1000, Minor=446, Build=804, Revision=0 } + static Windows.ApplicationModel.PackageVersion Version{ get; }; + + /// The version of the Windows App SDK runtime; for example, "1000.446.804.0" + static String ToString{ get; }; + }; +} +``` + +`WindowsAppSDK-VersionInfo.h` (C/C++) and `Microsoft.WindowsAppRuntime.Release.Net` (.NET assembly) +provide constants of what Windows App SDK is used at build-time. The VersionInfo API provides the +equivalent information but the values are the version actually in use at runtime. + +# Appendix + +## Alternative Design: VERSIONINFO Resource + +An alternative design using a [VERSIONINFO resource](https://docs.microsoft.com/windows/win32/menurc/versioninfo-resource) was considered but discarded as a weaker alternative to the VersionInfo API for multiple reasons including... + +* Resource APIs aren't necessarily convenient or accessible to all languages (unlike a WinRT API) +* Data contracts offer poor flexibility for future evolution (unlike an API) +* Data is more complex than VERSIONINFO supports (unlike the VersionInfo API)