2012-05-18 91 views
2

我有一些COM對象,我正在.NET應用程序的線程上創建和運行。線程被標記爲Single Threaded Apartments,並且一切似乎都在起作用。我的理解是,如果這些線程試圖從主線程訪問COM對象,那麼這些對象將在.NET中自動被封送和序列化,所以即使在這種情況下,我也會處理這些事情,所有的事情都是安全和整潔的,儘管也許有點慢。在這種情況下是否需要STA消息循環?

我的問題是,雖然事情似乎工作正常,我是而不是在我創建的STA線程中抽取消息循環。如果可以的話,我寧願避免消息循環,因爲它會導致額外的複雜性(以及可能的效率損失)。

我讀過一堆關於爲什麼消息循環是必要的建議(主要來自非常有幫助的Hans Passant),我的理解是消息循環在線程A上給出了一個位置,其中一些其他線程B可以請求居住在線程A上的COM對象可以被封送和播放。如果這是正確的,那麼只要沒有其他線程從線程A上的COM對象請求任何東西,線程A是否安全不抽取消息循環?或者還有其他情況下消息循環可能會發揮作用嗎?

我在這裏玩火嗎?有沒有一種情況下,你問你是否在玩火,而你不是?

+0

您有任何事件?你是否可以控制事件處理程序來確保它們的重新進入調用不會導致無限遞歸?如果您有消息泵,通常會使用發佈消息來打破此循環。 –

+0

我想我不知道與此相關的問題。什麼會導致一個事件發生在我創建並且沒有其他人正在看的線程中?我正在使用的COM對象?據我所知,他們不會引發任何事件... – user12861

+0

如果您的COM對象的設計包括通知外部世界發生了什麼,那麼您可以實現傳出事件接口,如IConnectionPointContainer。 –

回答

3

STA合同要求抽取消息循環。但是,是的,有可能不抽水。有兩個主要的事情可能出錯:

  • 是對接口方法做出從另一個公寓,其中包括另一個STA線程或MTA線程將無法完成任何呼叫。這看起來像程序中的死鎖,該調用根本不會返回。當心你可以很好地控制你自己的調用,但是你不知道COM組件在做什麼。它可能會啓動一個線程本身。你可以在Debug + Windows + Threads的調試器中看到它。確保你在非託管模式下運行調試器,並且你可以考慮你看到的所有線程。順便說一句,不是特別容易

  • 許多公寓線程COM組件都依賴於有一個消息循環來照顧他們自己的需要。這可能是一個無關的定時器,它不會在沒有循環時打勾。或者它可能在內部進行編組。使用Spy ++並檢查是否有任何隱藏的窗口擁有您的新STA線程,如果您看到其中一個,肯定會遇到麻煩。診斷僅僅是行爲不當的部分。不提高事件是一種常見的事故。

當你對服務器的內部知識不夠了解時,沒有什麼東西可以釘在牆上。一定要測試一下它。

+0

有見地的答案。非常感激。 – user12861

+0

我想我們對'CDO.Message' COM對象有類似的問題。當用戶瘋狂地移動MDI窗口時,它從不從'Send()'返回。可能是因爲它依賴於消息隊列,並且無法向其發佈消息,因爲它的隊列完全不受所有窗口移動的影響,並且實現忘記檢查「PostMessage」失敗。 –

1

COM調用可以在沒有消息循環的情況下編組。

當您的STA線程正在等待某件事情時,它在大多數情況下會自動處理任何掛起的COM調用。

Thread.Join文檔說Blocks the calling thread [...] while continuing to perform standard COM and SendMessage pumping.

同樣的情況,許多所謂代表你的其他功能(CoWaitForMultipleHandles等),如當你的線程正在等待IO。

+0

好點。感謝您的建議。 – user12861

相關問題