Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2241 lines
61 KiB

  1. #include "ctlspriv.h"
  2. #pragma hdrstop
  3. #include "usrctl32.h"
  4. #include "edit.h"
  5. //---------------------------------------------------------------------------//
  6. #define WS_EX_EDGEMASK (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)
  7. #define GetCharABCWidthsAorW ((ped)->fAnsi ? GetCharABCWidthsA : GetCharABCWidthsW)
  8. #define GetCharWidthAorW ((ped)->fAnsi ? GetCharWidthA : GetCharWidthW)
  9. //---------------------------------------------------------------------------//
  10. INT Edit_GetStateId(PED ped)
  11. {
  12. INT iStateId;
  13. if (ped->fDisabled)
  14. {
  15. iStateId = ETS_DISABLED;
  16. }
  17. else if (ped->fReadOnly)
  18. {
  19. iStateId = ETS_READONLY;
  20. }
  21. else if (ped->fFocus)
  22. {
  23. iStateId = ETS_FOCUSED;
  24. }
  25. else if (ped->fHot)
  26. {
  27. iStateId = ETS_HOT;
  28. }
  29. else
  30. {
  31. iStateId = ETS_NORMAL;
  32. }
  33. return iStateId;
  34. }
  35. //---------------------------------------------------------------------------//
  36. VOID Edit_SetMargin(PED ped, UINT wFlags, long lMarginValues, BOOL fRedraw)
  37. {
  38. BOOL fUseFontInfo = FALSE;
  39. UINT wValue, wOldLeftMargin, wOldRightMargin;
  40. if (wFlags & EC_LEFTMARGIN)
  41. {
  42. //
  43. // Set the left margin
  44. //
  45. if ((int) (wValue = (int)(short)LOWORD(lMarginValues)) < 0)
  46. {
  47. fUseFontInfo = TRUE;
  48. wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegA);
  49. }
  50. ped->rcFmt.left += wValue - ped->wLeftMargin;
  51. wOldLeftMargin = ped->wLeftMargin;
  52. ped->wLeftMargin = wValue;
  53. }
  54. if (wFlags & EC_RIGHTMARGIN)
  55. {
  56. //
  57. // Set the Right margin
  58. //
  59. if ((int) (wValue = (int)(short)HIWORD(lMarginValues)) < 0)
  60. {
  61. fUseFontInfo = TRUE;
  62. wValue = min((ped->aveCharWidth / 2), (int)ped->wMaxNegC);
  63. }
  64. ped->rcFmt.right -= wValue - ped->wRightMargin;
  65. wOldRightMargin = ped->wRightMargin;
  66. ped->wRightMargin = wValue;
  67. }
  68. if (fUseFontInfo)
  69. {
  70. if (ped->rcFmt.right - ped->rcFmt.left < 2 * ped->aveCharWidth)
  71. {
  72. TraceMsg(TF_STANDARD, "EDIT: Edit_SetMargin: rcFmt is too narrow for EC_USEFONTINFO");
  73. if (wFlags & EC_LEFTMARGIN)
  74. {
  75. //
  76. // Reset the left margin
  77. //
  78. ped->rcFmt.left += wOldLeftMargin - ped->wLeftMargin;
  79. ped->wLeftMargin = wOldLeftMargin;
  80. }
  81. if (wFlags & EC_RIGHTMARGIN)
  82. {
  83. //
  84. // Reset the Right margin
  85. //
  86. ped->rcFmt.right -= wOldRightMargin - ped->wRightMargin;
  87. ped->wRightMargin = wOldRightMargin;
  88. }
  89. return;
  90. }
  91. }
  92. if (fRedraw)
  93. {
  94. Edit_InvalidateClient(ped, TRUE);
  95. }
  96. }
  97. //---------------------------------------------------------------------------//
  98. VOID Edit_CalcMarginForDBCSFont(PED ped, BOOL fRedraw)
  99. {
  100. if (ped->fTrueType)
  101. {
  102. if (!ped->fSingle)
  103. {
  104. //
  105. // wMaxNegA came from ABC CharWidth.
  106. //
  107. if (ped->wMaxNegA != 0)
  108. {
  109. Edit_SetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  110. MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO),fRedraw);
  111. }
  112. }
  113. else
  114. {
  115. int iMaxNegA = 0, iMaxNegC = 0;
  116. int i;
  117. PVOID lpBuffer;
  118. LPABC lpABCBuff;
  119. ABC ABCInfo;
  120. HFONT hOldFont;
  121. HDC hdc = GetDC(ped->hwnd);
  122. if (!ped->hFont || !(hOldFont = SelectFont(hdc, ped->hFont)))
  123. {
  124. ReleaseDC(ped->hwnd, hdc);
  125. return;
  126. }
  127. if (lpBuffer = UserLocalAlloc(0,sizeof(ABC) * 256))
  128. {
  129. lpABCBuff = lpBuffer;
  130. GetCharABCWidthsAorW(hdc, 0, 255, lpABCBuff);
  131. }
  132. else
  133. {
  134. lpABCBuff = &ABCInfo;
  135. GetCharABCWidthsAorW(hdc, 0, 0, lpABCBuff);
  136. }
  137. i = 0;
  138. while (TRUE)
  139. {
  140. iMaxNegA = min(iMaxNegA, lpABCBuff->abcA);
  141. iMaxNegC = min(iMaxNegC, lpABCBuff->abcC);
  142. if (++i == 256)
  143. {
  144. break;
  145. }
  146. if (lpBuffer)
  147. {
  148. lpABCBuff++;
  149. }
  150. else
  151. {
  152. GetCharABCWidthsAorW(hdc, i, i, lpABCBuff);
  153. }
  154. }
  155. SelectFont(hdc, hOldFont);
  156. if (lpBuffer)
  157. {
  158. UserLocalFree(lpBuffer);
  159. }
  160. ReleaseDC(ped->hwnd, hdc);
  161. if ((iMaxNegA != 0) || (iMaxNegC != 0))
  162. {
  163. Edit_SetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  164. MAKELONG((UINT)(-iMaxNegC), (UINT)(-iMaxNegA)),fRedraw);
  165. }
  166. }
  167. }
  168. }
  169. //---------------------------------------------------------------------------//
  170. //
  171. // GetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRIC lptm, LPINT lpcy)
  172. //
  173. // if an app set a font for vertical writing, even though we don't
  174. // handle it with EC, the escapement of tm can be NON 0. Then cxWidth from
  175. // GetCharDimenstions() could be 0 in GetCharDimensions().
  176. // This will break our caller who don't expect 0 at return. So I created
  177. // this entry for the case the caller set vertical font.
  178. //
  179. //
  180. // PORTPORT: Duplicates functionality of GetCharDimensions() in prsht.c
  181. int UserGetCharDimensionsEx(HDC hDC, HFONT hfont, LPTEXTMETRICW lptm, LPINT lpcy)
  182. {
  183. static CONST WCHAR AveCharWidthData[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  184. int cxWidth;
  185. TEXTMETRICW tm;
  186. LOGFONTW lf;
  187. WCHAR wchFaceName[LF_FACESIZE];
  188. //
  189. // Is this font vertical font ??
  190. //
  191. wchFaceName[0] = 0;
  192. GetTextFaceW(hDC, LF_FACESIZE, wchFaceName);
  193. if (wchFaceName[0] != L'@')
  194. {
  195. //
  196. // if not call GDI...
  197. //
  198. return(GdiGetCharDimensions(hDC, lptm, lpcy));
  199. }
  200. if (!lptm)
  201. {
  202. lptm = &tm;
  203. }
  204. GetTextMetricsW(hDC, lptm);
  205. // TMPF_FIXED_PITCH
  206. //
  207. // If this bit is set the font is a variable pitch font.
  208. // If this bit is clear the font is a fixed pitch font.
  209. // Note very carefully that those meanings are the opposite of what the constant name implies.
  210. //
  211. if (!(lptm->tmPitchAndFamily & TMPF_FIXED_PITCH))
  212. {
  213. //
  214. // This is fixed pitch font....
  215. //
  216. cxWidth = lptm->tmAveCharWidth;
  217. }
  218. else
  219. {
  220. //
  221. // This is variable pitch font...
  222. //
  223. if (hfont && GetObjectW(hfont, sizeof(LOGFONTW), &lf) && (lf.lfEscapement != 0))
  224. {
  225. cxWidth = lptm->tmAveCharWidth;
  226. }
  227. else
  228. {
  229. SIZE size;
  230. GetTextExtentPointW(hDC, AveCharWidthData, 52, &size);
  231. cxWidth = ((size.cx / 26) + 1) / 2;
  232. }
  233. }
  234. if (lpcy)
  235. {
  236. *lpcy = lptm->tmHeight;
  237. }
  238. return cxWidth;
  239. }
  240. //---------------------------------------------------------------------------//
  241. //
  242. // Edit_GetTextHandler AorW
  243. //
  244. // Copies at most maxCchToCopy chars to the buffer lpBuffer. Returns
  245. // how many chars were actually copied. Null terminates the string based
  246. // on the fNullTerminate flag:
  247. // fNullTerminate --> at most (maxCchToCopy - 1) characters will be copied
  248. // !fNullTerminate --> at most (maxCchToCopy) characters will be copied
  249. //
  250. ICH Edit_GetTextHandler(PED ped, ICH maxCchToCopy, LPSTR lpBuffer, BOOL fNullTerminate)
  251. {
  252. PSTR pText;
  253. if (maxCchToCopy)
  254. {
  255. //
  256. // Zero terminator takes the extra byte
  257. //
  258. if (fNullTerminate)
  259. {
  260. maxCchToCopy--;
  261. }
  262. maxCchToCopy = min(maxCchToCopy, ped->cch);
  263. //
  264. // Zero terminate the string
  265. //
  266. if (ped->fAnsi)
  267. {
  268. *(LPSTR)(lpBuffer + maxCchToCopy) = 0;
  269. }
  270. else
  271. {
  272. *(((LPWSTR)lpBuffer) + maxCchToCopy) = 0;
  273. }
  274. pText = Edit_Lock(ped);
  275. RtlCopyMemory(lpBuffer, pText, maxCchToCopy*ped->cbChar);
  276. Edit_Unlock(ped);
  277. }
  278. return maxCchToCopy;
  279. }
  280. //---------------------------------------------------------------------------//
  281. BOOL Edit_NcCreate( PED ped, HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  282. {
  283. BOOL fAnsi;
  284. ULONG ulStyle;
  285. ULONG ulStyleEx;
  286. //
  287. // Initialize the ped
  288. //
  289. ped->hwnd = hwnd;
  290. ped->pww = (PWW)GetWindowLongPtr(hwnd, GWLP_WOWWORDS);
  291. ulStyle = GET_STYLE(ped);
  292. ulStyleEx = GET_EXSTYLE(ped);
  293. //
  294. // (phellyar) All strings sent to us via standard WM_* messages or
  295. // control specific EM_* messages are expanded to unicode
  296. // for us by user. Therefore we need worry about
  297. // whether be are created by and ANSI app.
  298. //
  299. //fAnsi = TESTFLAG(GET_STATE(ped), WS_ST_ANSICREATOR);
  300. fAnsi = 0;
  301. ped->fEncoded = FALSE;
  302. ped->iLockLevel = 0;
  303. ped->chLines = NULL;
  304. ped->pTabStops = NULL;
  305. ped->charWidthBuffer = NULL;
  306. ped->fAnsi = fAnsi ? 1 : 0; // Force TRUE to be 1 because its a 1 bit field
  307. ped->cbChar = (WORD)(fAnsi ? sizeof(CHAR) : sizeof(WCHAR));
  308. ped->hInstance = lpCreateStruct->hInstance;
  309. // IME
  310. ped->hImcPrev = NULL_HIMC;
  311. {
  312. DWORD dwVer = UserGetVersion();
  313. ped->fWin31Compat = Is310Compat(dwVer);
  314. ped->f40Compat = Is400Compat(dwVer);
  315. }
  316. //
  317. // NOTE:
  318. // The order of the following two checks is important. People can
  319. // create edit fields with a 3D and a normal border, and we don't
  320. // want to disallow that. But we need to detect the "no 3D border"
  321. // border case too.
  322. //
  323. if ( ulStyleEx & WS_EX_EDGEMASK )
  324. {
  325. ped->fBorder = TRUE;
  326. }
  327. else if ( ulStyle & WS_BORDER )
  328. {
  329. ClearWindowState(hwnd, WS_BORDER);
  330. ped->fFlatBorder = TRUE;
  331. ped->fBorder = TRUE;
  332. }
  333. if ( !(ulStyle & ES_MULTILINE) )
  334. {
  335. ped->fSingle = TRUE;
  336. }
  337. if ( ulStyle & WS_DISABLED )
  338. {
  339. ped->fDisabled = TRUE;
  340. }
  341. if ( ulStyle & ES_READONLY)
  342. {
  343. if (!ped->fWin31Compat)
  344. {
  345. //
  346. // BACKWARD COMPATIBILITY HACK
  347. //
  348. // "MileStone" unknowingly sets the ES_READONLY style. So, we strip this
  349. // style here for all Win3.0 apps (this style is new for Win3.1).
  350. // Fix for Bug #12982 -- SANKAR -- 01/24/92 --
  351. //
  352. ClearWindowState(hwnd, ES_READONLY);
  353. }
  354. else
  355. {
  356. ped->fReadOnly = TRUE;
  357. }
  358. }
  359. //
  360. // Allocate storage for the text for the edit controls. Storage for single
  361. // line edit controls will always get allocated in the local data segment.
  362. // Multiline will allocate in the local ds but the app may free this and
  363. // allocate storage elsewhere...
  364. //
  365. ped->hText = LocalAlloc(LHND, CCHALLOCEXTRA*ped->cbChar);
  366. if (!ped->hText)
  367. {
  368. return FALSE;
  369. }
  370. ped->cchAlloc = CCHALLOCEXTRA;
  371. ped->lineHeight = 1;
  372. ped->hwndParent = lpCreateStruct->hwndParent;
  373. ped->hTheme = OpenThemeData(ped->hwnd, L"Edit");
  374. ped->wImeStatus = 0;
  375. return (BOOL)DefWindowProc(hwnd, WM_NCCREATE, 0, (LPARAM)lpCreateStruct);
  376. }
  377. //---------------------------------------------------------------------------//
  378. BOOL Edit_Create(PED ped, LONG windowStyle)
  379. {
  380. HDC hdc;
  381. //
  382. // Get values from the window instance data structure and put
  383. // them in the ped so that we can access them easier.
  384. //
  385. if ( windowStyle & ES_AUTOHSCROLL )
  386. {
  387. ped->fAutoHScroll = 1;
  388. }
  389. if ( windowStyle & ES_NOHIDESEL )
  390. {
  391. ped->fNoHideSel = 1;
  392. }
  393. ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK));
  394. if ((windowStyle & ES_RIGHT) && !ped->format)
  395. {
  396. ped->format = ES_RIGHT;
  397. }
  398. //
  399. // Max # chars we will initially allow
  400. //
  401. ped->cchTextMax = MAXTEXT;
  402. //
  403. // Set up undo initial conditions... (ie. nothing to undo)
  404. //
  405. ped->ichDeleted = (ICH)-1;
  406. ped->ichInsStart = (ICH)-1;
  407. ped->ichInsEnd = (ICH)-1;
  408. //
  409. // initial charset value - need to do this BEFORE EditML_Create is called
  410. // so that we know not to fool with scrollbars if nessacary
  411. //
  412. hdc = Edit_GetDC(ped, TRUE);
  413. ped->charSet = (BYTE)GetTextCharset(hdc);
  414. Edit_ReleaseDC(ped, hdc, TRUE);
  415. //
  416. // FE_IME
  417. // EC_INSERT_COMPOSITION_CHARACTER: Edit_Create() - call Edit_InitInsert()
  418. //
  419. Edit_InitInsert(ped, GetKeyboardLayout(0));
  420. if( g_pLpkEditCallout )
  421. {
  422. ped->pLpkEditCallout = g_pLpkEditCallout;
  423. }
  424. else
  425. {
  426. ped->pLpkEditCallout = NULL;
  427. }
  428. return ped->pLpkEditCallout ? ped->pLpkEditCallout->EditCreate((PED0)ped, ped->hwnd) : TRUE;
  429. }
  430. //---------------------------------------------------------------------------//
  431. //
  432. // Do this once at process startup. The edit control has special
  433. // callouts in lpk.dll to help it render complex script languages
  434. // such as Arabic. The registry probing alg executed here is the same
  435. // as the one performed in win32k!InitializeGre.
  436. //
  437. // We then call GetModuleHandle rather than LoadLibrary, since lpk.dll
  438. // will be guaranteed to be loaded and initialized already by gdi32. This
  439. // fixes the scenario in which the user turns on complex scripts but
  440. // doesn't reboot, which caused us to try and load lpk without it having
  441. // been initialized on the kernel side.
  442. //
  443. VOID InitEditLpk()
  444. {
  445. LONG lError;
  446. HKEY hKey;
  447. lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  448. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\LanguagePack"),
  449. 0,
  450. KEY_QUERY_VALUE,
  451. &hKey);
  452. if (lError == ERROR_SUCCESS)
  453. {
  454. HANDLE hLpk;
  455. DWORD dwLpkShapingDlls;
  456. DWORD dwIndex;
  457. TCHAR szTemp[256];
  458. DWORD dwTempSize;
  459. DWORD dwValueType;
  460. DWORD dwValue;
  461. DWORD dwValueSize;
  462. dwLpkShapingDlls = 0;
  463. dwIndex = 0;
  464. do
  465. {
  466. dwTempSize = ARRAYSIZE(szTemp);
  467. dwValueSize = SIZEOF(DWORD);
  468. lError = RegEnumValue(hKey,
  469. dwIndex++,
  470. szTemp,
  471. &dwTempSize,
  472. NULL,
  473. &dwValueType,
  474. (LPVOID)&dwValue,
  475. &dwValueSize);
  476. if ((lError == ERROR_SUCCESS) && (dwValueType == REG_DWORD))
  477. {
  478. dwLpkShapingDlls |= 1 << dwValue;
  479. }
  480. }
  481. while (lError != ERROR_NO_MORE_ITEMS);
  482. if (dwLpkShapingDlls != 0)
  483. {
  484. hLpk = GetModuleHandle(TEXT("LPK"));
  485. if (hLpk != NULL)
  486. {
  487. g_pLpkEditCallout = (PLPKEDITCALLOUT)GetProcAddress(hLpk, "LpkEditControl");
  488. if (g_pLpkEditCallout == NULL)
  489. {
  490. FreeLibrary(hLpk);
  491. }
  492. }
  493. }
  494. RegCloseKey(hKey);
  495. }
  496. }
  497. //---------------------------------------------------------------------------//
  498. //
  499. // Destroys the edit control ped by freeing up all memory used by it.
  500. //
  501. VOID Edit_NcDestroyHandler(HWND hwnd, PED ped)
  502. {
  503. //
  504. // ped could be NULL if WM_NCCREATE failed to create it...
  505. //
  506. if (ped)
  507. {
  508. //
  509. // Free the text buffer (always present?)
  510. //
  511. LocalFree(ped->hText);
  512. //
  513. // Free up undo buffer and line start array (if present)
  514. //
  515. if (ped->hDeletedText != NULL)
  516. {
  517. GlobalFree(ped->hDeletedText);
  518. }
  519. //
  520. // Free tab stop buffer (if present)
  521. //
  522. if (ped->pTabStops)
  523. {
  524. UserLocalFree(ped->pTabStops);
  525. }
  526. //
  527. // Free line start array (if present)
  528. //
  529. if (ped->chLines)
  530. {
  531. UserLocalFree(ped->chLines);
  532. }
  533. //
  534. // Free the character width buffer (if present)
  535. //
  536. if (ped->charWidthBuffer)
  537. {
  538. UserLocalFree(ped->charWidthBuffer);
  539. }
  540. //
  541. // Free the cursor bitmap
  542. //
  543. if (ped->pLpkEditCallout && ped->hCaretBitmap)
  544. {
  545. DeleteObject(ped->hCaretBitmap);
  546. }
  547. //
  548. // Free the cached font handle
  549. //
  550. if ( ped->hFontSave )
  551. {
  552. DeleteObject(ped->hFontSave);
  553. }
  554. //
  555. // Close an open theme handle
  556. //
  557. if ( ped->hTheme )
  558. {
  559. CloseThemeData(ped->hTheme);
  560. }
  561. //
  562. // Free the memory used by CueBannerText
  563. //
  564. Str_SetPtr(&(ped->pszCueBannerText), NULL);
  565. //
  566. // free the allocated password font
  567. //
  568. if ( ped->hFontPassword )
  569. {
  570. DeleteObject(ped->hFontPassword);
  571. }
  572. //
  573. // Last but not least, free the ped
  574. //
  575. UserLocalFree(ped);
  576. }
  577. TraceMsg(TF_STANDARD, "EDIT: Clearing edit instance pointer.");
  578. Edit_SetPtr(hwnd, NULL);
  579. // If we're part of a combo box, let it know we're gone
  580. #if 0 // PORTPORT: Expose fnid field in WND struct.
  581. pwndParent = REBASEPWND(pwnd, spwndParent);
  582. if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) {
  583. ComboBoxWndProcWorker(pwndParent, WM_PARENTNOTIFY,
  584. MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd), FALSE);
  585. }
  586. #endif
  587. }
  588. //---------------------------------------------------------------------------//
  589. //
  590. // Edit_SetPasswordCharHandler AorW
  591. //
  592. // Sets the password char to display.
  593. //
  594. VOID Edit_SetPasswordCharHandler(PED ped, UINT pwchar)
  595. {
  596. HDC hdc;
  597. SIZE size = {0};
  598. ped->charPasswordChar = pwchar;
  599. if (pwchar)
  600. {
  601. hdc = Edit_GetDC(ped, TRUE);
  602. if (ped->fAnsi)
  603. {
  604. GetTextExtentPointA(hdc, (LPSTR)&pwchar, 1, &size);
  605. }
  606. else
  607. {
  608. GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
  609. }
  610. GetTextExtentPointW(hdc, (LPWSTR)&pwchar, 1, &size);
  611. ped->cPasswordCharWidth = max(size.cx, 1);
  612. Edit_ReleaseDC(ped, hdc, TRUE);
  613. }
  614. if (pwchar)
  615. {
  616. SetWindowState(ped->hwnd, ES_PASSWORD);
  617. }
  618. else
  619. {
  620. ClearWindowState(ped->hwnd, ES_PASSWORD);
  621. }
  622. if ( g_fIMMEnabled )
  623. {
  624. Edit_EnableDisableIME(ped);
  625. }
  626. }
  627. //---------------------------------------------------------------------------//
  628. //
  629. // GetNegABCwidthInfo()
  630. //
  631. // This function fills up the ped->charWidthBuffer buffer with the
  632. // negative A,B and C widths for all the characters below 0x7f in the
  633. // currently selected font.
  634. //
  635. // Returns:
  636. // TRUE, if the function succeeded.
  637. // FALSE, if GDI calls to get the char widths have failed.
  638. //
  639. // Note: not used if LPK installed
  640. //
  641. BOOL GetNegABCwidthInfo(PED ped, HDC hdc)
  642. {
  643. LPABC lpABCbuff;
  644. int i;
  645. int CharWidthBuff[CHAR_WIDTH_BUFFER_LENGTH]; // Local char width buffer.
  646. int iOverhang;
  647. if (!GetCharABCWidthsA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPABC)ped->charWidthBuffer))
  648. {
  649. TraceMsg(TF_STANDARD, "UxEdit: GetNegABCwidthInfo: GetCharABCWidthsA Failed");
  650. return FALSE;
  651. }
  652. //
  653. // The (A+B+C) returned for some fonts (eg: Lucida Caligraphy) does not
  654. // equal the actual advanced width returned by GetCharWidths() minus overhang.
  655. // This is due to font bugs. So, we adjust the 'B' width so that this
  656. // discrepancy is removed.
  657. // Fix for Bug #2932 --sankar-- 02/17/93
  658. //
  659. iOverhang = ped->charOverhang;
  660. GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, (LPINT)CharWidthBuff);
  661. lpABCbuff = (LPABC)ped->charWidthBuffer;
  662. for(i = 0; i < CHAR_WIDTH_BUFFER_LENGTH; i++)
  663. {
  664. lpABCbuff->abcB = CharWidthBuff[i] - iOverhang
  665. - lpABCbuff->abcA
  666. - lpABCbuff->abcC;
  667. lpABCbuff++;
  668. }
  669. return TRUE;
  670. }
  671. //---------------------------------------------------------------------------//
  672. //
  673. // Edit_Size() -
  674. //
  675. // Handle sizing for an edit control's client rectangle.
  676. // Use lprc as the bounding rectangle if specified; otherwise use the current
  677. // client rectangle.
  678. //
  679. VOID Edit_Size(PED ped, LPRECT lprc, BOOL fRedraw)
  680. {
  681. RECT rc;
  682. //
  683. // BiDi VB32 Creates an Edit Control and immediately sends a WM_SIZE
  684. // message which causes EXSize to be called before Edit_SetFont, which
  685. // in turn causes a divide by zero exception below. This check for
  686. // ped->lineHeight will pick it up safely. [samera] 3/5/97
  687. //
  688. if(ped->lineHeight == 0)
  689. {
  690. return;
  691. }
  692. //
  693. // assume that we won't be able to display the caret
  694. //
  695. ped->fCaretHidden = TRUE;
  696. if ( lprc )
  697. {
  698. CopyRect(&rc, lprc);
  699. }
  700. else
  701. {
  702. GetClientRect(ped->hwnd, &rc);
  703. }
  704. if (!(rc.right - rc.left) || !(rc.bottom - rc.top))
  705. {
  706. if (ped->rcFmt.right - ped->rcFmt.left)
  707. {
  708. return;
  709. }
  710. rc.left = 0;
  711. rc.top = 0;
  712. rc.right = ped->aveCharWidth * 10;
  713. rc.bottom = ped->lineHeight;
  714. }
  715. if (!lprc)
  716. {
  717. //
  718. // subtract the margins from the given rectangle --
  719. // make sure that this rectangle is big enough to have these margins.
  720. //
  721. if ((rc.right - rc.left) > (int)(ped->wLeftMargin + ped->wRightMargin))
  722. {
  723. rc.left += ped->wLeftMargin;
  724. rc.right -= ped->wRightMargin;
  725. }
  726. }
  727. //
  728. // Leave space so text doesn't touch borders.
  729. // For 3.1 compatibility, don't subtract out vertical borders unless
  730. // there is room.
  731. //
  732. if (ped->fBorder)
  733. {
  734. INT cxBorder = GetSystemMetrics(SM_CXBORDER);
  735. INT cyBorder = GetSystemMetrics(SM_CYBORDER);
  736. if (ped->fFlatBorder)
  737. {
  738. cxBorder *= 2;
  739. cyBorder *= 2;
  740. }
  741. if (rc.bottom < rc.top + ped->lineHeight + 2*cyBorder)
  742. {
  743. cyBorder = 0;
  744. }
  745. InflateRect(&rc, -cxBorder, -cyBorder);
  746. }
  747. //
  748. // Is the resulting rectangle too small? Don't change it then.
  749. //
  750. if ((!ped->fSingle) && ((rc.right - rc.left < (int) ped->aveCharWidth) ||
  751. ((rc.bottom - rc.top) / ped->lineHeight == 0)))
  752. {
  753. return;
  754. }
  755. //
  756. // now, we know we're safe to display the caret
  757. //
  758. ped->fCaretHidden = FALSE;
  759. CopyRect(&ped->rcFmt, &rc);
  760. if (ped->fSingle)
  761. {
  762. ped->rcFmt.bottom = min(rc.bottom, rc.top + ped->lineHeight);
  763. }
  764. else
  765. {
  766. EditML_Size(ped, fRedraw);
  767. }
  768. if (fRedraw)
  769. {
  770. InvalidateRect(ped->hwnd, NULL, TRUE);
  771. }
  772. //
  773. // FE_IME
  774. // Edit_Size() - call Edit_ImmSetCompositionWindow()
  775. //
  776. // normally this isn't needed because WM_SIZE will cause
  777. // WM_PAINT and the paint handler will take care of IME
  778. // composition window. However when the edit window is
  779. // restored from maximized window and client area is out
  780. // of screen, the window will not be redrawn.
  781. //
  782. if (ped->fFocus && g_fIMMEnabled && ImmIsIME(GetKeyboardLayout(0)))
  783. {
  784. POINT pt;
  785. GetCaretPos(&pt);
  786. Edit_ImmSetCompositionWindow(ped, pt.x, pt.y);
  787. }
  788. }
  789. //---------------------------------------------------------------------------//
  790. //
  791. // Edit_SetFont AorW
  792. //
  793. // Sets the font used in the edit control. Warning: Memory compaction may
  794. // occur if the font wasn't previously loaded. If the font handle passed
  795. // in is NULL, assume the system font.
  796. //
  797. BOOL Edit_SetFont(PED ped, HFONT hfont, BOOL fRedraw)
  798. {
  799. TEXTMETRICW TextMetrics = {0};
  800. HDC hdc;
  801. HFONT hOldFont=NULL;
  802. DWORD dwMaxOverlapChars;
  803. CHWIDTHINFO cwi;
  804. UINT uExtracharPos;
  805. BOOL fRet = FALSE;
  806. hdc = GetDC(ped->hwnd);
  807. if (hdc)
  808. {
  809. #ifdef _USE_DRAW_THEME_TEXT_
  810. if (hfont)
  811. {
  812. ped->hFontSave = hfont;
  813. }
  814. if ( ped->hTheme )
  815. {
  816. //
  817. // use the theme font if we're themed
  818. //
  819. HRESULT hr;
  820. LOGFONT lf;
  821. hr = GetThemeFont(ped->hTheme, hdc, EP_EDITTEXT, 0, TMT_FONT, &lf);
  822. if ( SUCCEEDED(hr) )
  823. {
  824. hfont = CreateFontIndirect(&lf);
  825. }
  826. }
  827. #endif // _USE_DRAW_THEME_TEXT_
  828. ped->hFont = hfont;
  829. if (ped->hFont)
  830. {
  831. //
  832. // Since the default font is the system font, no need to select it in
  833. // if that's what the user wants.
  834. //
  835. hOldFont = SelectObject(hdc, hfont);
  836. if (!hOldFont)
  837. {
  838. hfont = ped->hFont = NULL;
  839. }
  840. //
  841. // Get the metrics and ave char width for the currently selected font
  842. //
  843. //
  844. // Call Vertical font-aware AveWidth compute function...
  845. //
  846. // FE_SB
  847. ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
  848. //
  849. // This might fail when people uses network fonts (or bad fonts).
  850. //
  851. if (ped->aveCharWidth == 0)
  852. {
  853. TraceMsg(TF_STANDARD, "EDIT: Edit_SetFont: GdiGetCharDimensions failed");
  854. if (hOldFont != NULL)
  855. {
  856. SelectObject(hdc, hOldFont);
  857. }
  858. //
  859. // We've messed up the ped so let's reset the font.
  860. // Note that we won't recurse more than once because we'll
  861. // pass hfont == NULL.
  862. // Too bad WM_SETFONT doesn't return a value.
  863. //
  864. return Edit_SetFont(ped, NULL, fRedraw);
  865. }
  866. }
  867. else
  868. {
  869. ped->aveCharWidth = UserGetCharDimensionsEx(hdc, hfont, &TextMetrics, &ped->lineHeight);
  870. // We should always be able to get the dimensions of the system font. Just in case
  871. // set these guys to known system font constants
  872. if ( ped->aveCharWidth == 0 )
  873. {
  874. ped->aveCharWidth = SYSFONT_CXCHAR;
  875. ped->lineHeight = SYSFONT_CYCHAR;
  876. }
  877. }
  878. ped->charOverhang = TextMetrics.tmOverhang;
  879. //
  880. // assume that they don't have any negative widths at all.
  881. //
  882. ped->wMaxNegA = ped->wMaxNegC = ped->wMaxNegAcharPos = ped->wMaxNegCcharPos = 0;
  883. //
  884. // Check if Proportional Width Font
  885. //
  886. // NOTE: as SDK doc says about TEXTMETRIC:
  887. // TMPF_FIXED_PITCH
  888. // If this bit is set the font is a variable pitch font. If this bit is clear
  889. // the font is a fixed pitch font. Note very carefully that those meanings are
  890. // the opposite of what the constant name implies.
  891. //
  892. // Thus we have to reverse the value using logical not (fNonPropFont has 1 bit width)
  893. //
  894. ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & FIXED_PITCH);
  895. //
  896. // Check for a TrueType font
  897. // Older app OZWIN chokes if we allocate a bigger buffer for TrueType fonts
  898. // So, for apps older than 4.0, no special treatment for TrueType fonts.
  899. //
  900. if (ped->f40Compat && (TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE))
  901. {
  902. ped->fTrueType = GetCharWidthInfo(hdc, &cwi);
  903. #if DBG
  904. if (!ped->fTrueType)
  905. {
  906. TraceMsg(TF_STANDARD, "EDIT: Edit_SetFont: GetCharWidthInfo Failed");
  907. }
  908. #endif
  909. }
  910. else
  911. {
  912. ped->fTrueType = FALSE;
  913. }
  914. // FE_SB
  915. //
  916. // In DBCS Windows, Edit Control must handle Double Byte Character
  917. // if tmCharSet field of textmetrics is double byte character set
  918. // such as SHIFTJIS_CHARSET(128:Japan), HANGEUL_CHARSET(129:Korea).
  919. //
  920. // We call Edit_GetDBCSVector even when fAnsi is false so that we could
  921. // treat ped->fAnsi and ped->fDBCS indivisually. I changed Edit_GetDBCSVector
  922. // function so that it returns 0 or 1, because I would like to set ped->fDBCS
  923. // bit field here.
  924. //
  925. ped->fDBCS = Edit_GetDBCSVector(ped,hdc,TextMetrics.tmCharSet);
  926. ped->charSet = TextMetrics.tmCharSet;
  927. if (ped->fDBCS)
  928. {
  929. //
  930. // Free the character width buffer if ped->fDBCS.
  931. //
  932. // I expect single GetTextExtentPoint call is faster than multiple
  933. // GetTextExtentPoint call (because the graphic engine has a cache buffer).
  934. // See editec.c/ECTabTheTextOut().
  935. //
  936. if (ped->charWidthBuffer)
  937. {
  938. LocalFree(ped->charWidthBuffer);
  939. ped->charWidthBuffer = NULL;
  940. }
  941. //
  942. // if FullWidthChar : HalfWidthChar == 2 : 1....
  943. //
  944. // TextMetrics.tmMaxCharWidth = FullWidthChar width
  945. // ped->aveCharWidth = HalfWidthChar width
  946. //
  947. if (ped->fNonPropFont &&
  948. ((ped->aveCharWidth * 2) == TextMetrics.tmMaxCharWidth))
  949. {
  950. ped->fNonPropDBCS = TRUE;
  951. }
  952. else
  953. {
  954. ped->fNonPropDBCS = FALSE;
  955. }
  956. }
  957. else
  958. {
  959. //
  960. // Since the font has changed, let us obtain and save the character width
  961. // info for this font.
  962. //
  963. // First left us find out if the maximum chars that can overlap due to
  964. // negative widths. Since we can't access USER globals, we make a call here.
  965. //
  966. if (!(ped->fSingle || ped->pLpkEditCallout))
  967. {
  968. //
  969. // Is this a multiline edit control with no LPK present?
  970. //
  971. UINT wBuffSize;
  972. LPINT lpCharWidthBuff;
  973. SHORT i;
  974. //
  975. // For multiline edit controls, we maintain a buffer that contains
  976. // the character width information.
  977. //
  978. wBuffSize = (ped->fTrueType) ? (CHAR_WIDTH_BUFFER_LENGTH * sizeof(ABC)) :
  979. (CHAR_WIDTH_BUFFER_LENGTH * sizeof(int));
  980. if (ped->charWidthBuffer)
  981. {
  982. //
  983. // If buffer already present
  984. //
  985. lpCharWidthBuff = ped->charWidthBuffer;
  986. ped->charWidthBuffer = UserLocalReAlloc(lpCharWidthBuff, wBuffSize, HEAP_ZERO_MEMORY);
  987. if (ped->charWidthBuffer == NULL)
  988. {
  989. UserLocalFree((HANDLE)lpCharWidthBuff);
  990. }
  991. }
  992. else
  993. {
  994. ped->charWidthBuffer = UserLocalAlloc(HEAP_ZERO_MEMORY, wBuffSize);
  995. }
  996. if (ped->charWidthBuffer != NULL)
  997. {
  998. if (ped->fTrueType)
  999. {
  1000. ped->fTrueType = GetNegABCwidthInfo(ped, hdc);
  1001. }
  1002. //
  1003. // It is possible that the above attempts could have failed and reset
  1004. // the value of fTrueType. So, let us check that value again.
  1005. //
  1006. if (!ped->fTrueType)
  1007. {
  1008. if (!GetCharWidthA(hdc, 0, CHAR_WIDTH_BUFFER_LENGTH-1, ped->charWidthBuffer))
  1009. {
  1010. UserLocalFree((HANDLE)ped->charWidthBuffer);
  1011. ped->charWidthBuffer=NULL;
  1012. }
  1013. else
  1014. {
  1015. //
  1016. // We need to subtract out the overhang associated with
  1017. // each character since GetCharWidth includes it...
  1018. //
  1019. for (i=0;i < CHAR_WIDTH_BUFFER_LENGTH;i++)
  1020. {
  1021. ped->charWidthBuffer[i] -= ped->charOverhang;
  1022. }
  1023. }
  1024. }
  1025. }
  1026. }
  1027. }
  1028. {
  1029. //
  1030. // Calculate MaxNeg A C metrics
  1031. //
  1032. #if 0 // PORTPORT: How to get this info in user mode? And if we
  1033. // set it to zero what is the effect?
  1034. dwMaxOverlapChars = GetMaxOverlapChars();
  1035. #endif
  1036. dwMaxOverlapChars = 0;
  1037. if (ped->fTrueType)
  1038. {
  1039. if (cwi.lMaxNegA < 0)
  1040. {
  1041. ped->wMaxNegA = -cwi.lMaxNegA;
  1042. }
  1043. else
  1044. {
  1045. ped->wMaxNegA = 0;
  1046. }
  1047. if (cwi.lMaxNegC < 0)
  1048. {
  1049. ped->wMaxNegC = -cwi.lMaxNegC;
  1050. }
  1051. else
  1052. {
  1053. ped->wMaxNegC = 0;
  1054. }
  1055. if (cwi.lMinWidthD != 0)
  1056. {
  1057. ped->wMaxNegAcharPos = (ped->wMaxNegA + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
  1058. ped->wMaxNegCcharPos = (ped->wMaxNegC + cwi.lMinWidthD - 1) / cwi.lMinWidthD;
  1059. if (ped->wMaxNegA + ped->wMaxNegC > (UINT)cwi.lMinWidthD)
  1060. {
  1061. uExtracharPos = (ped->wMaxNegA + ped->wMaxNegC - 1) / cwi.lMinWidthD;
  1062. ped->wMaxNegAcharPos += uExtracharPos;
  1063. ped->wMaxNegCcharPos += uExtracharPos;
  1064. }
  1065. }
  1066. else
  1067. {
  1068. ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
  1069. ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
  1070. }
  1071. }
  1072. else if (ped->charOverhang != 0)
  1073. {
  1074. //
  1075. // Some bitmaps fonts (i.e., italic) have under/overhangs;
  1076. // this is pretty much like having negative A and C widths.
  1077. //
  1078. ped->wMaxNegA = ped->wMaxNegC = ped->charOverhang;
  1079. ped->wMaxNegAcharPos = LOWORD(dwMaxOverlapChars); // Left
  1080. ped->wMaxNegCcharPos = HIWORD(dwMaxOverlapChars); // Right
  1081. }
  1082. }
  1083. if (!hfont)
  1084. {
  1085. //
  1086. // We are getting the stats for the system font so update the system
  1087. // font fields in the ed structure since we use these when calculating
  1088. // some spacing.
  1089. //
  1090. ped->cxSysCharWidth = ped->aveCharWidth;
  1091. ped->cySysCharHeight= ped->lineHeight;
  1092. }
  1093. else if (hOldFont)
  1094. {
  1095. SelectObject(hdc, hOldFont);
  1096. }
  1097. if (ped->fFocus)
  1098. {
  1099. UINT cxCaret;
  1100. SystemParametersInfo(SPI_GETCARETWIDTH, 0, (LPVOID)&cxCaret, 0);
  1101. //
  1102. // Update the caret.
  1103. //
  1104. HideCaret(ped->hwnd);
  1105. DestroyCaret();
  1106. if (ped->pLpkEditCallout)
  1107. {
  1108. ped->pLpkEditCallout->EditCreateCaret((PED0)ped, hdc, cxCaret, ped->lineHeight, 0);
  1109. }
  1110. else
  1111. {
  1112. CreateCaret(ped->hwnd, (HBITMAP)NULL, cxCaret, ped->lineHeight);
  1113. }
  1114. ShowCaret(ped->hwnd);
  1115. }
  1116. ReleaseDC(ped->hwnd, hdc);
  1117. //
  1118. // Update password character.
  1119. //
  1120. if (ped->charPasswordChar)
  1121. {
  1122. Edit_SetPasswordCharHandler(ped, ped->charPasswordChar);
  1123. }
  1124. //
  1125. // If it is a TrueType font and it's a new app, set both the margins at the
  1126. // max negative width values for all types of the edit controls.
  1127. // (NOTE: Can't use ped->f40Compat here because edit-controls inside dialog
  1128. // boxes without DS_LOCALEDIT style are always marked as 4.0 compat.
  1129. // This is the fix for NETBENCH 3.0)
  1130. //
  1131. if (ped->fTrueType && ped->f40Compat)
  1132. {
  1133. if (ped->fDBCS)
  1134. {
  1135. //
  1136. // For DBCS TrueType Font, we calc margin from ABC width.
  1137. //
  1138. Edit_CalcMarginForDBCSFont(ped, fRedraw);
  1139. }
  1140. else
  1141. {
  1142. Edit_SetMargin(ped, EC_LEFTMARGIN | EC_RIGHTMARGIN,
  1143. MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO), fRedraw);
  1144. }
  1145. }
  1146. //
  1147. // We need to calc maxPixelWidth when font changes.
  1148. // If the word-wrap is ON, then this is done in EditML_Size() called later.
  1149. //
  1150. if((!ped->fSingle) && (!ped->fWrap))
  1151. {
  1152. EditML_BuildchLines(ped, 0, 0, FALSE, NULL, NULL);
  1153. }
  1154. //
  1155. // Recalc the layout.
  1156. //
  1157. Edit_Size(ped, NULL, fRedraw);
  1158. if ( ped->fFocus && ImmIsIME(GetKeyboardLayout(0)) )
  1159. {
  1160. Edit_SetCompositionFont( ped );
  1161. }
  1162. fRet = TRUE;
  1163. }
  1164. return fRet;
  1165. }
  1166. //---------------------------------------------------------------------------//
  1167. //
  1168. // Edit_IsCharNumeric AorW
  1169. //
  1170. // Tests whether the character entered is a numeral.
  1171. // For multiline and singleline edit controls with the ES_NUMBER style.
  1172. //
  1173. BOOL Edit_IsCharNumeric(PED ped, DWORD keyPress)
  1174. {
  1175. WORD wCharType;
  1176. if (ped->fAnsi)
  1177. {
  1178. char ch = (char)keyPress;
  1179. LCID lcid = (LCID)((ULONG_PTR)GetKeyboardLayout(0) & 0xFFFF);
  1180. GetStringTypeA(lcid, CT_CTYPE1, &ch, 1, &wCharType);
  1181. }
  1182. else
  1183. {
  1184. WCHAR wch = (WCHAR)keyPress;
  1185. GetStringTypeW(CT_CTYPE1, &wch, 1, &wCharType);
  1186. }
  1187. return (wCharType & C1_DIGIT ? TRUE : FALSE);
  1188. }
  1189. //---------------------------------------------------------------------------//
  1190. VOID Edit_EnableDisableIME(PED ped)
  1191. {
  1192. if ( ped->fReadOnly || ped->charPasswordChar )
  1193. {
  1194. //
  1195. // IME should be disabled
  1196. //
  1197. HIMC hImc;
  1198. hImc = ImmGetContext( ped->hwnd );
  1199. if ( hImc != NULL_HIMC )
  1200. {
  1201. ImmReleaseContext( ped->hwnd, hImc );
  1202. ped->hImcPrev = ImmAssociateContext( ped->hwnd, NULL_HIMC );
  1203. }
  1204. }
  1205. else
  1206. {
  1207. //
  1208. // IME should be enabled
  1209. //
  1210. if ( ped->hImcPrev != NULL_HIMC )
  1211. {
  1212. ped->hImcPrev = ImmAssociateContext( ped->hwnd, ped->hImcPrev );
  1213. //
  1214. // Font and the caret position might be changed while
  1215. // IME was being disabled. Set those now if the window
  1216. // has the focus.
  1217. //
  1218. if ( ped->fFocus )
  1219. {
  1220. POINT pt;
  1221. Edit_SetCompositionFont( ped );
  1222. GetCaretPos( &pt );
  1223. Edit_ImmSetCompositionWindow( ped, pt.x, pt.y );
  1224. }
  1225. }
  1226. }
  1227. Edit_InitInsert(ped, GetKeyboardLayout(0));
  1228. }
  1229. //---------------------------------------------------------------------------//
  1230. VOID Edit_ImmSetCompositionWindow(PED ped, LONG x, LONG y)
  1231. {
  1232. COMPOSITIONFORM cf = {0};
  1233. COMPOSITIONFORM cft = {0};
  1234. RECT rcScreenWindow;
  1235. HIMC hImc;
  1236. hImc = ImmGetContext(ped->hwnd);
  1237. if ( hImc != NULL_HIMC )
  1238. {
  1239. if ( ped->fFocus )
  1240. {
  1241. GetWindowRect( ped->hwnd, &rcScreenWindow);
  1242. //
  1243. // assuming RECT.left is the first and and RECT.top is the second field
  1244. //
  1245. MapWindowPoints( ped->hwnd, HWND_DESKTOP, (LPPOINT)&rcScreenWindow, 2);
  1246. if (ped->fInReconversion)
  1247. {
  1248. DWORD dwPoint = (DWORD)(ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_POSFROMCHAR, ped->ichMinSel, 0);
  1249. x = GET_X_LPARAM(dwPoint);
  1250. y = GET_Y_LPARAM(dwPoint);
  1251. TraceMsg(TF_STANDARD, "UxEdit: Edit_ImmSetCompositionWindow: fInReconversion (%d,%d)", x, y);
  1252. }
  1253. //
  1254. // The window currently has the focus.
  1255. //
  1256. if (ped->fSingle)
  1257. {
  1258. //
  1259. // Single line edit control.
  1260. //
  1261. cf.dwStyle = CFS_POINT;
  1262. cf.ptCurrentPos.x = x;
  1263. cf.ptCurrentPos.y = y;
  1264. SetRectEmpty(&cf.rcArea);
  1265. }
  1266. else
  1267. {
  1268. //
  1269. // Multi line edit control.
  1270. //
  1271. cf.dwStyle = CFS_RECT;
  1272. cf.ptCurrentPos.x = x;
  1273. cf.ptCurrentPos.y = y;
  1274. cf.rcArea = ped->rcFmt;
  1275. }
  1276. ImmGetCompositionWindow( hImc, &cft );
  1277. if ( (!RtlEqualMemory(&cf,&cft,sizeof(COMPOSITIONFORM))) ||
  1278. (ped->ptScreenBounding.x != rcScreenWindow.left) ||
  1279. (ped->ptScreenBounding.y != rcScreenWindow.top) )
  1280. {
  1281. ped->ptScreenBounding.x = rcScreenWindow.left;
  1282. ped->ptScreenBounding.y = rcScreenWindow.top;
  1283. ImmSetCompositionWindow( hImc, &cf );
  1284. }
  1285. }
  1286. ImmReleaseContext( ped->hwnd, hImc );
  1287. }
  1288. }
  1289. //---------------------------------------------------------------------------//
  1290. VOID Edit_SetCompositionFont(PED ped)
  1291. {
  1292. HIMC hImc;
  1293. LOGFONTW lf;
  1294. hImc = ImmGetContext( ped->hwnd );
  1295. if (hImc != NULL_HIMC)
  1296. {
  1297. if (ped->hFont)
  1298. {
  1299. GetObjectW(ped->hFont, sizeof(LOGFONTW), (LPLOGFONTW)&lf);
  1300. }
  1301. else
  1302. {
  1303. GetObjectW(GetStockObject(SYSTEM_FONT), sizeof(LOGFONTW), (LPLOGFONTW)&lf);
  1304. }
  1305. ImmSetCompositionFontW( hImc, &lf );
  1306. ImmReleaseContext( ped->hwnd, hImc );
  1307. }
  1308. }
  1309. //---------------------------------------------------------------------------//
  1310. //
  1311. // Edit_InitInsert
  1312. //
  1313. // this function is called when:
  1314. // 1) a edit control window is initialized
  1315. // 2) active keyboard layout of current thread is changed
  1316. // 3) read only attribute of this edit control is changed
  1317. //
  1318. VOID Edit_InitInsert( PED ped, HKL hkl )
  1319. {
  1320. ped->fKorea = FALSE;
  1321. ped->fInsertCompChr = FALSE;
  1322. ped->fNoMoveCaret = FALSE;
  1323. ped->fResultProcess = FALSE;
  1324. if (g_fIMMEnabled && ImmIsIME(hkl) )
  1325. {
  1326. if (PRIMARYLANGID(LOWORD(HandleToUlong(hkl))) == LANG_KOREAN )
  1327. {
  1328. ped->fKorea = TRUE;
  1329. }
  1330. //
  1331. // LATER:this flag should be set based on the IME caps
  1332. // retrieved from IME. (Such IME caps should be defined)
  1333. // For now, we can safely assume that only Korean IMEs
  1334. // set CS_INSERTCHAR.
  1335. //
  1336. if ( ped->fKorea )
  1337. {
  1338. ped->fInsertCompChr = TRUE;
  1339. }
  1340. }
  1341. //
  1342. // if we had a composition character, the shape of caret
  1343. // is changed. We need to reset the caret shape.
  1344. //
  1345. if ( ped->fReplaceCompChr )
  1346. {
  1347. ped->fReplaceCompChr = FALSE;
  1348. Edit_SetCaretHandler( ped );
  1349. }
  1350. }
  1351. //---------------------------------------------------------------------------//
  1352. VOID Edit_SetCaretHandler(PED ped)
  1353. {
  1354. HDC hdc;
  1355. PSTR pText;
  1356. SIZE size = {0};
  1357. //
  1358. // In any case destroy caret beforehand otherwise SetCaretPos()
  1359. // will get crazy.. win95d-B#992,B#2370
  1360. //
  1361. if (ped->fFocus)
  1362. {
  1363. HideCaret(ped->hwnd);
  1364. DestroyCaret();
  1365. if ( ped->fReplaceCompChr )
  1366. {
  1367. hdc = Edit_GetDC(ped, TRUE );
  1368. pText = Edit_Lock(ped);
  1369. if ( ped->fAnsi)
  1370. {
  1371. GetTextExtentPointA(hdc, pText + ped->ichCaret, 2, &size);
  1372. }
  1373. else
  1374. {
  1375. GetTextExtentPointW(hdc, (LPWSTR)pText + ped->ichCaret, 1, &size);
  1376. }
  1377. Edit_Unlock(ped);
  1378. Edit_ReleaseDC(ped, hdc, TRUE);
  1379. CreateCaret(ped->hwnd, (HBITMAP)NULL, size.cx, ped->lineHeight);
  1380. }
  1381. else
  1382. {
  1383. CreateCaret(ped->hwnd,
  1384. (HBITMAP)NULL,
  1385. (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
  1386. ped->lineHeight);
  1387. }
  1388. hdc = Edit_GetDC(ped, TRUE );
  1389. if ( ped->fSingle )
  1390. {
  1391. EditSL_SetCaretPosition( ped, hdc );
  1392. }
  1393. else
  1394. {
  1395. EditML_SetCaretPosition( ped, hdc );
  1396. }
  1397. Edit_ReleaseDC(ped, hdc, TRUE);
  1398. ShowCaret(ped->hwnd);
  1399. }
  1400. }
  1401. //---------------------------------------------------------------------------//
  1402. #define GET_COMPOSITION_STRING (ped->fAnsi ? ImmGetCompositionStringA : ImmGetCompositionStringW)
  1403. BOOL Edit_ResultStrHandler(PED ped)
  1404. {
  1405. HIMC himc;
  1406. LPSTR lpStr;
  1407. LONG dwLen;
  1408. ped->fInsertCompChr = FALSE; // clear the state
  1409. ped->fNoMoveCaret = FALSE;
  1410. himc = ImmGetContext(ped->hwnd);
  1411. if ( himc == NULL_HIMC )
  1412. {
  1413. return FALSE;
  1414. }
  1415. dwLen = GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, NULL, 0);
  1416. if (dwLen == 0)
  1417. {
  1418. ImmReleaseContext(ped->hwnd, himc);
  1419. return FALSE;
  1420. }
  1421. dwLen *= ped->cbChar;
  1422. dwLen += ped->cbChar;
  1423. lpStr = (LPSTR)GlobalAlloc(GPTR, dwLen);
  1424. if (lpStr == NULL)
  1425. {
  1426. ImmReleaseContext(ped->hwnd, himc);
  1427. return FALSE;
  1428. }
  1429. GET_COMPOSITION_STRING(himc, GCS_RESULTSTR, lpStr, dwLen);
  1430. if (ped->fSingle)
  1431. {
  1432. EditSL_ReplaceSel(ped, lpStr);
  1433. }
  1434. else
  1435. {
  1436. EditML_ReplaceSel(ped, lpStr);
  1437. }
  1438. GlobalFree((HGLOBAL)lpStr);
  1439. ImmReleaseContext(ped->hwnd, himc);
  1440. ped->fReplaceCompChr = FALSE;
  1441. ped->fNoMoveCaret = FALSE;
  1442. ped->fResultProcess = FALSE;
  1443. Edit_SetCaretHandler(ped);
  1444. return TRUE;
  1445. }
  1446. //---------------------------------------------------------------------------//
  1447. LRESULT Edit_ImeComposition(PED ped, WPARAM wParam, LPARAM lParam)
  1448. {
  1449. INT ich;
  1450. LRESULT lReturn = 1;
  1451. HDC hdc;
  1452. BOOL fSLTextUpdated = FALSE;
  1453. ICH iResult;
  1454. HIMC hImc;
  1455. BYTE TextBuf[4];
  1456. if (!ped->fInsertCompChr)
  1457. {
  1458. if (lParam & GCS_RESULTSTR)
  1459. {
  1460. Edit_InOutReconversionMode(ped, FALSE);
  1461. if (!ped->fKorea && ped->wImeStatus & EIMES_GETCOMPSTRATONCE)
  1462. {
  1463. ResultAtOnce:
  1464. Edit_ResultStrHandler(ped);
  1465. lParam &= ~GCS_RESULTSTR;
  1466. }
  1467. }
  1468. return DefWindowProc(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1469. }
  1470. //
  1471. // In case of Ansi edit control, the length of minimum composition string
  1472. // is 2. Check here maximum byte of edit control.
  1473. //
  1474. if( ped->fAnsi && ped->cchTextMax == 1 )
  1475. {
  1476. HIMC hImc;
  1477. hImc = ImmGetContext( ped->hwnd );
  1478. ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0L);
  1479. ImmReleaseContext( ped->hwnd, hImc );
  1480. MessageBeep(MB_ICONEXCLAMATION);
  1481. return lReturn;
  1482. }
  1483. //
  1484. // Don't move this after CS_NOMOVECARET check.
  1485. // In case if skip the message, fNoMoveCaret should not be set.
  1486. //
  1487. if ((lParam & CS_INSERTCHAR) && ped->fResultProcess)
  1488. {
  1489. //
  1490. // Now we're in result processing. GCS_RESULTSTR ends up
  1491. // to WM_IME_CHAR and WM_CHAR. Since WM_CHAR is posted,
  1492. // the message(s) will come later than this CS_INSERTCHAR
  1493. // message. This composition character should be handled
  1494. // after the WM_CHAR message(s).
  1495. //
  1496. if(ped->fAnsi)
  1497. {
  1498. PostMessageA(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1499. }
  1500. else
  1501. {
  1502. PostMessageW(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1503. }
  1504. ped->fResultProcess = FALSE;
  1505. return lReturn;
  1506. }
  1507. if (lParam & GCS_RESULTSTR)
  1508. {
  1509. if (!ped->fKorea && ped->wImeStatus & EIMES_GETCOMPSTRATONCE)
  1510. {
  1511. goto ResultAtOnce;
  1512. }
  1513. ped->fResultProcess = TRUE;
  1514. if ( ped->fReplaceCompChr )
  1515. {
  1516. //
  1517. // we have a DBCS character to be replaced.
  1518. // let's delete it before inserting the new one.
  1519. //
  1520. ich = (ped->fAnsi) ? 2 : 1;
  1521. ped->fReplaceCompChr = FALSE;
  1522. ped->ichMaxSel = min(ped->ichCaret + ich, ped->cch);
  1523. ped->ichMinSel = ped->ichCaret;
  1524. if ( Edit_DeleteText( ped ) > 0 )
  1525. {
  1526. if ( ped->fSingle )
  1527. {
  1528. //
  1529. // Update the display
  1530. //
  1531. Edit_NotifyParent(ped, EN_UPDATE);
  1532. hdc = Edit_GetDC(ped,FALSE);
  1533. EditSL_DrawText(ped, hdc, 0);
  1534. Edit_ReleaseDC(ped,hdc,FALSE);
  1535. //
  1536. // Tell parent our text contents changed.
  1537. //
  1538. Edit_NotifyParent(ped, EN_CHANGE);
  1539. }
  1540. }
  1541. Edit_SetCaretHandler( ped );
  1542. }
  1543. }
  1544. else if (lParam & CS_INSERTCHAR)
  1545. {
  1546. //
  1547. // If we are in the middle of a mousedown command, don't do anything.
  1548. //
  1549. if (ped->fMouseDown)
  1550. {
  1551. return lReturn;
  1552. }
  1553. //
  1554. // We can safely assume that interimm character is always DBCS.
  1555. //
  1556. ich = ( ped->fAnsi ) ? 2 : 1;
  1557. if ( ped->fReplaceCompChr )
  1558. {
  1559. //
  1560. // we have a character to be replaced.
  1561. // let's delete it before inserting the new one.
  1562. // when we have a composition characters, the
  1563. // caret is placed before the composition character.
  1564. //
  1565. ped->ichMaxSel = min(ped->ichCaret+ich, ped->cch);
  1566. ped->ichMinSel = ped->ichCaret;
  1567. }
  1568. //
  1569. // let's delete current selected text or composition character
  1570. //
  1571. if ( ped->fSingle )
  1572. {
  1573. if ( Edit_DeleteText( ped ) > 0 )
  1574. {
  1575. fSLTextUpdated = TRUE;
  1576. }
  1577. }
  1578. else
  1579. {
  1580. EditML_DeleteText( ped );
  1581. }
  1582. //
  1583. // When the composition charcter is canceled, IME may give us NULL wParam,
  1584. // with CS_INSERTCHAR flag on. We shouldn't insert a NULL character.
  1585. //
  1586. if ( wParam != 0 )
  1587. {
  1588. if ( ped->fAnsi )
  1589. {
  1590. TextBuf[0] = HIBYTE(LOWORD(wParam)); // leading byte
  1591. TextBuf[1] = LOBYTE(LOWORD(wParam)); // trailing byte
  1592. TextBuf[2] = '\0';
  1593. }
  1594. else
  1595. {
  1596. TextBuf[0] = LOBYTE(LOWORD(wParam));
  1597. TextBuf[1] = HIBYTE(LOWORD(wParam));
  1598. TextBuf[2] = '\0';
  1599. TextBuf[3] = '\0';
  1600. }
  1601. if ( ped->fSingle )
  1602. {
  1603. iResult = EditSL_InsertText( ped, (LPSTR)TextBuf, ich );
  1604. if (iResult == 0)
  1605. {
  1606. //
  1607. // Couldn't insert the text, for e.g. the text exceeded the limit.
  1608. //
  1609. MessageBeep(0);
  1610. }
  1611. else if (iResult > 0)
  1612. {
  1613. //
  1614. // Remember we need to update the text.
  1615. //
  1616. fSLTextUpdated = TRUE;
  1617. }
  1618. }
  1619. else
  1620. {
  1621. iResult = EditML_InsertText( ped, (LPSTR)TextBuf, ich, TRUE);
  1622. }
  1623. if ( iResult > 0 )
  1624. {
  1625. //
  1626. // ped->fReplaceCompChr will be reset:
  1627. //
  1628. // 1) when the character is finalized.
  1629. // we will receive GCS_RESULTSTR
  1630. //
  1631. // 2) when the character is canceled.
  1632. //
  1633. // we will receive WM_IME_COMPOSITION|CS_INSERTCHAR
  1634. // with wParam == 0 (in case of user types backspace
  1635. // at the first element of composition character).
  1636. //
  1637. // or
  1638. //
  1639. // we will receive WM_IME_ENDCOMPOSITION message
  1640. //
  1641. ped->fReplaceCompChr = TRUE;
  1642. //
  1643. // Caret should be placed BEFORE the composition
  1644. // character.
  1645. //
  1646. ped->ichCaret = max( 0, (INT)ped->ichCaret - ich);
  1647. Edit_SetCaretHandler( ped );
  1648. }
  1649. else
  1650. {
  1651. //
  1652. // We failed to insert a character. We might run out
  1653. // of memory, or reached to the text size limit. let's
  1654. // cancel the composition character.
  1655. //
  1656. hImc = ImmGetContext(ped->hwnd);
  1657. ImmNotifyIME(hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
  1658. ImmReleaseContext(ped->hwnd, hImc);
  1659. ped->fReplaceCompChr = FALSE;
  1660. Edit_SetCaretHandler( ped );
  1661. }
  1662. }
  1663. else
  1664. {
  1665. //
  1666. // the composition character is canceled.
  1667. //
  1668. ped->fReplaceCompChr = FALSE;
  1669. Edit_SetCaretHandler( ped );
  1670. }
  1671. //
  1672. // We won't notify parent the text change
  1673. // because the composition character has
  1674. // not been finalized.
  1675. //
  1676. if ( fSLTextUpdated )
  1677. {
  1678. //
  1679. // Update the display
  1680. //
  1681. Edit_NotifyParent(ped, EN_UPDATE);
  1682. hdc = Edit_GetDC(ped,FALSE);
  1683. if ( ped->fReplaceCompChr )
  1684. {
  1685. //
  1686. // move back the caret to the original position
  1687. // temporarily so that our new block cursor can
  1688. // be located within the visible area of window.
  1689. //
  1690. ped->ichCaret = min( ped->cch, ped->ichCaret + ich);
  1691. EditSL_ScrollText(ped, hdc);
  1692. ped->ichCaret = max( 0, (INT)ped->ichCaret - ich);
  1693. }
  1694. else
  1695. {
  1696. EditSL_ScrollText(ped, hdc);
  1697. }
  1698. EditSL_DrawText(ped, hdc, 0);
  1699. Edit_ReleaseDC(ped,hdc,FALSE);
  1700. //
  1701. // Tell parent our text contents changed.
  1702. //
  1703. Edit_NotifyParent(ped, EN_CHANGE);
  1704. }
  1705. return lReturn;
  1706. }
  1707. return DefWindowProc(ped->hwnd, WM_IME_COMPOSITION, wParam, lParam);
  1708. }
  1709. //---------------------------------------------------------------------------//
  1710. //
  1711. // HanjaKeyHandler
  1712. //
  1713. // VK_HANJA handler - Korean only
  1714. //
  1715. BOOL HanjaKeyHandler(PED ped)
  1716. {
  1717. BOOL changeSelection = FALSE;
  1718. if (ped->fKorea && !ped->fReadOnly)
  1719. {
  1720. ICH oldCaret = ped->ichCaret;
  1721. if (ped->fReplaceCompChr)
  1722. {
  1723. return FALSE;
  1724. }
  1725. if (ped->ichMinSel < ped->ichMaxSel)
  1726. {
  1727. ped->ichCaret = ped->ichMinSel;
  1728. }
  1729. if (!ped->cch || ped->cch == ped->ichCaret)
  1730. {
  1731. ped->ichCaret = oldCaret;
  1732. MessageBeep(MB_ICONEXCLAMATION);
  1733. return FALSE;
  1734. }
  1735. if (ped->fAnsi)
  1736. {
  1737. if (ImmEscapeA(GetKeyboardLayout(0), ImmGetContext(ped->hwnd),
  1738. IME_ESC_HANJA_MODE, (Edit_Lock(ped) + ped->ichCaret * ped->cbChar)))
  1739. {
  1740. changeSelection = TRUE;
  1741. }
  1742. else
  1743. {
  1744. ped->ichCaret = oldCaret;
  1745. }
  1746. Edit_Unlock(ped);
  1747. }
  1748. else
  1749. {
  1750. if (ImmEscapeW(GetKeyboardLayout(0), ImmGetContext(ped->hwnd),
  1751. IME_ESC_HANJA_MODE, (Edit_Lock(ped) + ped->ichCaret * ped->cbChar)))
  1752. {
  1753. changeSelection = TRUE;
  1754. }
  1755. else
  1756. {
  1757. ped->ichCaret = oldCaret;
  1758. }
  1759. Edit_Unlock(ped);
  1760. }
  1761. }
  1762. return changeSelection;
  1763. }
  1764. //---------------------------------------------------------------------------//
  1765. // Edit_RequestHandler()
  1766. //
  1767. // Handles WM_IME_REQUEST message originated by IME
  1768. //
  1769. #define MAX_ECDOCFEED 20
  1770. ICH Edit_ImeGetDocFeedMin(PED ped, LPSTR lpstr)
  1771. {
  1772. ICH ich;
  1773. if (ped->ichMinSel > MAX_ECDOCFEED)
  1774. {
  1775. ich = ped->ichMinSel - MAX_ECDOCFEED;
  1776. ich = Edit_AdjustIch(ped, lpstr, ich);
  1777. }
  1778. else
  1779. {
  1780. ich = 0;
  1781. }
  1782. return ich;
  1783. }
  1784. ICH Edit_ImeGetDocFeedMax(PED ped, LPSTR lpstr)
  1785. {
  1786. ICH ich;
  1787. if ((ped->cch - ped->ichMaxSel) > MAX_ECDOCFEED)
  1788. {
  1789. ich = ped->ichMaxSel + MAX_ECDOCFEED;
  1790. ich = Edit_AdjustIch(ped, lpstr, ich);
  1791. }
  1792. else
  1793. {
  1794. ich = ped->cch;
  1795. }
  1796. return ich;
  1797. }
  1798. LRESULT Edit_RequestHandler(PED ped, WPARAM dwSubMsg, LPARAM lParam)
  1799. {
  1800. LRESULT lreturn = 0L;
  1801. switch (dwSubMsg)
  1802. {
  1803. case IMR_CONFIRMRECONVERTSTRING:
  1804. //
  1805. // CHECK VERSION of the structure
  1806. //
  1807. if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0)
  1808. {
  1809. TraceMsg(TF_STANDARD, "Edit_RequestHandler: RECONVERTSTRING dwVersion is not expected.",
  1810. ((LPRECONVERTSTRING)lParam)->dwVersion);
  1811. return 0L;
  1812. }
  1813. if (lParam && ped && ped->fFocus && ped->hText && ImmIsIME(GetKeyboardLayout(0)))
  1814. {
  1815. LPVOID lpSrc;
  1816. lpSrc = Edit_Lock(ped);
  1817. if (lpSrc == NULL)
  1818. {
  1819. TraceMsg(TF_STANDARD, "Edit_RequestHandler: LOCALLOCK(ped) failed.");
  1820. }
  1821. else
  1822. {
  1823. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
  1824. ICH ichStart;
  1825. ICH ichEnd;
  1826. UINT cchLen;
  1827. ichStart = Edit_ImeGetDocFeedMin(ped, lpSrc);
  1828. ichEnd = Edit_ImeGetDocFeedMax(ped, lpSrc);
  1829. UserAssert(ichEnd >= ichStart);
  1830. cchLen = ichEnd - ichStart; // holds character count.
  1831. Edit_Unlock(ped);
  1832. if (lpRCS->dwStrLen != cchLen)
  1833. {
  1834. TraceMsg(TF_STANDARD, "Edit_RequestHandler: the given string length is not expected.");
  1835. }
  1836. else
  1837. {
  1838. ICH ichSelStart;
  1839. ICH ichSelEnd;
  1840. ichSelStart = ichStart + (lpRCS->dwCompStrOffset / ped->cbChar);
  1841. ichSelEnd = ichSelStart + lpRCS->dwCompStrLen;
  1842. (ped->fAnsi ? SendMessageA : SendMessageW)(ped->hwnd, EM_SETSEL, ichSelStart, ichSelEnd);
  1843. lreturn = 1L;
  1844. }
  1845. }
  1846. }
  1847. break;
  1848. case IMR_RECONVERTSTRING:
  1849. //
  1850. // CHECK VERSION of the structure
  1851. //
  1852. if (lParam && ((LPRECONVERTSTRING)lParam)->dwVersion != 0)
  1853. {
  1854. TraceMsg(TF_STANDARD, "UxEdit: Edit_RequestHandler: RECONVERTSTRING dwVersion is not expected.");
  1855. return 0L;
  1856. }
  1857. if (ped && ped->fFocus && ped->hText && ImmIsIME(GetKeyboardLayout(0)))
  1858. {
  1859. ICH ichStart;
  1860. ICH ichEnd;
  1861. UINT cchLen;
  1862. UINT cchSelLen;
  1863. LPVOID lpSrc;
  1864. lpSrc = Edit_Lock(ped);
  1865. if (lpSrc == NULL)
  1866. {
  1867. TraceMsg(TF_STANDARD, "Edit_RequestHandler: LOCALLOCK(ped) failed.");
  1868. return 0L;
  1869. }
  1870. ichStart = Edit_ImeGetDocFeedMin(ped, lpSrc);
  1871. ichEnd = Edit_ImeGetDocFeedMax(ped, lpSrc);
  1872. UserAssert(ichEnd >= ichStart);
  1873. cchLen = ichEnd - ichStart; // holds character count.
  1874. cchSelLen = ped->ichMaxSel - ped->ichMinSel; // holds character count.
  1875. if (cchLen == 0)
  1876. {
  1877. // if we have no selection,
  1878. // just return 0.
  1879. break;
  1880. }
  1881. UserAssert(ped->cbChar == sizeof(BYTE) || ped->cbChar == sizeof(WCHAR));
  1882. // This Edit Control has selection.
  1883. if (lParam == 0)
  1884. {
  1885. //
  1886. // IME just want to get required size for buffer.
  1887. // cchLen + 1 is needed to reserve room for trailing L'\0'.
  1888. // ~~~~
  1889. lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
  1890. }
  1891. else
  1892. {
  1893. LPRECONVERTSTRING lpRCS = (LPRECONVERTSTRING)lParam;
  1894. LPVOID lpDest = (LPBYTE)lpRCS + sizeof(RECONVERTSTRING);
  1895. // check buffer size
  1896. // if the given buffer is smaller than actual needed size,
  1897. // shrink our size to fit the buffer
  1898. if ((INT)lpRCS->dwSize <= sizeof(RECONVERTSTRING) + cchLen * ped->cbChar)
  1899. {
  1900. TraceMsg(TF_STANDARD, "UxEdit: Edit_Request: ERR09");
  1901. cchLen = (lpRCS->dwSize - sizeof(RECONVERTSTRING)) / ped->cbChar - ped->cbChar;
  1902. }
  1903. lpRCS->dwStrOffset = sizeof(RECONVERTSTRING); // buffer begins just after RECONVERTSTRING
  1904. lpRCS->dwCompStrOffset =
  1905. lpRCS->dwTargetStrOffset = (ped->ichMinSel - ichStart) * ped->cbChar; // BYTE count offset
  1906. lpRCS->dwStrLen = cchLen; // TCHAR count
  1907. lpRCS->dwCompStrLen =
  1908. lpRCS->dwTargetStrLen = cchSelLen; // TCHAR count
  1909. RtlCopyMemory(lpDest,
  1910. (LPBYTE)lpSrc + ichStart * ped->cbChar,
  1911. cchLen * ped->cbChar);
  1912. // Null-Terminate the string
  1913. if (ped->fAnsi)
  1914. {
  1915. LPBYTE psz = (LPBYTE)lpDest;
  1916. psz[cchLen] = '\0';
  1917. }
  1918. else
  1919. {
  1920. LPWSTR pwsz = (LPWSTR)lpDest;
  1921. pwsz[cchLen] = L'\0';
  1922. }
  1923. Edit_Unlock(ped);
  1924. // final buffer size
  1925. lreturn = sizeof(RECONVERTSTRING) + (cchLen + 1) * ped->cbChar;
  1926. Edit_InOutReconversionMode(ped, TRUE);
  1927. Edit_ImmSetCompositionWindow(ped, 0, 0);
  1928. }
  1929. }
  1930. break;
  1931. }
  1932. return lreturn;
  1933. }