Skip to content

Commit

Permalink
Fixed #18
Browse files Browse the repository at this point in the history
Added alternative method for enumerating installed instances of Visual Studio
  • Loading branch information
Hefaistos68 committed Oct 11, 2023
1 parent 49d4220 commit 55391cf
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 24 deletions.
125 changes: 101 additions & 24 deletions VSLXshared/DataModel/VisualStudioInstanceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
using System.Xml.Linq;

using Newtonsoft.Json;
using Microsoft.VisualStudio.Setup.Configuration;

using VSLauncher.Helpers;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace VSLauncher.DataModel
{
Expand Down Expand Up @@ -121,46 +124,120 @@ public static List<VisualStudioInstance> ReadAllInstances()
// read all data from WMI using CimInstance MSFT_VSInstance
// https://docs.microsoft.com/en-us/windows/win32/wmisdk/msft-vsinstance

ManagementObjectSearcher searcher = new ManagementObjectSearcher
try
{
Query = new SelectQuery("MSFT_VSInstance ", "", new[] { "Name", "Version", "ProductLocation", "IdentifyingNumber" })
};
ManagementObjectCollection collection = searcher.Get();
ManagementObjectCollection.ManagementObjectEnumerator em = collection.GetEnumerator();
ManagementObjectSearcher searcher = new ManagementObjectSearcher
{
Query = new SelectQuery("MSFT_VSInstance ", "", new[] { "Name", "Version", "ProductLocation", "IdentifyingNumber" })
};
ManagementObjectCollection collection = searcher.Get();
ManagementObjectCollection.ManagementObjectEnumerator em = collection.GetEnumerator();

while (em.MoveNext())
{
ManagementBaseObject baseObj = em.Current;
if (baseObj.Properties["Version"].Value != null)
{
try
{
string? name = baseObj.Properties["Name"].Value.ToString();
string? version = baseObj.Properties["Version"].Value.ToString();
string? location = baseObj.Properties["ProductLocation"].Value.ToString();
string? identifier = baseObj.Properties["IdentifyingNumber"].Value.ToString();

if (name != null && version != null && location != null && identifier != null)
{
list.Add(new VisualStudioInstance(name, version, location, identifier, VisualStudioInstanceManager.YearFromVersion(version[..2])));
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
}

em?.Dispose();
collection?.Dispose();
searcher?.Dispose();

}
catch
{
// something went wrong, try the alternative way using the Setup API
list = ReadAllInstancesFromSetupApi();
}

list.Sort((x, y) => x.Version.CompareTo(y.Version));

while (em.MoveNext())
return list;
}

private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154);

/// <summary>
/// Reads the all instances from VS setup api.
/// </summary>
/// <returns>A list of VisualStudioInstances.</returns>
private static List<VisualStudioInstance> ReadAllInstancesFromSetupApi()
{
List<VisualStudioInstance> list = new();

try
{
ManagementBaseObject baseObj = em.Current;
if (baseObj.Properties["Version"].Value != null)
var query = new SetupConfiguration();
var query2 = (ISetupConfiguration2)query;
var e = query2.EnumAllInstances();

var helper = (ISetupHelper)query;

int fetched;
var instances = new ISetupInstance[1];
do
{
try
e.Next(1, instances, out fetched);
if (fetched > 0)
{
string? name = baseObj.Properties["Name"].Value.ToString();
string? version = baseObj.Properties["Version"].Value.ToString();
string? location = baseObj.Properties["ProductLocation"].Value.ToString();
string? identifier = baseObj.Properties["IdentifyingNumber"].Value.ToString();
var instance = instances[0];

var instance2 = (ISetupInstance2)instance;
var state = instance2.GetState();

string? name = ((state & InstanceState.Registered) == InstanceState.Registered) ? instance2.GetProduct().GetId() : null;
string? version = instance.GetInstallationVersion();
string? location = ((state & InstanceState.Local) == InstanceState.Local) ? instance2.GetInstallationPath() : null;
string? identifier = instance2.GetInstanceId();

if (name != null && version != null && location != null && identifier != null)
{
list.Add(new VisualStudioInstance(name, version, location, identifier, VisualStudioInstanceManager.YearFromVersion(version[..2])));
location = Path.Combine(location, "Common7", "IDE", "devenv.exe");
var year = VisualStudioInstanceManager.YearFromVersion(version[..2]);
name = NormalizeName(name, year);
list.Add(new VisualStudioInstance(name, version, location, identifier, year));
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());

}
}
}
while (fetched > 0);

em?.Dispose();
collection?.Dispose();
searcher?.Dispose();

list.Sort((x, y) => x.Version.CompareTo(y.Version));
}
catch (COMException ex) when (ex.HResult == REGDB_E_CLASSNOTREG)
{
Debug.WriteLine("The query API is not registered. Assuming no instances are installed.");
}
catch (Exception ex)
{
Debug.WriteLine($"Error 0x{ex.HResult:x8}: {ex.Message}");
}

return list;
}

private static string NormalizeName(string name, string year)
{
return name.Replace("Microsoft.Visual", "Visual ").Replace(".Product.", " ") + " " + year;
}

/// <summary>
/// Gets the version number from the year
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions VSLXshared/VSLXshared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="3.7.2175" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Management" Version="7.0.2" />
Expand Down

0 comments on commit 55391cf

Please sign in to comment.