test: context.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# context.c

Go to the documentation of this file.

    00001 /**************************************************************************\
    00002 * Module Name: context.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Context management routines for imm32 dll
    00007 *
    00008 * History:
    00009 * 03-Jan-1996 wkwok       Created
    00010 \**************************************************************************/
    00011
    00012 #include "precomp.h"
    00013 #pragma hdrstop
    00014
    00015 #define IMCC_ALLOC_TOOLARGE             0x1000
    00016
    00017
    00018 /**************************************************************************\
    00019 * ImmCreateContext
    00020 *
    00021 * Creates and initializes an input context.
    00022 *
    00023 * 17-Jan-1996 wkwok       Created
    00024 \**************************************************************************/
    00025
    00026 HIMC WINAPI ImmCreateContext(void)
    00027 {
    00028     PCLIENTIMC pClientImc;
    00029     HIMC       hImc = NULL_HIMC;
    00030
    00031     if (!IS_IME_ENABLED()) {
    00032         return NULL_HIMC;
    00033     }
    00034
    00035     pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
    00036
    00037     if (pClientImc != NULL) {
    00038
    00039         hImc = NtUserCreateInputContext((ULONG_PTR)pClientImc);
    00040         if (hImc == NULL_HIMC) {
    00041             ImmLocalFree(pClientImc);
    00042             return NULL_HIMC;
    00043         }
    00044
    00045         InitImcCrit(pClientImc);
    00046         pClientImc->dwImeCompatFlags = (DWORD)NtUserGetThreadState(UserThreadStateImeCompatFlags);
    00047     }
    00048
    00049     return hImc;
    00050 }
    00051
    00052
    00053 /**************************************************************************\
    00054 * ImmDestroyContext
    00055 *
    00056 * Destroys an input context.
    00057 *
    00058 * 17-Jan-1996 wkwok       Created
    00059 \**************************************************************************/
    00060
    00061 BOOL WINAPI ImmDestroyContext(
    00062     HIMC hImc)
    00063 {
    00064     if (!IS_IME_ENABLED()) {
    00065         return FALSE;
    00066     }
    00067
    00068     if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
    00069         RIPMSG1(RIP_WARNING,
    00070               "ImmDestroyContext: Invalid input context access %lx.", hImc);
    00071         return FALSE;
    00072     }
    00073
    00074     return DestroyInputContext(hImc, GetKeyboardLayout(0), FALSE);
    00075 }
    00076
    00077
    00078 /**************************************************************************\
    00079 * ImmAssociateContext
    00080 *
    00081 * Associates an input context to the specified window handle.
    00082 *
    00083 * 17-Jan-1996 wkwok       Created
    00084 \**************************************************************************/
    00085
    00086 HIMC WINAPI ImmAssociateContext(
    00087     HWND hWnd,
    00088     HIMC hImc)
    00089 {
    00090     PWND  pWnd;
    00091     HIMC  hPrevImc;
    00092     AIC_STATUS Status;
    00093
    00094     // early out
    00095     if (!IS_IME_ENABLED()) {
    00096         return NULL_HIMC;
    00097     }
    00098
    00099     if ((pWnd = ValidateHwnd(hWnd)) == (PWND)NULL) {
    00100         RIPMSG1(RIP_WARNING,
    00101               "ImmAssociateContext: invalid window handle %x", hWnd);
    00102         return NULL_HIMC;
    00103     }
    00104
    00105
    00106
    00107     if (hImc != NULL_HIMC &&
    00108             GetInputContextThread(hImc) != GetCurrentThreadId()) {
    00109         RIPMSG1(RIP_WARNING,
    00110               "ImmAssociateContext: Invalid input context access %lx.", hImc);
    00111         return NULL_HIMC;
    00112     }
    00113
    00114     /*
    00115      * associate to the same input context, do nothing.
    00116      */
    00117     if (pWnd->hImc == hImc)
    00118         return hImc;
    00119
    00120     hPrevImc = pWnd->hImc;
    00121
    00122     Status = NtUserAssociateInputContext(hWnd, hImc, 0);
    00123
    00124     switch (Status) {
    00125     case AIC_FOCUSCONTEXTCHANGED:
    00126         if (IsWndEqual(NtUserQueryWindow(hWnd, WindowFocusWindow), hWnd)) {
    00127             ImmSetActiveContext(hWnd, hPrevImc, FALSE);
    00128             ImmSetActiveContext(hWnd, hImc, TRUE);
    00129         }
    00130
    00131         // Fall thru.
    00132
    00133     case AIC_SUCCESS:
    00134         return hPrevImc;
    00135
    00136     default:
    00137         return NULL_HIMC;
    00138     }
    00139 }
    00140
    00141
    00142 BOOL WINAPI ImmAssociateContextEx(
    00143     HWND hWnd,
    00144     HIMC hImc,
    00145     DWORD dwFlag)
    00146 {
    00147     HWND hWndFocus;
    00148     PWND pWndFocus;
    00149     HIMC hImcFocusOld;
    00150     AIC_STATUS Status;
    00151
    00152     if (!IS_IME_ENABLED()) {
    00153         return FALSE;
    00154     }
    00155
    00156     hWndFocus = NtUserQueryWindow(hWnd, WindowFocusWindow);
    00157
    00158     if (hImc != NULL_HIMC && !(dwFlag & IACE_DEFAULT) &&
    00159             GetInputContextThread(hImc) != GetCurrentThreadId()) {
    00160         RIPMSG1(RIP_WARNING,
    00161               "ImmAssociateContextEx: Invalid input context access %lx.", hImc);
    00162         return FALSE;
    00163     }
    00164
    00165     if ((pWndFocus = ValidateHwnd(hWndFocus)) != (PWND)NULL)
    00166         hImcFocusOld = pWndFocus->hImc;
    00167     else
    00168         hImcFocusOld = NULL_HIMC;
    00169
    00170     Status = NtUserAssociateInputContext(hWnd, hImc, dwFlag);
    00171
    00172     switch (Status) {
    00173     case AIC_FOCUSCONTEXTCHANGED:
    00174         if ((pWndFocus = ValidateHwnd(hWndFocus)) != (PWND)NULL) {
    00175             hImc = pWndFocus->hImc;
    00176             if (hImc != hImcFocusOld) {
    00177                 ImmSetActiveContext(hWndFocus, hImcFocusOld, FALSE);
    00178                 ImmSetActiveContext(hWndFocus, hImc, TRUE);
    00179             };
    00180         };
    00181
    00182         // Fall thru.
    00183
    00184     case AIC_SUCCESS:
    00185         return TRUE;
    00186
    00187     default:
    00188         return FALSE;
    00189     }
    00190 }
    00191
    00192
    00193 /**************************************************************************\
    00194 * ImmGetContext
    00195 *
    00196 * Retrieves the input context that is associated to the given window.
    00197 *
    00198 * 17-Jan-1996 wkwok       Created
    00199 \**************************************************************************/
    00200
    00201 HIMC WINAPI ImmGetContext(
    00202     HWND hWnd)
    00203 {
    00204     if ( hWnd == NULL ) {
    00205         RIPMSG1(RIP_WARNING,
    00206               "ImmGetContext: invalid window handle %x", hWnd);
    00207         return NULL_HIMC;
    00208     }
    00209     /*
    00210      * for non-NULL hWnd, ImmGetSaveContext will do the
    00211      * validation and "same process" checking.
    00212      */
    00213     return ImmGetSaveContext( hWnd, IGSC_WINNLSCHECK );
    00214 }
    00215
    00216
    00217 /**************************************************************************\
    00218 * ImmGetSaveContext
    00219 *
    00220 * Retrieves the input context that is associated to the given window.
    00221 *
    00222 * 15-Mar-1996 wkwok       Created
    00223 \**************************************************************************/
    00224
    00225 HIMC ImmGetSaveContext(
    00226     HWND  hWnd,
    00227     DWORD dwFlag)
    00228 {
    00229     HIMC       hRetImc;
    00230     PCLIENTIMC pClientImc;
    00231     PWND  pwnd;
    00232
    00233     if (!IS_IME_ENABLED()) {
    00234         return NULL_HIMC;
    00235     }
    00236
    00237     if (hWnd == NULL) {
    00238         /*
    00239          * Retrieves the default input context of current thread.
    00240          */
    00241         hRetImc = (HIMC)NtUserGetThreadState(UserThreadStateDefaultInputContext);
    00242     }
    00243     else {
    00244         /*
    00245          * Retrieves the input context associated to the given window.
    00246          */
    00247         if ((pwnd = ValidateHwnd(hWnd)) == (PWND)NULL) {
    00248             RIPMSG1(RIP_WARNING,
    00249                   "ImmGetSaveContext: invalid window handle %x", hWnd);
    00250             return NULL_HIMC;
    00251         }
    00252         /*
    00253          * Don't allow other process to access input context
    00254          */
    00255         if (!TestWindowProcess(pwnd)) {
    00256             RIPMSG0(RIP_WARNING,
    00257                   "ImmGetSaveContext: can not get input context of other process");
    00258             return NULL_HIMC;
    00259         }
    00260         hRetImc = pwnd->hImc;
    00261
    00262         if (hRetImc == NULL_HIMC && (dwFlag & IGSC_DEFIMCFALLBACK)) {
    00263             /*
    00264              * hWnd associated with NULL input context, retrieves the
    00265              * default input context of the hWnd's creator thread.
    00266              */
    00267             hRetImc = (HIMC)NtUserQueryWindow(hWnd, WindowDefaultInputContext);
    00268         }
    00269     }
    00270
    00271     pClientImc = ImmLockClientImc(hRetImc);
    00272     if (pClientImc == NULL)
    00273         return NULL_HIMC;
    00274
    00275     if ((dwFlag & IGSC_WINNLSCHECK) && TestICF(pClientImc, IMCF_WINNLSDISABLE))
    00276         hRetImc = NULL_HIMC;
    00277
    00278     ImmUnlockClientImc(pClientImc);
    00279
    00280     return hRetImc;
    00281 }
    00282
    00283
    00284 /**************************************************************************\
    00285 * ImmReleaseContext
    00286 *
    00287 * Releases the input context retrieved by ImmGetContext().
    00288 *
    00289 * 17-Jan-1996 wkwok       Created
    00290 \**************************************************************************/
    00291
    00292 BOOL WINAPI ImmReleaseContext(
    00293     HWND hWnd,
    00294     HIMC hImc)
    00295 {
    00296     UNREFERENCED_PARAMETER(hWnd);
    00297     UNREFERENCED_PARAMETER(hImc);
    00298
    00299     return TRUE;
    00300 }
    00301
    00302
    00303 /**************************************************************************\
    00304 * ImmSetActiveContext
    00305 *
    00306 * 15-Mar-1996 wkwok       Created
    00307 \**************************************************************************/
    00308
    00309 BOOL ImmSetActiveContext(
    00310     HWND hWnd,
    00311     HIMC hImc,
    00312     BOOL fActivate)
    00313 {
    00314     PCLIENTIMC    pClientImc;
    00315     PINPUTCONTEXT pInputContext;
    00316     PIMEDPI       pImeDpi;
    00317     DWORD         dwISC;
    00318     HIMC          hSaveImc;
    00319     HWND          hDefImeWnd;
    00320     DWORD         dwOpenStatus = 0;
    00321     DWORD         dwConversion = 0;
    00322 #ifdef DEBUG
    00323     PWND          pWnd = ValidateHwnd(hWnd);
    00324
    00325     if (pWnd != NULL && GETPTI(pWnd) != PtiCurrent()) {
    00326         RIPMSG1(RIP_WARNING, "hWnd (=%lx) is not of current thread.", hWnd);
    00327     }
    00328 #endif
    00329
    00330     if (!IS_IME_ENABLED()) {
    00331         return FALSE;
    00332     }
    00333
    00334     dwISC = ISC_SHOWUIALL;
    00335
    00336     pClientImc = ImmLockClientImc(hImc);
    00337
    00338     if (!fActivate) {
    00339         if (pClientImc != NULL)
    00340             ClrICF(pClientImc, IMCF_ACTIVE);
    00341         goto NotifySetActive;
    00342     }
    00343
    00344     if (hImc == NULL_HIMC) {
    00345         hSaveImc = ImmGetSaveContext(hWnd, IGSC_DEFIMCFALLBACK);
    00346         pInputContext = ImmLockIMC(hSaveImc);
    00347         if (pInputContext != NULL) {
    00348             pInputContext->hWnd = hWnd;
    00349             ImmUnlockIMC(hSaveImc);
    00350         }
    00351         goto NotifySetActive;
    00352     }
    00353
    00354     /*
    00355      * Non-NULL input context, window handle have to be updated.
    00356      */
    00357     if (pClientImc == NULL)
    00358         return FALSE;
    00359
    00360     pInputContext = ImmLockIMC(hImc);
    00361     if (pInputContext == NULL) {
    00362         ImmUnlockClientImc(pClientImc);
    00363         return FALSE;
    00364     }
    00365
    00366     pInputContext->hWnd = hWnd;
    00367     SetICF(pClientImc, IMCF_ACTIVE);
    00368
    00369 #ifdef LATER
    00370     // Do uNumLangVKey checking later
    00371 #endif
    00372
    00373     if (pInputContext->fdw31Compat & F31COMPAT_MCWHIDDEN)
    00374         dwISC = ISC_SHOWUIALL - ISC_SHOWUICOMPOSITIONWINDOW;
    00375
    00376     dwOpenStatus = (DWORD)pInputContext->fOpen;
    00377     dwConversion = pInputContext->fdwConversion;
    00378     ImmUnlockIMC(hImc);
    00379
    00380 NotifySetActive:
    00381
    00382     pImeDpi = ImmLockImeDpi(GetKeyboardLayout(0));
    00383     if (pImeDpi != NULL) {
    00384         (*pImeDpi->pfn.ImeSetActiveContext)(hImc, fActivate);
    00385         ImmUnlockImeDpi(pImeDpi);
    00386     }
    00387
    00388     /*
    00389      * Notify UI
    00390      */
    00391     if (IsWindow(hWnd)) {
    00392         SendMessage(hWnd, WM_IME_SETCONTEXT, fActivate, dwISC);
    00393
    00394         /*
    00395          * send notify to shell / keyboard driver
    00396          */
    00397         if ( fActivate )
    00398             NtUserNotifyIMEStatus( hWnd, dwOpenStatus, dwConversion );
    00399     }
    00400     else if (!fActivate) {
    00401         /*
    00402          * Because hWnd is not there (maybe destroyed), we send
    00403          * WM_IME_SETCONTEXT to the default IME window.
    00404          */
    00405         if ((hDefImeWnd = ImmGetDefaultIMEWnd(NULL)) != NULL) {
    00406             SendMessage(hDefImeWnd, WM_IME_SETCONTEXT, fActivate, dwISC);
    00407         }
    00408         else {
    00409             RIPMSG0(RIP_WARNING,
    00410                   "ImmSetActiveContext: can't send WM_IME_SETCONTEXT(FALSE).");
    00411         }
    00412     }
    00413 #ifdef DEBUG
    00414     else {
    00415         RIPMSG0(RIP_WARNING,
    00416               "ImmSetActiveContext: can't send WM_IME_SETCONTEXT(TRUE).");
    00417     }
    00418 #endif
    00419
    00420 #ifdef LATER
    00421     // Implements ProcessIMCEvent() later.
    00422 #endif
    00423
    00424     if (pClientImc != NULL)
    00425         ImmUnlockClientImc(pClientImc);
    00426
    00427     return TRUE;
    00428 }
    00429
    00430 /**************************************************************************\
    00431 * ModeSaver related routines
    00432 *
    00433 * Dec-1998 hiroyama     Created
    00434 \**************************************************************************/
    00435
    00436 PIMEMODESAVER GetImeModeSaver(
    00437     PINPUTCONTEXT pInputContext,
    00438     HKL hkl)
    00439 {
    00440     PIMEMODESAVER pModeSaver;
    00441     USHORT langId = PRIMARYLANGID(HKL_TO_LANGID(hkl));
    00442
    00443     for (pModeSaver = pInputContext->pImeModeSaver; pModeSaver; pModeSaver = pModeSaver->next) {
    00444         if (pModeSaver->langId == langId) {
    00445             break;
    00446         }
    00447     }
    00448
    00449     if (pModeSaver == NULL) {
    00450         TAGMSG1(DBGTAG_IMM, "GetImeModeSaver: creating ModeSaver for langId=%04x", langId);
    00451         pModeSaver = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof *pModeSaver);
    00452         if (pModeSaver == NULL) {
    00453             RIPMSG1(RIP_WARNING, "GetImeModeSaver: failed to create ModeSaver for langId=%04x", langId);
    00454             return NULL;
    00455         }
    00456         pModeSaver->langId = langId;
    00457         pModeSaver->next = pInputContext->pImeModeSaver;
    00458         pInputContext->pImeModeSaver = pModeSaver;
    00459     }
    00460
    00461     return pModeSaver;
    00462 }
    00463
    00464 VOID DestroyImeModeSaver(
    00465     PINPUTCONTEXT pInputContext)
    00466 {
    00467     PIMEMODESAVER pModeSaver = pInputContext->pImeModeSaver;
    00468
    00469     //
    00470     // Destroy mode savers
    00471     //
    00472     while (pModeSaver) {
    00473         PIMEMODESAVER pNext = pModeSaver->next;
    00474         PIMEPRIVATEMODESAVER pPrivateModeSaver = pModeSaver->pImePrivateModeSaver;
    00475
    00476         //
    00477         // Destroy private mode savers
    00478         //
    00479         while (pPrivateModeSaver) {
    00480             PIMEPRIVATEMODESAVER pPrivateNext = pPrivateModeSaver->next;
    00481             ImmLocalFree(pPrivateModeSaver);
    00482             pPrivateModeSaver = pPrivateNext;
    00483         }
    00484
    00485         ImmLocalFree(pModeSaver);
    00486         pModeSaver = pNext;
    00487     }
    00488
    00489     pInputContext->pImeModeSaver = NULL;
    00490 }
    00491
    00492 PIMEPRIVATEMODESAVER GetImePrivateModeSaver(
    00493     PIMEMODESAVER pImeModeSaver,
    00494     HKL hkl)
    00495 {
    00496     PIMEPRIVATEMODESAVER pPrivateModeSaver;
    00497
    00498     for (pPrivateModeSaver = pImeModeSaver->pImePrivateModeSaver; pPrivateModeSaver; pPrivateModeSaver = pPrivateModeSaver->next) {
    00499         if (pPrivateModeSaver->hkl == hkl) {
    00500             break;
    00501         }
    00502     }
    00503
    00504     if (pPrivateModeSaver == NULL) {
    00505         TAGMSG1(DBGTAG_IMM, "GetImePrivateModeSaver: creating private mode saver for hkl=%08x", hkl);
    00506         pPrivateModeSaver = ImmLocalAlloc(0, sizeof *pPrivateModeSaver);
    00507         if (pPrivateModeSaver == NULL) {
    00508             RIPMSG1(RIP_WARNING, "GetImePrivateModeSaver: failed to create PrivateModeSaver for hlk=%08x", hkl);
    00509             return NULL;
    00510         }
    00511         pPrivateModeSaver->hkl = hkl;
    00512         pPrivateModeSaver->fdwSentence = 0;
    00513         pPrivateModeSaver->next = pImeModeSaver->pImePrivateModeSaver;
    00514         pImeModeSaver->pImePrivateModeSaver = pPrivateModeSaver;
    00515     }
    00516
    00517     return pPrivateModeSaver;
    00518 }
    00519
    00520 BOOL SavePrivateMode(
    00521     PINPUTCONTEXT pInputContext,
    00522     PIMEMODESAVER pImeModeSaver,
    00523     HKL hkl)
    00524 {
    00525     PIMEPRIVATEMODESAVER pPrivateModeSaver = GetImePrivateModeSaver(pImeModeSaver, hkl);
    00526
    00527     if (pPrivateModeSaver == NULL) {
    00528         return FALSE;
    00529     }
    00530
    00531     //
    00532     // Save private sentence mode
    00533     //
    00534     pPrivateModeSaver->fdwSentence = pInputContext->fdwSentence & 0xffff0000;
    00535     return TRUE;
    00536 }
    00537
    00538 BOOL RestorePrivateMode(
    00539     PINPUTCONTEXT pInputContext,
    00540     PIMEMODESAVER pImeModeSaver,
    00541     HKL hkl)
    00542 {
    00543     PIMEPRIVATEMODESAVER pPrivateModeSaver = GetImePrivateModeSaver(pImeModeSaver, hkl);
    00544
    00545     if (pPrivateModeSaver == NULL) {
    00546         return FALSE;
    00547     }
    00548
    00549     //
    00550     // Restore private sentence mode
    00551     //
    00552     ImmAssert(LOWORD(pPrivateModeSaver->fdwSentence) == 0);
    00553     pInputContext->fdwSentence |= pPrivateModeSaver->fdwSentence;
    00554     return TRUE;
    00555 }
    00556
    00557 /**************************************************************************\
    00558 * CreateInputContext
    00559 *
    00560 * 20-Feb-1996 wkwok       Created
    00561 \**************************************************************************/
    00562
    00563 BOOL CreateInputContext(
    00564     HIMC hImc,
    00565     HKL  hKL,
    00566     BOOL fCanCallImeSelect)
    00567 {
    00568     PIMEDPI            pImeDpi;
    00569     PCLIENTIMC         pClientImc;
    00570     DWORD              dwPrivateDataSize;
    00571     DWORD              fdwInitConvMode = 0;    // do it later
    00572     BOOL               fInitOpen = FALSE;      // do it later
    00573     PINPUTCONTEXT      pInputContext;
    00574     PCOMPOSITIONSTRING pCompStr;
    00575     PCANDIDATEINFO     pCandInfo;
    00576     PGUIDELINE         pGuideLine;
    00577     int                i;
    00578
    00579     pInputContext = ImmLockIMC(hImc);
    00580     if (!pInputContext) {
    00581         RIPMSG1(RIP_WARNING, "CreateContext: Lock hIMC %x failure", hImc);
    00582         goto CrIMCLockErrOut;
    00583     }
    00584
    00585     /*
    00586      * Initialize the member of INPUTCONTEXT
    00587      */
    00588     pInputContext->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
    00589     if (!pInputContext->hCompStr) {
    00590         RIPMSG0(RIP_WARNING, "CreateContext: Create hCompStr failure");
    00591         goto CrIMCUnlockIMC;
    00592     }
    00593
    00594     pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
    00595     if (!pCompStr) {
    00596         RIPMSG1(RIP_WARNING,
    00597               "CreateContext: Lock hCompStr %x failure", pInputContext->hCompStr);
    00598         goto CrIMCFreeCompStr;
    00599     }
    00600
    00601     pCompStr->dwSize = sizeof(COMPOSITIONSTRING);
    00602     ImmUnlockIMCC(pInputContext->hCompStr);
    00603
    00604     pInputContext->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
    00605     if (!pInputContext->hCandInfo) {
    00606         RIPMSG0(RIP_WARNING, "CreateContext: Create hCandInfo failure");
    00607         goto CrIMCFreeCompStr;
    00608     }
    00609
    00610     pCandInfo = (PCANDIDATEINFO)ImmLockIMCC(pInputContext->hCandInfo);
    00611     if (!pCandInfo) {
    00612         RIPMSG1(RIP_WARNING,
    00613               "CreateContext: Lock hCandInfo %x failure", pInputContext->hCandInfo);
    00614         goto CrIMCFreeCandInfo;
    00615     }
    00616
    00617     pCandInfo->dwSize = sizeof(CANDIDATEINFO);
    00618     ImmUnlockIMCC(pInputContext->hCandInfo);
    00619
    00620     pInputContext->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
    00621     if (!pInputContext->hGuideLine) {
    00622         RIPMSG0(RIP_WARNING, "CreateContext: Create hGuideLine failure");
    00623         goto CrIMCFreeCandInfo;
    00624     }
    00625
    00626     pGuideLine = (PGUIDELINE)ImmLockIMCC(pInputContext->hGuideLine);
    00627     if (!pGuideLine) {
    00628         RIPMSG1(RIP_WARNING,
    00629               "CreateContext: Lock hGuideLine %x failure", pInputContext->hGuideLine);
    00630         goto CrIMCFreeGuideLine;
    00631     }
    00632
    00633     pGuideLine->dwSize = sizeof(GUIDELINE);
    00634     ImmUnlockIMCC(pInputContext->hGuideLine);
    00635
    00636     pInputContext->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
    00637     if (!pInputContext->hMsgBuf) {
    00638         RIPMSG0(RIP_WARNING, "CreateContext: Create hMsgBuf failure");
    00639         goto CrIMCFreeGuideLine;
    00640     }
    00641
    00642     pInputContext->dwNumMsgBuf = 0;
    00643     pInputContext->fOpen = fInitOpen;
    00644     pInputContext->fdwConversion = fdwInitConvMode;
    00645     pInputContext->fdwSentence = 0;
    00646
    00647     for (i = 0; i < 4; i++) {
    00648         pInputContext->cfCandForm[i].dwIndex = (DWORD)(-1);
    00649     }
    00650
    00651     pImeDpi = ImmLockImeDpi(hKL);
    00652     if (pImeDpi != NULL) {
    00653         if ((pClientImc = ImmLockClientImc(hImc)) == NULL) {
    00654             RIPMSG0(RIP_WARNING, "CreateContext: ImmLockClientImc() failure");
    00655             ImmUnlockImeDpi(pImeDpi);
    00656             goto CrIMCFreeMsgBuf;
    00657         }
    00658
    00659         /*
    00660          * Unicode based IME expects an Uncode based input context.
    00661          */
    00662         if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
    00663             SetICF(pClientImc, IMCF_UNICODE);
    00664
    00665         pClientImc->dwCodePage = IMECodePage(pImeDpi);
    00666
    00667         ImmUnlockClientImc(pClientImc);
    00668
    00669         dwPrivateDataSize = pImeDpi->ImeInfo.dwPrivateDataSize;
    00670     }
    00671     else {
    00672         dwPrivateDataSize = sizeof(UINT);
    00673     }
    00674
    00675     pInputContext->hPrivate = ImmCreateIMCC(dwPrivateDataSize);
    00676     if (!pInputContext->hPrivate) {
    00677         RIPMSG0(RIP_WARNING, "CreateContext: Create hPrivate failure");
    00678         ImmUnlockImeDpi(pImeDpi);
    00679         goto CrIMCFreeMsgBuf;
    00680     }
    00681
    00682     pInputContext->pImeModeSaver = NULL;
    00683
    00684     if (pImeDpi != NULL) {
    00685         if (fCanCallImeSelect) {
    00686             (*pImeDpi->pfn.ImeSelect)(hImc, TRUE);
    00687         }
    00688         ImmUnlockImeDpi(pImeDpi);
    00689     }
    00690
    00691     ImmUnlockIMC(hImc);
    00692     return TRUE;
    00693
    00694     /*
    00695      * context failure case
    00696      */
    00697 CrIMCFreeMsgBuf:
    00698     ImmDestroyIMCC(pInputContext->hMsgBuf);
    00699 CrIMCFreeGuideLine:
    00700     ImmDestroyIMCC(pInputContext->hGuideLine);
    00701 CrIMCFreeCandInfo:
    00702     ImmDestroyIMCC(pInputContext->hCandInfo);
    00703 CrIMCFreeCompStr:
    00704     ImmDestroyIMCC(pInputContext->hCompStr);
    00705 CrIMCUnlockIMC:
    00706     ImmUnlockIMC(hImc);
    00707 CrIMCLockErrOut:
    00708     return FALSE;
    00709 }
    00710
    00711
    00712 /**************************************************************************\
    00713 * DestroyInputContext
    00714 *
    00715 * 20-Feb-1996 wkwok       Created
    00716 \**************************************************************************/
    00717
    00718 BOOL DestroyInputContext(
    00719     HIMC      hImc,
    00720     HKL       hKL,
    00721     BOOL      bTerminate)
    00722 {
    00723     PINPUTCONTEXT pInputContext;
    00724     PIMEDPI       pImeDpi;
    00725     PIMC          pImc;
    00726     PCLIENTIMC    pClientImc;
    00727
    00728     if (!IS_IME_ENABLED()) {
    00729         return FALSE;
    00730
    00731     }
    00732     if (hImc == NULL_HIMC) {
    00733         RIPMSG0(RIP_VERBOSE, "DestroyInputContext: hImc is NULL.");
    00734         return FALSE;
    00735     }
    00736
    00737     pImc = HMValidateHandle((HANDLE)hImc, TYPE_INPUTCONTEXT);
    00738
    00739     /*
    00740      * Cannot destroy input context from other thread.
    00741      */
    00742     if (pImc == NULL || GETPTI(pImc) != PtiCurrent())
    00743         return FALSE;
    00744
    00745     /*
    00746      * We are destroying this hImc so we don't bother calling
    00747      * ImmLockClientImc() to get the pClientImc. Instead, we
    00748      * reference the pImc->dwClientImcData directly and call
    00749      * InterlockedIncrement(&pClientImc->cLockObj) right after
    00750      * several quick checks.
    00751      */
    00752     pClientImc = (PCLIENTIMC)pImc->dwClientImcData;
    00753
    00754     if (pClientImc == NULL) {
    00755         /*
    00756          * Client side Imc has not been initialzed yet.
    00757          * We simply destroy this input context from kernel.
    00758          */
    00759         if (bTerminate) {
    00760             /*
    00761              * If called from THREAD_DETACH, we don't
    00762              * have to destroy kernel side Input Context.
    00763              */
    00764             return TRUE;
    00765         }
    00766         return NtUserDestroyInputContext(hImc);
    00767     }
    00768
    00769     if (TestICF(pClientImc, IMCF_DEFAULTIMC) && !bTerminate) {
    00770         /*
    00771          * Cannot destroy default input context unless the
    00772          * thread is terminating.
    00773          */
    00774         return FALSE;
    00775     }
    00776
    00777     if (TestICF(pClientImc, IMCF_INDESTROY)) {
    00778         /*
    00779          * This hImc is being destroyed. Returns as success.
    00780          */
    00781         return TRUE;
    00782     }
    00783
    00784     /*
    00785      * Time to lock up the pClientImc.
    00786      */
    00787     InterlockedIncrement(&pClientImc->cLockObj);
    00788
    00789     if (pClientImc->hInputContext != NULL) {
    00790
    00791         pInputContext = ImmLockIMC(hImc);
    00792         if (!pInputContext) {
    00793             RIPMSG1(RIP_WARNING, "DestroyContext: Lock hImc %x failure", hImc);
    00794             ImmUnlockClientImc(pClientImc);
    00795             return FALSE;
    00796         }
    00797
    00798         pImeDpi = ImmLockImeDpi(hKL);
    00799         if (pImeDpi != NULL) {
    00800             (*pImeDpi->pfn.ImeSelect)(hImc, FALSE);
    00801             ImmUnlockImeDpi(pImeDpi);
    00802         }
    00803
    00804         ImmDestroyIMCC(pInputContext->hPrivate);
    00805         ImmDestroyIMCC(pInputContext->hMsgBuf);
    00806         ImmDestroyIMCC(pInputContext->hGuideLine);
    00807         ImmDestroyIMCC(pInputContext->hCandInfo);
    00808         ImmDestroyIMCC(pInputContext->hCompStr);
    00809
    00810         /*
    00811          * Free all ImeModeSaver.
    00812          */
    00813         DestroyImeModeSaver(pInputContext);
    00814
    00815         ImmUnlockIMC(hImc);
    00816     }
    00817
    00818     SetICF(pClientImc, IMCF_INDESTROY);
    00819
    00820     /*
    00821      * ImmUnlockClientImc() will free up the pClientImc
    00822      * when InterlockedDecrement(&pClientImc->cLockObj)
    00823      * reaches 0.
    00824      */
    00825     ImmUnlockClientImc(pClientImc);
    00826
    00827     return (bTerminate) ? TRUE : NtUserDestroyInputContext(hImc);
    00828 }
    00829
    00830
    00831 /**************************************************************************\
    00832 * SelectInputContext
    00833 *
    00834 * 20-Feb-1996 wkwok       Created
    00835 \**************************************************************************/
    00836
    00837 VOID SelectInputContext(
    00838     HKL  hSelKL,
    00839     HKL  hUnSelKL,
    00840     HIMC hImc)
    00841 {
    00842     PIMEDPI            pSelImeDpi, pUnSelImeDpi;
    00843     PCLIENTIMC         pClientImc;
    00844     PINPUTCONTEXT      pInputContext;
    00845     DWORD              dwSelPriv = 0, dwUnSelPriv = 0, dwSize;
    00846     HIMCC              hImcc;
    00847     PCOMPOSITIONSTRING pCompStr;
    00848     PCANDIDATEINFO     pCandInfo;
    00849     PGUIDELINE         pGuideLine;
    00850     BOOLEAN            fLogFontInited;
    00851
    00852     TAGMSG3(DBGTAG_IMM, "SelectInputContext: called for sel=%08p unsel=%08p hImc=%08p",
    00853             hSelKL, hUnSelKL, hImc);
    00854
    00855     pClientImc = ImmLockClientImc(hImc);
    00856     if (pClientImc == NULL) {
    00857         RIPMSG0(RIP_VERBOSE, "SelectInputContext: cannot lock client Imc. Bailing out.");
    00858         return;
    00859     }
    00860
    00861     pSelImeDpi   = ImmLockImeDpi(hSelKL);
    00862
    00863     if (hSelKL != hUnSelKL) {
    00864         /*
    00865          * If those new sel and unsel do no match but
    00866          * somehow SelectInput is called, that means
    00867          * we should initialize the input contex again
    00868          * without dumping the old information.
    00869          */
    00870         pUnSelImeDpi = ImmLockImeDpi(hUnSelKL);
    00871     } else {
    00872         pUnSelImeDpi = NULL;
    00873     }
    00874
    00875     if (pSelImeDpi != NULL) {
    00876         /*
    00877          * According to private memory size of the two layout, we decide
    00878          * whether we nee to reallocate this memory block
    00879          */
    00880         dwSelPriv = pSelImeDpi->ImeInfo.dwPrivateDataSize;
    00881
    00882         /*
    00883          * Setup the code page of the newly selected IME.
    00884          */
    00885         pClientImc->dwCodePage = IMECodePage(pSelImeDpi);
    00886     }
    00887     else {
    00888         pClientImc->dwCodePage = CP_ACP;
    00889     }
    00890
    00891     if (pUnSelImeDpi != NULL)
    00892         dwUnSelPriv = pUnSelImeDpi->ImeInfo.dwPrivateDataSize;
    00893
    00894     dwSelPriv   = max(dwSelPriv,   sizeof(UINT));
    00895     dwUnSelPriv = max(dwUnSelPriv, sizeof(UINT));
    00896
    00897     /*
    00898      * Unselect the input context.
    00899      */
    00900     if (pUnSelImeDpi != NULL)
    00901         (*pUnSelImeDpi->pfn.ImeSelect)(hImc, FALSE);
    00902
    00903     /*
    00904      * Reinitialize the client side input context for the selected layout.
    00905      */
    00906     if ((pInputContext = InternalImmLockIMC(hImc, FALSE)) != NULL) {
    00907         DWORD fdwOldConversion = pInputContext->fdwConversion;
    00908         DWORD fdwOldSentence = pInputContext->fdwSentence;
    00909         BOOL fOldOpen = pInputContext->fOpen;
    00910         PIMEMODESAVER pUnSelModeSaver, pSelModeSaver;
    00911         const DWORD fdwConvPreserve = IME_CMODE_EUDC;
    00912
    00913         fLogFontInited = ((pInputContext->fdwInit & INIT_LOGFONT) == INIT_LOGFONT);
    00914
    00915         if (TestICF(pClientImc, IMCF_UNICODE) && pSelImeDpi != NULL &&
    00916                 !(pSelImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) {
    00917             /*
    00918              * Check if there is any LOGFONT to be converted.
    00919              */
    00920             if (fLogFontInited) {
    00921                 LOGFONTA LogFontA;
    00922
    00923                 LFontWtoLFontA(&pInputContext->lfFont.W, &LogFontA);
    00924                 RtlCopyMemory(&pInputContext->lfFont.A, &LogFontA, sizeof(LOGFONTA));
    00925             }
    00926
    00927             ClrICF(pClientImc, IMCF_UNICODE);
    00928         }
    00929         else if (!TestICF(pClientImc, IMCF_UNICODE) && pSelImeDpi != NULL &&
    00930                  (pSelImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) {
    00931             /*
    00932              * Check if there is any LOGFONT to be converted.
    00933              */
    00934             if (fLogFontInited) {
    00935                 LOGFONTW LogFontW;
    00936
    00937                 LFontAtoLFontW(&pInputContext->lfFont.A, &LogFontW);
    00938                 RtlCopyMemory(&pInputContext->lfFont.W, &LogFontW, sizeof(LOGFONTW));
    00939             }
    00940
    00941             SetICF(pClientImc, IMCF_UNICODE);
    00942         }
    00943
    00944         /*
    00945          * hPrivate
    00946          */
    00947         if (dwUnSelPriv != dwSelPriv) {
    00948             hImcc = ImmReSizeIMCC(pInputContext->hPrivate, dwSelPriv);
    00949             if (hImcc) {
    00950                 pInputContext->hPrivate = hImcc;
    00951             }
    00952             else {
    00953                 RIPMSG1(RIP_WARNING,
    00954                       "SelectContext: resize hPrivate %lX failure",
    00955                       pInputContext->hPrivate);
    00956                 ImmDestroyIMCC(pInputContext->hPrivate);
    00957                 pInputContext->hPrivate = ImmCreateIMCC(dwSelPriv);
    00958             }
    00959         }
    00960
    00961         /*
    00962          * hMsgBuf
    00963          */
    00964         dwSize = ImmGetIMCCSize(pInputContext->hMsgBuf);
    00965
    00966         if (ImmGetIMCCLockCount(pInputContext->hMsgBuf) != 0 ||
    00967                 dwSize > IMCC_ALLOC_TOOLARGE) {
    00968
    00969             RIPMSG0(RIP_WARNING, "SelectContext: create new hMsgBuf");
    00970             ImmDestroyIMCC(pInputContext->hMsgBuf);
    00971             pInputContext->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
    00972             pInputContext->dwNumMsgBuf = 0;
    00973         }
    00974
    00975         /*
    00976          * hGuideLine
    00977          */
    00978         dwSize = ImmGetIMCCSize(pInputContext->hGuideLine);
    00979
    00980         if (ImmGetIMCCLockCount(pInputContext->hGuideLine) != 0 ||
    00981                 dwSize < sizeof(GUIDELINE) || dwSize > IMCC_ALLOC_TOOLARGE) {
    00982
    00983             RIPMSG0(RIP_WARNING, "SelectContext: create new hGuideLine");
    00984             ImmDestroyIMCC(pInputContext->hGuideLine);
    00985             pInputContext->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
    00986             pGuideLine = (PGUIDELINE)ImmLockIMCC(pInputContext->hGuideLine);
    00987
    00988             if (pGuideLine != NULL) {
    00989                 pGuideLine->dwSize = sizeof(GUIDELINE);
    00990                 ImmUnlockIMCC(pInputContext->hGuideLine);
    00991             }
    00992         }
    00993
    00994         /*
    00995          * hCandInfo
    00996          */
    00997         dwSize = ImmGetIMCCSize(pInputContext->hCandInfo);
    00998
    00999         if (ImmGetIMCCLockCount(pInputContext->hCandInfo) != 0 ||
    01000                 dwSize < sizeof(CANDIDATEINFO) || dwSize > IMCC_ALLOC_TOOLARGE) {
    01001
    01002             RIPMSG0(RIP_WARNING, "SelectContext: create new hCandInfo");
    01003             ImmDestroyIMCC(pInputContext->hCandInfo);
    01004             pInputContext->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
    01005             pCandInfo = (PCANDIDATEINFO)ImmLockIMCC(pInputContext->hCandInfo);
    01006
    01007             if (pCandInfo != NULL) {
    01008                 pCandInfo->dwSize = sizeof(CANDIDATEINFO);
    01009                 ImmUnlockIMCC(pInputContext->hCandInfo);
    01010             }
    01011         }
    01012
    01013         /*
    01014          * hCompStr
    01015          */
    01016         dwSize = ImmGetIMCCSize(pInputContext->hCompStr);
    01017
    01018         if (ImmGetIMCCLockCount(pInputContext->hCompStr) != 0 ||
    01019                 dwSize < sizeof(COMPOSITIONSTRING) || dwSize > IMCC_ALLOC_TOOLARGE) {
    01020
    01021             RIPMSG0(RIP_WARNING, "SelectContext: create new hCompStr");
    01022             ImmDestroyIMCC(pInputContext->hCompStr);
    01023             pInputContext->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
    01024             pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
    01025
    01026             if (pCompStr != NULL) {
    01027                 pCompStr->dwSize = sizeof(COMPOSITIONSTRING);
    01028                 ImmUnlockIMCC(pInputContext->hCompStr);
    01029             }
    01030         }
    01031
    01032         //
    01033         // Save and restore the IME modes when the primary
    01034         // language changes.
    01035         //
    01036
    01037         if (pUnSelImeDpi) {
    01038             //
    01039             // If UnSelKL is IME, get ModeSaver per language.
    01040             //
    01041             pUnSelModeSaver = GetImeModeSaver(pInputContext, hUnSelKL);
    01042             TAGMSG1(DBGTAG_IMM, "pUnSelModeSaver=%p", pUnSelModeSaver);
    01043
    01044             //
    01045             // Firstly save the private sentence mode per IME.
    01046             //
    01047             SavePrivateMode(pInputContext, pUnSelModeSaver, hUnSelKL);
    01048         }
    01049         else {
    01050             pUnSelModeSaver = NULL;
    01051         }
    01052
    01053         if (pSelImeDpi) {
    01054             //
    01055             // If SelKL is IME, get is ModeSaver per language.
    01056             //
    01057             pSelModeSaver = GetImeModeSaver(pInputContext, hSelKL);
    01058             TAGMSG1(DBGTAG_IMM, "pSelImeDpi. pImeModeSaver=%p", pSelModeSaver);
    01059         }
    01060         else {
    01061             pSelModeSaver = NULL;
    01062         }
    01063
    01064         //
    01065         // If the primary language of KL changes, save the current mode
    01066         // and restore the previous modes of new language.
    01067         //
    01068         if (pUnSelModeSaver != pSelModeSaver) {
    01069             //
    01070             // If old KL is IME, save the current conversion, sentence and open mode.
    01071             //
    01072             if (pUnSelModeSaver) {
    01073                 pUnSelModeSaver->fOpen = (pInputContext->fOpen != FALSE);
    01074
    01075                 //
    01076                 // Don't have to save the preserved bits for conversion mode.
    01077                 //
    01078                 pUnSelModeSaver->fdwConversion = pInputContext->fdwConversion & ~fdwConvPreserve;
    01079
    01080                 pUnSelModeSaver->fdwSentence = LOWORD(pInputContext->fdwSentence);
    01081                 pUnSelModeSaver->fdwInit = pInputContext->fdwInit;
    01082             }
    01083
    01084             //
    01085             // If new KL is IME, restore the previous conversion, sentence and open mode.
    01086             //
    01087             if (pSelModeSaver) {
    01088                 if (pInputContext->fdwDirty & IMSS_INIT_OPEN) {
    01089                     //
    01090                     // HKL change may be kicked from private IME hotkey, and
    01091                     // a user wants it opened when switched.
    01092                     //
    01093                     pInputContext->fOpen = TRUE;
    01094                     pInputContext->fdwDirty &= ~IMSS_INIT_OPEN;
    01095                 } else {
    01096                     pInputContext->fOpen = pSelModeSaver->fOpen;
    01097                 }
    01098
    01099                 //
    01100                 // Some bits are preserved across the languages.
    01101                 //
    01102                 pInputContext->fdwConversion &= fdwConvPreserve;
    01103                 ImmAssert((pSelModeSaver->fdwConversion & fdwConvPreserve) == 0);
    01104                 pInputContext->fdwConversion |= pSelModeSaver->fdwConversion & ~fdwConvPreserve;
    01105
    01106                 ImmAssert(HIWORD(pSelModeSaver->fdwSentence) == 0);
    01107                 pInputContext->fdwSentence = pSelModeSaver->fdwSentence;
    01108                 pInputContext->fdwInit = pSelModeSaver->fdwInit;
    01109             }
    01110         }
    01111         if (pSelModeSaver) {
    01112             //
    01113             // Restore the private sentence mode per IME.
    01114             //
    01115             RestorePrivateMode(pInputContext, pSelModeSaver, hSelKL);
    01116         }
    01117
    01118         /*
    01119          * Select the input context.
    01120          */
    01121         if (pSelImeDpi != NULL)
    01122             (*pSelImeDpi->pfn.ImeSelect)(hImc, TRUE);
    01123
    01124         //
    01125         // Set the dirty bits so that IMM can send notifications later.
    01126         // See SendNotificatonProc.
    01127         //
    01128         pInputContext->fdwDirty = 0;
    01129         if (pInputContext->fOpen != fOldOpen) {
    01130             pInputContext->fdwDirty |= IMSS_UPDATE_OPEN;
    01131         }
    01132         if (pInputContext->fdwConversion != fdwOldConversion) {
    01133             pInputContext->fdwDirty |= IMSS_UPDATE_CONVERSION;
    01134         }
    01135         if (pInputContext->fdwSentence != fdwOldSentence) {
    01136             pInputContext->fdwDirty |= IMSS_UPDATE_SENTENCE;
    01137         }
    01138         TAGMSG4(DBGTAG_IMM, "fOpen:%d fdwConv:%08x fdwSent:%08x dirty:%02x",
    01139                 pInputContext->fOpen, pInputContext->fdwConversion, pInputContext->fdwSentence, pInputContext->fdwDirty);
    01140
    01141         ImmUnlockIMC(hImc);
    01142     }
    01143     else {
    01144         //
    01145         // To keep the backward compatibility,
    01146         // select the input context here.
    01147         //
    01148         if (pSelImeDpi != NULL)
    01149             (*pSelImeDpi->pfn.ImeSelect)(hImc, TRUE);
    01150     }
    01151
    01152     ImmUnlockImeDpi(pUnSelImeDpi);
    01153     ImmUnlockImeDpi(pSelImeDpi);
    01154     ImmUnlockClientImc(pClientImc);
    01155 }
    01156
    01157 BOOL SendNotificationProc(
    01158     HIMC hImc,
    01159     LPARAM lParam)
    01160 {
    01161     PINPUTCONTEXT pInputContext = ImmLockIMC(hImc);
    01162
    01163     UNREFERENCED_PARAMETER(lParam);
    01164
    01165     if (pInputContext != NULL) {
    01166         HWND hwnd = pInputContext->hWnd;
    01167
    01168         if (IsWindow(hwnd)) {
    01169             TAGMSG2(DBGTAG_IMM, "SendNotificationProc: updating hImc=%08x dirty=%04x",
    01170                     hImc, pInputContext->fdwDirty);
    01171
    01172             if (pInputContext->fdwDirty & IMSS_UPDATE_OPEN) {
    01173                 SendMessageW(hwnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0);
    01174             }
    01175             if (pInputContext->fdwDirty & IMSS_UPDATE_CONVERSION) {
    01176                 SendMessageW(hwnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0);
    01177             }
    01178             if (pInputContext->fdwDirty & (IMSS_UPDATE_OPEN | IMSS_UPDATE_CONVERSION)) {
    01179                 NtUserNotifyIMEStatus(hwnd, pInputContext->fOpen, pInputContext->fdwConversion);
    01180             }
    01181             if (pInputContext->fdwDirty & IMSS_UPDATE_SENTENCE) {
    01182                 SendMessageW(hwnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0);
    01183             }
    01184         }
    01185         pInputContext->fdwDirty = 0;
    01186     }
    01187
    01188     return TRUE;
    01189 }
    01190
    01191 VOID ImmSendNotification(
    01192     BOOL fForProcess)
    01193 {
    01194     DWORD dwThreadId;
    01195
    01196     if (fForProcess) {
    01197         dwThreadId = -1;
    01198     } else {
    01199         dwThreadId = 0;
    01200     }
    01201
    01202     ImmEnumInputContext(dwThreadId, (IMCENUMPROC)SendNotificationProc, 0);
    01203 }
    01204
    01205 /**************************************************************************\
    01206 * ImmEnumInputContext
    01207 *
    01208 * 20-Feb-1996 wkwok       Created
    01209 \**************************************************************************/
    01210
    01211 BOOL WINAPI ImmEnumInputContext(
    01212     DWORD idThread,
    01213     IMCENUMPROC lpfn,
    01214     LPARAM lParam)
    01215 {
    01216     UINT i;
    01217     UINT cHimc;
    01218     HIMC *phimcT;
    01219     HIMC *phimcFirst;
    01220     BOOL fSuccess = TRUE;
    01221
    01222     /*
    01223      * Get the himc list.  It is returned in a block of memory
    01224      * allocated with ImmLocalAlloc.
    01225      */
    01226     if ((cHimc = BuildHimcList(idThread, &phimcFirst)) == 0) {
    01227         return FALSE;
    01228     }
    01229
    01230     /*
    01231      * Loop through the input contexts, call the function pointer back for
    01232      * each one. End loop if either FALSE is returned or the end-of-list is
    01233      * reached.
    01234      */
    01235     phimcT = phimcFirst;
    01236     for (i = 0; i < cHimc; i++) {
    01237         if (RevalidateHimc(*phimcT)) {
    01238             if (!(fSuccess = (*lpfn)(*phimcT, lParam)))
    01239                 break;
    01240         }
    01241         phimcT++;
    01242     }
    01243
    01244     /*
    01245      * Free up buffer and return status - TRUE if entire list was enumerated,
    01246      * FALSE otherwise.
    01247      */
    01248     ImmLocalFree(phimcFirst);
    01249
    01250     return fSuccess;
    01251 }
    01252
    01253 /**************************************************************************\
    01254 * BuildHimcList
    01255 *
    01256 * 20-Feb-1996 wkwok       Created
    01257 \**************************************************************************/
    01258
    01259 DWORD BuildHimcList(
    01260     DWORD idThread,
    01261     HIMC **pphimcFirst)
    01262 {
    01263     UINT cHimc;
    01264     HIMC *phimcFirst;
    01265     NTSTATUS Status;
    01266     int cTries;
    01267
    01268     /*
    01269      * Allocate a buffer to hold the names.
    01270      */
    01271     cHimc = 64;
    01272     phimcFirst = ImmLocalAlloc(0, cHimc * sizeof(HIMC));
    01273     if (phimcFirst == NULL)
    01274         return 0;
    01275
    01276     Status = NtUserBuildHimcList(idThread, cHimc, phimcFirst, &cHimc);
    01277
    01278     /*
    01279      * If the buffer wasn't big enough, reallocate
    01280      * the buffer and try again.
    01281      */
    01282     cTries = 0;
    01283     while (Status == STATUS_BUFFER_TOO_SMALL) {
    01284         ImmLocalFree(phimcFirst);
    01285
    01286         /*
    01287          * If we can't seem to get it right,
    01288          * call it quits
    01289          */
    01290         if (cTries++ == 10)
    01291             return 0;
    01292
    01293         phimcFirst = ImmLocalAlloc(0, cHimc * sizeof(HIMC));
    01294         if (phimcFirst == NULL)
    01295             return 0;
    01296
    01297         Status = NtUserBuildHimcList(idThread, cHimc, phimcFirst, &cHimc);
    01298     }
    01299
    01300     if (!NT_SUCCESS(Status) || cHimc == 0) {
    01301         ImmLocalFree(phimcFirst);
    01302         return 0;
    01303     }
    01304
    01305     *pphimcFirst = phimcFirst;
    01306
    01307     return cHimc;
    01308 }