{"id":22603,"date":"2008-04-24T10:00:00","date_gmt":"2008-04-24T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/04\/24\/user-interface-code-multi-threaded-apartment-death\/"},"modified":"2021-08-06T07:10:05","modified_gmt":"2021-08-06T14:10:05","slug":"20080424-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080424-00\/?p=22603","title":{"rendered":"User interface code + multi-threaded apartment = death"},"content":{"rendered":"<p>There are single-threaded apartments and multi-threaded apartments. Well, first there were only single-threaded apartments. No wait, let&#8217;s try that again.<\/p>\n<p>First, applications had only one thread. Remember, 16-bit Windows didn&#8217;t have threads. Each process had one of what we today call a thread, end of story. Compatibility with this ancient model still exists today, thanks to <a title=\"the dreaded &quot;main&quot; threading model\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040602-00\/?p=39053\"> the dreaded &#8220;main&#8221; threading model<\/a>. The less said about that threading model the better.<\/p>\n<p>OLE was developed back in the 16-bit days, so it used window messages to pass information between processes, there being no other inter-process communication mechanism available. When you initialized OLE, it created a secret <code>OleMainThreadWnd<\/code> window, and those secret windows were used to communicate between processes (and in Win32, threads). As we learned some time ago, <a title=\"Thread affinity of user interface objects, part 1: Window handles\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20051010-09\/?p=33843\"> window handles have thread affinity<\/a>, which means that these communication windows have thread affinity, which means that OLE has thread affinity. When you made a call to an object that belonged to another apartment, OLE posted a message to the owner thread&#8217;s secret <code>OleMainThreadWnd<\/code> window to tell it what needs to be done, and then it went into a private message loop waiting for the owner thread to do the work and post the results back.<\/p>\n<p>Meanwhile, the OLE team realized that there were really two parts to what they were doing. There was the low-level object and interface management stuff (<code>IUnknown<\/code>, <code>CoMarshalInterThreadInterfaceInStream<\/code>) and the high-level &#8220;object linking and embedding&#8221; stuff (<code>IOleWindow<\/code>, <code>IOleDocument<\/code>) that was the impetus for the OLE effort in the first place. The low-level stuff got broken out into a functional layer known as COM; the high-level stuff kept the name OLE.<\/p>\n<p>Breaking the low-level and high-level stuff apart allowed the low-level stuff to be used by non-GUI programs, which for quite some time were eyeing that object management functionality with some jealousy. As a result, COM grew two personalities, one focused on the GUI customers and another focused on the non-GUI customers. For the non-GUI customers, additional functionality such as multi-threaded apartments were added, and since the customers didn&#8217;t do GUI stuff, multi-threaded apartments weren&#8217;t burdened by the GUI rules. They didn&#8217;t post messages to communicate with each other; they used kernel objects and <code>WaitForSingleObject<\/code>. Everybody wins, right?<\/p>\n<p>Well, yes, everybody wins, but you have to know what side your bread is buttered on. If you initialize a GUI thread as a multi-threaded apartment, you have violated the assumptions under which multi-threaded apartments were invented! Multi-threaded apartments assume that they are not running on GUI threads since they don&#8217;t pump messages; they just use <code>WaitForSingleObject<\/code>. This not only clogs up broadcasts, but it can also deadlock your program. The thread that owns the object might try to send a message to your thread, but your thread can&#8217;t receive the message since it isn&#8217;t pumping messages.<\/p>\n<p>That&#8217;s why COM objects involved with user interface programming nearly always <a title=\"Why do I get E_NOINTERFACE when creating an object that supports that interface?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20041213-00\/?p=37043\"> require a single-threaded apartment<\/a> and <a href=\"http:\/\/web.archive.org\/web\/20060902130739\/http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/12\/06\/275659.aspx#276270\"> why <code>OleInitialize<\/code> initializes a single-threaded apartment<\/a>. Because multi-threaded apartments were designed on the assumption that there was no user interface. <a href=\"http:\/\/web.archive.org\/web\/20060902130739\/http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/12\/06\/275659.aspx#277587\"> Once you&#8217;re doing user interface work, you have to use a single-threaded apartment<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Multi-threaded apartments do not pump messages.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-22603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Multi-threaded apartments do not pump messages.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/22603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=22603"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/22603\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=22603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=22603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=22603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}