Skip to content

Commit

Permalink
Development (#23)
Browse files Browse the repository at this point in the history
* Updated discovery of VS instances to use the new WMI namespace Microsoft is using since 10/2023.
Now discovery tries the original WMI namespace, the new namespace and finally the Setup API.
Improvement on #18

* Added continuous GIT status updates
Added VS activity log access through a button
  • Loading branch information
Hefaistos68 committed Oct 17, 2023
1 parent 7f442e6 commit 20a2113
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 91 deletions.
5 changes: 5 additions & 0 deletions VSLXshared/DataModel/VisualStudioInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ public string ShortName
/// </summary>
public string ShortVersion { get { return String.Join('.', this.Version.Split('.').Take(2)); } }

/// <summary>
/// Gets the main version number, only major version
/// </summary>
public string MainVersion { get { return this.Version.Split('.').First(); } }

/// <summary>
/// Gets the release year/version
/// </summary>
Expand Down
167 changes: 125 additions & 42 deletions VSLXshared/DataModel/VisualStudioInstanceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class VisualStudioInstanceManager
/// </summary>
public VisualStudioInstanceManager()
{
allInstances = ReadAllInstances();
allInstances = ReadAllInstances() ?? new List<VisualStudioInstance>(); // just to not crash if no instances are found
}

/// <summary>
Expand All @@ -67,15 +67,15 @@ public int Count
/// Gets the installer path.
/// </summary>
public static string InstallerPath
{
{
get
{
string location = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Microsoft Visual Studio", "Installer");
string location86 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Microsoft Visual Studio", "Installer");
string installerPath = Path.Combine(location, "vs_installer.exe");
string installerPath86 = Path.Combine(location86, "vs_installer.exe");

if(Directory.Exists(location) || Directory.Exists(location86))
if (Directory.Exists(location) || Directory.Exists(location86))
{
if (File.Exists(installerPath))
{
Expand Down Expand Up @@ -114,60 +114,143 @@ public VisualStudioInstance this[string version]
}
}

/// <summary>
/// Reads the all installed Visual Studio instances, using either the original WMI class, the the WMI class in the new namespace, or finally the VS Setup API
/// </summary>
/// <returns>A list of VisualStudioInstances.</returns>
public static List<VisualStudioInstance>? ReadAllInstances()
{
List<VisualStudioInstance>? list = null;

try
{
list = ReadAllInstancesFromWMI1();
}
catch (System.Exception ex)
{
Debug.WriteLine($"Original MSFT_VSInstance WMi class not found or not able to read. ({ex.Message})");
}

if (list is null)
{
try
{
list = ReadAllInstancesFromWMI2();
}
catch (System.Exception ex)
{
Debug.WriteLine($"New MSFT_VSInstance WMi class not found or not able to read. ({ex.Message})");
}
}

if (list is null)
{
try
{
list = ReadAllInstancesFromSetupApi();
}
catch (System.Exception ex)
{
Debug.WriteLine($"failed to read from VS Setup API, no Visual Studio installation information available. ({ex.Message})");
}
}

return list;
}

/// <summary>
/// Reads the all installed Visual Studio instances from WMI
/// </summary>
/// <returns>A list of VisualStudioInstances.</returns>
public static List<VisualStudioInstance> ReadAllInstances()
public static List<VisualStudioInstance> ReadAllInstancesFromWMI1()
{
var list = new List<VisualStudioInstance>();
// read all data from WMI using CimInstance MSFT_VSInstance
// https://docs.microsoft.com/en-us/windows/win32/wmisdk/msft-vsinstance

try
ManagementObjectSearcher searcher = new ManagementObjectSearcher
{
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())
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)
{
ManagementBaseObject baseObj = em.Current;
if (baseObj.Properties["Version"].Value != null)
try
{
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)
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)
{
Debug.WriteLine(ex.ToString());
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

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


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

return list;
}

public static List<VisualStudioInstance> ReadAllInstancesFromWMI2()
{
var list = new List<VisualStudioInstance>();
// read all data from WMI using CimInstance MSFT_VSInstance but in the new VS namespace

ManagementScope scope = new ManagementScope("root/cimv2/vs");
ManagementObjectSearcher searcher = new ManagementObjectSearcher
{
Query = new SelectQuery("MSFT_VSInstance ", "", new[] { "Name", "Version", "ProductLocation", "IdentifyingNumber" }),
Scope = scope
};
ManagementObjectCollection collection = searcher.Get();
ManagementObjectCollection.ManagementObjectEnumerator em = collection.GetEnumerator();

while (em.MoveNext())
{
// something went wrong, try the alternative way using the Setup API
list = ReadAllInstancesFromSetupApi();
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();

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

return list;
Expand Down Expand Up @@ -267,7 +350,7 @@ public VsItemList GetRecentProjects(bool bOnlyDefaultInstances)
{
VsFolder solutionList = new VsFolder();

var vsDir = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft", "VisualStudio"));
var vsDir = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft", "VisualStudio"));

foreach (var dir in vsDir.GetDirectories("*", SearchOption.AllDirectories))
{
Expand Down Expand Up @@ -330,7 +413,7 @@ public VsItemList GetRecentProjects(bool bOnlyDefaultInstances)
catch (DirectoryNotFoundException)
{
}
catch(NullReferenceException)
catch (NullReferenceException)
{
// possibly invalid file
}
Expand Down Expand Up @@ -373,7 +456,7 @@ public VisualStudioInstance GetByName(string name)
if (string.IsNullOrEmpty(name))
return HighestVersion();

var vsi = this.allInstances.Where(x => x.ShortName.Equals(name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
var vsi = this.allInstances.Where(x => x.ShortName.Equals(name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();

return vsi is null ? HighestVersion() : vsi;
}
Expand All @@ -388,7 +471,7 @@ public VisualStudioInstance GetByVersion(string? version)
if (string.IsNullOrEmpty(version))
return HighestVersion();

var vsi = this.allInstances.Where(x => x.Version.StartsWith(version, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
var vsi = this.allInstances.Where(x => x.Version.StartsWith(version, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();

return vsi is null ? HighestVersion() : vsi;
}
Expand Down
Loading

0 comments on commit 20a2113

Please sign in to comment.