如何获取当前Visual Studio解决方案中的项目列表?

当我们在任何开放式解决方案中打开Package Manager Console时,它会显示该解决方案的所有项目。 如何加载同一解决方案的所有项目。 当我尝试下面显示的代码时,它正在取出我打开的第一个解决方案的项目。

private List GetProjects() { var dte = (DTE)Marshal.GetActiveObject(string.Format(CultureInfo.InvariantCulture, "VisualStudio.DTE.{0}.0", targetVsVersion)); var projects = dte.Solution.OfType().ToList(); return projects; } 

以下是一组各种函数,允许您枚举给定解决方案中的项目。 这是您在当前解决方案中使用它的方式:

 // get current solution IVsSolution solution = (IVsSolution)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(IVsSolution)); foreach(Project project in GetProjects(solution)) { .... } .... public static IEnumerable GetProjects(IVsSolution solution) { foreach (IVsHierarchy hier in GetProjectsInSolution(solution)) { EnvDTE.Project project = GetDTEProject(hier); if (project != null) yield return project; } } public static IEnumerable GetProjectsInSolution(IVsSolution solution) { return GetProjectsInSolution(solution, __VSENUMPROJFLAGS.EPF_LOADEDINSOLUTION); } public static IEnumerable GetProjectsInSolution(IVsSolution solution, __VSENUMPROJFLAGS flags) { if (solution == null) yield break; IEnumHierarchies enumHierarchies; Guid guid = Guid.Empty; solution.GetProjectEnum((uint)flags, ref guid, out enumHierarchies); if (enumHierarchies == null) yield break; IVsHierarchy[] hierarchy = new IVsHierarchy[1]; uint fetched; while (enumHierarchies.Next(1, hierarchy, out fetched) == VSConstants.S_OK && fetched == 1) { if (hierarchy.Length > 0 && hierarchy[0] != null) yield return hierarchy[0]; } } public static EnvDTE.Project GetDTEProject(IVsHierarchy hierarchy) { if (hierarchy == null) throw new ArgumentNullException("hierarchy"); object obj; hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out obj); return obj as EnvDTE.Project; } 

可能有一个更好的方法,但我快速了解并发现这个工作(它假设您有一种方式知道解决方案名称)。 根据这篇文章 , GetActiveObject不保证VS的当前实例,这就是你从另一个实例获得结果的原因。 相反,您可以使用GetDTE显示的GetDTE方法:

 [DllImport("ole32.dll")] private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc); public static DTE GetDTE(int processId) { string progId = "!VisualStudio.DTE.10.0:" + processId.ToString(); object runningObject = null; IBindCtx bindCtx = null; IRunningObjectTable rot = null; IEnumMoniker enumMonikers = null; try { Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx)); bindCtx.GetRunningObjectTable(out rot); rot.EnumRunning(out enumMonikers); IMoniker[] moniker = new IMoniker[1]; IntPtr numberFetched = IntPtr.Zero; while (enumMonikers.Next(1, moniker, numberFetched) == 0) { IMoniker runningObjectMoniker = moniker[0]; string name = null; try { if (runningObjectMoniker != null) { runningObjectMoniker.GetDisplayName(bindCtx, null, out name); } } catch (UnauthorizedAccessException) { // Do nothing, there is something in the ROT that we do not have access to. } if (!string.IsNullOrEmpty(name) && string.Equals(name, progId, StringComparison.Ordinal)) { Marshal.ThrowExceptionForHR(rot.GetObject(runningObjectMoniker, out runningObject)); break; } } } finally { if (enumMonikers != null) { Marshal.ReleaseComObject(enumMonikers); } if (rot != null) { Marshal.ReleaseComObject(rot); } if (bindCtx != null) { Marshal.ReleaseComObject(bindCtx); } } return (DTE)runningObject; } 

如果您事先知道解决方案名称,则可以在ProcessMainWindowTitle属性中找到它,并将ProcessID传递给上面的方法。

 var dte = GetDTE(System.Diagnostics.Process.GetProcesses().Where(x => x.MainWindowTitle.StartsWith("SolutionName") && x.ProcessName.Contains("devenv")).FirstOrDefault().Id); 

虽然上面的代码工作,但我遇到了一个COM错误,我使用此处显示的MessageFilter类修复了该错误。

MessageFilter文章中,这就是MessageFilter类的样子

 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); } 

然后您可以像这样访问项目名称

 var dte = GetDTE(System.Diagnostics.Process.GetProcesses().Where(x => x.MainWindowTitle.StartsWith("SolutionName") && x.ProcessName.Contains("devenv")).FirstOrDefault().Id); MessageFilter.Register(); var projects = dte.Solution.OfType().ToList(); MessageFilter.Revoke(); foreach (var proj in projects) { Debug.WriteLine(proj.Name); } Marshal.ReleaseComObject(dte); 

我相信你可以使用这样的东西:

 var dte = (EnvDTE.DTE)GetService(typeof(EnvDTE.DTE)); if (dte != null) { var solution = dte.Solution; if (solution != null) { // get your projects here } }