Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.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# VSIX中一个严重的COM互操作问题_C#_Visual Studio_Com Interop_Vsix - Fatal编程技术网

C# VSIX中一个严重的COM互操作问题

C# VSIX中一个严重的COM互操作问题,c#,visual-studio,com-interop,vsix,C#,Visual Studio,Com Interop,Vsix,一段时间以来,我在VisualStudio2010的VSIX包中发现了间歇性COM问题。尝试订阅IDE的一个基于COM的事件接收器会随机引发以下错误: “无法使用与其基础RCW分离的COM对象” repro案例归结为以下代码(显然必须在VSIX中使用): 我从网上对类似问题的大量描述中了解到了一个可能的原因。这基本上是运行时可调用包装器和GC在COM互操作期间交互方式的副作用。下面是一个类似问题的答案,并给出了完整的解释 我同意这种解释,特别是因为它建议了一种简单的解决方法——将事件接收器引用存

一段时间以来,我在VisualStudio2010的VSIX包中发现了间歇性COM问题。尝试订阅IDE的一个基于COM的事件接收器会随机引发以下错误:

“无法使用与其基础RCW分离的COM对象”

repro案例归结为以下代码(显然必须在VSIX中使用):

我从网上对类似问题的大量描述中了解到了一个可能的原因。这基本上是运行时可调用包装器和GC在COM互操作期间交互方式的副作用。下面是一个类似问题的答案,并给出了完整的解释

我同意这种解释,特别是因为它建议了一种简单的解决方法——将事件接收器引用存储在字段中,以防止它被过早地GC’ed。事实上,许多人似乎已经通过这种方式解决了他们的问题

困扰我的是它在我的情况下不起作用。我真不明白为什么。您可以清楚地看到,作为预防措施,我已经在字段中存储了所有对象引用。然而,错误仍然存在。我尝试在ctor的末尾使用
GC.KeepAlive()
调用更显式,但没有效果。还有别的事要做吗

如果没有解决方案,我的VSIX随机加载失败,用户只有一个选择:重新启动Visual Studio,希望下次不会发生这种情况


我们真诚地感谢您的帮助

我怀疑您的问题实际上是您试图过早地连接事件处理程序。通常,您需要在包/工具窗口/任何东西的方法中执行这些操作-一般来说,如果您需要使用在调用Initialize方法后需要执行的服务,则绝对不要在包的构造函数中执行这些操作


(这只是一种预感-您的
测试
类没有实现任何VSX接口,因此我无法从您的示例中看出何时调用构造函数)

好吧,我放弃了,只是做了我唯一想到的事情。我想,由于这显然是一个比赛条件,我无法以可预测的方式影响,如果我输了,我还不如重新参加比赛

因此,我将订阅行移动到一个
while
循环中,该循环
try
catch
-在执行一点
Thread.Sleep()之后重试。当两个订阅都成功时,或者当我连续输掉比赛超过2秒时,循环就会退出

关键是,自从我实施了这项改变以来,我从未输过一次比赛。一只真正的海森堡,如果我见过的话


无论如何,我会坚持这样做,直到找到合适的解决方案,或者错误再次出现。

在调用base.Initialize()之后,我正在从包的Initialize内部调用Test的构造函数。package类本身派生自Microsoft.VisualStudio.Project.ProjectPackage。所以,至少在这方面,一切似乎都很顺利。谢谢你告诉我你的解决方案。不完全是我想听的,但如果我找不到其他的东西,那就只好这样了。
using System;
using EnvDTE;
using EnvDTE80;

class Test
{
    private readonly Events _events;
    private readonly Events2 _events2;
    private readonly BuildEvents _buildEvents;
    private readonly ProjectItemsEvents _projectItemsEvents;

    public Test(IServiceProvider provider)
    {
        var dte = (DTE)provider.GetService(typeof(DTE));
        var dte2 = (DTE2)dte;

        // Store all references in fields as a GC precaution.
        _events = dte.Events;
        _events2 = (Events2)dte2.Events;
        _buildEvents = _events.BuildEvents;
        _projectItemsEvents = _events2.ProjectItemsEvents;

        // Proceed to subscribe to event sinks.
        _buildEvents.OnBuildBegin += BuildBeginHandler; // BOOM!
        _projectItemsEvents.ItemAdded += ItemAddedHandler;
    }

    private void ItemAddedHandler(ProjectItem projectItem) { }

    private void BuildBeginHandler(vsBuildScope scope, vsBuildAction action) { }
}