Skip to content
Merged
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: 1 addition & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestFeature"
"version": "8.0.200"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ namespace Grpc.Net.Client.Internal;
/// <summary>
/// Types for calling RtlGetVersion. See https://www.pinvoke.net/default.aspx/ntdll/RtlGetVersion.html
/// </summary>
internal static class NtDll
internal static class Native
{
#pragma warning disable SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern NTSTATUS RtlGetVersion(ref OSVERSIONINFOEX versionInfo);

[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern int GetCurrentApplicationUserModelId(ref uint applicationUserModelIdLength, byte[] applicationUserModelId);
#pragma warning restore SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time

internal static void DetectWindowsVersion(out Version version, out bool isWindowsServer)
Expand All @@ -46,6 +49,40 @@ internal static void DetectWindowsVersion(out Version version, out bool isWindow
isWindowsServer = osVersionInfo.ProductType == VER_NT_SERVER;
}

internal static bool IsUwp(string frameworkDescription, Version version)
{
if (frameworkDescription.StartsWith(".NET Native", StringComparison.OrdinalIgnoreCase))
{
return true;
}

// From https://github.com/dotnet/runtime/blob/d752f9a19f2d4bc4559e0e303e9374e4042a916e/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs#L190
const int Windows8Build = 9200;
if (version.Build < Windows8Build)
{
return false;
}
else
{
var bufferSize = 0U;
var result = GetCurrentApplicationUserModelId(ref bufferSize, Array.Empty<byte>());
switch (result)
{
case 15703: // APPMODEL_ERROR_NO_APPLICATION
return false;
case 0: // ERROR_SUCCESS
case 122: // ERROR_INSUFFICIENT_BUFFER
// Success is actually insufficient buffer as we're really only looking for
// not NO_APPLICATION and we're not actually giving a buffer here. The
// API will always return NO_APPLICATION if we're not running under a
// WinRT process, no matter what size the buffer is.
return true;
default:
throw new InvalidOperationException($"Failed to get AppModelId, result was {result}.");
}
}
}

internal enum NTSTATUS : uint
{
/// <summary>
Expand Down
11 changes: 7 additions & 4 deletions src/Grpc.Net.Client/Internal/OperatingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ private OperatingSystem()
// Get the value lazily so that it is only called if needed.
_isWindowsServer = new Lazy<bool>(() =>
{
if (IsWindows)
// RtlGetVersion is not available on UWP. Check it first.
if (IsWindows && !Native.IsUwp(RuntimeInformation.FrameworkDescription, Environment.OSVersion.Version))
{
NtDll.DetectWindowsVersion(out _, out var isWindowsServer);
Native.DetectWindowsVersion(out _, out var isWindowsServer);
return isWindowsServer;
}

Expand All @@ -72,9 +73,11 @@ private OperatingSystem()
//
// Get correct Windows version directly from Windows by calling RtlGetVersion.
// https://www.pinvoke.net/default.aspx/ntdll/RtlGetVersion.html
if (IsWindows)
//
// RtlGetVersion is not available on UWP. Check it first.
if (IsWindows && !Native.IsUwp(RuntimeInformation.FrameworkDescription, Environment.OSVersion.Version))
{
NtDll.DetectWindowsVersion(out var windowsVersion, out var windowsServer);
Native.DetectWindowsVersion(out var windowsVersion, out var windowsServer);
OSVersion = windowsVersion;
_isWindowsServer = new Lazy<bool>(() => windowsServer, LazyThreadSafetyMode.ExecutionAndPublication);
}
Expand Down
4 changes: 2 additions & 2 deletions test/Grpc.Net.Client.Tests/OperatingSystemTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class OperatingSystemTests
[Platform("Win", Reason = "Only runs on Windows where ntdll.dll is present.")]
public void DetectWindowsVersion_Windows_MatchesEnvironment()
{
NtDll.DetectWindowsVersion(out var version, out _);
Native.DetectWindowsVersion(out var version, out _);

// It is safe to compare Environment.OSVersion.Version on netfx because tests have no compatibility setting.
Assert.AreEqual(Environment.OSVersion.Version, version);
Expand All @@ -39,7 +39,7 @@ public void DetectWindowsVersion_Windows_MatchesEnvironment()
[Platform("Win", Reason = "Only runs on Windows where ntdll.dll is present.")]
public void InstanceAndIsWindowsServer_Windows_MatchesEnvironment()
{
NtDll.DetectWindowsVersion(out var version, out var isWindowsServer);
Native.DetectWindowsVersion(out var version, out var isWindowsServer);

Assert.AreEqual(true, OperatingSystem.Instance.IsWindows);
Assert.AreEqual(version, OperatingSystem.Instance.OSVersion);
Expand Down