aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/tools/vstool/main.cs
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/tools/vstool/main.cs')
-rw-r--r--linden/indra/tools/vstool/main.cs711
1 files changed, 711 insertions, 0 deletions
diff --git a/linden/indra/tools/vstool/main.cs b/linden/indra/tools/vstool/main.cs
new file mode 100644
index 0000000..cc268d5
--- /dev/null
+++ b/linden/indra/tools/vstool/main.cs
@@ -0,0 +1,711 @@
1// Code about getting running instances visual studio
2// was borrowed from
3// http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx
4
5
6using System;
7using System.Collections;
8using System.Collections.Generic;
9using System.Reflection;
10using System.Runtime.InteropServices;
11using System.Runtime.InteropServices.ComTypes;
12using Microsoft.CSharp;
13
14namespace VSTool
15{
16 // The MessageFilter class comes from:
17 // http://msdn.microsoft.com/en-us/library/ms228772(VS.80).aspx
18 // It allows vstool to get timing error messages from
19 // visualstudio and handle them.
20 public class MessageFilter : IOleMessageFilter
21 {
22 //
23 // Class containing the IOleMessageFilter
24 // thread error-handling functions.
25
26 // Start the filter.
27 public static void Register()
28 {
29 IOleMessageFilter newFilter = new MessageFilter();
30 IOleMessageFilter oldFilter = null;
31 CoRegisterMessageFilter(newFilter, out oldFilter);
32 }
33
34 // Done with the filter, close it.
35 public static void Revoke()
36 {
37 IOleMessageFilter oldFilter = null;
38 CoRegisterMessageFilter(null, out oldFilter);
39 }
40
41 //
42 // IOleMessageFilter functions.
43 // Handle incoming thread requests.
44 int IOleMessageFilter.HandleInComingCall(int dwCallType,
45 System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr
46 lpInterfaceInfo)
47 {
48 //Return the flag SERVERCALL_ISHANDLED.
49 return 0;
50 }
51
52 // Thread call was rejected, so try again.
53 int IOleMessageFilter.RetryRejectedCall(System.IntPtr
54 hTaskCallee, int dwTickCount, int dwRejectType)
55 {
56 if (dwRejectType == 2)
57 // flag = SERVERCALL_RETRYLATER.
58 {
59 // Retry the thread call immediately if return >=0 &
60 // <100.
61 return 99;
62 }
63 // Too busy; cancel call.
64 return -1;
65 }
66
67 int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee,
68 int dwTickCount, int dwPendingType)
69 {
70 //Return the flag PENDINGMSG_WAITDEFPROCESS.
71 return 2;
72 }
73
74 // Implement the IOleMessageFilter interface.
75 [DllImport("Ole32.dll")]
76 private static extern int
77 CoRegisterMessageFilter(IOleMessageFilter newFilter, out
78 IOleMessageFilter oldFilter);
79 }
80
81 [ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
82 InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
83 interface IOleMessageFilter
84 {
85 [PreserveSig]
86 int HandleInComingCall(
87 int dwCallType,
88 IntPtr hTaskCaller,
89 int dwTickCount,
90 IntPtr lpInterfaceInfo);
91
92 [PreserveSig]
93 int RetryRejectedCall(
94 IntPtr hTaskCallee,
95 int dwTickCount,
96 int dwRejectType);
97
98 [PreserveSig]
99 int MessagePending(
100 IntPtr hTaskCallee,
101 int dwTickCount,
102 int dwPendingType);
103 }
104
105 class ViaCOM
106 {
107 public static object GetProperty(object from_obj, string prop_name)
108 {
109 try
110 {
111 Type objType = from_obj.GetType();
112 return objType.InvokeMember(
113 prop_name,
114 BindingFlags.GetProperty, null,
115 from_obj,
116 null);
117 }
118 catch (Exception e)
119 {
120 Console.WriteLine("Error getting property: \"{0}\"", prop_name);
121 Console.WriteLine(e.Message);
122 throw e;
123 }
124 }
125
126 public static object SetProperty(object from_obj, string prop_name, object new_value)
127 {
128 try
129 {
130 object[] args = { new_value };
131 Type objType = from_obj.GetType();
132 return objType.InvokeMember(
133 prop_name,
134 BindingFlags.DeclaredOnly |
135 BindingFlags.Public |
136 BindingFlags.NonPublic |
137 BindingFlags.Instance |
138 BindingFlags.SetProperty,
139 null,
140 from_obj,
141 args);
142 }
143 catch (Exception e)
144 {
145 Console.WriteLine("Error setting property: \"{0}\"", prop_name);
146 Console.WriteLine(e.Message);
147 throw e;
148 }
149 }
150
151 public static object CallMethod(object from_obj, string method_name, params object[] args)
152 {
153 try
154 {
155 Type objType = from_obj.GetType();
156 return objType.InvokeMember(
157 method_name,
158 BindingFlags.DeclaredOnly |
159 BindingFlags.Public |
160 BindingFlags.NonPublic |
161 BindingFlags.Instance |
162 BindingFlags.InvokeMethod,
163 null,
164 from_obj,
165 args);
166 }
167 catch (Exception e)
168 {
169 Console.WriteLine("Error calling method \"{0}\"", method_name);
170 Console.WriteLine(e.Message);
171 throw e;
172 }
173 }
174 };
175
176 /// <summary>
177 /// The main entry point class for VSTool.
178 /// </summary>
179 class VSToolMain
180 {
181 #region Interop imports
182 [DllImport("ole32.dll")]
183 public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
184
185 [DllImport("ole32.dll")]
186 public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
187 #endregion
188
189 static System.Boolean ignore_case = true;
190
191 static string solution_name = null;
192 static bool use_new_vs = false;
193 static Hashtable projectDict = new Hashtable();
194 static string startup_project = null;
195 static string config = null;
196
197 static object dte = null;
198 static object solution = null;
199
200 /// <summary>
201 /// The main entry point for the application.
202 /// </summary>
203 [STAThread]
204 static int Main(string[] args)
205 {
206 int retVal = 0;
207 bool need_save = false;
208
209 try
210 {
211 parse_command_line(args);
212
213 Console.WriteLine("Editing solution: {0}", solution_name);
214
215 bool found_open_solution = GetDTEAndSolution();
216
217 if (dte == null || solution == null)
218 {
219 retVal = 1;
220 }
221 else
222 {
223 MessageFilter.Register();
224
225 // Walk through all of the projects in the solution
226 // and list the type of each project.
227 foreach (DictionaryEntry p in projectDict)
228 {
229 string project_name = (string)p.Key;
230 string working_dir = (string)p.Value;
231 if (SetProjectWorkingDir(solution, project_name, working_dir))
232 {
233 need_save = true;
234 }
235 }
236
237 if (config != null)
238 {
239 need_save = SetActiveConfig(config);
240 }
241
242 if (startup_project != null)
243 {
244 need_save = SetStartupProject(startup_project);
245 }
246
247 if (need_save)
248 {
249 if (found_open_solution == false)
250 {
251 ViaCOM.CallMethod(solution, "Close", null);
252 }
253 }
254 }
255 }
256 catch (Exception e)
257 {
258 Console.WriteLine(e.Message);
259 retVal = 1;
260 }
261 finally
262 {
263 if (solution != null)
264 {
265 Marshal.ReleaseComObject(solution);
266 solution = null;
267 }
268
269 if (dte != null)
270 {
271 Marshal.ReleaseComObject(dte);
272 dte = null;
273 }
274
275 MessageFilter.Revoke();
276 }
277 return retVal;
278 }
279
280 public static bool parse_command_line(string[] args)
281 {
282 string options_desc =
283 "--solution <solution_name> : MSVC solution name. (required)\n" +
284 "--use_new_vs : Ignore running versions of visual studio.\n" +
285 "--workingdir <project> <dir> : Set working dir of a VC project.\n" +
286 "--config <config> : Set the active config for the solution.\n" +
287 "--startup <project> : Set the startup project for the solution.\n";
288
289 try
290 {
291 // Command line param parsing loop.
292 int i = 0;
293 for (; i < args.Length; ++i)
294 {
295 if ("--solution" == args[i])
296 {
297 if (solution_name != null)
298 {
299 throw new ApplicationException("Found second --solution option");
300 }
301 solution_name = args[++i];
302 }
303 else if ("--use_new_vs" == args[i])
304 {
305 use_new_vs = true;
306 }
307
308 else if ("--workingdir" == args[i])
309 {
310 string project_name = args[++i];
311 string working_dir = args[++i];
312 projectDict.Add(project_name, working_dir);
313 }
314 else if ("--config" == args[i])
315 {
316 if (config != null)
317 {
318 throw new ApplicationException("Found second --config option");
319 }
320 config = args[++i];
321 }
322 else if ("--startup" == args[i])
323 {
324 if (startup_project != null)
325 {
326 throw new ApplicationException("Found second --startup option");
327 }
328 startup_project = args[++i];
329 }
330 else
331 {
332 throw new ApplicationException("Found unrecognized token on command line: " + args[i]);
333 }
334 }
335
336 if (solution_name == null)
337 {
338 throw new ApplicationException("The --solution option is required.");
339 }
340 }
341 catch(ApplicationException e)
342 {
343
344 Console.WriteLine("Oops! " + e.Message);
345 Console.Write("Command line:");
346 foreach (string arg in args)
347 {
348 Console.Write(" " + arg);
349 }
350 Console.Write("\n\n");
351 Console.WriteLine("VSTool command line usage");
352 Console.Write(options_desc);
353 throw e;
354 }
355 return true;
356 }
357
358 public static bool GetDTEAndSolution()
359 {
360 bool found_open_solution = true;
361
362 Console.WriteLine("Looking for existing VisualStudio instance...");
363
364 // Get an instance of the currently running Visual Studio .NET IDE.
365 // dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.7.1");
366 string full_solution_name = System.IO.Path.GetFullPath(solution_name);
367 if (false == use_new_vs)
368 {
369 dte = GetIDEInstance(full_solution_name);
370 }
371
372 if (dte == null)
373 {
374 try
375 {
376 Console.WriteLine(" Didn't find open solution, starting new background VisualStudio instance...");
377 Console.WriteLine(" Reading .sln file version...");
378 string version = GetSolutionVersion(full_solution_name);
379
380 Console.WriteLine(" Using version: {0}...", version);
381 string progid = GetVSProgID(version);
382
383 Type objType = Type.GetTypeFromProgID(progid);
384 dte = System.Activator.CreateInstance(objType);
385 Console.WriteLine(" Reading solution: \"{0}\"", full_solution_name);
386
387 solution = ViaCOM.GetProperty(dte, "Solution");
388 object[] openArgs = { full_solution_name };
389 ViaCOM.CallMethod(solution, "Open", openArgs);
390 }
391 catch (Exception e)
392 {
393 Console.WriteLine(e.Message);
394 Console.WriteLine("Quitting do to error opening: {0}", full_solution_name);
395 solution = null;
396 dte = null;
397 return found_open_solution;
398 }
399 found_open_solution = false;
400 }
401
402 if (solution == null)
403 {
404 solution = ViaCOM.GetProperty(dte, "Solution");
405 }
406
407 return found_open_solution;
408 }
409
410 /// <summary>
411 /// Get the DTE object for the instance of Visual Studio IDE that has
412 /// the specified solution open.
413 /// </summary>
414 /// <param name="solutionFile">The absolute filename of the solution</param>
415 /// <returns>Corresponding DTE object or null if no such IDE is running</returns>
416 public static object GetIDEInstance( string solutionFile )
417 {
418 Hashtable runningInstances = GetIDEInstances( true );
419 IDictionaryEnumerator enumerator = runningInstances.GetEnumerator();
420
421 while ( enumerator.MoveNext() )
422 {
423 try
424 {
425 object ide = enumerator.Value;
426 if (ide != null)
427 {
428 object sol = ViaCOM.GetProperty(ide, "Solution");
429 if (0 == string.Compare((string)ViaCOM.GetProperty(sol, "FullName"), solutionFile, ignore_case))
430 {
431 return ide;
432 }
433 }
434 }
435 catch{}
436 }
437
438 return null;
439 }
440
441 /// <summary>
442 /// Get a table of the currently running instances of the Visual Studio .NET IDE.
443 /// </summary>
444 /// <param name="openSolutionsOnly">Only return instances that have opened a solution</param>
445 /// <returns>A hashtable mapping the name of the IDE in the running object table to the corresponding DTE object</returns>
446 public static Hashtable GetIDEInstances( bool openSolutionsOnly )
447 {
448 Hashtable runningIDEInstances = new Hashtable();
449 Hashtable runningObjects = GetRunningObjectTable();
450
451 IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator();
452 while ( rotEnumerator.MoveNext() )
453 {
454 string candidateName = (string) rotEnumerator.Key;
455 if (!candidateName.StartsWith("!VisualStudio.DTE"))
456 continue;
457
458 object ide = rotEnumerator.Value;
459 if (ide == null)
460 continue;
461
462 if (openSolutionsOnly)
463 {
464 try
465 {
466 object sol = ViaCOM.GetProperty(ide, "Solution");
467 string solutionFile = (string)ViaCOM.GetProperty(sol, "FullName");
468 if (solutionFile != String.Empty)
469 {
470 runningIDEInstances[ candidateName ] = ide;
471 }
472 }
473 catch {}
474 }
475 else
476 {
477 runningIDEInstances[ candidateName ] = ide;
478 }
479 }
480 return runningIDEInstances;
481 }
482
483 /// <summary>
484 /// Get a snapshot of the running object table (ROT).
485 /// </summary>
486 /// <returns>A hashtable mapping the name of the object in the ROT to the corresponding object</returns>
487 [STAThread]
488 public static Hashtable GetRunningObjectTable()
489 {
490 Hashtable result = new Hashtable();
491
492 int numFetched = 0;
493 IRunningObjectTable runningObjectTable;
494 IEnumMoniker monikerEnumerator;
495 IMoniker[] monikers = new IMoniker[1];
496
497 GetRunningObjectTable(0, out runningObjectTable);
498 runningObjectTable.EnumRunning(out monikerEnumerator);
499 monikerEnumerator.Reset();
500
501 while (monikerEnumerator.Next(1, monikers, new IntPtr(numFetched)) == 0)
502 {
503 IBindCtx ctx;
504 CreateBindCtx(0, out ctx);
505
506 string runningObjectName;
507 monikers[0].GetDisplayName(ctx, null, out runningObjectName);
508
509 object runningObjectVal;
510 runningObjectTable.GetObject( monikers[0], out runningObjectVal);
511
512 result[ runningObjectName ] = runningObjectVal;
513 }
514
515 return result;
516 }
517
518 public static string GetSolutionVersion(string solutionFullFileName)
519 {
520 string version;
521 System.IO.StreamReader solutionStreamReader = null;
522 string firstLine;
523 string format;
524
525 try
526 {
527 solutionStreamReader = new System.IO.StreamReader(solutionFullFileName);
528 do
529 {
530 firstLine = solutionStreamReader.ReadLine();
531 }
532 while (firstLine == "");
533
534 format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim();
535
536 switch(format)
537 {
538 case "7.00":
539 version = "VC70";
540 break;
541
542 case "8.00":
543 version = "VC71";
544 break;
545
546 case "9.00":
547 version = "VC80";
548 break;
549
550 case "10.00":
551 version = "VC90";
552 break;
553 default:
554 throw new ApplicationException("Unknown .sln version: " + format);
555 }
556 }
557 finally
558 {
559 if(solutionStreamReader != null)
560 {
561 solutionStreamReader.Close();
562 }
563 }
564
565 return version;
566 }
567
568 public static string GetVSProgID(string version)
569 {
570 string progid = null;
571 switch(version)
572 {
573 case "VC70":
574 progid = "VisualStudio.DTE.7";
575 break;
576
577 case "VC71":
578 progid = "VisualStudio.DTE.7.1";
579 break;
580
581 case "VC80":
582 progid = "VisualStudio.DTE.8.0";
583 break;
584
585 case "VC90":
586 progid = "VisualStudio.DTE.9.0";
587 break;
588 default:
589 throw new ApplicationException("Can't handle VS version: " + version);
590 }
591
592 return progid;
593 }
594
595 public static bool SetProjectWorkingDir(object sol, string project_name, string working_dir)
596 {
597 bool made_change = false;
598 Console.WriteLine("Looking for project {0}...", project_name);
599 try
600 {
601 object prjs = ViaCOM.GetProperty(sol, "Projects");
602 object count = ViaCOM.GetProperty(prjs, "Count");
603 for(int i = 1; i <= (int)count; ++i)
604 {
605 object[] prjItemArgs = { (object)i };
606 object prj = ViaCOM.CallMethod(prjs, "Item", prjItemArgs);
607 string name = (string)ViaCOM.GetProperty(prj, "Name");
608 if (0 == string.Compare(name, project_name, ignore_case))
609 {
610 Console.WriteLine("Found project: {0}", project_name);
611 Console.WriteLine("Setting working directory");
612
613 string full_project_name = (string)ViaCOM.GetProperty(prj, "FullName");
614 Console.WriteLine(full_project_name);
615
616 // *NOTE:Mani Thanks to incompatibilities between different versions of the
617 // VCProjectEngine.dll assembly, we can't cast the objects recevied from the DTE to
618 // the VCProjectEngine types from a different version than the one built
619 // with. ie, VisualStudio.DTE.7.1 objects can't be converted in a project built
620 // in VS 8.0. To avoid this problem, we can use the com object interfaces directly,
621 // without the type casting. Its tedious code, but it seems to work.
622
623 // oCfgs should be assigned to a 'Project.Configurations' collection.
624 object oCfgs = ViaCOM.GetProperty(ViaCOM.GetProperty(prj, "Object"), "Configurations");
625
626 // oCount will be assigned to the number of configs present in oCfgs.
627 object oCount = ViaCOM.GetProperty(oCfgs, "Count");
628
629 for (int cfgIndex = 1; cfgIndex <= (int)oCount; ++cfgIndex)
630 {
631 object[] itemArgs = {(object)cfgIndex};
632 object oCfg = ViaCOM.CallMethod(oCfgs, "Item", itemArgs);
633 object oDebugSettings = ViaCOM.GetProperty(oCfg, "DebugSettings");
634 ViaCOM.SetProperty(oDebugSettings, "WorkingDirectory", (object)working_dir);
635 }
636
637 break;
638 }
639 }
640 made_change = true;
641 }
642 catch( Exception e )
643 {
644 Console.WriteLine(e.Message);
645 Console.WriteLine("Failed to set working dir for project, {0}.", project_name);
646 }
647
648 return made_change;
649 }
650
651 public static bool SetStartupProject(string startup_project)
652 {
653 bool result = false;
654 try
655 {
656 // You need the 'unique name of the project to set StartupProjects.
657 // find the project by generic name.
658 Console.WriteLine("Trying to set \"{0}\" to the startup project", startup_project);
659 object prjs = ViaCOM.GetProperty(solution, "Projects");
660 object count = ViaCOM.GetProperty(prjs, "Count");
661 for (int i = 1; i <= (int)count; ++i)
662 {
663 object[] itemArgs = { (object)i };
664 object prj = ViaCOM.CallMethod(prjs, "Item", itemArgs);
665 object prjName = ViaCOM.GetProperty(prj, "Name");
666 if (0 == string.Compare((string)prjName, startup_project, ignore_case))
667 {
668 object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild");
669 ViaCOM.SetProperty(solBuild, "StartupProjects", ViaCOM.GetProperty(prj, "UniqueName"));
670 Console.WriteLine(" Success!");
671 result = true;
672 break;
673 }
674 }
675
676 if (result == false)
677 {
678 Console.WriteLine(" Could not find project \"{0}\" in the solution.", startup_project);
679 }
680 }
681 catch (Exception e)
682 {
683 Console.WriteLine(" Failed to set the startup project!");
684 Console.WriteLine(e.Message);
685 }
686 return result;
687 }
688
689 public static bool SetActiveConfig(string config)
690 {
691 bool result = false;
692 try
693 {
694 Console.WriteLine("Trying to set active config to \"{0}\"", config);
695 object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild");
696 object solCfgs = ViaCOM.GetProperty(solBuild, "SolutionConfigurations");
697 object[] itemArgs = { (object)config };
698 object solCfg = ViaCOM.CallMethod(solCfgs, "Item", itemArgs);
699 ViaCOM.CallMethod(solCfg, "Activate", null);
700 Console.WriteLine(" Success!");
701 result = true;
702 }
703 catch (Exception e)
704 {
705 Console.WriteLine(" Failed to set \"{0}\" as the active config.", config);
706 Console.WriteLine(e.Message);
707 }
708 return result;
709 }
710 }
711}