Skip to content

Commit ffd803b

Browse files
committed
Initial implementation of the Debug Command Line drop down
1 parent a3e4cf7 commit ffd803b

File tree

1 file changed

+223
-1
lines changed

1 file changed

+223
-1
lines changed

Tvl.DebugCommandLine/DebugCommandLinePackage.cs

Lines changed: 223 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,25 @@
44
namespace Tvl.DebugCommandLine
55
{
66
using System;
7+
using System.Collections.Generic;
8+
using System.Collections.ObjectModel;
79
using System.ComponentModel.Design;
10+
using System.Linq;
811
using System.Runtime.InteropServices;
12+
using Microsoft.VisualStudio;
913
using Microsoft.VisualStudio.Shell;
14+
using Microsoft.VisualStudio.Shell.Interop;
1015

1116
[PackageRegistration(UseManagedResourcesOnly = true)]
17+
[ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)]
1218
[ProvideMenuResource("Menus.ctmenu", 1)]
1319
[Guid("238A874D-D659-4517-85D1-06B0E3CF4B7F")]
1420
internal class DebugCommandLinePackage : Package
1521
{
22+
private static readonly string[] KnownStartupProperties = { "CommandArguments", "StartArguments" };
23+
24+
private ReadOnlyCollection<string> RecentCommandLines = new ReadOnlyCollection<string>(new string[0]);
25+
1626
protected override void Initialize()
1727
{
1828
base.Initialize();
@@ -22,7 +32,7 @@ protected override void Initialize()
2232
{
2333
// This is the drop down combo box itself
2434
CommandID comboBoxCommandID = new DebugCommandLineCommandID(DebugCommandLineCommand.DebugCommandLineCombo);
25-
OleMenuCommand comboBoxCommand = new OleMenuCommand(HandleInvokeCombo, comboBoxCommandID);
35+
OleMenuCommand comboBoxCommand = new OleMenuCommand(HandleInvokeCombo, HandleChangeCombo, HandleBeforeQueryStatusCombo, comboBoxCommandID);
2636
menuCommandService.AddCommand(comboBoxCommand);
2737

2838
// This is the special command to get the list of drop down items
@@ -34,10 +44,222 @@ protected override void Initialize()
3444

3545
private void HandleInvokeCombo(object sender, EventArgs e)
3646
{
47+
OleMenuCmdEventArgs oleEventArgs = e as OleMenuCmdEventArgs;
48+
if (oleEventArgs == null)
49+
throw new ArgumentException("EventArgs required.");
50+
51+
string newChoice = oleEventArgs.InValue as string;
52+
if (newChoice != null)
53+
{
54+
SetStartupCommandArguments(newChoice);
55+
SetMostRecentString(newChoice);
56+
}
57+
58+
if (oleEventArgs.OutValue != IntPtr.Zero)
59+
{
60+
string commandArguments = TryGetStartupCommandArguments();
61+
SetMostRecentString(commandArguments);
62+
Marshal.GetNativeVariantForObject(commandArguments, oleEventArgs.OutValue);
63+
return;
64+
}
65+
}
66+
67+
private void HandleChangeCombo(object sender, EventArgs e)
68+
{
69+
}
70+
71+
private void HandleBeforeQueryStatusCombo(object sender, EventArgs e)
72+
{
73+
OleMenuCommand command = sender as OleMenuCommand;
74+
if (command == null)
75+
return;
76+
77+
DebugCommandLineCommandID commandID = command.CommandID as DebugCommandLineCommandID;
78+
if (commandID == null || commandID.ID != DebugCommandLineCommand.DebugCommandLineCombo)
79+
return;
80+
81+
command.Supported = true;
82+
83+
try
84+
{
85+
command.Enabled = !string.IsNullOrEmpty(TryGetStartupCommandArgumentsPropertyName());
86+
}
87+
catch (Exception ex)
88+
{
89+
if (ErrorHandler.IsCriticalException(ex))
90+
throw;
91+
92+
command.Enabled = false;
93+
}
3794
}
3895

3996
private void HandleInvokeComboGetList(object sender, EventArgs e)
4097
{
98+
OleMenuCmdEventArgs oleEventArgs = e as OleMenuCmdEventArgs;
99+
if (oleEventArgs == null)
100+
throw new ArgumentException("EventArgs required.");
101+
102+
if (oleEventArgs.InValue != null)
103+
throw new ArgumentException();
104+
105+
if (oleEventArgs.OutValue == IntPtr.Zero)
106+
throw new ArgumentException();
107+
108+
Marshal.GetNativeVariantForObject(RecentCommandLines.ToArray(), oleEventArgs.OutValue);
109+
}
110+
111+
private static EnvDTE.Properties TryGetDtePropertiesFromHierarchy(IVsHierarchy hierarchy)
112+
{
113+
try
114+
{
115+
EnvDTE.Project project = TryGetExtensibilityObject(hierarchy) as EnvDTE.Project;
116+
if (project == null)
117+
return null;
118+
119+
EnvDTE.ConfigurationManager configurationManager = project.ConfigurationManager;
120+
if (configurationManager == null)
121+
return null;
122+
123+
EnvDTE.Configuration activeConfiguration = configurationManager.ActiveConfiguration;
124+
if (activeConfiguration == null)
125+
return null;
126+
127+
return activeConfiguration.Properties;
128+
}
129+
catch (Exception ex)
130+
{
131+
if (ErrorHandler.IsCriticalException(ex))
132+
throw;
133+
134+
return null;
135+
}
136+
}
137+
138+
private static object TryGetExtensibilityObject(IVsHierarchy hierarchy, uint itemId = (uint)VSConstants.VSITEMID.Root)
139+
{
140+
try
141+
{
142+
object obj;
143+
int hr = hierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_ExtObject, out obj);
144+
if (ErrorHandler.Failed(hr))
145+
return null;
146+
147+
return obj;
148+
}
149+
catch (Exception ex)
150+
{
151+
if (ErrorHandler.IsCriticalException(ex))
152+
throw;
153+
154+
return null;
155+
}
156+
}
157+
158+
private EnvDTE.Properties TryGetStartupProjectProperties()
159+
{
160+
try
161+
{
162+
IVsSolutionBuildManager solutionBuildManager = GetGlobalService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager;
163+
if (solutionBuildManager == null)
164+
return null;
165+
166+
IVsHierarchy startupProject;
167+
if (ErrorHandler.Failed(solutionBuildManager.get_StartupProject(out startupProject)) || startupProject == null)
168+
return null;
169+
170+
EnvDTE.Properties properties = TryGetDtePropertiesFromHierarchy(startupProject);
171+
return properties;
172+
}
173+
catch (Exception ex)
174+
{
175+
if (ErrorHandler.IsCriticalException(ex))
176+
throw;
177+
178+
return null;
179+
}
180+
}
181+
182+
private string TryGetStartupCommandArgumentsPropertyName()
183+
{
184+
try
185+
{
186+
EnvDTE.Properties properties = TryGetStartupProjectProperties();
187+
if (properties == null)
188+
return null;
189+
190+
return KnownStartupProperties.FirstOrDefault(i => properties.OfType<EnvDTE.Property>().Any(property => string.Equals(i, property.Name, StringComparison.OrdinalIgnoreCase)));
191+
}
192+
catch (Exception ex)
193+
{
194+
if (ErrorHandler.IsCriticalException(ex))
195+
throw;
196+
197+
return null;
198+
}
199+
}
200+
201+
private string TryGetStartupCommandArguments()
202+
{
203+
EnvDTE.Properties properties = TryGetStartupProjectProperties();
204+
if (properties == null)
205+
return null;
206+
207+
try
208+
{
209+
// Iterating over the properties has proven much more reliable than calling Item()
210+
foreach (EnvDTE.Property property in properties)
211+
{
212+
foreach (var propertyName in KnownStartupProperties)
213+
{
214+
if (string.Equals(propertyName, property.Name, StringComparison.OrdinalIgnoreCase))
215+
{
216+
return property.Value as string;
217+
}
218+
}
219+
}
220+
221+
return null;
222+
}
223+
catch (Exception ex)
224+
{
225+
if (ErrorHandler.IsCriticalException(ex))
226+
throw;
227+
228+
return null;
229+
}
230+
}
231+
232+
private void SetStartupCommandArguments(string value)
233+
{
234+
EnvDTE.Properties properties = TryGetStartupProjectProperties();
235+
if (properties == null)
236+
throw new NotSupportedException("No startup project is set, or it does not support setting properties.");
237+
238+
// Iterating over the properties has proven much more reliable than calling Item()
239+
foreach (EnvDTE.Property property in properties)
240+
{
241+
foreach (var propertyName in KnownStartupProperties)
242+
{
243+
if (string.Equals(propertyName, property.Name, StringComparison.OrdinalIgnoreCase))
244+
{
245+
property.Value = value ?? string.Empty;
246+
return;
247+
}
248+
}
249+
}
250+
251+
throw new NotSupportedException("Could not identify the startup arguments property for the project.");
252+
}
253+
254+
private void SetMostRecentString(string command)
255+
{
256+
List<string> recentCommands = new List<string>(RecentCommandLines);
257+
recentCommands.Remove(command);
258+
recentCommands.Insert(0, command);
259+
while (recentCommands.Count > 15)
260+
recentCommands.RemoveAt(recentCommands.Count - 1);
261+
262+
RecentCommandLines = new ReadOnlyCollection<string>(recentCommands);
41263
}
42264
}
43265
}

0 commit comments

Comments
 (0)