{"id":44463,"date":"2015-03-16T07:00:00","date_gmt":"2015-03-16T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2015\/03\/16\/does-the-clr-really-call-coinitializeex-on-the-first-call-to-unmanaged-code-even-if-you-dont-deal-with-com-at-all-and-are-just-calling-native-code-via-pinvoke\/"},"modified":"2015-03-16T07:00:00","modified_gmt":"2015-03-16T07:00:00","slug":"does-the-clr-really-call-coinitializeex-on-the-first-call-to-unmanaged-code-even-if-you-dont-deal-with-com-at-all-and-are-just-calling-native-code-via-pinvoke","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150316-00\/?p=44463","title":{"rendered":"Does the CLR really call CoInitializeEx on the first call to unmanaged code, even if you don&#039;t deal with COM at all and are just calling native code via p\/invoke?"},"content":{"rendered":"<p>\nSome time ago,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/08\/11\/10548975.aspx\">\nI called out<\/a>\nthis part of the documentation\nregarding\nmanaged and unmanaged threading:\n<\/p><\/blockquote>\n<blockquote CLASS=\"q\"><p>\nOn the first call to unmanaged code,\nthe runtime calls <b>Co&shy;Initialize&shy;Ex<\/b>\nto initialize the COM apartment as either an MTA or an STA apartment.\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/5s8ee185%28v=vs.71%29.aspx\">\nYou can control the type of apartment created<\/a>\nby setting the\nSystem.Threading.ApartmentState property on the thread to <b>MTA<\/b>,\n<b>STA<\/b>, or <b>Unknown<\/b>.\n<\/p><\/blockquote>\n<p><p>\nCommenter T asks,\n&#8220;<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/08\/11\/10548975.aspx#10549183\">Does it do this even if you don&#8217;t deal with COM at all\nand call native code through a P\/Invoke<\/a>?&#8221;\n<\/p>\n<p>\nWell, the documentation says it does, and we can confirm with an experiment:\n<\/p>\n<pre>\nusing System.Runtime.InteropServices;\nclass Program\n{\n public static void Main()\n {\n  var thread = new System.Threading.Thread(\n    () =&gt; {\n   System.Console.WriteLine(\"about to p\/invoke\");\n   GetTickCount();\n  });\n  thread.Start();\n  thread.Join();\n }\n [DllImport(\"kernel32.dll\")]\n extern static uint GetTickCount();\n}\n<\/pre>\n<p>\nRun this program with a breakpoint on\n<code>Co&shy;InitializeEx<\/code>.\n<\/p>\n<p>\nFirst breakpoint is hit with this stack:\n<\/p>\n<pre>\nrax=00007ffebc529b70 rbx=00000000007c6100 rcx=0000000000000000\nrdx=0000000000000000 rsi=0000000000000001 rdi=0000000000000002\nrip=00007ffebc529b70 rsp=000000000056f038 rbp=000000000056f0b0\n r8=0000000000000001  r9=0000000000000000 r10=0000000000000000\nr11=0000000000000037 r12=0000000000004000 r13=0000000000000001\nr14=0000000000000001 r15=0000000000000001\ncombase!CoInitializeEx\nclr!Thread::SetApartment\nclr!SystemDomain::SetThreadAptState\nclr!SystemDomain::ExecuteMainMethod\nclr!ExecuteEXE\nclr!_CorExeMainInternal\nclr!CorExeMain\nmscoreei!CorExeMain\nMSCOREE!CorExeMain_Exported\nKERNEL32!BaseThreadInitThunk\nntdll!RtlUserThreadStart\n<\/pre>\n<p>\nThis call is initializing the main thread of the process.\nThe flags passed to this first call to\n<code>Co&shy;Initialize&shy;Ex<\/code> are 0,\nwhich means that the default threading model of\n<code>COINIT_MULTI&shy;THREADED<\/code> is used.\n<\/p>\n<p>\nThe next time the breakpoint hits is with this stack:\n<\/p>\n<pre>\nrax=00000000ffffffff rbx=00000000007d1180 rcx=0000000000000000\nrdx=0000000000000000 rsi=0000000000000001 rdi=00000000007d1180\nrip=00007ffebc529b70 rsp=000000001a6af9a8 rbp=000000001a6afa20\n r8=000000001a6af948  r9=0000000000000000 r10=00000000007f0340\nr11=00000000007f0328 r12=0000000000004000 r13=0000000000000000\nr14=0000000000000000 r15=0000000000000000\ncombase!CoInitializeEx\nclr!Thread::SetApartment\nclr!Thread::DoExtraWorkForFinalizer\nclr!WKS::GCHeap::FinalizerThreadWorker\nclr!ManagedThreadBase_DispatchInner\nclr!ManagedThreadBase_DispatchMiddle\nclr!ManagedThreadBase_DispatchOuter\nclr!WKS::GCHeap::FinalizerThreadStart\nclr!Thread::intermediateThreadProc\nKERNEL32!BaseThreadInitThunk\nntdll!RtlUserThreadStart\n<\/pre>\n<p>\nFrom the name <code>Finalizer&shy;Thread&shy;Start<\/code>,\nthis is clearly the finalizer thread.&sup1;\n<\/p>\n<p>\nNext.\n<\/p>\n<pre>\nrax=00000000ffffffff rbx=000000000039eb20 rcx=0000000000000000\nrdx=0000000000000000 rsi=0000000000000001 rdi=0000000000000000\nrip=00007ffebc529b70 rsp=000000001a5af3d8 rbp=000000001a5af450\n r8=0000000000000000  r9=000000001a5af3f0 r10=0000000000000000\nr11=0000000000000286 r12=0000000000004000 r13=0000000000000000\nr14=0000000000000000 r15=0000000000000000\ncombase!CoInitializeEx\nclr!Thread::SetApartment\nclr!Thread::PrepareApartmentAndContext\nclr!Thread::HasStarted\nclr!ThreadNative::KickOffThread\nclr!Thread::intermediateThreadProc\nKERNEL32!BaseThreadInitThunk\nntdll!RtlUserThreadStart\n<\/pre>\n<p>\nOkay, this looks like it&#8217;s\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/11\/12\/10466467.aspx\">\nkicking off<\/a> a new thread.\nI inferred this from the presence on the stack\nof the function which is deviously named\n<code>Kick&shy;Off&shy;Thread<\/code>.\n<\/p>\n<p>\nAnd the flags passed to this call to\n<code>Co&shy;Initialize&shy;Ex<\/code> are 0,\nwhich once again means that it defaults to MTA.\n<\/p>\n<p>\nThere, we have confirmed experimentally that, at least in this case,\nthe implementation matches the documentation.\n<\/p>\n<p>\nThat the implementation behaves this way is not surprising.\nAfter all, the CLR does not have insight into the\n<code>Get&shy;Tick&shy;Count<\/code> function.\nIt does not know <i>a priori<\/i> whether that function will\ncreate any COM objects.\nAfter all, we could have been p\/invoking to\n<code>SHGet&shy;Desktop&shy;Folder<\/code>, which does use COM.\nGiven that the CLR cannot tell whether a native function is going\nto use COM or not, it has to initialize COM just in case.\n<\/p>\n<p>\n&sup1;\nOr somebody who is trying to mislead us into thinking that it is\nthe finalizer thread.\nI tend to discount this theory because\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2014\/01\/31\/10495737.aspx\">\nas a general rule, code is not intentionally written to be\nimpossible to understand<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Some time ago, I called out this part of the documentation regarding managed and unmanaged threading: On the first call to unmanaged code, the runtime calls Co&shy;Initialize&shy;Ex to initialize the COM apartment as either an MTA or an STA apartment. You can control the type of apartment created by setting the System.Threading.ApartmentState property on the [&hellip;]<\/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-44463","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Some time ago, I called out this part of the documentation regarding managed and unmanaged threading: On the first call to unmanaged code, the runtime calls Co&shy;Initialize&shy;Ex to initialize the COM apartment as either an MTA or an STA apartment. You can control the type of apartment created by setting the System.Threading.ApartmentState property on the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/44463","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=44463"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/44463\/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=44463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=44463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=44463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}