none
SetThreadLocale no longer changes GUI language in Vista -

    Question

  • I have an MFC app that includes 10 languages. If you run the app on a Windows OS, the GUI defaults to the base language of the OS. This also appears to be true in Vista if you install a Language Pack on top of Vista English and switch the OS GUI to that language (i.e. on Vista English, if you switch the Vista GUI to Italian, my app defaults to Italian).

    However, starting in Win2k and also in WinXP, I was able to use calls to SetLocale in each thread to set my GUI language to (almost) any language that uses a similar code page (e.g. on XP English I could switch my app's GUI to Italian, French, German, Dutch, etc. but not Chinese). All calls after that point would return dialogs, strings, accelerators etc. for that language. My code does not really have to handle languages other than by calling SetLocale - MFC dialog classes and CString::LoadString et al. get the correct language resources for me.

    I have been testing my app in Vista Ultimate running within Virtual PC. My calls to SetLocale "succeed" (i.e. no error return value), but the GUI language of my app and all CString::LoadString calls still return English, even if I am sure to run the app as Administrator.

    Does anyone have any suggestions on how to fix or work around this? I'm not sure our Marketing folks will tolerate forcing the users to buy Ultimate just to be able to switch the GUI language.

    Saturday, April 14, 2007 9:22 PM

Answers

  • Dynamic linking IS the answer, I am not sure why there is so much resistance to that.

     

    But if you install the Vista Windows SDK then you will get the updated kernel32.lib.

     

    Michael

    Friday, April 27, 2007 4:13 PM

All replies

  • According to "Guide to Windows Vista Multilingual User Interface" Updated: March 07, 2007:

    "Licensing requirements state that versions of the Windows Vista operating system can include only a single language, with the exception of the Windows Vista™ Ultimate and the Windows Vista™ Enterprise editions. For editions other than Windows Vista Ultimate and Windows Vista Enterprise, Windows will automatically remove all non-default languages from the computer after the end user completes the Windows Welcome."

    Tuesday, April 17, 2007 4:33 PM
  • Yes, I had seen that statement in the "Guide to Windows Vista Multilingual User Interface"

    http://technet2.microsoft.com/WindowsVista/en/library/85e289ca-9fd8-4963-b06a-5ecc457006c71033.mspx?mfr=true


    But that does not really answer my question. The article above is about Vista removing Language Packs if they are not allowed, and says nothing about support for SetLocale (which does not rely on Language Packs).

    Furthermore, I am running Vista Ultimate, which DOES support multiple Language Packs.

    Does anyone know why SetLocale does not work in Vista?

    Tuesday, April 17, 2007 5:10 PM
  • How are you calling setlocale? Are you using LC_<string value>?
    Wednesday, April 18, 2007 8:07 PM
  • I am using the following:

            WORD LangID = MAKELANGID(Language, SubLanguage);
            bRetval = SetThreadLocale(MAKELCID(LangID, SORT_DEFAULT));


    where Language is e.g. LANG_CHINESE = 4, and SubLanguage is almost always SUBLANG_DEFAULT = 1. This worked fine in 2000 and XP, and it allowed my users to change the app language on the fly without rebooting or logging off. The function still returns a success result but appears to be ignored.

    I noticed that if you load a Language Pack in Vista Ultimate and switch the Vista GUI Language in Regional And Language Options | Keyboards and Languages | Display Language, my app follows the language of Vista.

    I also noticed that the Regional And Language Options dialog has a new Administrative tab that lets you set the System Locale. Oddly enough this has no effect on my app.

    Any suggestions?
    Wednesday, April 18, 2007 8:35 PM
  • Directly from MSDN:

     

    "...Windows 2000/XP: Do not use SetThreadLocale to select a user interface language. To select the resource that is defined in the .rc file with a LANGUAGE statement, the application must use the Win32 FindResourceEx function

     

    Windows Vista and later: Do not use SetThreadLocale to select a user interface language. The resource loader selects the resource that is defined in the .rc file with a LANGUAGE statement, or the application can use FindResourceEx..."

     

    Try using instead:

       SetThreadUILanguage

        http://msdn2.microsoft.com/en-us/library/ms776236.aspx

     

    Which is from the Multilingual User Interface Functions

    Thursday, April 19, 2007 5:53 PM
  • I tried adding a call to SetThreadUILanguage but none of the Studio 2005 include files list it. So I added a function declaration and even linked in Kernel32.lib as the documentation suggests, but the linker cannot find the function. So the documentation appears to describe a function that does not exist. Maybe I'm missing something?

    Note that the documentation basically says that in WinXP SetThreadUILanguage doesn't work (the langid parameter must be set to zero). That doesn't help much. And it doesn't exist at all on Win2k.

    Note also that the documentation for SetThreadLocale describes exactly the effect I want:

    The SetThreadLocale function affects the selection of resources that are defined in the .rc file with a LANGUAGE statement. This affects such Win32 functions as CreateDialog, DialogBox, LoadMenu. LoadString, and FindResource.

    But then the documentation goes on to say "Do not use SetThreadLocale to select a UI language". But that is EXACTLY what the function does! It then suggests using FindResourceEx to load all your resources, which seems like a lot of overhead to do what USED to work automatically via SetThreadLocale. It's like saying "here is a SetThreadLocale function, but don't use it." What was it intended for if not this? (Sorry for the rant - this might cause me several weeks of work if I can't find a workaround.)

    Can you confirm that SetThreadLocale no longer changes the thread's locale in Vista?

    Can you suggest a way to get SetThreadUILanguage to compile in Studio 2005 / C++?

    Another tidbit of info: SetThreadLocale "succeeds" in Vista, and calling GetThreadLocale afterwards returns the value I just set. But the dialogs and strings returned by MFC remain English when running on English Vista. Is this an MFC problem?

    Thanks
    Thursday, April 19, 2007 7:43 PM
  • Offhand I don't have another answer for this right now. If you are a partner and would like to create an incident for this I'd be happy to do so.

     

    Otherwise from all the bugs I've seen in the database it says you should kernel32!SetThreadUILanguage() on Vista. So your call may need to be OS dependent.

     

     As for as to where the function disappeared to on your Vista box..

     

    I used Dependancywalker to see that the function exists on my box in Kernel32.dll

     

    SetThreadUILanguage - Entry point is 0x000463C1

    Thursday, April 19, 2007 11:23 PM
  • Yes, I expect to make my function call OS dependent. I already test the OS and bypass SetThreadLocale if running inWin98, so this would be easy to extend to test for Vista.

    I am running Studio 2005 SP1 in WinXP Pro and I just applied the Update to SP1 for Vista (VS80sp1-KB932232-X86-ENU.exe) and still the linker does not find the function SetThreadUILanguage. It is not listed in any of the VisiC++ include files. Do I need some special patch to Studio 2005 to be able to compile a program using this function on a WinXP box? I certainly understand that the function might not exist in WinXP versions of Kernel32.dll (and certainly not on Win2k), but if Studio 2005 supports Vista I would think I should at least be able to compile the program with the new function.

    Any suggestions?

    Friday, April 20, 2007 5:12 PM
  • I suppose you've checked the Kernel32 to see if the function does exist on your build of XP. You might want to use the SetThreadLocale in XP and the SetThreadUILanguage in Vista.
    Tuesday, April 24, 2007 6:11 PM
  • That is indeed my plan - to use one function when running in XP and the other when running in Vista. And indeed my copy of c:\windows\system32\kernel32.dll does include SetThreadUILanguage.

    But as I said above I cannot do that if I cannot COMPILE the program. The Kernel32.lib that comes with Studio 2005 does not include this function, so the linker refuses to proceed.

    Any suggestions? Has Kernel32.lib been updated to include this function?

    Thanks for your patience.
    Tuesday, April 24, 2007 6:23 PM
  • One more question pass :-)

     

    On XP your stuff is working, on VISTA your Kernel32.lib is missing the export for SetThreadUILanguage?

    Tuesday, April 24, 2007 6:35 PM
  • I cannot get the program to compile / link, so it does not work on either OS. My development computer is running XP, and the copy of kernel32.lib that ships with Studio 2005 does not include this function (hence the failure to link). My program is statically linked, so kernel32.lib is what matters (not kernel32.dll in system32). And I don't have the option of switching to dynamic linking.

    Do you know where I can get a valid copy of kernel32.lib that includes the SetThreadUILanguage function?

    Tuesday, April 24, 2007 6:46 PM
  • Are you compiling only on XP?
    Tuesday, April 24, 2007 6:48 PM
  • No, I need to be able to compile the program when my development box is running any OS, whether it is WinXP, Win2k or Vista. The kernel32.lib file is incomplete and not fully valid. Whether my program would actually RUN if I invoke the SetThreadUILanguage function on an OS that doesn't support it would indeed be my problem, but I already know how to work around that.

    What I need is a valid copy of kernel32.lib that correctly contains the SetThreadUILanguage function so that I can compile and statically link my program when running Studio 2005 on WinXP. It has never been a requirement that you had to compile programs for Vista by running Studio on a box with Vista. It should compile just fine on an XP box. But it doesn't. So that's a bug in my eyes.

    Do you know where to get a valid copy of kernel32.lib? Do you have any contacts with the Studio developers?
    Tuesday, April 24, 2007 7:10 PM
  • Thanks. I have already posted it as a bug, but I'll try the Studio forums too.
    Tuesday, April 24, 2007 9:42 PM
  • For more info, please visit the link:
    http://msdn2.microsoft.com/en-us/library/ms776235.aspx

     

    Wednesday, April 25, 2007 6:35 AM
  • That is a very interesting solution, although it would require a significant re-architecting of my app. It also appears to only support Vista, and I am required to support Win2k and WinXP as well.

    Do you know whether SetThreadLocale has been disabled in Vista?

    Wednesday, April 25, 2007 1:19 PM
  • Hi,

    this could be a stupid question but..

    Do you have the Vista Platform SDK installed? I have found out that several definitions require the SDK installed.

    If it is installed, there is another possible problem:

    The Vista SDK is a bit picky about the _WIN32_WINNT (and related) #defines. I had to modify this value in a few of my libraries to 0x500 or later to get code compiled and linked that compiled and linked just fine without the vista SDK.

     

     

    Thursday, April 26, 2007 9:45 AM
  • I just tried loading the Vista SDK yesterday and that solved the problem of being able to call SetThreadUILanguage and link statically. Using SetThreadLocale compiles / links fine with or without the Vista SDK, but so far seems to have no effect when run in Vista. It "successfully" sets the locale, and GetThreadLocale returns the value I set, but the MFC libraries do not return resources for the new locale - only SetThreadUILanguage seems to have the desired effect.

    I still really want to see something in print that officially says SetThreadLocale no longer works in Vista. (Yeah, I'm a whiner.) I realize that the documentation for SetThreadLocale has said for years "do not use this function to change the GUI language", but that just seems silly given that's EXACTLY what the function does. To top things off their proposed "correct" solution is to use FindResourceEx, which totally negates the whole point of using MFC to handle that for you. What's next? Writing my own WinProc and WinMain like back in the good 'ol days?
     I don't understand why they would change the implementation of this function without explicitly saying "this won't have any effect in Vista".

    Programming should not have to be a "try something different until you figure out the hard way what works and what doesn't, in contradiction of the documentation."
    Thursday, April 26, 2007 1:17 PM
  • Dynamic linking IS the answer, I am not sure why there is so much resistance to that.

     

    But if you install the Vista Windows SDK then you will get the updated kernel32.lib.

     

    Michael

    Friday, April 27, 2007 4:13 PM
  • Hi Bill.

     

    I am (as far as I know) the first person to start cvomplaining about how SetThreadLocale started to stop working, a problem I noticed in Windows 2000, some time around Beta 2.

     

    The design (which fundamentally tried to change both resource loading and locale settings) was always quite flawed, and with the resource model changing to support MUI, this function simply was unable to do the job.

     

    It has become progressively worse through Windows XP and Server 2003 until finally in Vista the effort was made to create as new function to do the RIGHT job.

     

    I personally removed some calls to GetThreadLocale in Windows Vista, and helped recommend the removal of many others, given all of its problems. This work will continue with future versions of Windows as well as the entire notion of the thread locale has officially been a bad idea since 1998.

     

    As we approach the 10-year anniversary of this milestone, I would hope that asny developer considering how to impact resource loading would reject the SetThreadLocale function as an effective way to affect either resource loading or other locale behavior.

    Friday, April 27, 2007 4:24 PM
  • So what method would you recommend that I use to cause my resource loading to select a different language? I have to say that SetThreadLocale was a very low impact and quick way to modify my code to support changing my app's GUI language on the fly. Just about every other solution seems to require a huge re-architecting job.

    For example making my app MUI compatible via GetFileMUIPath et al. (see MUI Application Sample at http://msdn2.microsoft.com/en-us/library/ms776235.aspx) would be a huge change. And this solution can ONLY be compiled with the Vista SDK and can ONLY run on Vista. But I have to support Win98 (not much, but still....), Win2k, WinXP.

    So far the best option I've seen is to change the Vista OS GUI language, which my app seems to respect and it selects the correct language. I can live without changing my app language on the fly, but it would be nice if I could find a solution that wouldn't take weeks to implement just to get back to what used to work fine in XP (I would be shot at dawn.....).
    Friday, April 27, 2007 4:36 PM
  • Hmmm.... it did not work so well, even in XP -- the newsgroups and Microsoft support incidents are filled with cases that it failed.

     

    If it works well enough for you in those OS versions, then fine. You have a simple solution:

     

    1) Do a version check.

     

        A) When it is Vista, use the new Set UI language functionality (e.g. SetThreadUILanguage, et. al.) to change the language, using GetProcAddress to get to the functions.

     

        B) When running downlevel, do whatever you did before (Win98 did not support SetThreadLocale).

     

    This will take neither weeks nor to be honest more than a day to code up....

    Friday, April 27, 2007 5:03 PM
  • That's pretty much what I had planned to try. A brief test app seemed to cause the resource loader to indeed return the newly selected language, but the main dialog window didn't change (I know I'm forgetting something, so no big deal).

    Thanks for the suggestion.

    I guess another part of the answer to "why doesn't SetThreadLocale work" is that the OS seems to have clamped down on users changing the locale. The Regional and Language Options dialog Advanced tab has a place to set the System Locale for non-Unicode apps, and it requires Admin privileges. (See my posting at http://forums.microsoft.com/MSDN/AddPost.aspx?PostID=1531458&SiteID=1 about Chinese MBCS problems, which refers to http://windowshelp.microsoft.com/Windows/en-US/Help/63fe39ac-f098-4322-ba60-8210af13464d1033.mspx describing this aspect of the dialog.)

    This kind of implies to me that SetThreadLocale should explicitly say "you are not allowed to do this anymore. Period." I could handle that - I just hate having to dig to find out the hard way.

    Friday, April 27, 2007 5:18 PM
  • Well, note that none of the thread UI language settings require administrative permissions to run -- they are user settings, so user can modify them.

     

    Non-Unicode apps have their own rules here, since they need a mastching default system locale or they will not display text right. But these days if you aren't Unicode, your app is inadequate for just about every language outside of English....

    Saturday, April 28, 2007 9:56 PM
  • Nice article. thanks a lot for the information.

    I'm seeing similar issue in vista and 2008 OS, as per your suggestions, i updated code in my application like as follows even though it's NOT working. please let me know your comments on following snippet.

    void SetThreadLocalSettings(LANGID Language, LANGID SubLanguage)
    {

    OSVERSIONINFOEX osver;
    ZeroMemory(&osver, sizeof(osver));
    osver.dwOSVersionInfoSize = sizeof(osver);

    GetVersionEx((OSVERSIONINFO *)&osver);


    if ( (osver.dwMajorVersion > 5)) 
    {
    typedef LANGID (WINAPI *FMSetThreadUILanguage)(LANGID wReserved);
    FMSetThreadUILanguage fnPtr = (FMSetThreadUILanguage)GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"SetThreadUILanguage"); 
    if(fnPtr)
    { // vista or 2008
    LANGID langid = (*fnPtr)(Language);
    }
    else
    { // fallback for XP
    ::SetThreadLocale(MAKELCID(MAKELANGID(Language, SubLanguage), SORT_DEFAULT));
    }
    }
    else
    { //XP
    ::SetThreadLocale(MAKELCID(MAKELANGID(Language, SubLanguage), SORT_DEFAULT));
    }
    }

    Here i'm able to get the proper language code and after that my application is crashing and we uses the MFC and Unicode libraries.

    Please give your valuable suggestions on this. 


    Thanks & Regards,
    Murali Choudari.

    Friday, October 22, 2010 1:25 PM