4
4
namespace Tvl . DebugCommandLine
5
5
{
6
6
using System ;
7
+ using System . Collections . Generic ;
8
+ using System . Collections . ObjectModel ;
7
9
using System . ComponentModel . Design ;
10
+ using System . Linq ;
8
11
using System . Runtime . InteropServices ;
12
+ using Microsoft . VisualStudio ;
9
13
using Microsoft . VisualStudio . Shell ;
14
+ using Microsoft . VisualStudio . Shell . Interop ;
10
15
11
16
[ PackageRegistration ( UseManagedResourcesOnly = true ) ]
17
+ [ ProvideAutoLoad ( VSConstants . UICONTEXT . SolutionExists_string ) ]
12
18
[ ProvideMenuResource ( "Menus.ctmenu" , 1 ) ]
13
19
[ Guid ( "238A874D-D659-4517-85D1-06B0E3CF4B7F" ) ]
14
20
internal class DebugCommandLinePackage : Package
15
21
{
22
+ private static readonly string [ ] KnownStartupProperties = { "CommandArguments" , "StartArguments" } ;
23
+
24
+ private ReadOnlyCollection < string > RecentCommandLines = new ReadOnlyCollection < string > ( new string [ 0 ] ) ;
25
+
16
26
protected override void Initialize ( )
17
27
{
18
28
base . Initialize ( ) ;
@@ -22,7 +32,7 @@ protected override void Initialize()
22
32
{
23
33
// This is the drop down combo box itself
24
34
CommandID comboBoxCommandID = new DebugCommandLineCommandID ( DebugCommandLineCommand . DebugCommandLineCombo ) ;
25
- OleMenuCommand comboBoxCommand = new OleMenuCommand ( HandleInvokeCombo , comboBoxCommandID ) ;
35
+ OleMenuCommand comboBoxCommand = new OleMenuCommand ( HandleInvokeCombo , HandleChangeCombo , HandleBeforeQueryStatusCombo , comboBoxCommandID ) ;
26
36
menuCommandService . AddCommand ( comboBoxCommand ) ;
27
37
28
38
// This is the special command to get the list of drop down items
@@ -34,10 +44,222 @@ protected override void Initialize()
34
44
35
45
private void HandleInvokeCombo ( object sender , EventArgs e )
36
46
{
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
+ }
37
94
}
38
95
39
96
private void HandleInvokeComboGetList ( object sender , EventArgs e )
40
97
{
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 ) ;
41
263
}
42
264
}
43
265
}
0 commit comments