test: edecrare.c Source File

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

# edecrare.c

Go to the documentation of this file.

    00001 /****************************************************************************\
    00002 * edECRare.c - EC Edit controls Routines Called rarely are to be
    00003 * put in a seperate segment _EDECRare. This file contains
    00004 * these routines.
    00005 *
    00006 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00007 *
    00008 * Support Routines common to Single-line and Multi-Line edit controls
    00009 * called Rarely.
    00010 *
    00011 * Created: 02-08-89 sankar
    00012 \****************************************************************************/
    00013
    00014 #include "precomp.h"
    00015 #pragma hdrstop
    00016
    00017
    00018 extern LOOKASIDE EditLookaside;
    00019
    00020 #define WS_EX_EDGEMASK (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)
    00021
    00022 /*
    00023  * Those two macros assume PED can be referred as "ped."
    00024  */
    00025 #define GetCharABCWidthsAorW    ((ped)->fAnsi ? GetCharABCWidthsA : GetCharABCWidthsW)
    00026 #define GetCharWidthAorW        ((ped)->fAnsi ? GetCharWidthA : GetCharWidthW)
    00027
    00028 #define umin(a, b)  ((unsigned)(a) < (unsigned)(b) ? (unsigned)(a) : (unsigned)(b))
    00029
    00030 typedef BOOL (*PFNABCWIDTHS)(HDC, UINT, UINT, LPABC);
    00031 typedef BOOL (*PFNCHARWIDTH)(HDC, UINT, UINT, LPINT);
    00032
    00033 /***************************************************************************\
    00034 *
    00035 *  GetMaxOverlapChars - Gives maximum number of overlapping characters due to
    00036 *                       negative A or C widths.
    00037 *
    00038 \***************************************************************************/
    00039 DWORD GetMaxOverlapChars( void )
    00040 {
    00041     return (DWORD) MAKELONG( gpsi->wMaxLeftOverlapChars, gpsi->wMaxRightOverlapChars ) ;
    00042 }
    00043
    00044 /***************************************************************************\
    00045 *
    00046 *  ECSetMargin()
    00047 *
    00048 \***************************************************************************/
    00049 void ECSetMargin(PED ped, UINT  wFlags, long lMarginValues, BOOL fRedraw)
    00050 {
    00051     BOOL fUseFontInfo = FALSE;
    00052     UINT wValue, wOldLeftMargin, wOldRightMargin;
    00053
    00054
    00055     if (wFlags & EC_LEFTMARGIN)  /* Set the left margin */ {
    00056
    00057         if ((int) (wValue = (int)(short)LOWORD(lMarginValues)) < 0) {
    00058             fUseFontInfo = TRUE;
    00059             wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegA);
    00060         }
    00061
    00062         ped->rcFmt.left += wValue - ped->wLeftMargin;
    00063         wOldLeftMargin = ped->wLeftMargin;
    00064         ped->wLeftMargin = wValue;
    00065     }
    00066
    00067     if (wFlags & EC_RIGHTMARGIN)  /* Set the Right margin */ {
    00068
    00069         if ((int) (wValue = (int)(short)HIWORD(lMarginValues)) < 0) {
    00070             fUseFontInfo = TRUE;
    00071             wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegC);
    00072         }
    00073
    00074         ped->rcFmt.right -= wValue - ped->wRightMargin;
    00075         wOldRightMargin = ped->wRightMargin;
    00076         ped->wRightMargin = wValue;
    00077     }
    00078
    00079     if (fUseFontInfo) {
    00080         if (ped->rcFmt.right - ped->rcFmt.left < 2 * ped->aveCharWidth) {
    00081             RIPMSG0(RIP_WARNING, "ECSetMargin: rcFmt is too narrow for EC_USEFONTINFO");
    00082
    00083             if (wFlags & EC_LEFTMARGIN)  /* Reset the left margin */ {
    00084                 ped->rcFmt.left += wOldLeftMargin - ped->wLeftMargin;
    00085                 ped->wLeftMargin = wOldLeftMargin;
    00086             }
    00087
    00088             if (wFlags & EC_RIGHTMARGIN)  /* Reset the Right margin */ {
    00089                 ped->rcFmt.right -= wOldRightMargin - ped->wRightMargin;
    00090                 ped->wRightMargin = wOldRightMargin;
    00091             }
    00092
    00093             return;
    00094         }
    00095     }
    00096
    00097 //    NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
    00098     if (fRedraw) {
    00099         ECInvalidateClient(ped, TRUE);
    00100     }
    00101 }
    00102
    00103 // --------------------------------------------------------------------------
    00104 //
    00105 //  ECCalcMarginfForDBCSFont()
    00106 //
    00107 // Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (edecrare.c)
    00108 // --------------------------------------------------------------------------
    00109 void ECCalcMarginForDBCSFont(PED ped, BOOL fRedraw)
    00110 {
    00111     if (!ped->fTrueType)
    00112         return;
    00113
    00114     if (!ped->fSingle) {
    00115         // wMaxNegA came from ABC CharWidth.
    00116         if (ped->wMaxNegA != 0) {
    00117             ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
    00118                     MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO),fRedraw);
    00119         }
    00120     } else {
    00121         int    iMaxNegA = 0, iMaxNegC = 0;
    00122         int    i;
    00123         PVOID  lpBuffer;
    00124         LPABC  lpABCBuff;
    00125         ABC    ABCInfo;
    00126         HFONT  hOldFont;
    00127         HDC    hdc = NtUserGetDC(ped->hwnd);
    00128
    00129         if (!ped->hFont || !(hOldFont = SelectFont(hdc, ped->hFont))) {
    00130             ReleaseDC(ped->hwnd, hdc);
    00131             return;
    00132         }
    00133
    00134         if (lpBuffer = UserLocalAlloc(0,sizeof(ABC) * 256)) {
    00135             lpABCBuff = lpBuffer;
    00136             GetCharABCWidthsAorW(hdc, 0, 255, lpABCBuff);
    00137         } else {
    00138             lpABCBuff = &ABCInfo;
    00139             GetCharABCWidthsAorW(hdc, 0, 0, lpABCBuff);
    00140         }
    00141
    00142         i = 0;
    00143         while (TRUE) {
    00144             iMaxNegA = min(iMaxNegA, lpABCBuff->abcA);
    00145             iMaxNegC = min(iMaxNegC, lpABCBuff->abcC);
    00146             if (++i == 256)
    00147                 break;
    00148             if (lpBuffer) {
    00149                 lpABCBuff++;
    00150             } else {
    00151                 GetCharABCWidthsAorW(hdc, i, i, lpABCBuff);
    00152             }
    00153         }
    00154
    00155         SelectFont(hdc, hOldFont);
    00156
    00157         if (lpBuffer) UserLocalFree(lpBuffer);
    00158
    00159         ReleaseDC(ped->hwnd, hdc);
    00160
    00161         if ((iMaxNegA != 0) || (iMaxNegC != 0))
    00162            ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
    00163                     MAKELONG((UINT)(-iMaxNegC), (UINT)(-iMaxNegA)),fRedraw);
    00164     }
    00165
    00166     return;
    00167 }
    00168
    00169 // --------------------------------------------------------------------------
    00170 //
    00171 //  GetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
    00172 //
    00173 // Jun.24.1996 HideyukN - Ported from Windows95 FarEast version (wmclient.c)
    00174 // --------------------------------------------------------------------------
    00175
    00176 WCHAR AveCharWidthData[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    00177 //
    00178 // if an app set a font for vertical writing, even though we don't
    00179 // handle it with EC, the escapement of tm can be NON 0. Then cxWidth from
    00180 // GetCharDimenstions() could be 0 in GetCharDimensions().
    00181 // This will break our caller who don't expect 0 at return. So I created
    00182 // this entry  for the case the caller set vertical font.
    00183 //
    00184 //
    00185 int UserGetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
    00186 {
    00187     int         cxWidth;
    00188     TEXTMETRIC  tm;
    00189     LOGFONTW    lf;
    00190     WCHAR       wchFaceName[LF_FACESIZE];
    00191
    00192     //
    00193     // Is this font vertical font ??
    00194     //
    00195     GetTextFaceW(hDC, LF_FACESIZE, wchFaceName);
    00196     if (wchFaceName[0] != L'@') {
    00197         //
    00198         // if not call GDI...
    00199         //
    00200         return(GdiGetCharDimensions(hDC, lptm, lpcy));
    00201     }
    00202
    00203     if (!lptm)
    00204         lptm = &tm;
    00205
    00206     GetTextMetrics(hDC, lptm);
    00207
    00208     // TMPF_FIXED_PITCH
    00209     //
    00210     //   If this bit is set the font is a variable pitch font.
    00211     //   If this bit is clear the font is a fixed pitch font.
    00212     // Note very carefully that those meanings are the opposite of what the constant name implies.
    00213     //
    00214     if (!(lptm->tmPitchAndFamily & TMPF_FIXED_PITCH)) { // If !variable_width font
    00215         // This is fixed pitch font....
    00216         cxWidth = lptm->tmAveCharWidth;
    00217     } else {
    00218         // This is variable pitch font...
    00219         if (hfont && GetObjectW(hfont, sizeof(LOGFONTW), &lf) && (lf.lfEscapement != 0)) {
    00220             cxWidth = lptm->tmAveCharWidth;
    00221         } else {
    00222             SIZE size;
    00223             GetTextExtentPointW(hDC, AveCharWidthData, 52, &size);
    00224             cxWidth = ((size.cx / 26) + 1) / 2;
    00225         }
    00226     }
    00227
    00228     if (lpcy)
    00229         *lpcy = lptm->tmHeight;
    00230
    00231     return(cxWidth);
    00232 }
    00233
    00234 /***************************************************************************\
    00235 * ECGetText AorW
    00236 *
    00237 * Copies at most maxCchToCopy chars to the buffer lpBuffer. Returns
    00238 * how many chars were actually copied. Null terminates the string based
    00239 * on the fNullTerminate flag:
    00240 * fNullTerminate --> at most (maxCchToCopy - 1) characters will be copied
    00241 * !fNullTerminate --> at most (maxCchToCopy) characters will be copied
    00242 *
    00243 * History:
    00244 \***************************************************************************/
    00245
    00246 ICH ECGetText(
    00247     PED ped,
    00248     ICH maxCchToCopy,
    00249     LPSTR lpBuffer,
    00250     BOOL fNullTerminate)
    00251 {
    00252     PSTR pText;
    00253
    00254     if (maxCchToCopy) {
    00255
    00256         /*
    00257          * Zero terminator takes the extra byte
    00258          */
    00259         if (fNullTerminate)
    00260             maxCchToCopy--;
    00261         maxCchToCopy = min(maxCchToCopy, ped->cch);
    00262
    00263         /*
    00264          * Zero terminate the string
    00265          */
    00266         if (ped->fAnsi)
    00267             *(LPSTR)(lpBuffer + maxCchToCopy) = 0;
    00268         else
    00269             *(((LPWSTR)lpBuffer) + maxCchToCopy) = 0;
    00270
    00271         pText = ECLock(ped);
    00272         RtlCopyMemory(lpBuffer, pText, maxCchToCopy*ped->cbChar);
    00273         ECUnlock(ped);
    00274     }
    00275
    00276     return maxCchToCopy;
    00277 }
    00278
    00279 /***************************************************************************\
    00280 * ECNcCreate AorW
    00281 *
    00282 * History:
    00283 \***************************************************************************/
    00284
    00285 BOOL ECNcCreate(
    00286     PED ped,
    00287     PWND pwnd,
    00288     LPCREATESTRUCT lpCreateStruct)
    00289 {
    00290     HWND hwnd = HWq(pwnd);
    00291     BOOL fAnsi;
    00292
    00293     fAnsi = TestWF(pwnd, WFANSICREATOR);
    00294
    00295     /*
    00296      * Initialize the ped
    00297      */
    00298     ped->fEncoded = FALSE;
    00299     ped->iLockLevel = 0;
    00300
    00301     ped->chLines = NULL;
    00302     ped->pTabStops = NULL;
    00303     ped->charWidthBuffer = NULL;
    00304     ped->fAnsi = fAnsi ? 1 : 0; // Force TRUE to be 1 because its a 1 bit field
    00305     ped->cbChar = (WORD)(fAnsi ? sizeof(CHAR) : sizeof(WCHAR));
    00306     ped->hInstance = pwnd->hModule;
    00307     // IME
    00308     ped->hImcPrev = NULL_HIMC;
    00309
    00310     {
    00311         DWORD dwVer = GETEXPWINVER(lpCreateStruct->hInstance);
    00312
    00313         ped->fWin31Compat = (dwVer >= 0x030a);
    00314         ped->f40Compat = (dwVer >= 0x0400);
    00315     }
    00316
    00317     //
    00318     // NOTE:
    00319     // The order of the following two checks is important.  People can
    00320     // create edit fields with a 3D and a normal border, and we don't
    00321     // want to disallow that.  But we need to detect the "no 3D border"
    00322     // border case too.
    00323     //
    00324     if (TestWF(pwnd, WEFEDGEMASK))
    00325     {
    00326         ped->fBorder = TRUE;
    00327     }
    00328     else if (TestWF(pwnd, WFBORDER))
    00329     {
    00330         ClearWindowState(pwnd, WFBORDER);
    00331         ped->fFlatBorder = TRUE;
    00332         ped->fBorder = TRUE;
    00333     }
    00334
    00335     if (!TestWF(pwnd, EFMULTILINE))
    00336         ped->fSingle = TRUE;
    00337
    00338     if (TestWF(pwnd, WFDISABLED))
    00339         ped->fDisabled = TRUE;
    00340
    00341     if (TestWF(pwnd, EFREADONLY)) {
    00342         if (!ped->fWin31Compat) {
    00343             /*
    00344              * BACKWARD COMPATIBILITY HACK
    00345              *
    00346              * "MileStone" unknowingly sets the ES_READONLY style. So, we strip this
    00347              * style here for all Win3.0 apps (this style is new for Win3.1).
    00348              * Fix for Bug #12982 -- SANKAR -- 01/24/92 --
    00349              */
    00350              ClearWindowState(pwnd, EFREADONLY);
    00351         } else
    00352             ped->fReadOnly = TRUE;
    00353     }
    00354
    00355
    00356     /*
    00357      * Allocate storage for the text for the edit controls. Storage for single
    00358      * line edit controls will always get allocated in the local data segment.
    00359      * Multiline will allocate in the local ds but the app may free this and
    00360      * allocate storage elsewhere...
    00361      */
    00362     ped->hText = LOCALALLOC(LHND, CCHALLOCEXTRA*ped->cbChar, ped->hInstance);
    00363     if (!ped->hText) {
    00364         FreeLookasideEntry(&EditLookaside, ped);
    00365         NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT); /* No ped for this window */
    00366         return FALSE; /* If no_memory error */
    00367     }
    00368
    00369     ped->cchAlloc = CCHALLOCEXTRA;
    00370     ped->lineHeight = 1;
    00371
    00372     ped->hwnd = hwnd;
    00373     ped->hwndParent = lpCreateStruct->hwndParent;
    00374
    00375     ped->wImeStatus = 0;
    00376
    00377     return (BOOL)DefWindowProcWorker(pwnd, WM_NCCREATE, 0,
    00378             (LPARAM)lpCreateStruct, fAnsi);
    00379 }
    00380
    00381 /***************************************************************************\
    00382 * ECCreate AorW
    00383 *
    00384 * History:
    00385 \***************************************************************************/
    00386
    00387 BOOL ECCreate(
    00388     PED ped,
    00389     LONG windowStyle)
    00390 {
    00391     HDC hdc;
    00392
    00393     /*
    00394      * Get values from the window instance data structure and put them in the
    00395      * ped so that we can access them easier.
    00396      */
    00397     if (windowStyle & ES_AUTOHSCROLL)
    00398         ped->fAutoHScroll = 1;
    00399     if (windowStyle & ES_NOHIDESEL)
    00400         ped->fNoHideSel = 1;
    00401
    00402     ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK));
    00403     if (TestWF(ped->pwnd, WEFRIGHT) && !ped->format)
    00404         ped->format = ES_RIGHT;
    00405
    00406     ped->cchTextMax = MAXTEXT; /* Max # chars we will initially allow */
    00407
    00408     /*
    00409      * Set up undo initial conditions... (ie. nothing to undo)
    00410      */
    00411     ped->ichDeleted = (ICH)-1;
    00412     ped->ichInsStart = (ICH)-1;
    00413     ped->ichInsEnd = (ICH)-1;
    00414
    00415     // initial charset value - need to do this BEFORE MLCreate is called
    00416     // so that we know not to fool with scrollbars if nessacary
    00417     hdc = ECGetEditDC(ped, TRUE);
    00418     ped->charSet = (BYTE)GetTextCharset(hdc);
    00419     ECReleaseEditDC(ped, hdc, TRUE);
    00420
    00421     // FE_IME
    00422     // EC_INSERT_COMPOSITION_CHARACTER: ECCreate() - call ECInitInsert()
    00423     ECInitInsert(ped, THREAD_HKL());
    00424
    00425     if(ped->pLpkEditCallout = fpLpkEditControl) {
    00426         return ped->pLpkEditCallout->EditCreate(ped, HW(ped->pwnd));
    00427     } else
    00428         return TRUE;
    00429 }
    00430
    00431 /***************************************************************************\
    00432 * ECNcDestroyHandler AorW
    00433 *
    00434 * Destroys the edit control ped by freeing up all memory used by it.
    00435 *
    00436 * History:
    00437 \***************************************************************************/
    00438
    00439 void ECNcDestroyHandler(
    00440     PWND pwnd,
    00441     PED ped)
    00442 {
    00443     PWND pwndParent;
    00444
    00445     /*
    00446      * ped could be NULL if WM_NCCREATE failed to create it...
    00447      */
    00448     if (ped) {
    00449
    00450         /*
    00451          * Free the text buffer (always present?)
    00452          */
    00453         LOCALFREE(ped->hText, ped->hInstance);
    00454
    00455         /*
    00456          * Free up undo buffer and line start array (if present)
    00457          */
    00458         if (ped->hDeletedText != NULL)
    00459             UserGlobalFree(ped->hDeletedText);
    00460
    00461         /*
    00462          * Free tab stop buffer (if present)
    00463          */
    00464         if (ped->pTabStops)
    00465             UserLocalFree(ped->pTabStops);
    00466
    00467         /*
    00468          * Free line start array (if present)
    00469          */
    00470         if (ped->chLines) {
    00471             UserLocalFree(ped->chLines);
    00472         }
    00473
    00474         /*
    00475          * Free the character width buffer (if present)
    00476          */
    00477         if (ped->charWidthBuffer)
    00478             UserLocalFree(ped->charWidthBuffer);
    00479
    00480         /*
    00481          * Free the cursor bitmap
    00482          */
    00483         if (ped->pLpkEditCallout && ped->hCaretBitmap) {
    00484             DeleteObject(ped->hCaretBitmap);
    00485         }
    00486
    00487         /*
    00488          * Last but not least, free the ped
    00489          */
    00490         FreeLookasideEntry(&EditLookaside, ped);
    00491     }
    00492
    00493     /*
    00494      * Set the window's fnid status so that we can ignore rogue messages
    00495      */
    00496     NtUserSetWindowFNID(HWq(pwnd), FNID_CLEANEDUP_BIT);
    00497
    00498     /*
    00499      * If we're part of a combo box, let it know we're gone
    00500      */
    00501     pwndParent = REBASEPWND(pwnd, spwndParent);
    00502     if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) {
    00503         ComboBoxWndProcWorker(pwndParent, WM_PARENTNOTIFY,
    00504                 MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd), FALSE);
    00505     }
    00506 }
    00507
    00508 /***************************************************************************\
    00509 * ECSetPasswordChar AorW
    00510 *
    00511 * Sets the password char to display.
    00512 *
    00513 * History:
    00514 \***************************************************************************/
    00515
    00516 void ECSetPasswordChar(
    00517     PED ped,
    00518     UINT pwchar)
    00519 {
    00520     HDC hdc;
    00521     SIZE size;
    00522
    00523     ped->charPasswordChar = pwchar;
    00524
    00525     if (pwchar) {
    00526         hdc = ECGetEditDC(ped, TRUE);
    00527         if (ped->fAnsi)
    00528             GetTextExtentPointA(hdc, (LPSTR)&pwchar, 1, &size);
    00529         else
    00530             GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
    00531
    00532         GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
    00533         ped->cPasswordCharWidth = max(size.cx, 1);
    00534         ECReleaseEditDC(ped, hdc, TRUE);
    00535     }
    00536     if (pwchar)
    00537         SetWindowState(ped->pwnd, EFPASSWORD);
    00538     else
    00539         ClearWindowState(ped->pwnd, EFPASSWORD);
    00540
    00541     ECEnableDisableIME(ped);
    00542 }
    00543
    00544 /***************************************************************************\
    00545 *  GetNegABCwidthInfo()
    00546 *    This function fills up the ped->charWidthBuffer buffer with the
    00547 *      negative A,B and C widths for all the characters below 0x7f in the
    00548 *      currently selected font.
    00549 *  Returns:
    00550 * TRUE, if the function succeeded.
    00551 * FALSE, if GDI calls to get the char widths have failed.
    00552 *
    00553 * Note: not used if LPK installed
    00554 \***************************************************************************/
    00555 BOOL   GetNegABCwidthInfo(
    00556     PED ped,
    00557     HDC hdc)
    00558 {
    00559     LPABC lpABCbuff;
    00560     int   i;
    00561     int   CharWidthBuff[CHAR_WIDTH_BUFFER_LENGTH]; // Local char width buffer.
    00562     int   iOverhang;
    00563
    00564     if (!GetCharABCWidthsA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPABC)ped->charWidthBuffer)) {
    00565         RIPMSG0(RIP_WARNING, "GetNegABCwidthInfo: GetCharABCWidthsA Failed");
    00566         return FALSE;
    00567     }
    00568
    00569    // The (A+B+C) returned for some fonts (eg: Lucida Caligraphy) does not
    00570    // equal the actual advanced width returned by GetCharWidths() minus overhang.
    00571    // This is due to font bugs. So, we adjust the 'B' width so that this
    00572    // discrepancy is removed.
    00573    // Fix for Bug #2932 --sankar-- 02/17/93
    00574    iOverhang = ped->charOverhang;
    00575    GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPINT)CharWidthBuff);
    00576    lpABCbuff = (LPABC)ped->charWidthBuffer;
    00577    for(i = 0; i < CHAR_WIDTH_BUFFER_LENGTH; i++) {
    00578         lpABCbuff->abcB = CharWidthBuff[i] - iOverhang
    00579                 - lpABCbuff->abcA
    00580                 - lpABCbuff->abcC;
    00581         lpABCbuff++;
    00582    }
    00583
    00584    return(TRUE);
    00585 }
    00586
    00587 /***************************************************************************\
    00588 *
    00589 *  ECSize() -
    00590 *
    00591 *  Handle sizing for an edit control's client rectangle.
    00592 *  Use lprc as the bounding rectangle if specified; otherwise use the current
    00593 *  client rectangle.
    00594 *
    00595 \***************************************************************************/
    00596
    00597 void ECSize(
    00598     PED ped,
    00599     LPRECT lprc,
    00600     BOOL fRedraw)
    00601 {
    00602     RECT    rc;
    00603
    00604     /*
    00605      *  BiDi VB32 Creates an Edit Control and immediately sends a WM_SIZE
    00606      *  message which causes EXSize to be called before ECSetFont, which
    00607      *  in turn causes a divide by zero exception below. This check for
    00608      *  ped->lineHeight will pick it up safely. [samera] 3/5/97
    00609      */
    00610     if(ped->lineHeight == 0)
    00611         return;
    00612
    00613     // assume that we won't be able to display the caret
    00614     ped->fCaretHidden = TRUE;
    00615
    00616
    00617     if ( lprc )
    00618         CopyRect(&rc, lprc);
    00619     else
    00620         _GetClientRect(ped->pwnd, &rc);
    00621
    00622     if (!(rc.right - rc.left) || !(rc.bottom - rc.top)) {
    00623         if (ped->rcFmt.right - ped->rcFmt.left)
    00624             return;
    00625
    00626         rc.left     = 0;
    00627         rc.top      = 0;
    00628         rc.right    = ped->aveCharWidth * 10;
    00629         rc.bottom   = ped->lineHeight;
    00630     }
    00631
    00632     if (!lprc) {
    00633         // subtract the margins from the given rectangle --
    00634         // make sure that this rectangle is big enough to have these margins.
    00635         if ((rc.right - rc.left) > (int)(ped->wLeftMargin + ped->wRightMargin)) {
    00636             rc.left  += ped->wLeftMargin;
    00637             rc.right -= ped->wRightMargin;
    00638         }
    00639     }
    00640
    00641     //
    00642     // Leave space so text doesn't touch borders.
    00643     // For 3.1 compatibility, don't subtract out vertical borders unless
    00644     // there is room.
    00645     //
    00646     if (ped->fBorder) {
    00647         int cxBorder = SYSMET(CXBORDER);
    00648         int cyBorder = SYSMET(CYBORDER);
    00649
    00650         if (ped->fFlatBorder)
    00651         {
    00652             cxBorder *= 2;
    00653             cyBorder *= 2;
    00654         }
    00655
    00656         if (rc.bottom < rc.top + ped->lineHeight + 2*cyBorder)
    00657             cyBorder = 0;
    00658
    00659         InflateRect(&rc, -cxBorder, -cyBorder);
    00660     }
    00661
    00662     // Is the resulting rectangle too small?  Don't change it then.
    00663     if ((!ped->fSingle) && ((rc.right - rc.left < (int) ped->aveCharWidth) ||
    00664         ((rc.bottom - rc.top) / ped->lineHeight == 0)))
    00665         return;
    00666
    00667     // now, we know we're safe to display the caret
    00668     ped->fCaretHidden = FALSE;
    00669
    00670     CopyRect(&ped->rcFmt, &rc);
    00671
    00672     if (ped->fSingle)
    00673         ped->rcFmt.bottom = min(rc.bottom, rc.top + ped->lineHeight);
    00674     else
    00675         MLSize(ped, fRedraw);
    00676
    00677     if (fRedraw) {
    00678         NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
    00679         // UpdateWindow31(ped->hwnd);    Evaluates to NOP in Chicago - Johnl
    00680     }
    00681
    00682     // FE_IME
    00683     // ECSize()  - call ECImmSetCompositionWindow()
    00684     //
    00685     // normally this isn't needed because WM_SIZE will cause
    00686     // WM_PAINT and the paint handler will take care of IME
    00687     // composition window. However when the edit window is
    00688     // restored from maximized window and client area is out
    00689     // of screen, the window will not be redrawn.
    00690     //
    00691     if (ped->fFocus && fpImmIsIME(THREAD_HKL())) {
    00692         POINT pt;
    00693
    00694         NtUserGetCaretPos(&pt);
    00695         ECImmSetCompositionWindow(ped, pt.x, pt.y);
    00696     }
    00697 }
    00698
    00699 /***************************************************************************\
    00700 *
    00701 *  ECSetFont AorW () -
    00702 *
    00703 *  Sets the font used in the edit control.  Warning:  Memory compaction may
    00704 *  occur if the font wasn't previously loaded.  If the font handle passed
    00705 *  in is NULL, assume the system font.
    00706 *
    00707 \***************************************************************************/
    00708 void   ECSetFont(
    00709     PED ped,
    00710     HFONT hfont,
    00711     BOOL fRedraw)
    00712 {
    00713     short  i;
    00714     TEXTMETRIC      TextMetrics;
    00715     HDC             hdc;
    00716     HFONT           hOldFont=NULL;
    00717     UINT            wBuffSize;
    00718     LPINT           lpCharWidthBuff;
    00719     DWORD           dwMaxOverlapChars;
    00720     CHWIDTHINFO     cwi;
    00721     UINT            uExtracharPos;
    00722
    00723     hdc = NtUserGetDC(ped->hwnd);
    00724
    00725     if (ped->hFont = hfont) {
    00726         //
    00727         // Since the default font is the system font, no need to select it in
    00728         // if that's what the user wants.
    00729         //
    00730         if (!(hOldFont = SelectObject(hdc, hfont))) {
    00731             hfont = ped->hFont = NULL;
    00732         }
    00733
    00734         //
    00735         // Get the metrics and ave char width for the currently selected font
    00736         //
    00737
    00738         //
    00739         // Call Vertical font-aware AveWidth compute function...
    00740         //
    00741         // FE_SB
    00742         ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
    00743
    00744         /*
    00745          * This might fail when people uses network fonts (or bad fonts).
    00746          */
    00747         if (ped->aveCharWidth == 0) {
    00748             RIPMSG0(RIP_WARNING, "ECSetFont: GdiGetCharDimensions failed");
    00749             if (hOldFont != NULL) {
    00750                 SelectObject(hdc, hOldFont);
    00751             }
    00752
    00753             /*
    00754              * We've messed up the ped so let's reset the font.
    00755              *  Note that we won't recurse more than once because we'll
    00756              *  pass hfont == NULL.
    00757              * Too bad WM_SETFONT doesn't return a value.
    00758              */
    00759             ECSetFont(ped, NULL, fRedraw);
    00760             return;
    00761         }
    00762     } else {
    00763         ped->aveCharWidth = gpsi->cxSysFontChar;
    00764         ped->lineHeight = gpsi->cySysFontChar;
    00765         TextMetrics = gpsi->tmSysFont;
    00766     }
    00767
    00768     ped->charOverhang = TextMetrics.tmOverhang;
    00769
    00770     //assume that they don't have any negative widths at all.
    00771     ped->wMaxNegA = ped->wMaxNegC = ped->wMaxNegAcharPos = ped->wMaxNegCcharPos = 0;
    00772
    00773
    00774     // Check if Proportional Width Font
    00775     //
    00776     // NOTE: as SDK doc says about TEXTMETRIC:
    00777     // TMPF_FIXED_PITCH
    00778     // If this bit is set the font is a variable pitch font. If this bit is clear
    00779     // the font is a fixed pitch font. Note very carefully that those meanings are
    00780     // the opposite of what the constant name implies.
    00781     //
    00782     // Thus we have to reverse the value using logical not (fNonPropFont has 1 bit width)
    00783     //
    00784     ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & FIXED_PITCH);
    00785
    00786     // Check for a TrueType font
    00787     // Older app OZWIN chokes if we allocate a bigger buffer for TrueType fonts
    00788     // So, for apps older than 4.0, no special treatment for TrueType fonts.
    00789     if (ped->f40Compat && (TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
    00790         ped->fTrueType = GetCharWidthInfo(hdc, &cwi);
    00791 #if DBG
    00792         if (!ped->fTrueType) {
    00793             RIPMSG0(RIP_WARNING, "ECSetFont: GetCharWidthInfo Failed");
    00794         }
    00795 #endif
    00796     } else {
    00797         ped->fTrueType = FALSE;
    00798     }
    00799
    00800     // FE_SB
    00801     //
    00802     // In DBCS Windows, Edit Control must handle Double Byte Character
    00803     // if tmCharSet field of textmetrics is double byte character set
    00804     // such as SHIFTJIS_CHARSET(128:Japan), HANGEUL_CHARSET(129:Korea).
    00805     //
    00806     // We call ECGetDBCSVector even when fAnsi is false so that we could
    00807     // treat ped->fAnsi and ped->fDBCS indivisually. I changed ECGetDBCSVector
    00808     // function so that it returns 0 or 1, because I would like to set ped->fDBCS
    00809     // bit field here.
    00810     //
    00811     ped->fDBCS = ECGetDBCSVector(ped,hdc,TextMetrics.tmCharSet);
    00812     ped->charSet = TextMetrics.tmCharSet;
    00813
    00814     if (ped->fDBCS) {
    00815         //
    00816         // Free the character width buffer if ped->fDBCS.
    00817         //
    00818         // I expect single GetTextExtentPoint call is faster than multiple
    00819         // GetTextExtentPoint call (because the graphic engine has a cache buffer).
    00820         // See editec.c/ECTabTheTextOut().
    00821         //
    00822         if (ped->charWidthBuffer) {
    00823             LocalFree(ped->charWidthBuffer);
    00824             ped->charWidthBuffer = NULL;
    00825         }
    00826
    00827         //
    00828         // if FullWidthChar : HalfWidthChar == 2 : 1....
    00829         //
    00830         // TextMetrics.tmMaxCharWidth = FullWidthChar width
    00831         // ped->aveCharWidth          = HalfWidthChar width
    00832         //
    00833         if (ped->fNonPropFont &&
    00834             ((ped->aveCharWidth * 2) == TextMetrics.tmMaxCharWidth)) {
    00835             ped->fNonPropDBCS = TRUE;
    00836         } else {
    00837             ped->fNonPropDBCS = FALSE;
    00838         }
    00839
    00840     } else {
    00841
    00842         //
    00843         // Since the font has changed, let us obtain and save the character width
    00844         // info for this font.
    00845         //
    00846         // First left us find out if the maximum chars that can overlap due to
    00847         // negative widths. Since we can't access USER globals, we make a call here.
    00848         //
    00849         if (!(ped->fSingle || ped->pLpkEditCallout)) {  // Is this a multiline edit control with no LPK present?
    00850             //
    00851             // For multiline edit controls, we maintain a buffer that contains
    00852             // the character width information.
    00853             //
    00854             wBuffSize = (ped->fTrueType) ? (CHAR_WIDTH_BUFFER_LENGTH * sizeof(ABC)) :
    00855                                            (CHAR_WIDTH_BUFFER_LENGTH * sizeof(int));
    00856
    00857             if (ped->charWidthBuffer) { /* If buffer already present */
    00858                 lpCharWidthBuff = ped->charWidthBuffer;
    00859                 ped->charWidthBuffer = UserLocalReAlloc(lpCharWidthBuff, wBuffSize, HEAP_ZERO_MEMORY);
    00860                 if (ped->charWidthBuffer == NULL) {
    00861                     UserLocalFree((HANDLE)lpCharWidthBuff);
    00862                 }
    00863             } else {
    00864                 ped->charWidthBuffer = UserLocalAlloc(HEAP_ZERO_MEMORY, wBuffSize);
    00865             }
    00866
    00867             if (ped->charWidthBuffer != NULL) {
    00868                 if (ped->fTrueType) {
    00869                     ped->fTrueType = GetNegABCwidthInfo(ped, hdc);
    00870                 }
    00871
    00872                 /*
    00873                  * It is possible that the above attempts could have failed and reset
    00874                  * the value of fTrueType. So, let us check that value again.
    00875                  */
    00876                 if (!ped->fTrueType) {
    00877                     if (!GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, ped->charWidthBuffer)) {
    00878                         UserLocalFree((HANDLE)ped->charWidthBuffer);
    00879                         ped->charWidthBuffer=NULL;
    00880                     } else {
    00881                         /*
    00882                          * We need to subtract out the overhang associated with
    00883                          * each character since GetCharWidth includes it...
    00884                          */
    00885                         for (i=0;i < CHAR_WIDTH_BUFFER_LENGTH;i++)
    00886                             ped->charWidthBuffer[i] -= ped->charOverhang;
    00887                     }
    00888                 }
    00889             } /* if (ped->charWidthBuffer != NULL) */
    00890         } /* if (!ped->fSingle) */
    00891     } /* if (ped->fDBCS) */
    00892
    00893     {
    00894         /*
    00895          * Calculate MaxNeg A C metrics
    00896          */
    00897         dwMaxOverlapChars = GetMaxOverlapChars();
    00898         if (ped->fTrueType) {
    00899             if (cwi.lMaxNegA < 0)
    00900                 ped->wMaxNegA = -cwi.lMaxNegA;
    00901             else
    00902                 ped->wMaxNegA = 0;
    00903             if (cwi.lMaxNegC < 0)
    00904                 ped->wMaxNegC = -cwi.lMaxNegC;
    00905             else
    00906                 ped->wMaxNegC = 0;
    00907             if (cwi.lMinWidthD != 0) {
    00908                 ped->wMaxNegAcharPos = (ped->wMaxNegA + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
    00909                 ped->wMaxNegCcharPos = (ped->wMaxNegC + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
    00910                 if (ped->wMaxNegA + ped->wMaxNegC > (UINT)cwi.lMinWidthD) {
    00911                     uExtracharPos = (ped->wMaxNegA + ped->wMaxNegC - 1) / cwi.lMinWidthD;
    00912                     ped->wMaxNegAcharPos += uExtracharPos;
    00913                     ped->wMaxNegCcharPos += uExtracharPos;
    00914                 }
    00915             } else {
    00916                 ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars);     // Left
    00917                 ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars);     // Right
    00918             }
    00919
    00920         } else if (ped->charOverhang != 0) {
    00921             /*
    00922              * Some bitmaps fonts (i.e., italic) have under/overhangs;
    00923              *  this is pretty much like having negative A and C widths.
    00924              */
    00925             ped->wMaxNegA = ped->wMaxNegC = ped->charOverhang;
    00926             ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars);     // Left
    00927             ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars);     // Right
    00928         }
    00929     } /* if (ped->fDBCS) */
    00930
    00931     if (!hfont) {
    00932         //
    00933         // We are getting the stats for the system font so update the system
    00934         // font fields in the ed structure since we use these when calculating
    00935         // some spacing.
    00936         //
    00937         ped->cxSysCharWidth = ped->aveCharWidth;
    00938         ped->cySysCharHeight= ped->lineHeight;
    00939     } else if (hOldFont)
    00940         SelectObject(hdc, hOldFont);
    00941
    00942     if (ped->fFocus) {
    00943         //
    00944         // Update the caret.
    00945         //
    00946         NtUserHideCaret(ped->hwnd);
    00947         NtUserDestroyCaret();
    00948
    00949         if (ped->pLpkEditCallout) {
    00950             ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, 0);
    00951         }
    00952         else {
    00953             NtUserCreateCaret(ped->hwnd, (HBITMAP)NULL, ECGetCaretWidth(), ped->lineHeight);
    00954         }
    00955         NtUserShowCaret(ped->hwnd);
    00956     }
    00957
    00958     ReleaseDC(ped->hwnd, hdc);
    00959
    00960     //
    00961     // Update password character.
    00962     //
    00963     if (ped->charPasswordChar)
    00964         ECSetPasswordChar(ped, ped->charPasswordChar);
    00965
    00966     //
    00967     // If it is a TrueType font and it's a new app, set both the margins at the
    00968     // max negative width values for all types of the edit controls.
    00969     // (NOTE: Can't use ped->f40Compat here because edit-controls inside dialog
    00970     // boxes without DS_LOCALEDIT style are always marked as 4.0 compat.
    00971     // This is the fix for NETBENCH 3.0)
    00972     //
    00973
    00974     if (ped->fTrueType && (GETAPPVER() >= VER40))
    00975         if (ped->fDBCS) {
    00976             // For DBCS TrueType Font, we calc margin from ABC width.
    00977             ECCalcMarginForDBCSFont(ped, fRedraw);
    00978         } else {
    00979             ECSetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
    00980                         MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO), fRedraw);
    00981         }
    00982
    00983     //
    00984     // We need to calc maxPixelWidth when font changes.
    00985     // If the word-wrap is ON, then this is done in MLSize() called later.
    00986     //
    00987     if((!ped->fSingle) && (!ped->fWrap))
    00988         MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL);
    00989
    00990     //
    00991     // Recalc the layout.
    00992     //
    00993     ECSize(ped, NULL, fRedraw);
    00994
    00995     if ( ped->fFocus && fpImmIsIME(THREAD_HKL()) ) {
    00996         ECImmSetCompositionFont( ped );
    00997     }
    00998 }
    00999
    01000
    01001
    01002 /***************************************************************************\
    01003 *
    01004 *  ECIsCharNumeric AorW () -
    01005 *
    01006 *  Tests whether the character entered is a numeral.
    01007 *  For multiline and singleline edit controls with the ES_NUMBER style.
    01008 *
    01009 \***************************************************************************/
    01010 BOOL ECIsCharNumeric(
    01011     PED ped,
    01012     DWORD keyPress)
    01013 {
    01014     WORD wCharType;
    01015
    01016     if (ped->fAnsi) {
    01017         char ch = (char)keyPress;
    01018         LCID lcid = (LCID)((ULONG_PTR)THREAD_HKL() & 0xFFFF);
    01019         GetStringTypeA(lcid, CT_CTYPE1, &ch, 1, &wCharType);
    01020     } else {
    01021         WCHAR wch = (WCHAR)keyPress;
    01022         GetStringTypeW(CT_CTYPE1, &wch, 1, &wCharType);
    01023     }
    01024     return (wCharType & C1_DIGIT ? TRUE : FALSE);
    01025 }
    01026
    01027 /***************************************************************************\
    01028 *
    01029 *  ECEnableDisableIME( PED ped )
    01030 *
    01031 *
    01032 *  xx/xx/9x by somebody     Created for Win95
    01033 *  xx/xx/95 by kazum        Ported to NT-J 3.51
    01034 *  04/15/96 by takaok       Ported to NT 4.0
    01035 *
    01036 \***************************************************************************/
    01037 VOID ECEnableDisableIME( PED ped )
    01038 {
    01039     if ( ped->fReadOnly || ped->charPasswordChar ) {
    01040     //
    01041     // IME should be disabled
    01042     //
    01043         HIMC hImc;
    01044         hImc = fpImmGetContext( ped->hwnd );
    01045
    01046         if ( hImc != NULL_HIMC ) {
    01047             fpImmReleaseContext( ped->hwnd, hImc );
    01048             ped->hImcPrev = fpImmAssociateContext( ped->hwnd, NULL_HIMC );
    01049         }
    01050
    01051     } else {
    01052     //
    01053     // IME should be enabled
    01054     //
    01055         if ( ped->hImcPrev != NULL_HIMC ) {
    01056             ped->hImcPrev = fpImmAssociateContext( ped->hwnd, ped->hImcPrev );
    01057
    01058             //
    01059             // Font and the caret position might be changed while
    01060             // IME was being disabled. Set those now if the window
    01061             // has the focus.
    01062             //
    01063             if ( ped->fFocus ) {
    01064                 POINT pt;
    01065
    01066                 ECImmSetCompositionFont( ped );
    01067
    01068                 NtUserGetCaretPos( &pt );
    01069                 ECImmSetCompositionWindow( ped, pt.x, pt.y  );
    01070             }
    01071         }
    01072     }
    01073     ECInitInsert(ped, THREAD_HKL());
    01074 }
    01075
    01076
    01077 /***************************************************************************\
    01078 *
    01079 *  ECImmSetCompositionWindow( PED ped, LONG x, LONG y )
    01080 *
    01081 *  xx/xx/9x by somebody     Created for Win95
    01082 *  xx/xx/95 by kazum        Ported to NT-J 3.51
    01083 *  04/15/96 by takaok       Ported to NT 4.0
    01084 \***************************************************************************/
    01085 VOID ECImmSetCompositionWindow( PED ped, LONG x, LONG y )
    01086 {
    01087     COMPOSITIONFORM cf;
    01088     COMPOSITIONFORM cft;
    01089     RECT rcScreenWindow;
    01090     HIMC hImc;
    01091
    01092     hImc = fpImmGetContext( ped->hwnd );
    01093     if ( hImc != NULL_HIMC ) {
    01094
    01095         if ( ped->fFocus ) {
    01096             GetWindowRect( ped->hwnd, &rcScreenWindow);
    01097             // assuming RECT.left is the first and and RECT.top is the second field
    01098             MapWindowPoints( ped->hwnd, HWND_DESKTOP, (LPPOINT)&rcScreenWindow, 2);
    01099             if (ped->fInReconversion) {
    01100                 DWORD dwPoint = (DWORD)(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_POSFROMCHAR, ped->ichMinSel, 0);
    01101
    01102                 x = GET_X_LPARAM(dwPoint);
    01103                 y = GET_Y_LPARAM(dwPoint);
    01104
    01105                 RIPMSG2(RIP_WARNING, "ECImmSetCompositionWindow: fInReconversion (%d,%d)", x, y);
    01106             }
    01107             //
    01108             // The window currently has the focus.
    01109             //
    01110             if (ped->fSingle) {
    01111                 //
    01112                 // Single line edit control.
    01113                 //
    01114                 cf.dwStyle = CFS_POINT;
    01115                 cf.ptCurrentPos.x = x;
    01116                 cf.ptCurrentPos.y = y;
    01117                 SetRectEmpty(&cf.rcArea);
    01118
    01119             } else {
    01120                 //
    01121                 // Multi line edit control.
    01122                 //
    01123                 cf.dwStyle = CFS_RECT;
    01124                 cf.ptCurrentPos.x = x;
    01125                 cf.ptCurrentPos.y = y;
    01126                 cf.rcArea = ped->rcFmt;
    01127             }
    01128             fpImmGetCompositionWindow( hImc, &cft );
    01129             if ( (!RtlEqualMemory(&cf,&cft,sizeof(COMPOSITIONFORM))) ||
    01130                  (ped->ptScreenBounding.x != rcScreenWindow.left)    ||
    01131                  (ped->ptScreenBounding.y  != rcScreenWindow.top) ) {
    01132
    01133                 ped->ptScreenBounding.x = rcScreenWindow.left;
    01134                 ped->ptScreenBounding.y = rcScreenWindow.top;
    01135                 fpImmSetCompositionWindow( hImc, &cf );
    01136             }
    01137         }
    01138         fpImmReleaseContext( ped->hwnd, hImc );
    01139     }
    01140 }
    01141
    01142 /***************************************************************************\
    01143 *
    01144 *  ECImmSetCompositionFont( PED ped )
    01145 *
    01146 *  xx/xx/9x by somebody     Created for Win95
    01147 *  xx/xx/95 by kazum        Ported to NT-J 3.51
    01148 *  04/15/96 by takaok       Ported to NT 4.0
    01149 \***************************************************************************/
    01150 VOID  ECImmSetCompositionFont( PED ped )
    01151 {
    01152     HIMC hImc;
    01153     LOGFONTW lf;
    01154
    01155     if ( (hImc = fpImmGetContext( ped->hwnd )) != NULL_HIMC ) {
    01156
    01157         if (ped->hFont) {
    01158             GetObjectW( ped->hFont,
    01159                         sizeof(LOGFONTW),
    01160                         (LPLOGFONTW)&lf);
    01161         } else {
    01162             GetObjectW( GetStockObject(SYSTEM_FONT),
    01163                         sizeof(LOGFONTW),
    01164                         (LPLOGFONTW)&lf);
    01165         }
    01166         fpImmSetCompositionFontW( hImc, &lf );
    01167         fpImmReleaseContext( ped->hwnd, hImc );
    01168     }
    01169 }
    01170
    01171
    01172 /***************************************************************************\
    01173 *
    01174 *  ECInitInsert( PED ped, HKL hkl )
    01175 *
    01176 *  this function is called when:
    01177 *  1) a edit control window is initialized
    01178 *  2) active keyboard layout of current thread is changed
    01179 *  3) read only attribute of this edit control is changed
    01180 *
    01181 *  04/15/96 by takaok       Created
    01182 \***************************************************************************/
    01183 VOID ECInitInsert( PED ped, HKL hkl )
    01184 {
    01185     ped->fKorea = FALSE;
    01186     ped->fInsertCompChr = FALSE;
    01187     ped->fNoMoveCaret = FALSE;
    01188     ped->fResultProcess = FALSE;
    01189
    01190     if ( fpImmIsIME(hkl) ) {
    01191         if (  PRIMARYLANGID(LOWORD(HandleToUlong(hkl))) == LANG_KOREAN ) {
    01192
    01193             ped->fKorea = TRUE;
    01194         }
    01195         //
    01196         // LATER:this flag should be set based on the IME caps
    01197         // retrieved from IME. (Such IME caps should be defined)
    01198         // For now, we can safely assume that only Korean IMEs
    01199         // set CS_INSERTCHAR.
    01200         //
    01201         if ( ped->fKorea ) {
    01202             ped->fInsertCompChr = TRUE;
    01203         }
    01204     }
    01205
    01206     //
    01207     // if we had a composition character, the shape of caret
    01208     // is changed. We need to reset the caret shape.
    01209     //
    01210     if ( ped->fReplaceCompChr ) {
    01211         ped->fReplaceCompChr = FALSE;
    01212         ECSetCaretHandler( ped );
    01213     }
    01214 }
    01215
    01216 /***************************************************************************\
    01217 *
    01218 *  ECSetCaretHandler( PED ped )
    01219 *
    01220 * History:
    01221 *       07/16/96 by takaok      ported from NT 3.51
    01222 *
    01223 \***************************************************************************/
    01224
    01225 void ECSetCaretHandler(PED ped)
    01226 {
    01227     HDC     hdc;
    01228     SIZE    size;
    01229     PSTR    pText;
    01230
    01231 //    if (!ped->fInsertCompChr || ped->fReadOnly)
    01232 //        return;
    01233
    01234     // In any case destroy caret beforehand otherwise SetCaretPos()
    01235     // will get crazy.. win95d-B#992,B#2370
    01236     //
    01237     if (ped->fFocus) {
    01238
    01239         NtUserHideCaret(ped->hwnd);
    01240         DestroyCaret();
    01241         if ( ped->fReplaceCompChr ) {
    01242
    01243             hdc = ECGetEditDC(ped, TRUE );
    01244             pText = ECLock(ped);
    01245
    01246             if ( ped->fAnsi)
    01247                  GetTextExtentPointA(hdc, pText + ped->ichCaret, 2, &size);
    01248             else
    01249                  GetTextExtentPointW(hdc, (LPWSTR)pText + ped->ichCaret, 1, &size);
    01250
    01251             ECUnlock(ped);
    01252             ECReleaseEditDC(ped, hdc, TRUE);
    01253
    01254             CreateCaret(ped->hwnd, (HBITMAP)NULL, size.cx, ped->lineHeight);
    01255         }
    01256         else {
    01257             CreateCaret(ped->hwnd,
    01258                         (HBITMAP)NULL,
    01259                         (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
    01260                         ped->lineHeight);
    01261         }
    01262
    01263         hdc = ECGetEditDC(ped, TRUE );
    01264         if ( ped->fSingle )
    01265             SLSetCaretPosition( ped, hdc );
    01266         else
    01267             MLSetCaretPosition( ped, hdc );
    01268         ECReleaseEditDC(ped, hdc, TRUE);
    01269         NtUserShowCaret(ped->hwnd);
    01270     }
    01271 }
    01272
    01273
    01274 /***************************************************************************\
    01275 *
    01276 * LONG ECImeCompoistion( PED ped, WPARAM wParam, LPARAM lParam )
    01277 *
    01278 * WM_IME_COMPOSITION handler for Korean IME
    01279 *
    01280 * History:
    01281 \***************************************************************************/
    01282
    01283 extern void MLReplaceSel(PED, LPSTR);
    01284
    01285 #define GET_COMPOSITION_STRING  (ped->fAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW)
    01286
    01287 BOOL FAR PASCAL ECResultStrHandler(PED ped)
    01288 {
    01289     HIMC himc;
    01290     LPSTR lpStr;
    01291     LONG dwLen;
    01292
    01293     ped->fInsertCompChr = FALSE;    // clear the state
    01294     ped->fNoMoveCaret = FALSE;
    01295
    01296     if ((himc = fpImmGetContext(ped->hwnd)) == 0) {
    01297         return FALSE;
    01298     }
    01299
    01300     dwLen = GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, NULL, 0);
    01301
    01302     if (dwLen == 0) {
    01303         fpImmReleaseContext(ped->hwnd, himc);
    01304         return FALSE;
    01305     }
    01306
    01307     dwLen *= ped->cbChar;
    01308     dwLen += ped->cbChar;
    01309
    01310     lpStr = (LPSTR)UserGlobalAlloc(GPTR, dwLen);
    01311     if (lpStr == NULL) {
    01312         fpImmReleaseContext(ped->hwnd, himc);
    01313         return FALSE;
    01314     }
    01315
    01316     GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, lpStr, dwLen);
    01317
    01318     if (ped->fSingle) {
    01319         SLReplaceSel(ped, lpStr);
    01320     } else {
    01321         MLReplaceSel(ped, lpStr);
    01322     }
    01323
    01324     UserGlobalFree((HGLOBAL)lpStr);
    01325
    01326     fpImmReleaseContext(ped->hwnd, himc);
    01327
    01328     ped->fReplaceCompChr = FALSE;
    01329     ped->fNoMoveCaret = FALSE;
    01330     ped->fResultProcess = FALSE;
    01331
    01332     ECSetCaretHandler(ped);
    01333
    01334     return TRUE;
    01335 }
    01336
    01337 LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
    01338 {
    01339     INT ich;
    01340     LRESULT lReturn = 1;
    01341     HDC hdc;
    01342     BOOL fSLTextUpdated = FALSE;
    01343     ICH iResult;
    01344     HIMC hImc;
    01345     BYTE TextBuf[4];
    01346
    01347     if (!ped->fInsertCompChr) {
    01348         if (lParam & GCS_RESULTSTR) {
    01349             ECInOutReconversionMode(ped, FALSE);
    01350
    01351             if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) {
    01352 ResultAtOnce:
    01353                 ECResultStrHandler(ped);
    01354                 lParam &= ~GCS_RESULTSTR;
    01355             }
    01356         }
    01357         return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
    01358     }
    01359
    01360     // In case of Ansi edit control, the length of minimum composition string
    01361     // is 2. Check here maximum byte of edit control.
    01362     if( ped->fAnsi && ped->cchTextMax == 1 ) {
    01363         HIMC hImc;
    01364
    01365         hImc = fpImmGetContext( ped->hwnd );
    01366         fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
    01367         fpImmReleaseContext( ped->hwnd, hImc );
    01368         NtUserMessageBeep(MB_ICONEXCLAMATION);
    01369         return lReturn;
    01370     }
    01371
    01372     // Don't move this after CS_NOMOVECARET check.
    01373     // In case if skip the message, fNoMoveCaret should not be set.
    01374     if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) {
    01375
    01376         // Now we're in result processing. GCS_RESULTSTR ends up
    01377         // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
    01378         // the message(s) will come later than this CS_INSERTCHAR
    01379         // message. This composition character should be handled
    01380         // after the WM_CHAR message(s).
    01381         //
    01382         if(ped->fAnsi)
    01383             PostMessageA(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
    01384         else
    01385             PostMessageW(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
    01386         ped->fResultProcess = FALSE;
    01387         return lReturn;
    01388     }
    01389
    01390 //
    01391 // If fReplaceCompChr is TRUE, we change the shape of caret. A block
    01392 // caret is displayed on the composition character. From the user's
    01393 // point of view, there is no difference if the caret is before the
    01394 // composition character or after the composition character. When
    01395 // the composition character is finalized, the insertion point should
    01396 // be moved to after the character, any way. Therefore checking
    01397 // CS_NOMOVECARET bit doesn't make sense in our current implementation.
    01398 // [takaok]
    01399 //
    01400 #if 0
    01401     if (lParam & CS_NOMOVECARET)
    01402         ped->fNoMoveCaret=TRUE;   // stick to current caret pos.
    01403     else
    01404         ped->fNoMoveCaret=FALSE;
    01405 #endif
    01406
    01407     if (lParam & GCS_RESULTSTR) {
    01408
    01409         if (ped->wImeStatus & EIMES_GETCOMPSTRATONCE) {
    01410             goto ResultAtOnce;
    01411         }
    01412
    01413         ped->fResultProcess=TRUE;
    01414         if ( ped->fReplaceCompChr ) {
    01415             //
    01416             // we have a DBCS character to be replaced.
    01417             // let's delete it before inserting the new one.
    01418             //
    01419             ich = (ped->fAnsi) ? 2 : 1;
    01420             ped->fReplaceCompChr = FALSE;
    01421             ped->ichMaxSel = min(ped->ichCaret + ich, ped->cch);
    01422             ped->ichMinSel = ped->ichCaret;
    01423             if ( ECDeleteText( ped ) > 0 ) {
    01424                 if ( ped->fSingle ) {
    01425                     //
    01426                     // Update the display
    01427                     //
    01428                     ECNotifyParent(ped, EN_UPDATE);
    01429                     hdc = ECGetEditDC(ped,FALSE);
    01430                     SLDrawText(ped, hdc, 0);
    01431                     ECReleaseEditDC(ped,hdc,FALSE);
    01432                     //
    01433                     // Tell parent our text contents changed.
    01434                     //
    01435                     ECNotifyParent(ped, EN_CHANGE);
    01436                 }
    01437             }
    01438             ECSetCaretHandler( ped );
    01439         }
    01440
    01441     } else if(lParam & CS_INSERTCHAR) {
    01442
    01443         //
    01444         // If we are in the middle of a mousedown command, don't do anything.
    01445         //
    01446         if (ped->fMouseDown) {
    01447             return lReturn;
    01448         }
    01449
    01450         //
    01451         // We can safely assume that interimm character is always DBCS.
    01452         //
    01453         ich = ( ped->fAnsi ) ? 2 : 1;
    01454
    01455         if ( ped->fReplaceCompChr ) {
    01456             //
    01457             // we have a character to be replaced.
    01458             // let's delete it before inserting the new one.
    01459             // when we have a composition characters, the
    01460             // caret is placed before the composition character.
    01461             //
    01462             ped->ichMaxSel = min(ped->ichCaret+ich, ped->cch);
    01463             ped->ichMinSel = ped->ichCaret;
    01464         }
    01465
    01466         //
    01467         // let's delete current selected text or composition character
    01468         //
    01469         if ( ped->fSingle ) {
    01470             if ( ECDeleteText( ped ) > 0 ) {
    01471                 fSLTextUpdated = TRUE;
    01472             }
    01473         } else {
    01474             MLDeleteText( ped );
    01475         }
    01476
    01477         //
    01478         // When the composition charcter is canceled, IME may give us NULL wParam,
    01479         // with CS_INSERTCHAR flag on. We shouldn't insert a NULL character.
    01480         //
    01481         if ( wParam != 0 ) {
    01482
    01483             if ( ped->fAnsi ) {
    01484                 TextBuf[0] = HIBYTE(LOWORD(wParam)); // leading byte
    01485                 TextBuf[1] = LOBYTE(LOWORD(wParam)); // trailing byte
    01486                 TextBuf[2] = '\0';
    01487             } else {
    01488                 TextBuf[0] = LOBYTE(LOWORD(wParam));
    01489                 TextBuf[1] = HIBYTE(LOWORD(wParam));
    01490                 TextBuf[2] = '\0';
    01491                 TextBuf[3] = '\0';
    01492             }
    01493
    01494             if ( ped->fSingle ) {
    01495
    01496                 iResult = SLInsertText( ped, (LPSTR)TextBuf, ich );
    01497                 if (iResult == 0) {
    01498                     /*
    01499                      * Couldn't insert the text, for e.g. the text exceeded the limit.
    01500                      */
    01501                     NtUserMessageBeep(0);
    01502                 } else if (iResult > 0) {
    01503                     /*
    01504                      * Remember we need to update the text.
    01505                      */
    01506                     fSLTextUpdated = TRUE;
    01507                 }
    01508
    01509             } else {
    01510
    01511                 iResult = MLInsertText( ped, (LPSTR)TextBuf, ich, TRUE);
    01512             }
    01513
    01514             if ( iResult > 0 ) {
    01515                 //
    01516                 // ped->fReplaceCompChr will be reset:
    01517                 //
    01518                 // 1) when the character is finalized.
    01519                 //    we will receive GCS_RESULTSTR
    01520                 //
    01521                 // 2) when the character is canceled.
    01522                 //
    01523                 //    we will receive WM_IME_COMPOSITION|CS_INSERTCHAR
    01524                 //    with wParam == 0 (in case of user types backspace
    01525                 //    at the first element of composition character).
    01526                 //
    01527                 //      or
    01528                 //
    01529                 //    we will receive WM_IME_ENDCOMPOSITION message
    01530                 //
    01531                 ped->fReplaceCompChr = TRUE;
    01532
    01533                 //
    01534                 // Caret should be placed BEFORE the composition
    01535                 // character.
    01536                 //
    01537                 ped->ichCaret = max( 0, ped->ichCaret - ich);
    01538                 ECSetCaretHandler( ped );
    01539             } else {
    01540
    01541                 //
    01542                 // We failed to insert a character. We might run out
    01543                 // of memory, or reached to the text size limit. let's
    01544                 // cancel the composition character.
    01545                 //
    01546                 hImc = fpImmGetContext(ped->hwnd);
    01547                 fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
    01548                 fpImmReleaseContext(ped->hwnd, hImc);
    01549
    01550                 ped->fReplaceCompChr = FALSE;
    01551                 ECSetCaretHandler( ped );
    01552             }
    01553         } else {
    01554             //
    01555             // the composition character is canceled.
    01556             //
    01557             ped->fReplaceCompChr = FALSE;
    01558             ECSetCaretHandler( ped );
    01559         }
    01560
    01561         //
    01562         // We won't notify parent the text change
    01563         // because the composition character has
    01564         // not been finalized.
    01565         //
    01566         if ( fSLTextUpdated ) {
    01567
    01568             //
    01569             // Update the display
    01570             //
    01571             ECNotifyParent(ped, EN_UPDATE);
    01572
    01573             hdc = ECGetEditDC(ped,FALSE);
    01574
    01575             if ( ped->fReplaceCompChr ) {
    01576                 //
    01577                 // move back the caret to the original position
    01578                 // temporarily so that our new block cursor can
    01579                 // be located within the visible area of window.
    01580                 //
    01581                 ped->ichCaret = min( ped->cch, ped->ichCaret + ich);
    01582                 SLScrollText(ped, hdc);
    01583                 ped->ichCaret = max( 0, ped->ichCaret - ich);
    01584             } else {
    01585                 SLScrollText(ped, hdc);
    01586             }
    01587             SLDrawText(ped, hdc, 0);
    01588
    01589             ECReleaseEditDC(ped,hdc,FALSE);
    01590
    01591             //
    01592             // Tell parent our text contents changed.
    01593             //
    01594             ECNotifyParent(ped, EN_CHANGE);
    01595         }
    01596         return lReturn;
    01597     }
    01598
    01599     return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
    01600 }
    01601
    01602
    01603 #ifdef LATER    // fyi: window 98 equiv.
    01604 LRESULT ECImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
    01605 {
    01606     INT ich;
    01607     LRESULT lReturn = 1;
    01608     HDC hdc;
    01609     BOOL fSLTextUpdated = FALSE;
    01610     ICH iResult;
    01611     HIMC hImc;
    01612     BYTE TextBuf[4];
    01613
    01614     // In case of Ansi edit control, the length of minimum composition string
    01615     // is 2. Check here maximum byte of edit control.
    01616     if( ped->fAnsi && ped->cchTextMax == 1 ) {
    01617         HIMC hImc;
    01618
    01619         hImc = fpImmGetContext( ped->hwnd );
    01620         fpImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
    01621         fpImmReleaseContext( ped->hwnd, hImc );
    01622         MessageBeep(MB_ICONEXCLAMATION);
    01623         return lReturn;
    01624     }
    01625
    01626     // Don't move this after CS_NOMOVECARET check.
    01627     // In case if skip the message, fNoMoveCaret should not be set.
    01628     if ((lParam & CS_INSERTCHAR) && ped->fResultProcess) {
    01629
    01630         // Now we're in result processing. GCS_RESULTSTR ends up
    01631         // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
    01632         // the message(s) will come later than this CS_INSERTCHAR
    01633         // message. This composition character should be handled
    01634         // after the WM_CHAR message(s).
    01635         //
    01636         (ped->fAnsi ? PostMessageA : PostMessageW)(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
    01637         ped->fResultProcess = FALSE;
    01638         return lReturn;
    01639     }
    01640
    01641     ped->fNoMoveCaret = (lParam & CS_NOMOVECARET) != 0;
    01642
    01643     if (lParam & GCS_RESULTSTR) {
    01644         ECInOutReconversionMode(ped, FALSE);
    01645
    01646         if (ped->wImeStatus & EIMS_GETCOMPSTRATONCE) {
    01647             ECGetCompStrAtOnce(ped);
    01648
    01649             goto PassToDefaultWindowProc;
    01650         }
    01651
    01652         // Getting into result processing
    01653         ped->fResultProcess = TRUE;
    01654     }
    01655     else if (lParam & CS_INSERTCHAR) {
    01656         ped->fInsertCompChr = TRUE; // Process this composition character.
    01657
    01658         (ped->fSingleLine ? SLChar : MLChar)(ped, wParam, 0);
    01659
    01660         if (ped->fInsretCompChr) {
    01661             ped->fReplaceCompChr = TRUE;    // The next character will replace this.
    01662             ped->fInsertCompChr = FALSE;    // Clear the state for the next character.
    01663         }
    01664
    01665         ECSetCaretHandler(ped);
    01666         return 0;
    01667     }
    01668
    01669 PassToDefaultWindowProc:
    01670     return DefWindowProcWorker(ped->pwnd, WM_IME_COMPOSITION, wParam, lParam, ped->fAnsi);
    01671 }
    01672 #endif
    01673
    01674
    01675 /***************************************************************************\
    01676 *
    01677 * BOOL HanjaKeyHandler( PED ped )
    01678 *
    01679 * VK_HANJA handler - Korean only
    01680 *
    01681 * History: July 15,1996 takaok  ported from NT 3.51
    01682 \***************************************************************************/
    01683 BOOL HanjaKeyHandler( PED ped )
    01684 {
    01685     BOOL changeSelection = FALSE;
    01686
    01687     if (ped->fKorea && !ped->fReadOnly) {
    01688         ICH oldCaret = ped->ichCaret;
    01689
    01690         if (ped->fReplaceCompChr)
    01691                 return FALSE;
    01692
    01693         if (ped->ichMinSel < ped->ichMaxSel)
    01694             ped->ichCaret = ped->ichMinSel;
    01695
    01696         if (!ped->cch || ped->cch == ped->ichCaret) {
    01697             ped->ichCaret = oldCaret;
    01698             NtUserMessageBeep(MB_ICONEXCLAMATION);
    01699             return FALSE;
    01700         }
    01701
    01702         if (ped->fAnsi) {
    01703             if (fpImmEscapeA(THREAD_HKL(), fpImmGetContext(ped->hwnd),
    01704                 IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) {
    01705                 changeSelection = TRUE;
    01706             }
    01707             else
    01708                 ped->ichCaret = oldCaret;
    01709             ECUnlock(ped);
    01710         }
    01711         else {
    01712             if (fpImmEscapeW(THREAD_HKL(), fpImmGetContext(ped->hwnd),
    01713                 IME_ESC_HANJA_MODE, (ECLock(ped) + ped->ichCaret * ped->cbChar))) {
    01714                 changeSelection = TRUE;
    01715             }
    01716             else
    01717                 ped->ichCaret = oldCaret;
    01718             ECUnlock(ped);
    01719         }
    01720     }
    01721     return changeSelection;
    01722 }
    01723
    01724
    01726 // EcImeRequestHandler()
    01727 //
    01728 // Handles WM_IME_REQUEST message originated by IME
    01729 //
    01730 // Histroy:
    01731 // 27-Mar-97 Hiroyama Created
    01733
    01734
    01735 LRESULT EcImeRequestHandler(PED ped, WPARAM dwSubMsg, LPARAM lParam)
    01736 {
    01737     LRESULT lreturn = 0L;
    01738
    01739     switch (dwSubMsg) {
    01740     case IMR_CONFIRMRECONVERTSTRING:
    01741         // Edit control does not allow IME to change it.
    01742         break;
    01743
    01744     case IMR_RECONVERTSTRING:
    01745         //
    01746         // CHECK VERSION of the structure
    01747         //
    01748         if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0) {
    01749             RIPMSG1(RIP_WARNING, "EcImeRequestHandler: RECONVERTSTRING dwVersion is not expected.",
    01750                 ((LPRECONVERTSTRING)lParam)->dwVersion);
    01751             return 0L;
    01752         }
    01753
    01754         if (ped && ped->fFocus && ped->hText && fpImmIsIME(THREAD_HKL())) {
    01755             UINT cchLen = ped->ichMaxSel - ped->ichMinSel;    // holds character count.
    01756             if (cchLen == 0) {
    01757                 // if we have no selection,
    01758                 // just return 0.
    01759                 break;
    01760             }
    01761
    01762             UserAssert(ped->cbChar == sizeof(BYTE) || ped->cbChar == sizeof(WCHAR));
    01763
    01764             // This Edit Control has selection.
    01765             if (lParam == 0) {
    01766                 //
    01767                 // IME just want to get required size for buffer.
    01768                 // cchLen + 1 is needed to reserve room for trailing L'\0'.
    01769                 //       ~~~~
    01770                 lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
    01771             } else {
    01772                 LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
    01773                 LPVOID lpSrc;
    01774                 LPVOID lpDest = (LPBYTE)lpRCS + sizeof(RECONVERTSTRING);
    01775
    01776                 // check buffer size
    01777                 // if the given buffer is smaller than actual needed size,
    01778                 // shrink our size to fit the buffer
    01779                 if ((INT)lpRCS->dwSize <= sizeof(RECONVERTSTRING) + cchLen * ped->cbChar) {
    01780                     RIPMSG0(RIP_WARNING, "EcImeRequest: ERR09");
    01781                     cchLen = (lpRCS->dwSize - sizeof(RECONVERTSTRING)) / ped->cbChar - ped->cbChar;
    01782                 }
    01783
    01784                 lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // buffer begins just after RECONVERTSTRING
    01785                 lpRCS->dwCompStrOffset =
    01786                 lpRCS->dwTargetStrOffset = 0;
    01787                 lpRCS->dwStrLen =
    01788                 lpRCS->dwCompStrLen =
    01789                 lpRCS->dwTargetStrLen = cchLen; // StrLen means TCHAR count
    01790
    01791                 lpSrc = ECLock(ped);
    01792                 if (lpSrc == NULL) {
    01793                     RIPMSG0(RIP_WARNING, "EcImeRequestHandler: LOCALLOCK(ped) failed.");
    01794                 } else {
    01795                     RtlCopyMemory(lpDest,
    01796                                   (LPBYTE)lpSrc + ped->ichMinSel * ped->cbChar,
    01797                                   cchLen * ped->cbChar);
    01798                     // Null-Terminate the string
    01799                     if (ped->fAnsi) {
    01800                         LPBYTE psz = (LPBYTE)lpDest;
    01801                         psz[cchLen] = '\0';
    01802                     } else {
    01803                         LPWSTR pwsz = (LPWSTR)lpDest;
    01804                         pwsz[cchLen] = L'\0';
    01805                     }
    01806                     ECUnlock(ped);
    01807                     // final buffer size
    01808                     lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
    01809
    01810                     ECInOutReconversionMode(ped, TRUE);
    01811                     ECImmSetCompositionWindow(ped, 0, 0);
    01812                 }
    01813             }
    01814
    01815         }
    01816         break;
    01817     }
    01818
    01819     return lreturn;
    01820 }