-
-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Joao Grassi <[email protected]> Co-authored-by: Anton Ovchinnikov <[email protected]>
- Loading branch information
1 parent
0afcf08
commit c8e014e
Showing
15 changed files
with
921 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
#if NETFX | ||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.Win32; | ||
|
||
namespace Sentry.PlatformAbstractions | ||
{ | ||
/// <summary> | ||
/// Information about .NET Framework in the running machine | ||
/// </summary> | ||
public static partial class FrameworkInfo | ||
{ | ||
/// <summary> | ||
/// Get the latest Framework installation for the specified CLR | ||
/// </summary> | ||
/// <remarks> | ||
/// Supports the current 3 CLR versions: | ||
/// CLR 1 => .NET 1.0, 1.1 | ||
/// CLR 2 => .NET 2.0, 3.0, 3.5 | ||
/// CLR 4 => .NET 4.0, 4.5.x, 4.6.x, 4.7.x | ||
/// </remarks> | ||
/// <param name="clrVersion">The CLR version: 1, 2 or 4</param> | ||
/// <returns>The framework installation or null if none is found.</returns> | ||
public static FrameworkInstallation? GetLatest(int clrVersion) | ||
{ | ||
// CLR versions | ||
// https://docs.microsoft.com/en-us/dotnet/standard/clr | ||
if (clrVersion != 1 && clrVersion != 2 && clrVersion != 4) | ||
{ | ||
return null; | ||
} | ||
|
||
if (clrVersion == 4) | ||
{ | ||
var release = Get45PlusLatestInstallationFromRegistry(); | ||
if (release != null) | ||
{ | ||
return new FrameworkInstallation | ||
{ | ||
Version = GetNetFxVersionFromRelease(release.Value), | ||
Release = release | ||
}; | ||
} | ||
} | ||
|
||
FrameworkInstallation latest = null; | ||
foreach (var installation in GetInstallations()) | ||
{ | ||
latest ??= installation; | ||
|
||
if (clrVersion == 2) | ||
{ | ||
// CLR 2 runs .NET 2 to 3.5 | ||
if ((installation.Version.Major == 2 || installation.Version.Major == 3) | ||
&& installation.Version >= latest.Version) | ||
{ | ||
latest = installation; | ||
} | ||
else | ||
{ | ||
break; | ||
} | ||
} | ||
else if (clrVersion == 4) | ||
{ | ||
if (installation.Version.Major == 4 | ||
&& installation.Version >= latest.Version) | ||
{ | ||
latest = installation; | ||
} | ||
else | ||
{ | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return latest; | ||
} | ||
|
||
/// <summary> | ||
/// Get all .NET Framework installations in this machine | ||
/// </summary> | ||
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed#to-find-net-framework-versions-by-querying-the-registry-in-code-net-framework-1-4"/> | ||
/// <returns>Enumeration of installations</returns> | ||
public static IEnumerable<FrameworkInstallation> GetInstallations() | ||
{ | ||
using var ndpKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty) | ||
.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\"); | ||
if (ndpKey == null) | ||
{ | ||
yield break; | ||
} | ||
|
||
foreach (var versionKeyName in ndpKey.GetSubKeyNames()) | ||
{ | ||
if (!versionKeyName.StartsWith("v") || !(ndpKey.OpenSubKey(versionKeyName) is RegistryKey versionKey)) | ||
{ | ||
continue; | ||
} | ||
|
||
var version = versionKey.GetString("Version"); | ||
if (version != null && versionKey.GetInt("Install") == 1) | ||
{ | ||
// 1.0 to 3.5 | ||
Version.TryParse(version, out var parsed); | ||
yield return new FrameworkInstallation | ||
{ | ||
ShortName = versionKeyName, | ||
Version = parsed, | ||
ServicePack = versionKey.GetInt("SP") | ||
}; | ||
|
||
continue; | ||
} | ||
|
||
// 4.0+ | ||
foreach (var subKeyName in versionKey.GetSubKeyNames()) | ||
{ | ||
var subKey = versionKey.OpenSubKey(subKeyName); | ||
if (subKey?.GetInt("Install") != 1) | ||
{ | ||
continue; | ||
} | ||
|
||
yield return GetFromV4(subKey, subKeyName); | ||
} | ||
} | ||
} | ||
|
||
private static FrameworkInstallation GetFromV4(RegistryKey subKey, string subKeyName) | ||
{ | ||
var hasRelease = int.TryParse( | ||
subKey.GetValue("Release", null)?.ToString(), out var release); | ||
|
||
Version version = null; | ||
if (hasRelease) | ||
{ | ||
// 4.5+ | ||
var displayableVersion = GetNetFxVersionFromRelease(release); | ||
if (displayableVersion != null) | ||
{ | ||
version = displayableVersion; | ||
} | ||
} | ||
|
||
if (version == null) | ||
{ | ||
Version.TryParse(subKey.GetString("Version"), out var parsed); | ||
version = parsed; | ||
} | ||
|
||
return new FrameworkInstallation | ||
{ | ||
Profile = subKeyName switch | ||
{ | ||
"Full" => FrameworkProfile.Full, | ||
"Client" => FrameworkProfile.Client, | ||
_ => null | ||
}, | ||
Version = version, | ||
ServicePack = subKey.GetInt("SP"), | ||
Release = hasRelease ? release : null as int? | ||
}; | ||
} | ||
|
||
// https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed#to-find-net-framework-versions-by-querying-the-registry-in-code-net-framework-45-and-later | ||
internal static int? Get45PlusLatestInstallationFromRegistry() | ||
{ | ||
using var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32) | ||
.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"); | ||
return ndpKey?.GetInt("Release"); | ||
} | ||
|
||
internal static Version GetNetFxVersionFromRelease(int release) | ||
{ | ||
NetFxReleaseVersionMap.TryGetValue(release, out var version); | ||
Version.TryParse(version, out var parsed); | ||
return parsed; | ||
} | ||
} | ||
} | ||
|
||
#endif |
29 changes: 29 additions & 0 deletions
29
src/Sentry/PlatformAbstractions/FrameworkInfo.NetStandard.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#if !NETFX | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Sentry.PlatformAbstractions | ||
{ | ||
/// <summary> | ||
/// No-op version for netstandard targets | ||
/// </summary> | ||
public static partial class FrameworkInfo | ||
{ | ||
/// <summary> | ||
/// No-op version for netstandard targets | ||
/// </summary> | ||
/// <param name="clr"></param> | ||
/// <returns></returns> | ||
public static FrameworkInstallation? GetLatest(int clr) => null; | ||
|
||
/// <summary> | ||
/// No-op version for netstandard targets | ||
/// </summary> | ||
/// <returns></returns> | ||
public static IEnumerable<FrameworkInstallation> GetInstallations() | ||
=> Enumerable.Empty<FrameworkInstallation>(); | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Sentry.PlatformAbstractions | ||
{ | ||
/// <summary> | ||
/// Information about .NET Framework in the running machine | ||
/// The purpose of this partial class is to expose the API to all targets | ||
/// For netstandard, the call to methods will be a simple no-op. | ||
/// </summary> | ||
public static partial class FrameworkInfo | ||
{ | ||
/// <summary> | ||
/// The map between release number and version number | ||
/// </summary> | ||
/// <see href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed" /> | ||
public static IReadOnlyDictionary<int, string> NetFxReleaseVersionMap { get; } | ||
= new Dictionary<int, string> | ||
{ | ||
{378389, "4.5"}, | ||
{378675, "4.5.1"}, | ||
{378758, "4.5.1"}, | ||
{379893, "4.5.2"}, | ||
{393295, "4.6"}, | ||
{393297, "4.6"}, | ||
{394254, "4.6.1"}, | ||
{394271, "4.6.1"}, | ||
{394802, "4.6.2"}, | ||
{394806, "4.6.2"}, | ||
{460798, "4.7"}, | ||
{460805, "4.7"}, | ||
{461308, "4.7.1"}, | ||
{461310, "4.7.1"}, | ||
{461808, "4.7.2"}, | ||
{461814, "4.7.2"}, | ||
{528040, "4.8"}, | ||
{528049, "4.8"}, | ||
{528209, "4.8"}, | ||
{528372, "4.8"}, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
using System; | ||
|
||
namespace Sentry.PlatformAbstractions | ||
{ | ||
/// <summary> | ||
/// A .NET Framework installation | ||
/// </summary> | ||
/// <seealso href="https://en.wikipedia.org/wiki/.NET_Framework_version_history"/> | ||
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed"/> | ||
public class FrameworkInstallation | ||
{ | ||
/// <summary> | ||
/// Short name | ||
/// </summary> | ||
/// <example> | ||
/// v2.0.50727, v3.5, v4.0 | ||
/// </example> | ||
public string? ShortName { get; set; } | ||
/// <summary> | ||
/// Version | ||
/// </summary> | ||
/// <example> | ||
/// 2.0.50727.4927, 3.0.30729.4926, 3.5.30729.4926 | ||
/// </example> | ||
public Version? Version { get; set; } | ||
/// <summary> | ||
/// Service pack number, if any | ||
/// </summary> | ||
/// <remarks> | ||
/// Only relevant prior to .NET 4 | ||
/// </remarks> | ||
public int? ServicePack { get; set; } | ||
/// <summary> | ||
/// Type of Framework profile | ||
/// </summary> | ||
/// <remarks>Only relevant for .NET 3.5 and 4.0</remarks> | ||
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/framework/deployment/client-profile"/> | ||
public FrameworkProfile? Profile { get; set; } | ||
/// <summary> | ||
/// A .NET Framework release key | ||
/// </summary> | ||
/// <remarks> | ||
/// Windows registry key: | ||
/// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\Release | ||
/// Only applicable when on Windows, with full .NET Framework 4.5 and later. | ||
/// </remarks> | ||
/// <see href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed"/> | ||
public int? Release { get; set; } | ||
|
||
/// <inheritdoc /> | ||
public override string ToString() | ||
{ | ||
return Version?.Build > 0 | ||
? $"{Version.Major}.{Version.Minor}.{Version.Build}" | ||
: $"{Version?.Major ?? 0}.{Version?.Minor ?? 0}"; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Type of Framework profile | ||
/// </summary> | ||
/// <remarks>Only relevant for .NET 3.5 and 4.0</remarks> | ||
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/framework/deployment/client-profile"/> | ||
public enum FrameworkProfile | ||
{ | ||
/// <summary> | ||
/// The .NET Client Profile is a subset of the .NET Framework | ||
/// </summary> | ||
Client, | ||
/// <summary> | ||
/// The full .NET Framework | ||
/// </summary> | ||
Full | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#if NETFX | ||
using Microsoft.Win32; | ||
|
||
namespace Sentry.PlatformAbstractions | ||
{ | ||
internal static class RegistryKeyExtensions | ||
{ | ||
public static string? GetString(this RegistryKey key, string value) | ||
=> key.GetValue(value) as string; | ||
|
||
public static int? GetInt(this RegistryKey key, string value) | ||
=> (int?)key.GetValue(value); | ||
} | ||
} | ||
#endif |
Oops, something went wrong.