Automating Visual Studio with EnvDTE

前端 未结 3 473
栀梦
栀梦 2020-12-13 02:27

I am successfully instantiating/automating Visual Studio using the following code:

System.Type t = System.Type.GetTypeFromProgID(\"VisualStudio.DTE.9.0\");
o         


        
相关标签:
3条回答
  • 2020-12-13 02:49

    I haven't had much luck with the IVSSolutionEvents technique (though I didn't try the code exactly as above). Instead, I created a small function to help me retry the call. I know that isn't particularly beautiful, but it is simple to call and it works!

    Here's a link to my answer to another, similar question: https://stackoverflow.com/a/8565990/1106459

    (It also helps with 'server busy' errors when calling other EnvDTE functions as well as opening and closing the solution.)

    0 讨论(0)
  • 2020-12-13 02:51

    While the solutions here are creative they either won't completely fix the problem or are very cumbersome to use. You should just register a message filter as Microsoft recommends.

    Code copied here for convenience (replace VisualStudio.DTE.10.0 with whatever version of VS you want to open), just pay attention to decorate the Main method with STAThread attribute, message filtering won't work without it and it is skipped in original MSDN solution.

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-13 02:55

    As a solution to this issue you can register to an event that notifies when the solution load is done.

    This is a sample of class that lets you listen to events on solution loading:

    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
    }
    

    Usage example:

    DTE2 applicationObject = dte;
    var serviceProvider = new ServiceProvider(applicationObject as IServiceProvider);
    solutionEventsListener = new SolutionEventsListener(serviceProvider);
    solutionEventsListener.AfterSolutionLoaded += () => /* logic here */ ;
    
    0 讨论(0)
提交回复
热议问题