代码之家  ›  专栏  ›  技术社区  ›  Dave Swersky

使用envdte自动化visual studio

  •  28
  • Dave Swersky  · 技术社区  · 15 年前

    我正在使用以下代码成功实例化/自动化Visual Studio:

    System.Type t = System.Type.GetTypeFromProgID("VisualStudio.DTE.9.0");
    object obj = Activator.CreateInstance(t, true);
    dte = (DTE)obj;
    Solution sln = dte.Solution;
    sln.Open(SolutionFile);
    System.Threading.Thread.Sleep(1000);
    //Do stuff with the solution
    

    注意到 Thread.Sleep(1000) 打电话?如果我不包括这个,那么代码会在实例准备好之前尝试对其进行窃听,我会得到一个异常:

    the message filter indicated that the application is busy.
    

    与其等待N秒,是否有方法轮询此对象以备就绪?

    3 回复  |  直到 9 年前
        1
  •  32
  •   Elisha    15 年前

    作为此问题的解决方案,您可以注册到解决方案加载完成时通知的事件。

    这是一个类示例,允许您在加载解决方案时侦听事件:

    public class SolutionEventsListener : IVsSolutionEvents, IDisposable
    {
        private IVsSolution solution;
        private uint solutionEventsCookie;
    
        public event Action AfterSolutionLoaded;
        public event Action BeforeSolutionClosed;
    
        public SolutionEventsListener(IServiceProvider serviceProvider)
        {
            InitNullEvents();
    
            solution = serviceProvider.GetService(typeof (SVsSolution)) as IVsSolution;
            if (solution != null)
            {
                solution.AdviseSolutionEvents(this, out solutionEventsCookie);
            }
        }
    
        private void InitNullEvents()
        {
            AfterSolutionLoaded += () => { };
            BeforeSolutionClosed += () => { };
        }
    
        #region IVsSolutionEvents Members
    
        int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
        {
            AfterSolutionLoaded();
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnBeforeCloseSolution(object pUnkReserved)
        {
            BeforeSolutionClosed();
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
        {
            return VSConstants.S_OK;
        }
    
        int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
        {
            return VSConstants.S_OK;
        }
    
        #endregion
    
        #region IDisposable Members
    
        public void Dispose()
        {
            if (solution != null && solutionEventsCookie != 0)
            {
                GC.SuppressFinalize(this);
                solution.UnadviseSolutionEvents(solutionEventsCookie);
                AfterSolutionLoaded = null;
                BeforeSolutionClosed = null;
                solutionEventsCookie = 0;
                solution = null;
            }
        }
    
        #endregion
    }
    

    用法示例:

    DTE2 applicationObject = dte;
    var serviceProvider = new ServiceProvider(applicationObject as IServiceProvider);
    solutionEventsListener = new SolutionEventsListener(serviceProvider);
    solutionEventsListener.AfterSolutionLoaded += () => /* logic here */ ;
    
        2
  •  7
  •   Michal Hosala    9 年前

    虽然这里的解决方案很有创意,但它们要么不能完全解决问题,要么使用起来非常麻烦。你应该 register a message filter as Microsoft recommends .

    为方便起见,在此复制代码(替换 VisualStudio.DTE.10.0 无论你想打开哪个版本的vs),只要注意装饰 Main 方法与 STAThread 属性,没有它,消息筛选将无法工作,并且在原始msdn解决方案中跳过它。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using EnvDTE;
    using EnvDTE80;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                EnvDTE80.DTE2 dte;
                object obj = null;
                System.Type t = null;
    
                // Get the ProgID for DTE 8.0.
                t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0",
                  true);
                // Create a new instance of the IDE.
                obj = System.Activator.CreateInstance(t, true);
                // Cast the instance to DTE2 and assign to variable dte.
                dte = (EnvDTE80.DTE2)obj;
    
                // Register the IOleMessageFilter to handle any threading 
                // errors.
                MessageFilter.Register();
                // Display the Visual Studio IDE.
                dte.MainWindow.Activate();
    
                // =====================================
                // ==Insert your automation code here.==
                // =====================================
                // For example, get a reference to the solution2 object
                // and do what you like with it.
                Solution2 soln = (Solution2)dte.Solution;
                System.Windows.Forms.MessageBox.Show
                  ("Solution count: " + soln.Count);
                // =====================================
    
                // All done, so shut down the IDE...
                dte.Quit();
                // and turn off the IOleMessageFilter.
                MessageFilter.Revoke();
    
            }
        }
    
        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; 
                int hr = CoRegisterMessageFilter(newFilter, out oldFilter);
                if (hr != 0)
                  Marshal.ThrowExceptionForHR(hr);
            }
    
            // 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);
        }
    }
    
        3
  •  0
  •   Community CDub    8 年前

    我对ivssolutionvents技术没有太多的运气(尽管我没有完全按照上面的方法尝试代码)。相反,我创建了一个小函数来帮助我重试调用。我知道这不是特别漂亮,但它是简单的调用和它的工作!

    下面是我对另一个类似问题的答案的链接: https://stackoverflow.com/a/8565990/1106459

    (在调用其他envdte函数以及打开和关闭解决方案时,它还可以帮助处理“服务器忙”错误。)