Skip to content

Commit 9ddca96

Browse files
authored
Merge pull request #4538 from gewarren/dte
[Extensibility] Add new topic for launching VS through DTE
2 parents 8b44eff + 9bc334f commit 9ddca96

File tree

4 files changed

+240
-25
lines changed

4 files changed

+240
-25
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
---
2+
title: Launch Visual Studio using DTE
3+
ms.date: 04/26/2019
4+
ms.topic: conceptual
5+
author: gewarren
6+
ms.author:
7+
manager: jillfra
8+
ms.workload:
9+
- "vssdk"
10+
---
11+
# Launch Visual Studio using DTE
12+
13+
Starting with Visual Studio 2017, the mechanism to launch Visual Studio using DTE is different to launching previous versions of Visual Studio. This change is necessary because Visual Studio 2017 and later supports side-by-side installations of major releases (for example, you can have a preview and a release version installed side by side).
14+
15+
The remainder of this article shows the code you can use to launch Visual Studio 2019 using DTE.
16+
17+
## Set up the project
18+
19+
To see the launching code in action, create a project by following these steps.
20+
21+
1. Create a new **Console App** project for the .NET Framework.
22+
23+
2. Install the [Microsoft.VisualStudio.Setup.Configuration.Interop](https://www.nuget.org/packages/Microsoft.VisualStudio.Setup.Configuration.Interop/) NuGet package and add a reference to the assembly.
24+
25+
3. Add a reference to EnvDTE.
26+
27+
4. Paste the [example code](#example-code) that follows into the *Program.cs* file.
28+
29+
5. Press **F5** to run the program. You should see Visual Studio 2019 open before the program exits.
30+
31+
## Example code
32+
33+
```csharp
34+
using Microsoft.VisualStudio.Setup.Configuration;
35+
using System;
36+
using System.Collections.Generic;
37+
using System.Diagnostics;
38+
using System.IO;
39+
using System.Linq;
40+
using System.Runtime.InteropServices;
41+
using System.Runtime.InteropServices.ComTypes;
42+
using System.Threading;
43+
44+
namespace ConsoleLauncherApp
45+
{
46+
class Program
47+
{
48+
static void Main(string[] args)
49+
{
50+
EnvDTE.DTE dte = LaunchVsDte(isPreRelease: false);
51+
52+
dte.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateMaximize;
53+
dte.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateMinimize;
54+
dte.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateNormal;
55+
dte.Quit();
56+
}
57+
58+
private static EnvDTE.DTE LaunchVsDte(bool isPreRelease)
59+
{
60+
ISetupInstance setupInstance = GetSetupInstance(isPreRelease);
61+
string installationPath = setupInstance.GetInstallationPath();
62+
string executablePath = Path.Combine(installationPath, @"Common7\IDE\devenv.exe");
63+
Process vsProcess = Process.Start(executablePath);
64+
string runningObjectDisplayName = $"VisualStudio.DTE.16.0:{vsProcess.Id}";
65+
66+
IEnumerable<string> runningObjectDisplayNames = null;
67+
object runningObject;
68+
for (int i = 0; i < 60; i++)
69+
{
70+
try
71+
{
72+
runningObject = GetRunningObject(runningObjectDisplayName, out runningObjectDisplayNames);
73+
}
74+
catch
75+
{
76+
runningObject = null;
77+
}
78+
79+
if (runningObject != null)
80+
{
81+
return (EnvDTE.DTE)runningObject;
82+
}
83+
84+
Thread.Sleep(millisecondsTimeout: 1000);
85+
}
86+
87+
throw new TimeoutException($"Failed to retrieve DTE object. Current running objects: {string.Join(";", runningObjectDisplayNames)}");
88+
}
89+
90+
private static object GetRunningObject(string displayName, out IEnumerable<string> runningObjectDisplayNames)
91+
{
92+
IBindCtx bindContext = null;
93+
NativeMethods.CreateBindCtx(0, out bindContext);
94+
95+
IRunningObjectTable runningObjectTable = null;
96+
bindContext.GetRunningObjectTable(out runningObjectTable);
97+
98+
IEnumMoniker monikerEnumerator = null;
99+
runningObjectTable.EnumRunning(out monikerEnumerator);
100+
101+
object runningObject = null;
102+
List<string> runningObjectDisplayNameList = new List<string>();
103+
IMoniker[] monikers = new IMoniker[1];
104+
IntPtr numberFetched = IntPtr.Zero;
105+
while (monikerEnumerator.Next(1, monikers, numberFetched) == 0)
106+
{
107+
IMoniker moniker = monikers[0];
108+
109+
string objectDisplayName = null;
110+
try
111+
{
112+
moniker.GetDisplayName(bindContext, null, out objectDisplayName);
113+
}
114+
catch (UnauthorizedAccessException)
115+
{
116+
// Some ROT objects require elevated permissions.
117+
}
118+
119+
if (!string.IsNullOrWhiteSpace(objectDisplayName))
120+
{
121+
runningObjectDisplayNameList.Add(objectDisplayName);
122+
if (objectDisplayName.EndsWith(displayName, StringComparison.Ordinal))
123+
{
124+
runningObjectTable.GetObject(moniker, out runningObject);
125+
if (runningObject == null)
126+
{
127+
throw new InvalidOperationException($"Failed to get running object with display name {displayName}");
128+
}
129+
}
130+
}
131+
}
132+
133+
runningObjectDisplayNames = runningObjectDisplayNameList;
134+
return runningObject;
135+
}
136+
137+
private static ISetupInstance GetSetupInstance(bool isPreRelease)
138+
{
139+
return GetSetupInstances().First(i => IsPreRelease(i) == isPreRelease);
140+
}
141+
142+
private static IEnumerable<ISetupInstance> GetSetupInstances()
143+
{
144+
ISetupConfiguration setupConfiguration = new SetupConfiguration();
145+
IEnumSetupInstances enumerator = setupConfiguration.EnumInstances();
146+
147+
int count;
148+
do
149+
{
150+
ISetupInstance[] setupInstances = new ISetupInstance[1];
151+
enumerator.Next(1, setupInstances, out count);
152+
if (count == 1 &&
153+
setupInstances != null &&
154+
setupInstances.Length == 1 &&
155+
setupInstances[0] != null)
156+
{
157+
yield return setupInstances[0];
158+
}
159+
}
160+
while (count == 1);
161+
}
162+
163+
private static bool IsPreRelease(ISetupInstance setupInstance)
164+
{
165+
ISetupInstanceCatalog setupInstanceCatalog = (ISetupInstanceCatalog)setupInstance;
166+
return setupInstanceCatalog.IsPrerelease();
167+
}
168+
169+
private static class NativeMethods
170+
{
171+
[DllImport("ole32.dll")]
172+
public static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
173+
174+
[DllImport("ole32.dll")]
175+
public static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
176+
}
177+
}
178+
}
179+
```
180+
181+
## See also
182+
183+
- [Locate Visual Studio](locating-visual-studio.md)
184+
- [Walkthrough: Access the DTE object from an editor extension](walkthrough-accessing-the-dte-object-from-an-editor-extension.md)

docs/extensibility/locating-visual-studio.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ To find Visual Studio and other tools in build environments, PowerShell scripts,
3636
## See also
3737

3838
* [Changes to Visual Studio 2017 setup](https://devblogs.microsoft.com/setup/changes-to-visual-studio-15-setup/)
39+
* [Launch Visual Studio using DTE](launch-visual-studio-dte.md)

docs/extensibility/toc.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -489,16 +489,16 @@
489489
href: the-structure-of-the-content-types-dot-xml-file.md
490490
- name: VSIX Manifest Designer
491491
href: vsix-manifest-designer.md
492-
- name: Localizing VSIX Packages
492+
- name: Localize VSIX Packages
493493
href: localizing-vsix-packages.md
494494
items:
495495
- name: VSIX Language Pack Schema 2.0 Reference
496496
href: vsix-language-pack-schema-2-0-reference.md
497497
- name: Update a Visual Studio Extension
498498
href: how-to-update-a-visual-studio-extension.md
499-
- name: Preparing Extensions for Windows Installer Deployment
499+
- name: Prepare Extensions for Windows Installer Deployment
500500
href: preparing-extensions-for-windows-installer-deployment.md
501-
- name: Signing VSIX Packages
501+
- name: Sign VSIX Packages
502502
href: signing-vsix-packages.md
503503
- name: Private Galleries
504504
href: private-galleries.md
@@ -507,7 +507,7 @@
507507
href: how-to-create-an-atom-feed-for-a-private-gallery.md
508508
- name: Manage a Private Gallery By Using Registry Settings
509509
href: how-to-manage-a-private-gallery-by-using-registry-settings.md
510-
- name: Supporting Multiple Versions of Visual Studio
510+
- name: Support Multiple Versions of Visual Studio
511511
href: supporting-multiple-versions-of-visual-studio.md
512512
items:
513513
- name: Choosing Between Shared and Versioned VSPackages
@@ -523,8 +523,10 @@
523523
href: registering-verbs-for-file-name-extensions.md
524524
- name: Managing Side-by-Side File Associations
525525
href: managing-side-by-side-file-associations.md
526-
- name: Locating Visual Studio
526+
- name: Locate Visual Studio
527527
href: locating-visual-studio.md
528+
- name: Launch Visual Studio using DTE
529+
href: launch-visual-studio-dte.md
528530
- name: Inside the Visual Studio SDK
529531
href: internals/toc.yml
530532
- name: Support for the Visual Studio SDK
Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
title: "Walkthrough: Accessing the DTE Object from an Editor Extension | Microsoft Docs"
3-
ms.date: "11/04/2016"
4-
ms.topic: "conceptual"
2+
title: Access the DTE Object from an editor extension
3+
ms.date: 04/24/2019
4+
ms.topic: conceptual
55
helpviewer_keywords:
66
- "editors [Visual Studio SDK], new - getting the DTE object"
77
ms.assetid: c1f40bab-c6ec-45b0-8333-ea5ceb02a39d
@@ -11,51 +11,79 @@ manager: jillfra
1111
ms.workload:
1212
- "vssdk"
1313
---
14-
# Walkthrough: Accessing the DTE object from an editor extension
14+
# Walkthrough: Access the DTE object from an editor extension
15+
1516
In VSPackages, you can get the DTE object by calling the <xref:Microsoft.VisualStudio.Shell.Package.GetService%2A> method with the type of the DTE object. In Managed Extensibility Framework (MEF) extensions, you can import <xref:Microsoft.VisualStudio.Shell.SVsServiceProvider> and then call the <xref:Microsoft.VisualStudio.Shell.ServiceProvider.GetService%2A> method with a type of <xref:EnvDTE.DTE>.
1617

1718
## Prerequisites
18-
To follow this walkthrough, you must install the Visual Studio SDK. For more information, see [Visual Studio SDK](../extensibility/visual-studio-sdk.md).
1919

20-
## Getting the DTE object
20+
To follow this walkthrough, you must install the Visual Studio SDK. For more information, see [Visual Studio SDK](../extensibility/visual-studio-sdk.md).
2121

22-
### To get the DTE object from the ServiceProvider
22+
## Get the DTE object
2323

24-
1. Create a C# VSIX project named `DTETest`. Add an Editor Classifier item template and name it `DTETest`. For more information, see [Create an extension with an editor item template](../extensibility/creating-an-extension-with-an-editor-item-template.md).
24+
1. Create a C# VSIX project and name it **DTETest**. Add an **Editor Classifier** item template and name it **DTETest**.
2525

26-
2. Add the following assembly references to the project:
26+
For more information, see [Create an extension with an editor item template](../extensibility/creating-an-extension-with-an-editor-item-template.md).
2727

28-
- EnvDTE
28+
::: moniker range=">=vs-2019"
2929

30-
- EnvDTE80
30+
2. Add the following assembly reference to the project:
3131

3232
- Microsoft.VisualStudio.Shell.Immutable.10.0
3333

34-
3. Go to the *DTETest.cs* file, and add the following `using` directives:
34+
3. In the *DTETestProvider.cs* file, add the following `using` directives:
3535

3636
```csharp
3737
using EnvDTE;
38-
using EnvDTE80;
3938
using Microsoft.VisualStudio.Shell;
40-
4139
```
4240

43-
4. In the `GetDTEProvider` class, import a <xref:Microsoft.VisualStudio.Shell.SVsServiceProvider>.
41+
4. In the `DTETestProvider` class, import an <xref:Microsoft.VisualStudio.Shell.SVsServiceProvider>.
4442

4543
```csharp
4644
[Import]
4745
internal SVsServiceProvider ServiceProvider = null;
48-
4946
```
5047

51-
5. In the `GetClassifier()` method, add the following code.
48+
5. In the `GetClassifier()` method, add the following code before the `return` statement:
5249

5350
```csharp
54-
DTE dte = (DTE)ServiceProvider.GetService(typeof(DTE));
51+
ThreadHelper.ThrowIfNotOnUIThread();
52+
DTE dte = (DTE)ServiceProvider.GetService(typeof(DTE));
53+
```
54+
55+
::: moniker-end
56+
57+
::: moniker range="vs-2017"
5558

59+
2. Add the following assembly references to the project:
60+
61+
- EnvDTE
62+
- Microsoft.VisualStudio.Shell.Framework
63+
64+
3. In the *DTETestProvider.cs* file, add the following `using` directives:
65+
66+
```csharp
67+
using EnvDTE;
68+
using Microsoft.VisualStudio.Shell;
5669
```
5770

58-
6. If you have to use the <xref:EnvDTE80.DTE2> interface, you can cast the DTE object to it.
71+
4. In the `DTETestProvider` class, import an <xref:Microsoft.VisualStudio.Shell.SVsServiceProvider>.
72+
73+
```csharp
74+
[Import]
75+
internal SVsServiceProvider ServiceProvider = null;
76+
```
77+
78+
5. In the `GetClassifier()` method, add the following code before the `return` statement:
79+
80+
```csharp
81+
DTE dte = (DTE)ServiceProvider.GetService(typeof(DTE));
82+
```
83+
84+
::: moniker-end
5985

6086
## See also
61-
- [Language service and editor extension points](../extensibility/language-service-and-editor-extension-points.md)
87+
88+
- [Language service and editor extension points](../extensibility/language-service-and-editor-extension-points.md)
89+
- [Launch Visual Studio using DTE](launch-visual-studio-dte.md)

0 commit comments

Comments
 (0)