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 }

Generated on Sat May 15 19:39:34 2004 for test by doxygen 1.3.7