Search code examples
c#visual-studiovisual-studio-extensionsvsxvspackage

How get the current running Visual Studio installation path from VSPackage


I've created a VSPackage which should copy some XML schema files to Visual Studio's installation path: %VS install path% \Xml\Schemas.

I have multiple Visual Studios installed on my machine:

  • Visual Studio 2013 Professional.
  • Visual Studio 2015 Community Edition.
  • Visual Studio Express Editions.

I need to detect the path to the Visual Studio from which my VSPackage is executing its command.

How can I get the current running Visual Studio's installation path in the package?


Solution

  • First, I agree with Carlos in that particular point that an extension should never require elevated priviledges. But that does not mean, your problem cannot be solved; I would just suggest to do it in another way...

    I had a similiar issue with one of my extensions; and I was looking for a solution which would not require a Windows installer setup, but work for pure VSIX packages. I solved it by creating a small console application, which I referenced by my package assembly. I added an application manifest to the console application, allowing me to request the required execution level; for instance:

    <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
    

    The console application looks like...

    public class HelperExe
    {
        public static int Main(params string[] args)
        {
            // TODO: 
        }
    }
    

    The console application will do the work that requires elevated priviledges. The package creates a new process using the Process class; the image´s file path can be obtained from the defining assembly (because this might be a random path, if the package is installed from VSIX).

    var consoleAssemblyLocation = new Uri(typeof(HelperExe).Assembly.CodeBase);
    var file = new FileInfo(consoleAssemblyLocation.LocalPath);
    if (file.Exists)
    {
        var consoleProcess = new Process 
        {
            StartInfo = new ProcessStartInfo(file.FullName)
            {
                CreateNoWindow = true
            }
        };
    
        consoleProcess.Start();
        var timeout = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;
        consoleProces.WaitForExit(timeout);
    }
    

    Since the manifest will involve the UAC to elevate the process... this has also the nice side-effect, that the user can cancel that operation. Make sure that your extension can handle that...

    Visual Studio´s installation folder can be read from the registry; you can pass the obtained path to the console application via a commandline argument. I did it like this...

    static string GetVisualStudioInstallationFolder(string visualStudioVersion)
    {
        string subKeyName = string.Format(
            CultureInfo.InvariantCulture, 
            @"Software\Microsoft\VisualStudio\{0}_Config", 
            visualStudioVersion);
    
        using (RegistryKey key = Registry.CurrentUser.OpenSubKey(subKeyName))
        {
            if (key != null)
            {
                return (string)key.GetValue("ShellFolder");
            }
        }
    
        return null;
    }
    

    The visualStudioVersion parameter can be obtained from the DTE.Version property...