4

しばらくの間、Visual Studio 2010のVSIXパッケージで断続的なCOMの問題が発生しました。IDEのCOMベースのイベントシンクの1つをサブスクライブしようとすると、次のエラーがランダムにスローされます。

「基になるRCWから分離されたCOMオブジェクトは使用できません」

再現ケースは、このコードに要約されます(明らかに、VSIXで使用する必要があります)。

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

ネット上で見つけられる同様の問題の多くの説明から、考えられる原因について学びました。これは基本的に、COM相互運用中にRuntimeCallableWrappersとGCが相互作用する方法の副作用です。これは、説明付きの同様の問題へのリンクです。

特に、簡単な回避策を提案しているので、その説明は問題ありません。イベントシンク参照をフィールドに保存して、早期にGCされるのを防ぎます。確かに、多くの人がこの方法で問題を解決したようです。

私を悩ませているのは、私の場合は機能しないということです。私はその理由について本当に困惑しています。ご覧のとおり、念のため、すべてのオブジェクト参照をフィールドに格納しています。それでもエラーは発生します。GC.KeepAlive()ctorの最後で呼び出しを使用してさらに明示的にしようとしましたが、役に立ちませんでした。他にやるべきことはありますか?

解決策がないと、私のVSIXはランダムにロードに失敗し、ユーザーに1つのオプションを残します。VisualStudioを再起動し、次回はロードされないことを願っています。

どんな助けでも本当にありがたいです!

4

2 に答える 2

1

さて、私はあきらめて、頭に浮かんだ唯一のことをしました。これは明らかに競合状態であるため、予測可能な方法で影響を与えることはできないので、負けた場合は再度レースに参加したほうがよいと思いました。

だから私はサブスクリプションラインをwhileループに移動しtryましたcatch..-esそれらと少しの後に再試行しますThread.Sleep()。両方のサブスクリプションが成功したとき、または2秒以上レースに負け続けたときに、ループは終了します。

キッカーは、変更を実装して以来、一度もレースに負けたことはありません。本当の特異なバグ、もし私が見たことがあれば。

とにかく、適切な解決策が私に起こるか、バグが再び現れるまで、私はこれに固執するつもりです。

于 2011-07-18T13:26:12.957 に答える
0

あなたの問題は、イベントハンドラーをすぐに接続しようとしていることだと思います。通常、パッケージ/ツールウィンドウなどのInitializeメソッドでこれらの種類のことを行う必要があります。一般的に言えば、Initializeメソッドが呼び出された後に実行する必要があるサービスを使用する必要がある場合は、絶対にこれを実行しないでください。パッケージのコンストラクターで。

(これは単なる予感です。TestクラスはVSXインターフェースを実装していないため、コンストラクターが呼び出されているときにサンプルからはわかりません)

于 2011-07-15T09:43:59.270 に答える