Programmatically retrieve Visual Studio install di

2020-02-09 07:35发布

问题:

I know there is a registry key indicating the install directory, but I don't remember what it is off-hand.

I am currently interested in Visual Studio 2008 install directory, though it wouldn't hurt to list others for future reference.

回答1:

I'm sure there's a registry entry as well but I couldn't easily locate it. There is the VS90COMNTOOLS environment variable that you could use as well.



回答2:

I use this method to find the installation path of Visual Studio 2010:

    private string GetVisualStudioInstallationPath()
    {
        string installationPath = null;
        if (Environment.Is64BitOperatingSystem)
        {
            installationPath = (string)Registry.GetValue(
               "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\10.0\\",
                "InstallDir",
                null);
        }
        else
        {
            installationPath = (string)Registry.GetValue(
       "HKEY_LOCAL_MACHINE\\SOFTWARE  \\Microsoft\\VisualStudio\\10.0\\",
              "InstallDir",
              null);
        }
        return installationPath;

    }


回答3:

Registry Method

I recommend querying the registry for this information. This gives the actual installation directory without the need for combining paths, and it works for express editions as well. This could be an important distinction depending on what you need to do (e.g. templates get installed to different directories depending on the edition of Visual Studio). The registry locations are as follows (note that Visual Studio is a 32-bit program and will be installed to the 32-bit section of the registry on x64 machines):

  • Visual Studio: HKLM\SOFTWARE\Microsoft\Visual Studio\Major.Minor:InstallDir
  • Visual C# Express: HKLM\SOFTWARE\Microsoft\VCSExpress\Major.Minor:InstallDir
  • Visual Basic Express: HKLM\SOFTWARE\Microsoft\VBExpress\Major.Minor:InstallDir
  • Visual C++ Express: HKLM\SOFTWARE\Microsoft\VCExpress\Major.Minor:InstallDir

where Major is the major version number, Minor is the minor version number, and the text after the colon is the name of the registry value. For example, the installation directory of Visual Studio 2008 Professional would be located at the HKLM\SOFTWARE\Microsoft\Visual Studio\9.0 key, in the InstallDir value.

Here's a code example that prints the installation directory of several versions of Visual Studio and Visual C# Express:

string visualStudioRegistryKeyPath = @"SOFTWARE\Microsoft\VisualStudio";
string visualCSharpExpressRegistryKeyPath = @"SOFTWARE\Microsoft\VCSExpress";

