From d05ffe1693e3ad7968651739ee9dd6285111171a Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 22 Mar 2021 01:13:47 +0100 Subject: [PATCH] Restore VSTool --- .gitignore | 1 - indra/tools/vstool/DispatchUtility.cs | 271 ++++++++++ indra/tools/vstool/README.txt | 9 + indra/tools/vstool/VSTool.csproj | 98 ++++ indra/tools/vstool/VSTool.exe | Bin 0 -> 24576 bytes indra/tools/vstool/VSTool.sln | 19 + indra/tools/vstool/app.config | 3 + indra/tools/vstool/main.cs | 733 ++++++++++++++++++++++++++ 8 files changed, 1133 insertions(+), 1 deletion(-) create mode 100644 indra/tools/vstool/DispatchUtility.cs create mode 100644 indra/tools/vstool/README.txt create mode 100644 indra/tools/vstool/VSTool.csproj create mode 100644 indra/tools/vstool/VSTool.exe create mode 100644 indra/tools/vstool/VSTool.sln create mode 100644 indra/tools/vstool/app.config create mode 100644 indra/tools/vstool/main.cs diff --git a/.gitignore b/.gitignore index 73af4d1201..5fa4a04a62 100755 --- a/.gitignore +++ b/.gitignore @@ -108,4 +108,3 @@ my_autobuild.xml compile_commands.json # ignore tracy for now indra/tracy -indra/tools/vstool/ diff --git a/indra/tools/vstool/DispatchUtility.cs b/indra/tools/vstool/DispatchUtility.cs new file mode 100644 index 0000000000..6056ac55a1 --- /dev/null +++ b/indra/tools/vstool/DispatchUtility.cs @@ -0,0 +1,271 @@ +#region Using Directives + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Reflection; +using System.Security.Permissions; + +#endregion + +namespace TestDispatchUtility +{ + /// + /// Provides helper methods for working with COM IDispatch objects that have a registered type library. + /// + public static class DispatchUtility + { + #region Private Constants + + private const int S_OK = 0; //From WinError.h + private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800 + + #endregion + + #region Public Methods + + /// + /// Gets whether the specified object implements IDispatch. + /// + /// An object to check. + /// True if the object implements IDispatch. False otherwise. + public static bool ImplementsIDispatch(object obj) + { + bool result = obj is IDispatchInfo; + return result; + } + + /// + /// Gets a Type that can be used with reflection. + /// + /// An object that implements IDispatch. + /// Whether an exception should be thrown if a Type can't be obtained. + /// A .NET Type that can be used with reflection. + /// If doesn't implement IDispatch. + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + public static Type GetType(object obj, bool throwIfNotFound) + { + RequireReference(obj, "obj"); + Type result = GetType((IDispatchInfo)obj, throwIfNotFound); + return result; + } + + /// + /// Tries to get the DISPID for the requested member name. + /// + /// An object that implements IDispatch. + /// The name of a member to lookup. + /// If the method returns true, this holds the DISPID on output. + /// If the method returns false, this value should be ignored. + /// True if the member was found and resolved to a DISPID. False otherwise. + /// If doesn't implement IDispatch. + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + public static bool TryGetDispId(object obj, string name, out int dispId) + { + RequireReference(obj, "obj"); + bool result = TryGetDispId((IDispatchInfo)obj, name, out dispId); + return result; + } + + /// + /// Invokes a member by DISPID. + /// + /// An object that implements IDispatch. + /// The DISPID of a member. This can be obtained using + /// . + /// The arguments to pass to the member. + /// The member's return value. + /// + /// This can invoke a method or a property get accessor. + /// + public static object Invoke(object obj, int dispId, object[] args) + { + string memberName = "[DispId=" + dispId + "]"; + object result = Invoke(obj, memberName, args); + return result; + } + + /// + /// Invokes a member by name. + /// + /// An object. + /// The name of the member to invoke. + /// The arguments to pass to the member. + /// The member's return value. + /// + /// This can invoke a method or a property get accessor. + /// + public static object Invoke(object obj, string memberName, object[] args) + { + RequireReference(obj, "obj"); + Type type = obj.GetType(); + object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, + null, obj, args, null); + return result; + } + + #endregion + + #region Private Methods + + /// + /// Requires that the value is non-null. + /// + /// The type of the value. + /// The value to check. + /// The name of the value. + private static void RequireReference(T value, string name) where T : class + { + if (value == null) + { + throw new ArgumentNullException(name); + } + } + + /// + /// Gets a Type that can be used with reflection. + /// + /// An object that implements IDispatch. + /// Whether an exception should be thrown if a Type can't be obtained. + /// A .NET Type that can be used with reflection. + private static Type GetType(IDispatchInfo dispatch, bool throwIfNotFound) + { + RequireReference(dispatch, "dispatch"); + + Type result = null; + int typeInfoCount; + int hr = dispatch.GetTypeInfoCount(out typeInfoCount); + if (hr == S_OK && typeInfoCount > 0) + { + // Type info isn't usually culture-aware for IDispatch, so we might as well pass + // the default locale instead of looking up the current thread's LCID each time + // (via CultureInfo.CurrentCulture.LCID). + dispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out result); + } + + if (result == null && throwIfNotFound) + { + // If the GetTypeInfoCount called failed, throw an exception for that. + Marshal.ThrowExceptionForHR(hr); + + // Otherwise, throw the same exception that Type.GetType would throw. + throw new TypeLoadException(); + } + + return result; + } + + /// + /// Tries to get the DISPID for the requested member name. + /// + /// An object that implements IDispatch. + /// The name of a member to lookup. + /// If the method returns true, this holds the DISPID on output. + /// If the method returns false, this value should be ignored. + /// True if the member was found and resolved to a DISPID. False otherwise. + private static bool TryGetDispId(IDispatchInfo dispatch, string name, out int dispId) + { + RequireReference(dispatch, "dispatch"); + RequireReference(name, "name"); + + bool result = false; + + // Members names aren't usually culture-aware for IDispatch, so we might as well + // pass the default locale instead of looking up the current thread's LCID each time + // (via CultureInfo.CurrentCulture.LCID). + Guid iidNull = Guid.Empty; + int hr = dispatch.GetDispId(ref iidNull, ref name, 1, LOCALE_SYSTEM_DEFAULT, out dispId); + + const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006); //From WinError.h + const int DISPID_UNKNOWN = -1; //From OAIdl.idl + if (hr == S_OK) + { + result = true; + } + else if (hr == DISP_E_UNKNOWNNAME && dispId == DISPID_UNKNOWN) + { + // This is the only supported "error" case because it means IDispatch + // is saying it doesn't know the member we asked about. + result = false; + } + else + { + // The other documented result codes are all errors. + Marshal.ThrowExceptionForHR(hr); + } + + return result; + } + + #endregion + + #region Private Interfaces + + /// + /// A partial declaration of IDispatch used to lookup Type information and DISPIDs. + /// + /// + /// This interface only declares the first three methods of IDispatch. It omits the + /// fourth method (Invoke) because there are already plenty of ways to do dynamic + /// invocation in .NET. But the first three methods provide dynamic type metadata + /// discovery, which .NET doesn't provide normally if you have a System.__ComObject + /// RCW instead of a strongly-typed RCW. + /// + /// Note: The original declaration of IDispatch is in OAIdl.idl. + /// + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("00020400-0000-0000-C000-000000000046")] + private interface IDispatchInfo + { + /// + /// Gets the number of Types that the object provides (0 or 1). + /// + /// Returns 0 or 1 for the number of Types provided by . + /// + /// http://msdn.microsoft.com/en-us/library/da876d53-cb8a-465c-a43e-c0eb272e2a12(VS.85) + /// + [PreserveSig] + int GetTypeInfoCount(out int typeInfoCount); + + /// + /// Gets the Type information for an object if returned 1. + /// + /// Must be 0. + /// Typically, LOCALE_SYSTEM_DEFAULT (2048). + /// Returns the object's Type information. + /// + /// http://msdn.microsoft.com/en-us/library/cc1ec9aa-6c40-4e70-819c-a7c6dd6b8c99(VS.85) + /// + void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, + MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo); + + /// + /// Gets the DISPID of the specified member name. + /// + /// Must be IID_NULL. Pass a copy of Guid.Empty. + /// The name of the member to look up. + /// Must be 1. + /// Typically, LOCALE_SYSTEM_DEFAULT (2048). + /// If a member with the requested + /// is found, this returns its DISPID and the method's return value is 0. + /// If the method returns a non-zero value, then this parameter's output value is + /// undefined. + /// Zero for success. Non-zero for failure. + /// + /// http://msdn.microsoft.com/en-us/library/6f6cf233-3481-436e-8d6a-51f93bf91619(VS.85) + /// + [PreserveSig] + int GetDispId(ref Guid riid, ref string name, int nameCount, int lcid, out int dispId); + + // NOTE: The real IDispatch also has an Invoke method next, but we don't need it. + // We can invoke methods using .NET's Type.InvokeMember method with the special + // [DISPID=n] syntax for member "names", or we can get a .NET Type using GetTypeInfo + // and invoke methods on that through reflection. + // Type.InvokeMember: http://msdn.microsoft.com/en-us/library/de3dhzwy.aspx + } + + #endregion + } +} diff --git a/indra/tools/vstool/README.txt b/indra/tools/vstool/README.txt new file mode 100644 index 0000000000..e419180031 --- /dev/null +++ b/indra/tools/vstool/README.txt @@ -0,0 +1,9 @@ +VSTool is a command line utility to manipulate VisualStudio settings. + +The windows cmake project configuration uses VSTool.exe + +A handy upgrade: + figure out how to make cmake build this csharp app + - or write the app using script (jscript?!?) so it doesn't need to be built. + + diff --git a/indra/tools/vstool/VSTool.csproj b/indra/tools/vstool/VSTool.csproj new file mode 100644 index 0000000000..7f431e85c7 --- /dev/null +++ b/indra/tools/vstool/VSTool.csproj @@ -0,0 +1,98 @@ + + + + Local + 8.0.50727 + 2.0 + {96943E2D-1373-4617-A117-D0F997A94919} + Debug + AnyCPU + + + + + VSTool + + + JScript + Grid + IE50 + false + Exe + VSTool + Always + VSTool.VSToolMain + + + + + v2.0 + 2.0 + + + .\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + .\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/indra/tools/vstool/VSTool.exe b/indra/tools/vstool/VSTool.exe new file mode 100644 index 0000000000000000000000000000000000000000..751540413a0af3256f6bbb30f9a49c7232699d9a GIT binary patch literal 24576 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 W1gZ#B5vU?iMWBj66@fnq1pXH?h%2K2 literal 0 HcmV?d00001 diff --git a/indra/tools/vstool/VSTool.sln b/indra/tools/vstool/VSTool.sln new file mode 100644 index 0000000000..21e3d75971 --- /dev/null +++ b/indra/tools/vstool/VSTool.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSTool", "VSTool.csproj", "{96943E2D-1373-4617-A117-D0F997A94919}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/indra/tools/vstool/app.config b/indra/tools/vstool/app.config new file mode 100644 index 0000000000..8494f728ff --- /dev/null +++ b/indra/tools/vstool/app.config @@ -0,0 +1,3 @@ + + + diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs new file mode 100644 index 0000000000..1d6b2f14d1 --- /dev/null +++ b/indra/tools/vstool/main.cs @@ -0,0 +1,733 @@ +// Code about getting running instances visual studio +// was borrowed from +// http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Microsoft.CSharp; + +namespace VSTool +{ + // The MessageFilter class comes from: + // http://msdn.microsoft.com/en-us/library/ms228772(VS.80).aspx + // It allows vstool to get timing error messages from + // visualstudio and handle them. + public class MessageFilter : IOleMessageFilter + { + // + // Class containing the IOleMessageFilter + // thread error-handling functions. + + // Start the filter. + public static void Register() + { + IOleMessageFilter newFilter = new MessageFilter(); + IOleMessageFilter oldFilter = null; + CoRegisterMessageFilter(newFilter, out oldFilter); + } + + // Done with the filter, close it. + public static void Revoke() + { + IOleMessageFilter oldFilter = null; + CoRegisterMessageFilter(null, out oldFilter); + } + + // + // IOleMessageFilter functions. + // Handle incoming thread requests. + int IOleMessageFilter.HandleInComingCall(int dwCallType, + System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr + lpInterfaceInfo) + { + //Return the flag SERVERCALL_ISHANDLED. + return 0; + } + + // Thread call was rejected, so try again. + int IOleMessageFilter.RetryRejectedCall(System.IntPtr + hTaskCallee, int dwTickCount, int dwRejectType) + { + if (dwRejectType == 2) + // flag = SERVERCALL_RETRYLATER. + { + // Retry the thread call immediately if return >=0 & + // <100. + return 99; + } + // Too busy; cancel call. + return -1; + } + + int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, + int dwTickCount, int dwPendingType) + { + //Return the flag PENDINGMSG_WAITDEFPROCESS. + return 2; + } + + // Implement the IOleMessageFilter interface. + [DllImport("Ole32.dll")] + private static extern int + CoRegisterMessageFilter(IOleMessageFilter newFilter, out + IOleMessageFilter oldFilter); + } + + [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + interface IOleMessageFilter + { + [PreserveSig] + int HandleInComingCall( + int dwCallType, + IntPtr hTaskCaller, + int dwTickCount, + IntPtr lpInterfaceInfo); + + [PreserveSig] + int RetryRejectedCall( + IntPtr hTaskCallee, + int dwTickCount, + int dwRejectType); + + [PreserveSig] + int MessagePending( + IntPtr hTaskCallee, + int dwTickCount, + int dwPendingType); + } + + class ViaCOM + { + public static object GetProperty(object from_obj, string prop_name) + { + try + { + Type objType = from_obj.GetType(); + return objType.InvokeMember( + prop_name, + BindingFlags.GetProperty, null, + from_obj, + null); + } + catch (Exception e) + { + Console.WriteLine("Error getting property: \"{0}\"", prop_name); + Console.WriteLine(e.Message); + throw e; + } + } + + public static object SetProperty(object from_obj, string prop_name, object new_value) + { + try + { + object[] args = { new_value }; + Type objType = from_obj.GetType(); + return objType.InvokeMember( + prop_name, + BindingFlags.DeclaredOnly | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.SetProperty, + null, + from_obj, + args); + } + catch (Exception e) + { + Console.WriteLine("Error setting property: \"{0}\"", prop_name); + Console.WriteLine(e.Message); + throw e; + } + } + + public static object CallMethod(object from_obj, string method_name, params object[] args) + { + try + { + Type objType = from_obj.GetType(); + return objType.InvokeMember( + method_name, + BindingFlags.DeclaredOnly | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.InvokeMethod, + null, + from_obj, + args); + } + catch (Exception e) + { + Console.WriteLine("Error calling method \"{0}\"", method_name); + Console.WriteLine(e.Message); + throw e; + } + } + }; + + /// + /// The main entry point class for VSTool. + /// + class VSToolMain + { + #region Interop imports + [DllImport("ole32.dll")] + public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); + + [DllImport("ole32.dll")] + public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); + #endregion + + static System.Boolean ignore_case = true; + + static string solution_name = null; + static bool use_new_vs = false; + static Hashtable projectDict = new Hashtable(); + static string startup_project = null; + static string config = null; + + static object dte = null; + static object solution = null; + + /// + /// The main entry point for the application. + /// + [STAThread] + static int Main(string[] args) + { + int retVal = 0; + bool need_save = false; + + try + { + parse_command_line(args); + + Console.WriteLine("Editing solution: {0}", solution_name); + + bool found_open_solution = GetDTEAndSolution(); + + if (dte == null || solution == null) + { + retVal = 1; + } + else + { + MessageFilter.Register(); + + // Walk through all of the projects in the solution + // and list the type of each project. + foreach (DictionaryEntry p in projectDict) + { + string project_name = (string)p.Key; + string working_dir = (string)p.Value; + if (SetProjectWorkingDir(solution, project_name, working_dir)) + { + need_save = true; + } + } + + if (config != null) + { + need_save = SetActiveConfig(config); + } + + if (startup_project != null) + { + need_save = SetStartupProject(startup_project); + } + + if (need_save) + { + if (found_open_solution == false) + { + ViaCOM.CallMethod(solution, "Close", null); + } + } + } + } + catch (Exception e) + { + Console.WriteLine(e.Message); + retVal = 1; + } + finally + { + if (solution != null) + { + Marshal.ReleaseComObject(solution); + solution = null; + } + + if (dte != null) + { + Marshal.ReleaseComObject(dte); + dte = null; + } + + MessageFilter.Revoke(); + } + return retVal; + } + + public static bool parse_command_line(string[] args) + { + string options_desc = + "--solution : MSVC solution name. (required)\n" + + "--use_new_vs : Ignore running versions of visual studio.\n" + + "--workingdir : Set working dir of a VC project.\n" + + "--config : Set the active config for the solution.\n" + + "--startup : Set the startup project for the solution.\n"; + + try + { + // Command line param parsing loop. + int i = 0; + for (; i < args.Length; ++i) + { + if ("--solution" == args[i]) + { + if (solution_name != null) + { + throw new ApplicationException("Found second --solution option"); + } + solution_name = args[++i]; + } + else if ("--use_new_vs" == args[i]) + { + use_new_vs = true; + } + + else if ("--workingdir" == args[i]) + { + string project_name = args[++i]; + string working_dir = args[++i]; + projectDict.Add(project_name, working_dir); + } + else if ("--config" == args[i]) + { + if (config != null) + { + throw new ApplicationException("Found second --config option"); + } + config = args[++i]; + } + else if ("--startup" == args[i]) + { + if (startup_project != null) + { + throw new ApplicationException("Found second --startup option"); + } + startup_project = args[++i]; + } + else + { + throw new ApplicationException("Found unrecognized token on command line: " + args[i]); + } + } + + if (solution_name == null) + { + throw new ApplicationException("The --solution option is required."); + } + } + catch(ApplicationException e) + { + + Console.WriteLine("Oops! " + e.Message); + Console.Write("Command line:"); + foreach (string arg in args) + { + Console.Write(" " + arg); + } + Console.Write("\n\n"); + Console.WriteLine("VSTool command line usage"); + Console.Write(options_desc); + throw e; + } + return true; + } + + public static bool GetDTEAndSolution() + { + bool found_open_solution = true; + + Console.WriteLine("Looking for existing VisualStudio instance..."); + + // Get an instance of the currently running Visual Studio .NET IDE. + // dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.7.1"); + string full_solution_name = System.IO.Path.GetFullPath(solution_name); + if (false == use_new_vs) + { + dte = GetIDEInstance(full_solution_name); + } + + if (dte == null) + { + try + { + Console.WriteLine(" Didn't find open solution, starting new background VisualStudio instance..."); + Console.WriteLine(" Reading .sln file version..."); + string version = GetSolutionVersion(full_solution_name); + + Console.WriteLine(" Using version: {0}...", version); + string progid = GetVSProgID(version); + + Type objType = Type.GetTypeFromProgID(progid); + dte = System.Activator.CreateInstance(objType); + Console.WriteLine(" Reading solution: \"{0}\"", full_solution_name); + + solution = ViaCOM.GetProperty(dte, "Solution"); + object[] openArgs = { full_solution_name }; + ViaCOM.CallMethod(solution, "Open", openArgs); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + Console.WriteLine("Quitting do to error opening: {0}", full_solution_name); + solution = null; + dte = null; + return found_open_solution; + } + found_open_solution = false; + } + + if (solution == null) + { + solution = ViaCOM.GetProperty(dte, "Solution"); + } + + return found_open_solution; + } + + /// + /// Get the DTE object for the instance of Visual Studio IDE that has + /// the specified solution open. + /// + /// The absolute filename of the solution + /// Corresponding DTE object or null if no such IDE is running + public static object GetIDEInstance( string solutionFile ) + { + Hashtable runningInstances = GetIDEInstances( true ); + IDictionaryEnumerator enumerator = runningInstances.GetEnumerator(); + + while ( enumerator.MoveNext() ) + { + try + { + object ide = enumerator.Value; + if (ide != null) + { + object sol = ViaCOM.GetProperty(ide, "Solution"); + if (0 == string.Compare((string)ViaCOM.GetProperty(sol, "FullName"), solutionFile, ignore_case)) + { + return ide; + } + } + } + catch{} + } + + return null; + } + + /// + /// Get a table of the currently running instances of the Visual Studio .NET IDE. + /// + /// Only return instances that have opened a solution + /// A hashtable mapping the name of the IDE in the running object table to the corresponding DTE object + public static Hashtable GetIDEInstances( bool openSolutionsOnly ) + { + Hashtable runningIDEInstances = new Hashtable(); + Hashtable runningObjects = GetRunningObjectTable(); + + IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator(); + while ( rotEnumerator.MoveNext() ) + { + string candidateName = (string) rotEnumerator.Key; + if (!candidateName.StartsWith("!VisualStudio.DTE")) + continue; + + object ide = rotEnumerator.Value; + if (ide == null) + continue; + + if (openSolutionsOnly) + { + try + { + object sol = ViaCOM.GetProperty(ide, "Solution"); + string solutionFile = (string)ViaCOM.GetProperty(sol, "FullName"); + if (solutionFile != String.Empty) + { + runningIDEInstances[ candidateName ] = ide; + } + } + catch {} + } + else + { + runningIDEInstances[ candidateName ] = ide; + } + } + return runningIDEInstances; + } + + /// + /// Get a snapshot of the running object table (ROT). + /// + /// A hashtable mapping the name of the object in the ROT to the corresponding object + [STAThread] + public static Hashtable GetRunningObjectTable() + { + Hashtable result = new Hashtable(); + + int numFetched = 0; + IRunningObjectTable runningObjectTable; + IEnumMoniker monikerEnumerator; + IMoniker[] monikers = new IMoniker[1]; + + GetRunningObjectTable(0, out runningObjectTable); + runningObjectTable.EnumRunning(out monikerEnumerator); + monikerEnumerator.Reset(); + + while (monikerEnumerator.Next(1, monikers, new IntPtr(numFetched)) == 0) + { + IBindCtx ctx; + CreateBindCtx(0, out ctx); + + string runningObjectName; + monikers[0].GetDisplayName(ctx, null, out runningObjectName); + + object runningObjectVal; + runningObjectTable.GetObject( monikers[0], out runningObjectVal); + + result[ runningObjectName ] = runningObjectVal; + } + + return result; + } + + public static string GetSolutionVersion(string solutionFullFileName) + { + string version; + System.IO.StreamReader solutionStreamReader = null; + string firstLine; + string format; + + try + { + solutionStreamReader = new System.IO.StreamReader(solutionFullFileName); + do + { + firstLine = solutionStreamReader.ReadLine(); + } + while (firstLine == ""); + + format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim(); + + switch(format) + { + case "7.00": + version = "VC70"; + break; + + case "8.00": + version = "VC71"; + break; + + case "9.00": + version = "VC80"; + break; + + case "10.00": + version = "VC90"; + break; + + case "11.00": + version = "VC100"; + break; + + case "12.00": + version = "VC150"; + break; + + default: + throw new ApplicationException("Unknown .sln version: " + format); + } + } + finally + { + if(solutionStreamReader != null) + { + solutionStreamReader.Close(); + } + } + + return version; + } + + public static string GetVSProgID(string version) + { + string progid = null; + switch(version) + { + case "VC70": + progid = "VisualStudio.DTE.7"; + break; + + case "VC71": + progid = "VisualStudio.DTE.7.1"; + break; + + case "VC80": + progid = "VisualStudio.DTE.8.0"; + break; + + case "VC90": + progid = "VisualStudio.DTE.9.0"; + break; + + case "VC100": + progid = "VisualStudio.DTE.10.0"; + break; + + case "VC120": + progid = "VisualStudio.DTE.12.0"; + break; + + case "VC150": + progid = "VisualStudio.DTE.15.0"; + break; + + default: + throw new ApplicationException("Can't handle VS version: " + version); + } + + return progid; + } + + public static bool SetProjectWorkingDir(object sol, string project_name, string working_dir) + { + bool made_change = false; + Console.WriteLine("Looking for project {0}...", project_name); + try + { + object prjs = ViaCOM.GetProperty(sol, "Projects"); + object count = ViaCOM.GetProperty(prjs, "Count"); + for(int i = 1; i <= (int)count; ++i) + { + object[] prjItemArgs = { (object)i }; + object prj = ViaCOM.CallMethod(prjs, "Item", prjItemArgs); + string name = (string)ViaCOM.GetProperty(prj, "Name"); + if (0 == string.Compare(name, project_name, ignore_case)) + { + Console.WriteLine("Found project: {0}", project_name); + Console.WriteLine("Setting working directory"); + + string full_project_name = (string)ViaCOM.GetProperty(prj, "FullName"); + Console.WriteLine(full_project_name); + + // *NOTE:Mani Thanks to incompatibilities between different versions of the + // VCProjectEngine.dll assembly, we can't cast the objects recevied from the DTE to + // the VCProjectEngine types from a different version than the one built + // with. ie, VisualStudio.DTE.7.1 objects can't be converted in a project built + // in VS 8.0. To avoid this problem, we can use the com object interfaces directly, + // without the type casting. Its tedious code, but it seems to work. + + // oCfgs should be assigned to a 'Project.Configurations' collection. + object oCfgs = ViaCOM.GetProperty(ViaCOM.GetProperty(prj, "Object"), "Configurations"); + + // oCount will be assigned to the number of configs present in oCfgs. + object oCount = ViaCOM.GetProperty(oCfgs, "Count"); + + for (int cfgIndex = 1; cfgIndex <= (int)oCount; ++cfgIndex) + { + object[] itemArgs = {(object)cfgIndex}; + object oCfg = ViaCOM.CallMethod(oCfgs, "Item", itemArgs); + object oDebugSettings = ViaCOM.GetProperty(oCfg, "DebugSettings"); + ViaCOM.SetProperty(oDebugSettings, "WorkingDirectory", (object)working_dir); + } + + break; + } + } + made_change = true; + } + catch( Exception e ) + { + Console.WriteLine(e.Message); + Console.WriteLine("Failed to set working dir for project, {0}.", project_name); + } + + return made_change; + } + + public static bool SetStartupProject(string startup_project) + { + bool result = false; + try + { + // You need the 'unique name of the project to set StartupProjects. + // find the project by generic name. + Console.WriteLine("Trying to set \"{0}\" to the startup project", startup_project); + object prjs = ViaCOM.GetProperty(solution, "Projects"); + object count = ViaCOM.GetProperty(prjs, "Count"); + for (int i = 1; i <= (int)count; ++i) + { + object[] itemArgs = { (object)i }; + object prj = ViaCOM.CallMethod(prjs, "Item", itemArgs); + object prjName = ViaCOM.GetProperty(prj, "Name"); + if (0 == string.Compare((string)prjName, startup_project, ignore_case)) + { + object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); + ViaCOM.SetProperty(solBuild, "StartupProjects", ViaCOM.GetProperty(prj, "UniqueName")); + Console.WriteLine(" Success!"); + result = true; + break; + } + } + + if (result == false) + { + Console.WriteLine(" Could not find project \"{0}\" in the solution.", startup_project); + } + } + catch (Exception e) + { + Console.WriteLine(" Failed to set the startup project!"); + Console.WriteLine(e.Message); + } + return result; + } + + public static bool SetActiveConfig(string config) + { + bool result = false; + try + { + Console.WriteLine("Trying to set active config to \"{0}\"", config); + object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); + object solCfgs = ViaCOM.GetProperty(solBuild, "SolutionConfigurations"); + object[] itemArgs = { (object)config }; + object solCfg = ViaCOM.CallMethod(solCfgs, "Item", itemArgs); + ViaCOM.CallMethod(solCfg, "Activate", null); + Console.WriteLine(" Success!"); + result = true; + } + catch (Exception e) + { + Console.WriteLine(" Failed to set \"{0}\" as the active config.", config); + Console.WriteLine(e.Message); + } + return result; + } + } +}