在进行visual studio自动化时,是否有更好的方法来处理RPC_E_CALL_REJECTEDexception?

这就是我目前正在做的事情:

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

现在我尝试阻止大多数调用EnvDTE的东西,它运行得很好。 我遇到的问题是当我遍历一个集合并对每个项目执行一次操作时。

 foreach(ProjectItem pi in pProject.ProjectItems) { // do something to pi } 

有时我在foreach(ProjectItem pi in pProject.ProjectItems)行中得到exception。 因为如果我得到RPC_E_CALL_REJECTEDexception,我不想启动foreach循环,我不知道我能做什么。

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

首先,汉斯不想这么说,但“如何做到这一点”的最佳答案是“不要这样做”。 如果可能的话,只需使用visual studio的单独实例进行自动化和其他工作。

您需要将问题陈述带出可以处理错误的地方。 您可以使用整数索引而不是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); } } } } 

这个MSDN页面上有一个解决方案: 如何:修复“应用程序忙”和“被调用者拒绝调用”错误 。 它显示了如何实现COM IOleMessageFilter接口,以便它自动重试该调用。

从MSDN推荐的方式我没有太多运气,看起来相当复杂。 我所做的是将重试逻辑(就像在原始post中一样)包装成通用效用函数。 你这样称呼它:

 Projects projects = Utils.call( () => (m_dteSolution.Projects) ); 

‘call’函数调用函数(作为lambda表达式传入)并在必要时重试。 因为它是一个通用函数,您可以使用它来调用任何EnvDTE属性或方法,它将返回正确的类型。

这是函数的代码:

 public static T call(Func 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."); } 

正如最初的post所说,关于EnvDTE集合的foreach可能是一个问题,因为在循环期间存在隐式调用。 所以我使用我的'call'函数来获得Count proprty,然后使用索引进行迭代。 它比foreach更丑陋,但是“召唤”function并没有那么糟糕,因为没有那么多尝试......抓住它们。 例如:

 int numProjects = Utils.call(() => (projects.Count)); for (int i = 1; i <= numProjects; ++i) { Project project = Utils.call(() => (projects.Item(i))); parseProject(project); } 

我使用C#读取/写入Excel时遇到了同样的错误。 奇怪的是,它在调试模式下工作,但在部署的机器上却没有。 我只是将Excel应用程序更改为Visible,并且它可以正常工作,尽管大约慢两倍。 在屏幕上动态打开和关闭Excel应用程序很烦人,但这似乎是Excel最简单的解决方法。

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