Cutting the cord, revisited -- and documenting how to get the job done!

by Michael S. Kaplan, published on 2007/12/01 19:31 -05:00, original URI:

Over in the Suggestion Box, John Daintree asks:

Could you please follow up the missing functionality of LoadKeyboardLayout() on Windows Vista? I need to be able to load a specific layout for my application as the app starts.

The missing functionality in question is I believe what I described in Cutting the cord while someone else is shoring it up, which is the ability to load IMEs via a call to LoadKeyboardLayout, partially ameliorated by Office 2007 which adds three of them back:

  • Microsoft Pinyin IME 2007 for Simplified Chinese (KLID E0200804)
  • Microsoft Office IME 2007 for Korean (KLID E0200412)
  • Microsoft Office IME 2007 for Japanese (KLID E0200411)
  • Perhaps "add" is the wrong word since these three values don't exist in any prior version, but they do enable the LoadKeyboardLayout-style bootstrapping technique of loading up the appropriate IME....

    At the time, I suggested:

    (The question itself is one I'll provide some answers for another time -- since it involves for the IME a TSF sample!)

    However, when I looked into creating such a sample, I noticed a topic in MSDN entitled Language Bar, which states:

    An application cannot add items to the language bar; only a text service can add items to the language bar. An application can affect how certain items on the language bar appear.

    This is a clear departure from prior versions, since in the TSF world you have to have the IME "installed" to the Language Bar to make use of it, but the decision to place it in the Language Bar has clearly been moved to be considered a user decision, not an application one (back in the world of doing this via LoadKeyboardLayout it was obviously an easy application decision)....

    With that said, I ma curious about a situation where a user

    And interestingly, switching to an installed IME is an easy operation via an ActivateKeyboardLayout call, and the ability to add a keyboard layout or TSF TIP using the same technique as Regional Options does has now been documented, by calling the InstallLayoutOrTip function in input.dll.

    The latter function call provides the way to directly install or uninstall any keyboard layout or TIP from the Language Bar (it is also the same function that is used by MSKLC 1.4 to support the automatic install and uninstall of keyboard layouts in the automatically provided setup!).

    The function takes the same strings as Regional Options unattend does (discussed previously in On building a list of keyboards).

    The technique only works in Vista, Server 2008, and above (the function does not exist downlevel), though this is the only place that the LoadKeyboardLayout method is broken, so it is at least a step in right direction in terms of keeping functionality working....

    And I will be talking about some of the rest of these now-documented functions (now listed here along with previously documented TSF functions!) inupvoming blogs.


    This post brought to you by(U+0c8a, aka KANNADA LETTER UU)

    John Daintree on 15 Jan 2008 11:17 AM:

    Hi Michael,

    Interesting stuff, thanks for talking through this.  What I'm seeing on Vista is that if I call ActivateKeyboardLayout (or LoadKeyboardLayout), to activate an already installed layout, "at some time later" the keyboard reverts back to the default.

    What seems to happen is that next time I get to the Message Queue something in msctf.dll (Text Services I guess) switches the layout back (C stack is attached).  Do you have any ideas about what could be causing this?

    What I've done here is put a breakpoint on a Window proc when it gets a WM_INPUTLANGCHANGE message.

    The culprit seems to be:

    msctf.dll!PostInputLangRequest()  + 0xc9 bytes

    Thanks for your continued input (pardon the pun),


    > dyalog.exe!Session_wnd_proc(HWND__ * hWnd=0x002608fc, unsigned int msg=0x00000051, unsigned int wParam=0x00000000, long lParam=0x08090809)  Line 1879 C
    user32.dll!_InternalCallWinProc@20()  + 0x23 bytes
    user32.dll!_UserCallWinProcCheckWow@32()  + 0xb3 bytes
    user32.dll!_CallWindowProcAorW@24()  + 0x51 bytes
    user32.dll!_CallWindowProcW@20()  + 0x1b bytes
    dyalog.exe!OwnerProc(HWND__ * hWnd=0x002608fc, unsigned int msg=0x00000051, unsigned int wParam=0x00000000, long lParam=0x08090809)  Line 456 C
    user32.dll!_InternalCallWinProc@20()  + 0x23 bytes
    user32.dll!_UserCallWinProcCheckWow@32()  + 0xb3 bytes
    user32.dll!_DispatchClientMessage@20()  + 0x4b bytes
    user32.dll!___fnDWORD@4()  + 0x24 bytes
    ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x2e bytes
    user32.dll!_NtUserActivateKeyboardLayout@8()  + 0xc bytes
    msctf.dll!PostInputLangRequest()  + 0xc9 bytes
    msctf.dll!SyncActivateAssemblyByAsm()  + 0x1b914 bytes
    msctf.dll!SyncActivateAssembly()  + 0x76 bytes
    msctf.dll!ActivateAssemblyPostCleanupCallback()  + 0x22 bytes
    msctf.dll!CCleanupShared::~CCleanupShared()  + 0x2a bytes
    msctf.dll!CCleanupShared::`scalar deleting destructor'()  + 0xd bytes
    msctf.dll!CThreadInputMgr::_CleanupContextsWorker()  + 0x69 bytes
    msctf.dll!CThreadInputMgr::_CleanupContexts()  + 0x38 bytes
    msctf.dll!ActivateAssembly()  + 0xa4 bytes
    msctf.dll!SetFocusDIMForAssembly()  + 0x5e bytes
    msctf.dll!CThreadInputMgr::_SetFocus()  + 0x133 bytes
    msctf.dll!SetDIMFocus()  + 0x55 bytes
    msctf.dll!_GetMsgHook()  + 0x4afd bytes
    msctf.dll!_TF_Notify@12()  + 0x91 bytes
    user32.dll!_CtfHookProcWorker@16()  + 0x21 bytes
    user32.dll!_CallHookWithSEH@16()  + 0x21 bytes
    user32.dll!___fnHkINLPMSG@4()  + 0x25 bytes
    ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x2e bytes
    user32.dll!_NtUserGetMessage@16()  + 0xc bytes
    user32.dll!_GetMessageW@16()  + 0x2b bytes
    dyalog.exe!w3_next_message()  Line 848 + 0x10 bytes C
    dyalog.exe!MessageLoop(int (void)* readfn=0x00676ed0)  

    Michael S. Kaplan on 15 Jan 2008 1:12 PM:

    Okay, that issue goes a little beyond the scope of what I was trying to cover here, so I moved it over to the suggestion box, here....

    john daintree on 17 Jan 2008 6:11 AM:

    OK, I guessed as much. Thanks.

    Jon Fullerton on 24 Aug 2012 9:53 AM:


    I'm trying to use InstallLayoutOrTip to install Tips for the current user, but they seem to only go to local machine.  Can you provide a sample of the correct calling convention to have it apply to the current user.  From the above discussion I'm unclear on how you use ActivateKeyboardLayout if it is not proceeded by LoadKeyboardLayout.


    Please consider a donation to keep this archive running, maintained and free of advertising.
    Donate €20 or more to receive an offline copy of the whole archive including all images.

    referenced by

    2012/08/28 'If it is easy, then there are samples. And if it's very easy, everyone is writing them.'

    2012/08/27 When functions don't do what you want them to...

    2008/05/23 When the LANGID in the LOWORD of the KLID doesn't match the LANGID you want keyboard under?

    2008/02/03 When exactly will we take a hint about all of that keyboard cord cutting stuff?

    go to newer or older post, or back to index or month or day