Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用EnvDTE自动化visualstudio_C#_Visual Studio_Automation - Fatal编程技术网

C# 使用EnvDTE自动化visualstudio

C# 使用EnvDTE自动化visualstudio,c#,visual-studio,automation,C#,Visual Studio,Automation,我正在使用以下代码成功实例化/自动化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

我正在使用以下代码成功实例化/自动化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
注意
线程。Sleep(1000)
调用?如果我没有包括这些,代码会在实例准备就绪之前尝试对其进行bug,我会得到一个异常:

the message filter indicated that the application is busy.

有没有办法轮询此对象是否准备就绪,而不是只等待n秒?

作为此问题的解决方案,您可以注册到一个事件,该事件在解决方案加载完成时发出通知

这是一个示例类,可用于侦听解决方案加载时的事件:

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 */ ;

我在IVSSolutionEvents技术方面运气不太好(尽管我没有像上面那样尝试代码)。相反,我创建了一个小函数来帮助我重试调用。我知道这并不特别漂亮,但它很容易调用,而且很有效

下面是我对另一个类似问题的回答的链接:


(在调用其他EnvDTE函数以及打开和关闭解决方案时,它也有助于解决“服务器忙”错误。)

虽然这里的解决方案很有创意,但它们要么不能完全解决问题,要么使用起来很麻烦。你应该这样做

为方便起见,将代码复制到此处(将VisualStudio.DTE.10.0替换为您想要打开的VS的任何版本),只需注意使用STAThread属性修饰Main方法,没有它消息过滤将无法工作,并且在原始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);
    }
}
使用系统;
使用System.Collections.Generic;
使用系统文本;
使用EnvDTE;
使用EnvDTE80;
使用System.Runtime.InteropServices;
使用System.Windows.Forms;
命名空间控制台应用程序2
{
班级计划
{
[状态线程]
静态void Main(字符串[]参数)
{
EnvDTE80.DTE2-dte;
objectobj=null;
系统类型t=null;
//获取DTE 8.0的ProgID。
t=System.Type.GetTypeFromProgID(“VisualStudio.DTE.10.0”,
正确的);
//创建IDE的新实例。
obj=System.Activator.CreateInstance(t,true);
//将实例强制转换为DTE2并分配给变量dte。
dte=(EnvDTE80.DTE2)obj;
//注册IOleMessageFilter以处理任何线程
//错误。
MessageFilter.Register();
//显示VisualStudioIDE。
dte.MainWindow.Activate();
// =====================================
//==在此处插入您的自动化代码==
// =====================================
//例如,获取对solution2对象的引用
//你喜欢怎么做就怎么做。
Solution2 soln=(Solution2)dte.Solution;
System.Windows.Forms.MessageBox.Show
(“溶液计数:”+soln.count);
// =====================================
//全部完成,所以关闭IDE。。。
dte.Quit();
//并关闭IOleMessageFilter。
MessageFilter.Revoke();
}
}
公共类MessageFilter:IOleMessageFilter
{
//
//包含IOleMessageFilter的类
//线程错误处理函数。
//启动过滤器。
公共静态无效寄存器()
{
IOleMessageFilter newFilter=新消息过滤器();
IOleMessageFilter-oldFilter=null;
int hr=CoRegisterMessageFilter(新过滤器、旧过滤器);
如果(hr!=0)
元帅。通过hr(hr)的例外情况;
}
//完成过滤器,关闭它。
公共静态void Revoke()
{
IOleMessageFilter-oldFilter=null;
CoRegisterMessageFilter(null,out oldFilter);
}
//
//IOleMessageFilter函数。
//处理传入的线程请求。
int IOleMessageFilter.HandleInComingCall(int dwCallType,
System.IntPtr hTaskCaller,int dwTickCount,System.IntPtr
LPEINFO)
{
//返回标志SERVERCALL\u ISHANDLED。
返回0;
}
//线程调用被拒绝,请重试。
int IOleMessageFilter.RetryRejectedCall(System.IntPtr
hTaskCallee、int-dwTickCount、int-dwreturnType)
{
if(dwRejectType==2)
//flag=SERVERCALL\u RETRYLATER。
{
//如果返回>=0&

//这是一个很好的答案,效果很好。顺便说一句,我发现了一个同样有效的作弊方法-在使用Solution.Open打开解决方案后检查Solution.IsOpen属性。这显然是一个阻塞调用,它会强制等待devenv.exe的实例准备就绪。@Dave Swersky,我喜欢这个解决方案。IsOpen,它节省了大量代码:)这也帮助了我在VS11中解决了问题!很好的解决方案,这应该是答案。应该这样做。其他人没有一个对我来说是可靠的。只是一个提示,请注意[StatThread]在顶部,如果没有它,MessageFilter将不会注册,因为MTA不支持它。谢谢!中的重试解决方案或多或少也会这样做,但使用起来要麻烦得多。这使用com中内置的消息筛选器系统来重试调用。我使用了类似的编码UI,我不会等待页面加载,just尝试执行操作直到它工作。但是正如您所说的,长期使用它不那么透明和令人不快。特别是那些COM异常不仅可能在第一次调用中发生,而且以后也可能发生。