{"id":11933,"date":"2010-12-23T07:00:00","date_gmt":"2010-12-23T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/12\/23\/what-is-the-correct-way-of-temporarily-changing-a-threads-preferred-ui-language\/"},"modified":"2010-12-23T07:00:00","modified_gmt":"2010-12-23T07:00:00","slug":"what-is-the-correct-way-of-temporarily-changing-a-threads-preferred-ui-language","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20101223-00\/?p=11933","title":{"rendered":"What is the correct way of temporarily changing a thread&#039;s preferred UI language?"},"content":{"rendered":"<p>\nA customer ran into a crashing bug in their shell extension.\nThe shell extension wants to change the thread&#8217;s preferred UI language\ntemporarily, so that it can load its resources from a specific language.\nYou&#8217;d think this would be easy:\n<\/p>\n<pre>\n<i>\/\/ error checking elided for simplicity\n\/\/ There is a bug in this code - read on\n\/\/ Get the current thread preferred UI languages\nULONG cLanguages;\nPZZWSTR pszzPrevLanguages;\nULONG cchPrevLanguages = 0;\nGetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,\n                              &amp;cLanguages, NULL,\n                              &amp;cchPrevLanguages);\npszzPrevLanguages = new WCHAR[cchPrevLanguages];\nGetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,\n                              &amp;cLanguages,\n                              pszzPrevLanguages,\n                              &amp;cchPrevLanguages);\n... change the thread preferred UI languages ...\n... load resources ...\n\/\/ Restore the original thread preferred UI languages\nSetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,\n                              pszzPrevLanguages,\n                              &amp;cLanguages);\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/03\/66660.aspx\">delete[]<\/a> pszzPrevLanguages;<\/i>\n<\/pre>\n<p>\nApproximately ten seconds after this code runs, Explorer crashes\nwith the exception <code>STATUS_CALLBACK_RETURNED_LANG<\/code>\nwhose description is\n&#8220;A threadpool worker thread enter a callback,\nwhich left with preferred languages set.\nThis is unexpected, indicating that the callback missed clearing them.&#8221;\n(Just before Explorer crashes, the message\n&#8220;ThreadPool: callback 77180274(05B67430) returned with preferred languages set&#8221;\nappears on the debugger, which says basically the same thing as the\nstatus code.)\n<\/p>\n<p>\n<b>Exercise<\/b>: Why does it take ten seconds before the crash occurs?\n<\/p>\n<p>\nThis crash is puzzling, because it&#8217;s claiming that the callback didn&#8217;t\nreset the thread preferred languages, but you can see us doing it\nright there in the code when we call\n<code>Set&shy;Thread&shy;Preferred&shy;UI&shy;Languages<\/code>!\nSomebody&#8217;s on crack, but who?\n<\/p>\n<p>\nA closer reading of the error message indicates that the callback\nneeds to &#8220;clear&#8221; the thread preferred languages, not merely reset them\nto their original values, and the documentation for\n<code>Set&shy;Thread&shy;Preferred&shy;UI&shy;Languages<\/code> says,\n&#8220;To clear the thread preferred UI languages list,\nthe application can set this parameter to a null string\nor an empty double null-terminated string.&#8221;\nOkay, so now the question is,\n&#8220;How can I tell, when I call <code>Get&shy;Thread&shy;Preferred&shy;UI&shy;Languages<\/code>,\nthat the list of languages I receive back represents the\n<i>clear<\/i> state as opposed to indicating that some other\ncode called <code>Set&shy;Thread&shy;Preferred&shy;UI&shy;Languages<\/code> before I did?&#8221;\n<\/p>\n<p>\nThe magic is the flag\n<code>MUI_THREAD_LANGUAGES<\/code>.\nIf you pass this flag when you call\n<code>Get&shy;Thread&shy;Preferred&shy;UI&shy;Languages<\/code>,\nit will return a null string if the thread has not customized\nits preferred UI languages, indicating that the way to restore\nthe thread&#8217;s preferred UI language state is to clear it\nrather than setting it.\nFortunately, this lines up nicely with the way you&#8217;re supposed to\nclear the state,\nso at the end of the day there is no special case.\n<\/p>\n<p>\nThe fix to the above code, then, is to make the following simple\nchange:\n<\/p>\n<pre>\n\/\/ error checking elided for simplicity\n\/\/ Get the current thread preferred UI languages\nULONG cLanguages;\nPZZWSTR pszzPrevLanguages;\nULONG cchPrevLanguages = 0;\nGetThreadPreferredUILanguages(MUI_LANGUAGE_NAME <font COLOR=\"red\">|\n                              MUI_THREAD_LANGUAGES<\/font>,\n                              &amp;cLanguages, NULL,\n                              &amp;cchPrevLanguages);\npszzPrevLanguages = new WCHAR[cchPrevLanguages];\nGetThreadPreferredUILanguages(MUI_LANGUAGE_NAME <font COLOR=\"red\">|\n                              MUI_THREAD_LANGUAGES<\/font>,\n                              &amp;cLanguages,\n                              pszzPrevLanguages,\n                              &amp;cchPrevLanguages);\n... change the thread preferred UI languages ...\n... load resources ...\n\/\/ Restore the original thread preferred UI languages\nSetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,\n                              pszzPrevLanguages,\n                              &amp;cLanguages);\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/03\/66660.aspx\">delete[]<\/a> pszzPrevLanguages;\n<\/pre>\n<p>\nAs you might expect,\n<a HREF=\"http:\/\/blogs.msdn.com\/michkap\/archive\/2009\/12\/01\/9930855.aspx\">\nMichael Kaplan has his own thoughts on the\n<code>Set&shy;Thread&shy;Preferred&shy;UI&shy;Languages<\/code> function<\/a>.\nIn fact, he has\n<a HREF=\"http:\/\/www.bing.com\/search?q=site:blogs.msdn.com\/b\/michkap+SetThreadPreferredUILanguages\">\nseveral such thoughts<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer ran into a crashing bug in their shell extension. The shell extension wants to change the thread&#8217;s preferred UI language temporarily, so that it can load its resources from a specific language. You&#8217;d think this would be easy: \/\/ error checking elided for simplicity \/\/ There is a bug in this code &#8211; [&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-11933","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A customer ran into a crashing bug in their shell extension. The shell extension wants to change the thread&#8217;s preferred UI language temporarily, so that it can load its resources from a specific language. You&#8217;d think this would be easy: \/\/ error checking elided for simplicity \/\/ There is a bug in this code &#8211; [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11933","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=11933"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11933\/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=11933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=11933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=11933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}