Sunday, December 26, 2010

What is the correct way of temporarily changing a thread's preferred UI language?

A customer ran into a crashing bug in their shell extension. The shell extension wants to change the thread's preferred UI language temporarily, so that it can load its resources from a specific language. You'd think this would be easy:

// error checking elided for simplicity
// There is a bug in this code - read on
// Get the current thread preferred UI languages

ULONG cLanguages;
PZZWSTR pszzPrevLanguages;
ULONG cbPrevLanguages = 0;
GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                             &cLanguages, NULL,
                             &cbPrevLanguages);
pszzPrevLanguages = new WCHAR[cbPrevLanguages];
GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                             &cLanguages,
                             pszzPrevLanguages,
                             &cbPrevLanguages);
... change the thread preferred UI languages ...
... load resources ...
// Restore the original thread preferred UI languages
SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                             pszzPrevLanguages,
                             &cLanguages);
delete[] pszzPrevLanguages;

Approximately ten seconds after this code runs, Explorer crashes with the exception STATUS_CALLBACK_RETURNED_LANG whose description is "A threadpool worker thread enter a callback, which left with preferred languages set. This is unexpected, indicating that the callback missed clearing them." (Just before Explorer crashes, the message "ThreadPool: callback 77180274(05B67430) returned with preferred languages set" appears on the debugger, which says basically the same thing as the status code.)
Exercise: Why does it take ten seconds before the crash occurs?
This crash is puzzling, because it's claiming that the callback didn't reset the thread preferred languages, but you can see us doing it right there in the code when we call Set­Thread­Preferred­UI­Languages! Somebody's on crack, but who?

Read more: The old new thing