4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . Linq ;
7
- using System . Runtime . InteropServices ;
8
7
using System . Text . RegularExpressions ;
9
8
using Microsoft . DotNet . Tools . Uninstall . MacOs ;
10
9
using Microsoft . DotNet . Tools . Uninstall . Shared . BundleInfo ;
@@ -25,25 +24,8 @@ public IEnumerable<Bundle> GetInstalledBundles()
25
24
26
25
public virtual IEnumerable < Bundle > GetAllInstalledBundles ( )
27
26
{
28
- var uninstalls = Registry . LocalMachine
29
- . OpenSubKey ( "SOFTWARE" ) ;
30
-
31
- if ( RuntimeInformation . ProcessArchitecture == Architecture . X64 || RuntimeInformation . ProcessArchitecture == Architecture . Arm64 )
32
- {
33
- uninstalls = uninstalls . OpenSubKey ( "WOW6432Node" ) ;
34
- }
35
-
36
- uninstalls = uninstalls
37
- . OpenSubKey ( "Microsoft" )
38
- . OpenSubKey ( "Windows" )
39
- . OpenSubKey ( "CurrentVersion" )
40
- . OpenSubKey ( "Uninstall" ) ;
41
-
42
- var names = uninstalls . GetSubKeyNames ( ) ;
43
-
44
- var bundles = names
45
- . Select ( name => uninstalls . OpenSubKey ( name ) )
46
- . Where ( bundle => IsNetCoreBundle ( bundle ) ) ;
27
+ var bundles = GetNetCoreBundleKeys ( RegistryKey . OpenBaseKey ( RegistryHive . LocalMachine , RegistryView . Registry64 ) ) ;
28
+ bundles = bundles . Concat ( GetNetCoreBundleKeys ( RegistryKey . OpenBaseKey ( RegistryHive . LocalMachine , RegistryView . Registry32 ) ) ) ;
47
29
48
30
var wrappedBundles = bundles
49
31
. Select ( bundle => WrapRegistryKey ( bundle ) )
@@ -53,6 +35,26 @@ public virtual IEnumerable<Bundle> GetAllInstalledBundles()
53
35
return wrappedBundles ;
54
36
}
55
37
38
+ private IEnumerable < RegistryKey > GetNetCoreBundleKeys ( RegistryKey uninstallKey )
39
+ {
40
+ try
41
+ {
42
+ var uninstalls = uninstallKey
43
+ . OpenSubKey ( @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" ) ;
44
+
45
+ var names = uninstalls . GetSubKeyNames ( ) ;
46
+
47
+ return names
48
+ . Select ( name => uninstalls . OpenSubKey ( name ) )
49
+ . Where ( bundle => IsNetCoreBundle ( bundle ) ) ;
50
+ }
51
+ catch
52
+ {
53
+ return Enumerable . Empty < RegistryKey > ( ) ;
54
+ }
55
+
56
+ }
57
+
56
58
private static bool IsNetCoreBundle ( RegistryKey uninstallKey )
57
59
{
58
60
if ( uninstallKey == null )
@@ -75,7 +77,8 @@ internal static bool IsNetCoreBundle(string displayName, string displayVersion,
75
77
( ( displayName . IndexOf ( ".NET" , StringComparison . OrdinalIgnoreCase ) >= 0 ) ||
76
78
( displayName . IndexOf ( ".NET Runtime" , StringComparison . OrdinalIgnoreCase ) >= 0 ) ||
77
79
( displayName . IndexOf ( ".NET SDK" , StringComparison . OrdinalIgnoreCase ) >= 0 ) ||
78
- ( displayName . IndexOf ( "Dotnet Shared Framework for Windows Desktop" , StringComparison . OrdinalIgnoreCase ) >= 0 ) ) &&
80
+ ( displayName . IndexOf ( "Dotnet Shared Framework for Windows Desktop" , StringComparison . OrdinalIgnoreCase ) >= 0 ) ||
81
+ ( displayName . IndexOf ( "Windows Desktop Runtime" , StringComparison . OrdinalIgnoreCase ) >= 0 ) ) &&
79
82
( ! String . IsNullOrEmpty ( uninstallString ) ) &&
80
83
( uninstallString . IndexOf ( ".exe" , StringComparison . OrdinalIgnoreCase ) >= 0 ) &&
81
84
( uninstallString . IndexOf ( "msiexec" , StringComparison . OrdinalIgnoreCase ) < 0 ) &&
@@ -86,7 +89,7 @@ internal static bool IsNetCoreBundle(string displayName, string displayVersion,
86
89
private static Bundle WrapRegistryKey ( RegistryKey registryKey )
87
90
{
88
91
var displayName = registryKey . GetValue ( "DisplayName" ) as string ;
89
- var uninstallCommand = registryKey . GetValue ( "QuietUninstallString" ) as string ;
92
+ var uninstallCommand = registryKey . GetValue ( "QuietUninstallString" ) as string ?? registryKey . GetValue ( "UninstallString" ) as string ;
90
93
var bundleCachePath = registryKey . GetValue ( "BundleCachePath" ) as string ;
91
94
92
95
var version = GetBundleVersion ( displayName , uninstallCommand , bundleCachePath ) ;
@@ -103,11 +106,15 @@ private static Bundle WrapRegistryKey(RegistryKey registryKey)
103
106
public static BundleVersion GetBundleVersion ( string displayName , string uninstallString , string bundleCachePath )
104
107
{
105
108
var versionString = Regexes . VersionDisplayNameRegex . Match ( displayName ) ? . Value ?? string . Empty ;
106
- var cachePathMatch = Regexes . BundleCachePathRegex . Match ( bundleCachePath ) ;
107
- var hasAuxVersion = cachePathMatch . Groups [ Regexes . AuxVersionGroupName ] . Success ;
108
- var footnote = hasAuxVersion ?
109
- string . Format ( LocalizableStrings . HostingBundleFootnoteFormat , displayName , versionString ) :
110
- null ;
109
+ string footnote = null ;
110
+ if ( bundleCachePath != null )
111
+ {
112
+ var cachePathMatch = Regexes . BundleCachePathRegex . Match ( bundleCachePath ) ;
113
+ var hasAuxVersion = cachePathMatch . Groups [ Regexes . AuxVersionGroupName ] . Success ;
114
+ footnote = hasAuxVersion ?
115
+ string . Format ( LocalizableStrings . HostingBundleFootnoteFormat , displayName , versionString ) :
116
+ null ;
117
+ }
111
118
112
119
try
113
120
{
@@ -146,20 +153,35 @@ private static BundleArch GetBundleArch(string displayName, string bundleCachePa
146
153
{
147
154
const string x64String = "x64" ;
148
155
const string x86String = "x86" ;
156
+ const string arm64String = "arm64" ;
149
157
150
- var cachePathMatch = Regexes . BundleCachePathRegex . Match ( bundleCachePath ) ;
151
-
152
- var archString = cachePathMatch . Groups [ Regexes . ArchGroupName ] . Value ;
158
+ string archString = null ;
159
+ if ( bundleCachePath != null )
160
+ {
161
+ var cachePathMatch = Regexes . BundleCachePathRegex . Match ( bundleCachePath ) ;
162
+ archString = cachePathMatch . Groups [ Regexes . ArchGroupName ] . Value ;
163
+ }
153
164
154
165
if ( string . IsNullOrEmpty ( archString ) )
155
166
{
156
- archString = displayName . Contains ( x64String ) ? x64String : displayName . Contains ( x86String ) ? x86String : string . Empty ;
167
+ archString = displayName . Contains ( x64String ) ?
168
+ x64String :
169
+ displayName . Contains ( x86String ) ? x86String : string . Empty ;
170
+
171
+ archString = archString switch
172
+ {
173
+ string a when a . Contains ( x64String ) => x64String ,
174
+ string b when b . Contains ( x86String ) => x86String ,
175
+ string b when b . Contains ( arm64String ) => arm64String ,
176
+ _ => string . Empty
177
+ } ;
157
178
}
158
179
159
180
switch ( archString )
160
181
{
161
182
case x64String : return BundleArch . X64 ;
162
183
case x86String : return BundleArch . X86 ;
184
+ case arm64String : return BundleArch . Arm64 ;
163
185
case "" : return BundleArch . X64 | BundleArch . X86 ;
164
186
default : throw new ArgumentException ( ) ;
165
187
}
0 commit comments