Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update load asm binaries from registry logic #11261

Merged
merged 7 commits into from
Nov 19, 2020
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
152 changes: 116 additions & 36 deletions src/Tools/DynamoInstallDetective/ProductLookUp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,110 @@

namespace DynamoInstallDetective
{
// Utility class for interacting with the windows registry.
internal static class RegUtils
{
// Utility class to enable/disable registry caching within a scope.
class RegistryCacher : IDisposable
{
public RegistryCacher()
{
lock (mutex)
{
cacheEnabled = true;
}
}

public void Dispose()
{
lock (mutex)
{
cacheEnabled = false;
cachedRecords?.Clear();
cachedRecords = null;
}
}
}

public static string REG_KEY64 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\";
public static string REG_KEY32 = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\";

// Cached data from windows registry. Consists of a dictionary that maps The product name/code to Display Name (Tuple.item1) and Install Path(Tuple.item2)
// Dictionary<ProductCode, (DisplayName, InstallPath)>
private static Dictionary<string, (string DisplayName, string InstallLocation)> cachedRecords;
private static bool cacheEnabled = false;

private static readonly object mutex = new object();
pinzart90 marked this conversation as resolved.
Show resolved Hide resolved
pinzart90 marked this conversation as resolved.
Show resolved Hide resolved

public static RegistryKey OpenKey(string key)
{
var regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
return regKey.OpenSubKey(key);
}
public static string GetInstallLocation(RegistryKey key)
{
if (key != null)
return key.GetValue("InstallLocation") as string;

return string.Empty;
}

public static string GetDisplayName(RegistryKey key)
{
if (key != null)
return key.GetValue("DisplayName") as string;

return string.Empty;
}

// Returns all the products registered under "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" that have a valid DisplayName and an InstallLocation.
public static Dictionary<string, (string DisplayName, string InstallLocation)> GetInstalledProducts()
{
lock (mutex)
{
if (cacheEnabled && cachedRecords != null)
{
return cachedRecords;
}
}

var productInfo = new Dictionary<string, (string displayName, string installLocation)>();

var key = OpenKey(REG_KEY64);
foreach(string s in key.GetSubKeyNames())
{
try
{
var prodKey = key.OpenSubKey(s);
var displayName = GetDisplayName(prodKey);
var installLocation = GetInstallLocation(prodKey);
if (!string.IsNullOrEmpty(displayName) && !string.IsNullOrEmpty(installLocation))
{
productInfo.Add(s, (displayName, installLocation));
}
}
catch (Exception)
aparajit-pratap marked this conversation as resolved.
Show resolved Hide resolved
{
// Do nothing
}
}

lock (mutex)
{
if (cacheEnabled)
{
cachedRecords = new Dictionary<string, (string DisplayName, string InstallLocation)>(productInfo);
}
}
return productInfo;
}

public static IDisposable StartCache()
{
return new RegistryCacher();
}
}
pinzart90 marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Specifies an installed product
/// </summary>
Expand Down Expand Up @@ -63,7 +167,7 @@ public interface IProductLookUp
IInstalledProduct GetProductFromProductCode(string productCode);

/// <summary>
/// Returns product name list based on lookup criteria
/// Returns product name list using lookup criteria based on product names.
/// </summary>
/// <returns>Product name list</returns>
IEnumerable<string> GetProductNameList();
Expand Down Expand Up @@ -120,38 +224,13 @@ public interface IProductCollection
/// </summary>
public class InstalledProductLookUp : IProductLookUp
{
const string REG_KEY64 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\";
const string REG_KEY32 = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\";

/// <summary>
/// Product name for lookup
/// </summary>
public string ProductLookUpName { get; private set; }

private readonly Func<string, string> fileLocator;

static RegistryKey OpenKey(string key)
pinzart90 marked this conversation as resolved.
Show resolved Hide resolved
{
var regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
return regKey.OpenSubKey(key);
}

static string GetInstallLocation(RegistryKey key)
{
if (key != null)
return key.GetValue("InstallLocation") as string;

return string.Empty;
}

static string GetDisplayName(RegistryKey key)
{
if (key != null)
return key.GetValue("DisplayName") as string;

return string.Empty;
}

/// <summary>
/// Implements a product look up algorithm based on registry key.
/// </summary>
Expand Down Expand Up @@ -202,8 +281,9 @@ public IInstalledProduct GetProductFromProductCode(string productCode)

public virtual IEnumerable<string> GetProductNameList()
{
var key = OpenKey(REG_KEY64);
return key.GetSubKeyNames().Where(s => s.Contains(ProductLookUpName));
return RegUtils.GetInstalledProducts().Select(s => s.Value.DisplayName).Where(s => {
return s?.Contains(ProductLookUpName) ?? false;
});
pinzart90 marked this conversation as resolved.
Show resolved Hide resolved
}

public virtual bool ExistsAtPath(string basePath)
Expand All @@ -216,21 +296,21 @@ public virtual bool ExistsAtPath(string basePath)

public virtual string GetInstallLocationFromProductName(string name)
{
var key = OpenKey(REG_KEY64 + name);
return GetInstallLocation(key);
var key = RegUtils.OpenKey(RegUtils.REG_KEY64 + name);
return RegUtils.GetInstallLocation(key);
}

public virtual string GetInstallLocationFromProductCode(string productCode, out string productName)
{
string issProdKey = REG_KEY32 + productCode + "_is1";
var key = OpenKey(issProdKey);
string issProdKey = RegUtils.REG_KEY32 + productCode + "_is1";
var key = RegUtils.OpenKey(issProdKey);
if (null == key)
{
issProdKey = REG_KEY64 + productCode;
key = OpenKey(issProdKey);
issProdKey = RegUtils.REG_KEY64 + productCode;
key = RegUtils.OpenKey(issProdKey);
}
productName = GetDisplayName(key);
return GetInstallLocation(key);
productName = RegUtils.GetDisplayName(key);
return RegUtils.GetInstallLocation(key);
}

public virtual string GetCoreFilePathFromInstallation(string installPath)
Expand Down
25 changes: 14 additions & 11 deletions src/Tools/DynamoInstallDetective/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,22 @@ public static IEnumerable FindProductInstallations(string productSearchPattern,
/// info.</returns>
public static IEnumerable FindMultipleProductInstallations(List<string> productSearchPatterns, string fileSearchPattern)
{
var installs = new InstalledProducts();
// Look up products with ASM installed on user's computer
foreach (var productSearchPattern in productSearchPatterns)
using (RegUtils.StartCache())
pinzart90 marked this conversation as resolved.
Show resolved Hide resolved
{
installs.LookUpAndInitProducts(new InstalledProductLookUp(productSearchPattern, fileSearchPattern));
}
var installs = new InstalledProducts();
// Look up products with ASM installed on user's computer
foreach (var productSearchPattern in productSearchPatterns)
{
installs.LookUpAndInitProducts(new InstalledProductLookUp(productSearchPattern, fileSearchPattern));
}

return
installs.Products.Select(
p =>
new KeyValuePair<string, Tuple<int, int, int, int>>(
p.InstallLocation,
p.VersionInfo));
return
installs.Products.Select(
p =>
new KeyValuePair<string, Tuple<int, int, int, int>>(
p.InstallLocation,
p.VersionInfo));
}
}
}
}