C# 在执行visual studio自动化时,是否有更好的方法来处理RPC_E_CALL_拒绝的异常?

C# 在执行visual studio自动化时,是否有更好的方法来处理RPC_E_CALL_拒绝的异常?,c#,visual-studio-2010,code-generation,C#,Visual Studio 2010,Code Generation,这就是我目前正在做的: protected void setupProject() { bool lbDone = false; int liCount = 0; while (!lbDone && liCount < pMaxRetries) { try { pProject.ProjectItems.Item("

这就是我目前正在做的:

    protected void setupProject()
    {
        bool lbDone = false;
        int liCount = 0;
        while (!lbDone && liCount < pMaxRetries)
        {
            try
            {
                pProject.ProjectItems.Item("Class1.cs").Delete();
                lbDone = true;
            }
            catch (System.Runtime.InteropServices.COMException loE)
            {
                liCount++;
                if ((uint)loE.ErrorCode == 0x80010001)
                {
                    // RPC_E_CALL_REJECTED - sleep half sec then try again
                    System.Threading.Thread.Sleep(pDelayBetweenRetry);
                }
            }
        }
    }
有时我会在
foreach(ProjectItem pi in pProject.ProjectItems)
行中得到异常。 因为如果我得到RPC_E_CALL_REJECTED异常,我不想启动foreach循环,所以我不确定我能做什么

编辑以回答评论:
是的,我正在从另一个程序中自动化VS,是的,我通常在同一时间将VS用于其他用途。我们有一个应用程序,它读取xml文件,然后根据xml文件生成大约50个VS解决方案。这通常需要几个小时,所以我会在这期间尝试做其他工作。

首先,Hans不想这么说,但“如何做”的最佳答案是“不要做”。如果可能的话,只需在自动化和其他工作中使用单独的VisualStudio实例即可

你需要把你的问题陈述带到你能处理错误的地方。可以通过使用in-integer索引而不是foreach来实现这一点

// You might also need try/catch for this!
int cProjectItems = pProject.ProjectItems.Length;
for(iProjectItem = 0; iProjectItem < cProjectItems; iProjectItem++)
{
   bool bSucceeded = false;
   while(!bSucceeded)
   {
        try{
            ProjectItem pi = pProject.ProjectItems[iProjectItem];
            // do something with pi
            bSucceeded = true;
        }catch (System.Runtime.InteropServices.COMException loE)
        {
            liCount++;
            if ((uint)loE.ErrorCode == 0x80010001)                      {
                // RPC_E_CALL_REJECTED - sleep half sec then try again
                System.Threading.Thread.Sleep(pDelayBetweenRetry);
            }
        }  
   }

}
//您可能还需要try/catch!
int cProjectItems=pProject.ProjectItems.Length;
对于(iProjectItem=0;iProjectItem
此MSDN页面上有一个解决方案:。它展示了如何实现COM IOleMessageFilter接口,以便自动重试调用。

我对MSDN推荐的方法不太了解,而且它看起来相当复杂。我所做的是将重试逻辑封装成一个通用的实用函数,就像在原始帖子中一样。你这样称呼它:

Projects projects = Utils.call( () => (m_dteSolution.Projects) );
“call”函数调用该函数(作为lambda表达式传入),并在必要时重试。因为它是一个泛型函数,所以可以使用它调用任何EnvDTE属性或方法,并且它将返回正确的类型

下面是函数的代码:

public static T call<T>(Func<T> fn)
{
    // We will try to call the function up to 100 times...
    for (int i=0; i<100; ++i)
    {
        try
        {
            // We call the function passed in and return the result...
            return fn();
        }
        catch (COMException)
        {
            // We've caught a COM exception, which is most likely
            // a Server is Busy exception. So we sleep for a short
            // while, and then try again...
            Thread.Sleep(1);
        }
    }
    throw new Exception("'call' failed to call function after 100 tries.");
}
publicstatict调用(Func-fn)
{
//我们将尝试调用该函数最多100次。。。

对于(int i=0;i我在使用C#读取/写入Excel时遇到了相同的错误。奇怪的是,它在调试模式下工作,但在部署的计算机上没有工作。我只是将Excel应用程序更改为可见,并正常工作,尽管速度大约是原来的两倍。在屏幕上动态打开和关闭Excel应用程序很烦人,但这似乎是最简单的我不能为Excel工作

Microsoft.Office.Interop.Excel.Application oApp = new ApplicationClass();
oApp.Visible = true;
oApp.DisplayAlerts = false;

这是一个丑陋的低级错误。这里有什么不寻常的地方吗?您是否从另一个程序而不是加载项自动化VS?您是否确保在运行此程序时VS处于空闲状态?@Hans-我已经用我的回答更新了这个问题。嗯,进程外自动化和“尝试做其他工作”是这里的真正原因。你为什么不开始另一个VS实例?@Hans,为什么不做一个答案?@Ben-因为这不是他要求的。发问者对此有点生气,这是可以理解的。我不得不使用getEnumerator、MoveNext和Current而不是for循环。谢谢,这看起来会有帮助。这对我很有帮助n修复这些类型的错误。您在powershell中如何执行此操作?@Denis我不知道:-)我建议发布一个单独的问题,询问如何在powershell中应用该页面上显示的修复。显然,此修复仅在主应用程序具有[StatThread]时有效属性集,否则仍然会发生错误。谢谢。我必须尝试一下。它看起来比我当前的方法干净多了。请参阅下面的另一个答案-Microsoft官方。它工作得更好,因为不需要检测每个函数调用。但您必须将[StatThread]添加到main,否则它将无法工作。
int numProjects = Utils.call(() => (projects.Count));
for (int i = 1; i <= numProjects; ++i)
{
    Project project = Utils.call(() => (projects.Item(i)));
    parseProject(project);
}
Microsoft.Office.Interop.Excel.Application oApp = new ApplicationClass();
oApp.Visible = true;
oApp.DisplayAlerts = false;