Как правильно получить доступ к COM-объекту DTE2.Windows enumerator из другого потока? - PullRequest
1 голос
/ 22 декабря 2010

У меня есть надстройка Visual Studio, которая использует System.Timers.Timer myTimer.
Каждые N секунд myTimer запускает и выполняет этот код:

foreach(Window window in DTE2.Windows)
{
    TextDocument td = window.Document.Object("TextDocument") as TextDocument;
    // do stuff with td...  
}

Поскольку это вызывается из другого потока, я иногдаполучить одну из этих ошибок:

  • QI для IEnumVARIANT не удалось на неуправляемом сервере.
    в EnvDTE.Windows.GetEnumerator ()
    в строке foreach (окно окнав DTE2.Windows)

  • Приложение вызвало интерфейс, который был назначен для другого потока.(Исключение из HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
    в EnvDTE.Window.get_Document ()
    в строке TextDocument td = window.Document.Object ("TextDocument") как TextDocument;

Как правильно обращаться к этому перечислителю в другом потоке, так как задействованы COM-объекты?
Какой-то маршаллинг COM-потока?
Что-то еще?

1 Ответ

2 голосов
/ 22 декабря 2010

Вы столкнулись с COM, пытаясь защитить объектную модель, которая не является поточно-ориентированной.Таких сложных объектных моделей, как интерфейс автоматизации Visual Studio, никогда не было.COM пытается сделать это, автоматически направляя вызов, выполненный в фоновом потоке, в поток STA.Это делается через прокси-сервер, реплику исходного COM-интерфейса, который имеет все те же методы, но перенаправляет все вызовы, сделанные на них, в интерфейс, который выполняет методы в потоке STA., он может быть использован только в потоке, который его создал.DTE2 ваша проблема здесь.Если какой-либо код расширяемости выполнялся ранее и создавал экземпляр интерфейса DTE2, то DTE2 будет «реальным» указателем интерфейса, а не прокси.Если вы затем используете его в рабочем потоке, как тот, который Timer создает для своего события Elapsed, тогда вы получите бомбу.Это работает и наоборот: если DTE2 сначала создается вашим кодом, тогда вы бомбите любой код расширяемости, который выполняется обычным способом.

Возможно, DTE2.DTE решит вашу проблему, не уверен.В конечном итоге это ничего не исправляет, код всегда будет выполняться в потоке Visual Studio STA в любом случае.Только не используйте System.Timer.Timer, используйте синхронный таймер, такой как System.Windows.Forms.Timer

...