しばらくの間、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を再起動し、次回はロードされないことを願っています。
どんな助けでも本当にありがたいです!