List<Version> vsVersions = new List<Version>() { new Version("10.0"), new Version("9.0"), new Version("8.0") };
foreach (var version in vsVersions)
{
    foreach (var isExpress in new bool[] { false, true })
    {
        RegistryKey registryBase32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
        RegistryKey vsVersionRegistryKey = registryBase32.OpenSubKey(
            string.Format(@"{0}\{1}.{2}", (isExpress) ? visualCSharpExpressRegistryKeyPath : visualStudioRegistryKeyPath, version.Major, version.Minor));
        if (vsVersionRegistryKey == null) { continue; }
        Console.WriteLine(vsVersionRegistryKey.GetValue("InstallDir", string.Empty).ToString());
    }

Environment Variable Method

The non-express editions of Visual Studio also write an environment variable that you could check, but it gives the location of the common tools directory, not the installation directory, so you'll have to do some path combining. The format of the environment variable is VS*COMNTOOLS where * is the major and minor version number. For example, the environment variable for Visual Studio 2010 is VS100COMNTOOLS and contains a value like C:\Program Files\Microsoft Visual Studio 10.0\Common7\Tools.

Here's some example code to print the environment variable for several versions of Visual Studio:

List<Version> vsVersions = new List<Version>() { new Version("10.0"), new Version("9.0"), new Version("8.0") };
foreach (var version in vsVersions)
{
    Console.WriteLine(Path.Combine(Environment.GetEnvironmentVariable(string.Format("VS{0}{1}COMNTOOLS", version.Major, version.Minor)), @"..\IDE"));
}


回答4:

Environment: Thanks to Zeb and Sam for the VS*COMNTOOLS environment variable suggestion. To get to the IDE in PowerShell:

$vs = Join-Path $env:VS90COMNTOOLS '..\IDE\devenv.exe'

Registry: Looks like the registry location is HKLM\Software\Microsoft\VisualStudio, with version-specific subkeys for each install. In PowerShell:

$vsRegPath = 'HKLM:\Software\Microsoft\VisualStudio\9.0'
$vs = (Get-ItemProperty $vsRegPath).InstallDir + 'devenv.exe'

[Adapted from here]



回答5:

For Visual Studio 2017 and Visual Studio 2019 there is the Setup API from Microsoft.

In C#, just add the NuGet package "Microsoft.VisualStudio.Setup.Configuration.Interop", and use it in this way:

    try {
        var query = new SetupConfiguration();
        var query2 = (ISetupConfiguration2)query;
        var e = query2.EnumAllInstances();

        var helper = (ISetupHelper)query;

        int fetched;
        var instances = new ISetupInstance[1];
        do {
            e.Next(1, instances, out fetched);
            if (fetched > 0)
                Console.WriteLine(instances[0].GetInstallationPath());
        }
        while (fetched > 0);
        return 0;
    }
    catch (COMException ex) when (ex.HResult == REGDB_E_CLASSNOTREG) {
        Console.WriteLine("The query API is not registered. Assuming no instances are installed.");
        return 0;
    }

You can find more samples for VC, C#, and VB here.



回答6:

@Dim-Ka has a great answer. If you were curious how you'd implement this in a batch script, this is how.

@echo off
:: BATCH doesn't have logical or, otherwise I'd use it
SET platform=
IF /I [%PROCESSOR_ARCHITECTURE%]==[amd64] set platform=true
IF /I [%PROCESSOR_ARCHITEW6432%]==[amd64] set platform=true

:: default to VS2012 = 11.0
:: the Environment variable VisualStudioVersion is set by devenv.exe
:: if this batch is a child of devenv.exe external tools, we know which version to look at
if not defined VisualStudioVersion SET VisualStudioVersion=11.0

if defined platform (
set VSREGKEY=HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%VisualStudioVersion%
)  ELSE (
set VSREGKEY=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\%VisualStudioVersion%
)
for /f "skip=2 tokens=2,*" %%A in ('reg query "%VSREGKEY%" /v InstallDir') do SET VSINSTALLDIR=%%B

echo %VSINSTALLDIR%


回答7:

It is a real problem that all Visual Studio versions have their own location. So the solutions here proposed are not generic. However, Microsoft has made a utility available for free (including the source code) that solved this problem (i.e. annoyance). It is called vswhere.exe and you can download it from here. I am very happy with it, and hopefully it will also do for future releases. It makes the whole discussion on this page redundant.



回答8:

Ah, the 64-bit machine part was the issue. It turns out I need to make sure I'm running the PowerShell.exe under the syswow64 directory in order to get the x86 registry keys.

Now that wasn't very fun.



回答9:

Use Environment.GetEnvironmentVariable("VS90COMNTOOLS");.

Also in a 64-bit environment, it works for me.



回答10:

You can read the VSINSTALLDIR environment variable.



回答11:

Here's a solution to always get the path for the latest version:

$vsEnvVars = (dir Env:).Name -match "VS[0-9]{1,3}COMNTOOLS"
$latestVs = $vsEnvVars | Sort-Object | Select -Last 1
$vsPath = Get-Content Env:\$latestVs


回答12:

Note that if you're using Visual Studio Express or Visual C++ Express the keynames contain WDExpress or VCExpress, respectively, instead of VisualStudio.



回答13:

Aren't there environment settings?

I have VCToolkitInstallDir and VS71COMNTOOLS although I'm using Visual Studio 2003, I don't know if that changed for later versions. Type "set V" at the command line and see if you have them.



回答14:

Here is something I have been updating over the years... (for CudaPAD)

Usage examples:

var vsPath = VS_Tools.GetVSPath(avoidPrereleases:true, requiredWorkload:"NativeDesktop");
var vsPath = VS_Tools.GetVSPath();
var vsPath = VS_Tools.GetVSPath(specificVersion:"15");

The drop-in function:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Setup.Configuration;
using System.IO;
using Microsoft.Win32;

static class VS_Tools
{
    public static string GetVSPath(string specificVersion = "", bool avoidPrereleases = true, string requiredWorkload = "")
    {
        string vsPath = "";
        // Method 1 - use "Microsoft.VisualStudio.Setup.Configuration.SetupConfiguration" method.

        // Note: This code has is a heavily modified version of Heath Stewart's code.
        // original source: (Heath Stewart, May 2016) https://github.com/microsoft/vs-setup-samples/blob/80426ad4ba10b7901c69ac0fc914317eb65deabf/Setup.Configuration.CS/Program.cs
        try
        {
            var e = new SetupConfiguration().EnumAllInstances();

            int fetched;
            var instances = new ISetupInstance[1];
            do
            {
                e.Next(1, instances, out fetched);
                if (fetched > 0)
                {
                    var instance2 = (ISetupInstance2)instances[0];
                    var state = instance2.GetState();

                    // Let's make sure this install is complete.
                    if (state != InstanceState.Complete)
                        continue;

                    // If we have a version to match lets make sure to match it.
                    if (!string.IsNullOrWhiteSpace(specificVersion))
                        if (!instances[0].GetInstallationVersion().StartsWith(specificVersion))
                            continue;

                    // If instances[0] is null then skip
                    var catalog = instances[0] as ISetupInstanceCatalog;
                    if (catalog == null)
                        continue;

                    // If there is not installation path lets skip
                    if ((state & InstanceState.Local) != InstanceState.Local)
                        continue;

                    // Let's make sure it has the required workload - if one was given.
                    if (!string.IsNullOrWhiteSpace(requiredWorkload))
                    {
                        if ((state & InstanceState.Registered) == InstanceState.Registered)
                        {
                            if (!(from package in instance2.GetPackages()
                                    where string.Equals(package.GetType(), "Workload", StringComparison.OrdinalIgnoreCase)
                                    where package.GetId().Contains(requiredWorkload)
                                    orderby package.GetId()
                                    select package).Any())
                            {
                                continue;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }

                    // Let's save the installation path and make sure it has a value.
                    vsPath = instance2.GetInstallationPath();
                    if (string.IsNullOrWhiteSpace(vsPath))
                        continue;

                    // If specified, avoid Pre-release if possible
                    if (avoidPrereleases && catalog.IsPrerelease())
                        continue;

                    // We found the one we need - lets get out of here
                    return vsPath;
                }
            }
            while (fetched > 0);
        }
        catch (Exception){ }

        if (string.IsNullOrWhiteSpace(vsPath))
            return vsPath;

        // Fall-back Method: Find the location of visual studio (%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat)
        // Note: This code has is a heavily modified version of Kevin Kibler's code.
        // source: (Kevin Kibler, 2014) http://stackoverflow.com/questions/30504/programmatically-retrieve-visual-studio-install-directory
        List<Version> vsVersions = new List<Version>() { new Version("15.0"), new Version("14.0"),
            new Version("13.0"), new Version("12.0"), new Version("11.0") };
        foreach (var version in vsVersions)
        {
            foreach (var isExpress in new bool[] { false, true })
            {
                RegistryKey registryBase32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
                RegistryKey vsVersionRegistryKey = registryBase32.OpenSubKey(
                    string.Format(@"{0}\{1}.{2}",
                    (isExpress) ? @"SOFTWARE\Microsoft\VCSExpress" : @"SOFTWARE\Microsoft\VisualStudio",
                    version.Major, version.Minor));
                if (vsVersionRegistryKey == null) { continue; }
                string path = vsVersionRegistryKey.GetValue("InstallDir", string.Empty).ToString();
                if (!string.IsNullOrEmpty(path))
                {
                    path = Directory.GetParent(path).Parent.Parent.FullName;
                    if (File.Exists(path + @"\VC\bin\cl.exe") && File.Exists(path + @"\VC\vcvarsall.bat"))
                    {
                        vsPath = path;
                        break;
                    }
                }
            }
            if (!string.IsNullOrWhiteSpace(vsPath))
                break;
        }
        return vsPath;
    }
}