2010-12-22 62 views
1

我有一个使用System.Timers.Timer myTimer的Visual Studio加载项。
每N秒myTimer火灾并执行该代码:因为这会从另一个线程调用我有时会收到这些错误之一如何从另一个线程正确访问COM对象DTE2.Windows枚举器?

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线程编组?
还有别的吗?

+0

你是说,每次定时器触发时,代码段从不同的线程调用? – 2010-12-22 14:19:06

+0

是的。它会被调用System.Timers.Timer后台线程,因为它应该。 – 2010-12-22 14:27:35

回答

2

您正在运行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同步计时器