Leaked source code of windows server 2003
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.

1000 lines
35 KiB

  1. //////////////////////////////////////////////////////////////////////////
  2. // imemenu.c - IME Menu APIs
  3. //
  4. // handles IME specific menu retrieval
  5. //
  6. // Copyright (c) 1985 - 1999, Microsoft Corporation
  7. //
  8. // History:
  9. // 23-Mar-1997 hiroyama Created
  10. //////////////////////////////////////////////////////////////////////////
  11. #include "precomp.h"
  12. #ifdef HIRO_DEBUG
  13. #define D(x) x
  14. #else
  15. #define D(x)
  16. #endif
  17. #define IME_MENU_FILE_NAME L"ImmMenuInfo"
  18. #define IME_MENU_MAXMEM (128 * 1024) // maximum size of mapped file
  19. ////////////////////////////////////////////////////////////
  20. // private structurs for inter process communication
  21. //
  22. // NOTE for NT50: these are dedicated to internat.exe
  23. //
  24. // uses memory mapped file as shared buffer
  25. // all strings expect UNICODE
  26. // HBITMAP is de-compiled and then compiled again using
  27. // internat.exe's context
  28. //
  29. ////////////////////////////////////////////////////////////
  30. typedef struct _IMEMENU_BMP_HEADER {
  31. struct _IMEMENU_BMP_HEADER* lpNext;
  32. HBITMAP hBitmap;
  33. LPBYTE pBits;
  34. BITMAPINFO bmi;
  35. } IMEMENU_BMP_HEADER;
  36. typedef struct {
  37. UINT cbSize;
  38. UINT fType;
  39. UINT fState;
  40. UINT wID;
  41. IMEMENU_BMP_HEADER* lpBmpChecked;
  42. IMEMENU_BMP_HEADER* lpBmpUnchecked;
  43. DWORD dwItemData;
  44. WCHAR szString[IMEMENUITEM_STRING_SIZE]; // menu string: always UNICODE.
  45. IMEMENU_BMP_HEADER* lpBmpItem; // NULL means no bitmap in this menu
  46. } IMEMENU_ITEM;
  47. typedef struct {
  48. DWORD dwVersion; // holds version of this memory chunk
  49. DWORD dwMemSize; // size of memory buffer allocated
  50. DWORD dwFlags; // flags returned from IME
  51. DWORD dwType;
  52. IMEMENU_ITEM* lpImeParentMenu; // parent menu's offset (if any) passed from requester
  53. IMEMENU_ITEM* lpImeMenu; // offset to first menu item (will be set by IME side)
  54. DWORD dwSize; // number of menus to fill (not byte count)
  55. IMEMENU_BMP_HEADER* lpBmp; // offset to first bitmap header
  56. IMEMENU_BMP_HEADER* lpBmpNext; // points next available location for bmp buffer
  57. } IMEMENU_HEADER;
  58. // address conversion
  59. #define CONVTO_OFFSET(x) ((x) = (LPVOID)((x) ? ((LPBYTE)(x) - offset) : NULL))
  60. #define CONVTO_PTR(x) ((x) = (LPVOID)((x) ? ((LPBYTE)(x) + offset) : NULL))
  61. #if DBG
  62. #define CHK_OFFSET(x) if ((ULONG_PTR)(x) >= pHeader->dwMemSize) { \
  63. RIPMSG2(RIP_WARNING, "CHK_OFFSET(%s=%lx) is out of range.", #x, (ULONG_PTR)(x)); \
  64. }
  65. #define CHK_PTR(x) if ((LPVOID)(x) < (LPVOID)pHeader || (LPBYTE)(x) > (LPBYTE)pHeader + pHeader->dwMemSize) { \
  66. if ((x) != NULL) { \
  67. RIPMSG2(RIP_WARNING, "CHK_PTR(%s=%lx) is out of range.", #x, (ULONG_PTR)(x)); \
  68. DebugBreak(); \
  69. } \
  70. }
  71. #else
  72. #define CHK_OFFSET(x)
  73. #define CHK_PTR(x) if ((x) != NULL) { \
  74. if ((LPVOID)(x) < (LPVOID)pHeader || (LPBYTE)(x) > (LPBYTE)pHeader + pHeader->dwMemSize) { \
  75. goto cleanup; \
  76. } \
  77. }
  78. #endif
  79. int ConvertImeMenuItemInfoAtoW(LPIMEMENUITEMINFOA lpA, LPIMEMENUITEMINFOW lpW, int nCP, BOOL copyBmp)
  80. {
  81. int i;
  82. lpW->cbSize = lpA->cbSize;
  83. lpW->fType = lpA->fType;
  84. lpW->fState = lpA->fState;
  85. lpW->wID = lpA->wID;
  86. if (copyBmp) {
  87. lpW->hbmpChecked = lpA->hbmpChecked;
  88. lpW->hbmpUnchecked = lpA->hbmpUnchecked;
  89. lpW->hbmpItem = lpA->hbmpItem;
  90. }
  91. lpW->dwItemData = lpA->dwItemData;
  92. i = MultiByteToWideChar(nCP,
  93. 0,
  94. lpA->szString,
  95. lstrlenA(lpA->szString),
  96. lpW->szString,
  97. IMEMENUITEM_STRING_SIZE);
  98. if (i >= IMEMENUITEM_STRING_SIZE) {
  99. return 0;
  100. }
  101. else {
  102. lpW->szString[i] = L'\0';
  103. }
  104. return i;
  105. }
  106. int ConvertImeMenuItemInfoWtoA(LPIMEMENUITEMINFOW lpW, LPIMEMENUITEMINFOA lpA, int nCP)
  107. {
  108. int i;
  109. BOOL bUDC;
  110. lpA->cbSize = lpW->cbSize;
  111. lpA->fType = lpW->fType;
  112. lpA->fState = lpW->fState;
  113. lpA->wID = lpW->wID;
  114. lpA->hbmpChecked = lpW->hbmpChecked;
  115. lpA->hbmpUnchecked = lpW->hbmpUnchecked;
  116. lpA->dwItemData = lpW->dwItemData;
  117. lpA->hbmpItem = lpW->hbmpItem;
  118. i = WideCharToMultiByte(nCP,
  119. 0,
  120. lpW->szString,
  121. wcslen(lpW->szString),
  122. lpA->szString,
  123. IMEMENUITEM_STRING_SIZE,
  124. (LPSTR)NULL,
  125. &bUDC);
  126. if (i >= IMEMENUITEM_STRING_SIZE) {
  127. return 0;
  128. }
  129. else {
  130. lpA->szString[i] = '\0';
  131. }
  132. return i;
  133. }
  134. #if DBG
  135. void DumpBytes(LPBYTE pb, UINT size)
  136. {
  137. UINT i;
  138. TRACE(("\npbmi dump:"));
  139. for (i = 0; i < size; ++i) {
  140. TRACE(("%02X ", pb[i] & 0xff));
  141. }
  142. TRACE(("\n"));
  143. UNREFERENCED_PARAMETER(pb); // just in case
  144. }
  145. #else
  146. #define DumpBytes(a,b)
  147. #endif
  148. ////////////////////////////////////////////////////////////////////
  149. // SaveBitmapToMemory
  150. IMEMENU_BMP_HEADER* SaveBitmapToMemory(HDC hDC, HBITMAP hBmp, IMEMENU_BMP_HEADER* lpBH, IMEMENU_HEADER* pHeader)
  151. {
  152. HBITMAP hTmpBmp, hBmpOld;
  153. IMEMENU_BMP_HEADER* lpNext = NULL;
  154. PBITMAPINFO pbmi = &lpBH->bmi;
  155. ULONG sizBMI;
  156. if (!hBmp) {
  157. RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: hBmp == NULL");
  158. return NULL;
  159. }
  160. UserAssert(lpBH != NULL);
  161. //
  162. // Let the graphics engine to retrieve the dimension of the bitmap for us
  163. // GetDIBits uses the size to determine if it's BITMAPCOREINFO or BITMAPINFO
  164. // if BitCount != 0, color table will be retrieved
  165. //
  166. pbmi->bmiHeader.biSize = sizeof pbmi->bmiHeader;
  167. pbmi->bmiHeader.biBitCount = 0; // don't get the color table
  168. if ((GetDIBits(hDC, hBmp, 0, 0, (LPSTR)NULL, pbmi, DIB_RGB_COLORS)) == 0) {
  169. RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: failed to GetDIBits(NULL)");
  170. return NULL;
  171. }
  172. //
  173. // Note: 24 bits per pixel has no color table. So, we don't have to
  174. // allocate memory for retrieving that. Otherwise, we do.
  175. //
  176. switch (pbmi->bmiHeader.biBitCount) {
  177. case 24: // has color table
  178. sizBMI = sizeof(BITMAPINFOHEADER);
  179. break;
  180. case 16:
  181. case 32:
  182. sizBMI = sizeof(BITMAPINFOHEADER) + sizeof(DWORD) * 3;
  183. break;
  184. default:
  185. sizBMI = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << pbmi->bmiHeader.biBitCount);
  186. break;
  187. }
  188. //
  189. // check if the buffer has enough space to put bitmap
  190. //
  191. if ((LPBYTE)pHeader + pHeader->dwMemSize < (LPBYTE)lpBH + sizeof lpBH + sizBMI + pbmi->bmiHeader.biSizeImage) {
  192. RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: size of bmp image(s) exceed limit ");
  193. return FALSE;
  194. }
  195. //
  196. // Now that we know the size of the image, let pBits point the given buffer
  197. //
  198. lpBH->pBits = (LPBYTE)pbmi + sizBMI;
  199. //
  200. // Bitmap can't be selected into a DC when calling GetDIBits
  201. // Assume that the hDC is the DC where the bitmap would have been selected
  202. // if indeed it has been selected
  203. //
  204. if (hTmpBmp = CreateCompatibleBitmap(hDC, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight)) {
  205. hBmpOld = SelectObject(hDC, hTmpBmp);
  206. if (GetDIBits(hDC, hBmp, 0, pbmi->bmiHeader.biHeight, (LPSTR)lpBH->pBits, pbmi, DIB_RGB_COLORS) == 0){
  207. SelectObject(hDC, hBmpOld);
  208. RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: GetDIBits() failed.");
  209. return NULL;
  210. }
  211. lpNext = (IMEMENU_BMP_HEADER*)((LPBYTE)pbmi + sizBMI + pbmi->bmiHeader.biSizeImage);
  212. DumpBytes((LPBYTE)pbmi, sizeof *pbmi);
  213. } else {
  214. RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: CreateCompatibleBitmap() failed.");
  215. return NULL;
  216. }
  217. SelectObject(hDC, hBmpOld);
  218. DeleteObject(hTmpBmp);
  219. return lpNext;
  220. }
  221. //////////////////////////////////////////////////////////////////////////////
  222. // DecompileBitmap()
  223. //
  224. // decompile given hBitmap into IMEMENU_BMP_HEADER
  225. // manupilate IMEMENU_BMP_HEADER links in IMEMENU_HEADER
  226. //
  227. // History:
  228. // 23-Mar-1997 HiroYama Created
  229. //////////////////////////////////////////////////////////////////////////////
  230. IMEMENU_BMP_HEADER* DecompileBitmap(IMEMENU_HEADER* pHeader, HBITMAP hBitmap)
  231. {
  232. IMEMENU_BMP_HEADER* pBmp = pHeader->lpBmp;
  233. HDC hDC;
  234. // first search handled bitmap
  235. while (pBmp) {
  236. if (pBmp->hBitmap == hBitmap) {
  237. // if hBitmap is already de-compiled, return it
  238. return pBmp;
  239. }
  240. pBmp = pBmp->lpNext;
  241. }
  242. // not yet allocated, so prepare memory buffer
  243. pBmp = pHeader->lpBmpNext;
  244. UserAssert(pBmp != NULL);
  245. CHK_PTR(pBmp);
  246. if (pBmp == NULL) {
  247. RIPMSG1(RIP_WARNING, "DecompileBitmap: pBmp == NULL in L%d", __LINE__);
  248. return NULL;
  249. }
  250. // use desktop's DC
  251. hDC = GetDC(GetDesktopWindow());
  252. if (hDC == NULL) {
  253. RIPMSG1(RIP_WARNING, "DecompileBitmap: hDC == NULL in L%d", __LINE__);
  254. return NULL;
  255. }
  256. //
  257. // decompile hBitmap
  258. //
  259. pBmp->lpNext = pHeader->lpBmp;
  260. pHeader->lpBmpNext = SaveBitmapToMemory(hDC, hBitmap, pBmp, pHeader);
  261. if (pHeader->lpBmpNext == NULL) {
  262. RIPMSG1(RIP_WARNING, "DecompileBitmap: pHeader->lpBmpNext == NULL in L%d", __LINE__);
  263. // error case. restore bmp link, then returns NULL
  264. pHeader->lpBmpNext = pBmp;
  265. pHeader->lpBmp = pBmp->lpNext;
  266. pBmp = NULL;
  267. goto cleanup;
  268. }
  269. // if succeeded, mark this BITMAP_HEADER with hBitmap
  270. pBmp->hBitmap = hBitmap;
  271. //
  272. // put this BITMAP_HEADER in linked list
  273. //
  274. pHeader->lpBmp = pBmp;
  275. cleanup:
  276. if (hDC)
  277. ReleaseDC(GetDesktopWindow(), hDC);
  278. return pBmp;
  279. }
  280. //////////////////////////////////////////////////////////////////////////////
  281. // ImmPutImeMenuItemsIntoMappedFile()
  282. //
  283. // Interprocess IME Menu handler
  284. //
  285. // called from ImeSystemHandler() in user32.dll
  286. //
  287. // handler of WM_IME_SYSTEM:IMS_MENU_ITEM
  288. //
  289. // History:
  290. // 23-Mar-1997 HiroYama Created
  291. //////////////////////////////////////////////////////////////////////////////
  292. LRESULT ImmPutImeMenuItemsIntoMappedFile(HIMC hImc)
  293. {
  294. HANDLE hMap = NULL;
  295. LPVOID lpMap = NULL;
  296. IMEMENU_HEADER* pHeader;
  297. LPIMEMENUITEMINFO lpBuf = NULL;
  298. IMEMENU_ITEM* pMenu;
  299. IMEMENU_BMP_HEADER* pBmp;
  300. LRESULT lRet = 0;
  301. ULONG_PTR offset;
  302. DWORD i;
  303. // Open memory mapped file
  304. hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, IME_MENU_FILE_NAME);
  305. if (hMap == NULL) {
  306. RIPMSG0(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: cannot open mapped file.");
  307. return 0L;
  308. }
  309. // Map entire view of the file into the process memory space
  310. lpMap = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  311. if (lpMap == NULL) {
  312. RIPMSG0(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: cannot map view of file.");
  313. goto cleanup;
  314. // I wish if I could use C++...
  315. }
  316. pHeader = (IMEMENU_HEADER*)lpMap;
  317. ///////////////////
  318. // Version check
  319. ///////////////////
  320. if (pHeader->dwVersion != 1) {
  321. RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: dwVersion(%d) does not match.",
  322. pHeader->dwVersion);
  323. goto cleanup;
  324. }
  325. //////////////////////////////
  326. // convert offset to pointer
  327. offset = (ULONG_PTR)pHeader;
  328. CONVTO_PTR(pHeader->lpImeParentMenu);
  329. CHK_PTR(pHeader->lpImeParentMenu);
  330. pMenu = CONVTO_PTR(pHeader->lpImeMenu);
  331. CHK_PTR(pHeader->lpImeMenu);
  332. if (pHeader->dwSize) {
  333. UserAssert(pHeader->lpImeMenu); // if dwSize is specified, we need real buffer here
  334. lpBuf = ImmLocalAlloc(HEAP_ZERO_MEMORY, pHeader->dwSize * sizeof(IMEMENUITEMINFOW));
  335. if (lpBuf == NULL) {
  336. RIPMSG0(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: not enough memory for receiver's buffer.");
  337. goto cleanup;
  338. }
  339. }
  340. // preparation
  341. #if DBG
  342. if (pHeader->lpImeParentMenu) {
  343. UserAssert(!pHeader->lpImeParentMenu->lpBmpChecked &&
  344. !pHeader->lpImeParentMenu->lpBmpUnchecked &&
  345. !pHeader->lpImeParentMenu->lpBmpItem);
  346. }
  347. #endif
  348. //////////////////////////////////
  349. // Get IME menus
  350. pHeader->dwSize = ImmGetImeMenuItemsW(hImc, pHeader->dwFlags, pHeader->dwType,
  351. (LPIMEMENUITEMINFOW)pHeader->lpImeParentMenu, lpBuf,
  352. pHeader->dwSize * sizeof(IMEMENUITEMINFOW));
  353. // now, pHeader->dwSize contains number of menu items rather than byte size
  354. if (pHeader->dwSize == 0) {
  355. goto cleanup;
  356. }
  357. //////////////////////////////////
  358. //
  359. // Copy back the information
  360. //
  361. // if lpBuf != NULL, we need to copy back information
  362. //
  363. if (lpBuf) {
  364. LPIMEMENUITEMINFO lpMenuW = lpBuf;
  365. pHeader->lpBmp = NULL;
  366. // lpBmpNext will point first possible memory for bmp de-compile
  367. pHeader->lpBmpNext = (LPVOID)((LPBYTE)pHeader + (pHeader->dwSize + 1) * sizeof(IMEMENUITEMINFOW));
  368. // copy menuinfo
  369. for (i = 0; i < pHeader->dwSize; ++i, ++pMenu, ++lpMenuW) {
  370. RtlCopyMemory(pMenu, lpMenuW, sizeof *lpMenuW);
  371. // decompile hbitmap
  372. if (lpMenuW->hbmpChecked) {
  373. if ((pMenu->lpBmpChecked = DecompileBitmap(pHeader, lpMenuW->hbmpChecked)) == NULL) {
  374. RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: DecompileBitmap Failed in L%d", __LINE__);
  375. goto cleanup;
  376. }
  377. }
  378. if (lpMenuW->hbmpUnchecked) {
  379. if ((pMenu->lpBmpUnchecked = DecompileBitmap(pHeader, lpMenuW->hbmpUnchecked)) == NULL) {
  380. RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: DecompileBitmap Failed in L%d", __LINE__);
  381. goto cleanup;
  382. }
  383. }
  384. if (lpMenuW->hbmpItem) {
  385. if ((pMenu->lpBmpItem = DecompileBitmap(pHeader, lpMenuW->hbmpItem)) == NULL) {
  386. RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: DecompileBitmap Failed in L%d", __LINE__);
  387. goto cleanup;
  388. }
  389. }
  390. }
  391. //////////////////////////////////////////////////////////////////////
  392. //
  393. // convert pointer to offset
  394. //
  395. pMenu = pHeader->lpImeMenu;
  396. CONVTO_OFFSET(pHeader->lpImeMenu);
  397. // no need to convert parent menu, so let it be NULL
  398. D(pHeader->lpImeParentMenu = NULL);
  399. // pointer to BITMAP_HEADER in each menu
  400. for (i = 0; i < pHeader->dwSize; ++i, ++pMenu) {
  401. TRACE(("ImmPutImeMenuItemsIntoMappedFile: convertiong '%S'\n", pMenu->szString));
  402. CONVTO_OFFSET(pMenu->lpBmpChecked);
  403. CONVTO_OFFSET(pMenu->lpBmpUnchecked);
  404. TRACE(("ImmPutImeMenuItemsIntoMappedFile: before conversion (%#lx)\n", pMenu->lpBmpItem));
  405. CONVTO_OFFSET(pMenu->lpBmpItem);
  406. TRACE(("ImmPutImeMenuItemsIntoMappedFile: after conversion (%#lx)\n", pMenu->lpBmpItem));
  407. // check them
  408. CHK_OFFSET(pMenu->lpBmpChecked);
  409. CHK_OFFSET(pMenu->lpBmpChecked);
  410. CHK_OFFSET(pMenu->lpBmpItem);
  411. }
  412. //
  413. // first pointer to BITMAP_HEADER linked list
  414. //
  415. pBmp = pHeader->lpBmp;
  416. CONVTO_OFFSET(pHeader->lpBmp);
  417. CHK_OFFSET(pHeader->lpBmp);
  418. // pHeader->lpBmpNext will not be used, so let it be NULL
  419. D(pHeader->lpBmpNext = NULL);
  420. //
  421. // pointers in BITMAP_HEADER linked list
  422. //
  423. while (pBmp) {
  424. IMEMENU_BMP_HEADER* ptBmp = pBmp->lpNext;
  425. CONVTO_OFFSET(pBmp->pBits);
  426. CONVTO_OFFSET(pBmp->lpNext);
  427. CHK_OFFSET(pBmp->lpNext);
  428. pBmp = ptBmp;
  429. }
  430. //
  431. // pointer conversion finished
  432. //
  433. //////////////////////////////////////////////////////////////////////
  434. } // end if (lpBuf)
  435. //
  436. // everything went OK
  437. //
  438. lRet = 1;
  439. cleanup:
  440. if (lpBuf)
  441. ImmLocalFree(lpBuf);
  442. if (lpMap)
  443. UnmapViewOfFile(lpMap);
  444. if (hMap)
  445. CloseHandle(hMap);
  446. return lRet;
  447. }
  448. //////////////////////////////////////////////////////////////////////////////
  449. // InternalImeMenuCreateBitmap()
  450. //
  451. // create bitmap from IMEMENU_BMP_HEADER
  452. //////////////////////////////////////////////////////////////////////////////
  453. HBITMAP InternalImeMenuCreateBitmap(IMEMENU_BMP_HEADER* lpBH)
  454. {
  455. HDC hDC;
  456. if (lpBH == NULL) {
  457. RIPMSG1(RIP_WARNING, "InternalImeMenuCreateBitmap: lpBH == NULL in L%d", __LINE__);
  458. return NULL;
  459. }
  460. if (lpBH->pBits == NULL) {
  461. RIPMSG1(RIP_WARNING, "InternalImeMenuCreateBitmap: lpBH->pBits == NULL in L%d", __LINE__);
  462. return NULL;
  463. }
  464. if (lpBH->hBitmap) {
  465. TRACE(("InternalImeMenuCreateBitmap: lpBH->hBitmap != NULL. will return it.\n"));
  466. return lpBH->hBitmap;
  467. }
  468. if (hDC = GetDC(GetDesktopWindow())) {
  469. HDC hMyDC = CreateCompatibleDC(hDC);
  470. if (hMyDC) {
  471. // (select palette) needed ?
  472. lpBH->hBitmap = CreateDIBitmap(hDC, &lpBH->bmi.bmiHeader, CBM_INIT,
  473. lpBH->pBits, &lpBH->bmi, DIB_RGB_COLORS);
  474. if (lpBH->hBitmap == NULL) {
  475. DWORD dwErr = GetLastError();
  476. RIPMSG1(RIP_WARNING, "InternalImeMenuCreateBitmap: CreateDIBitmap Failed. Last error=%#x\n", dwErr);
  477. }
  478. DeleteDC(hMyDC);
  479. }
  480. else {
  481. RIPMSG0(RIP_WARNING, "InternalImeMenuCreateBitmap: CreateCompatibleDC failed.");
  482. }
  483. ReleaseDC(GetDesktopWindow(), hDC);
  484. }
  485. else {
  486. RIPMSG0(RIP_WARNING, "InternalImeMenuCreateBitmap: couldn't get Desktop DC.");
  487. }
  488. return lpBH->hBitmap;
  489. }
  490. //////////////////////////////////////////////////////////////////////////////
  491. // ImmGetImeMenuItemsInterProcess()
  492. //
  493. // Inter process IME Menu handler
  494. // sends WM_IME_SYSTEM:IMS_GETIMEMENU
  495. //
  496. // History:
  497. // 23-Mar-1997 HiroYama Created
  498. //////////////////////////////////////////////////////////////////////////////
  499. DWORD ImmGetImeMenuItemsInterProcess(HIMC hImc,
  500. DWORD dwFlags,
  501. DWORD dwType,
  502. LPIMEMENUITEMINFOW lpParentMenu,
  503. LPIMEMENUITEMINFOW lpMenu,
  504. DWORD dwSize)
  505. {
  506. HWND hwnd;
  507. HANDLE hMemFile = NULL;
  508. DWORD dwRet = 0;
  509. LPBYTE lpMap = NULL;
  510. IMEMENU_HEADER* pHeader;
  511. IMEMENU_ITEM* pMenuItem;
  512. IMEMENU_BMP_HEADER* pBmpHeader;
  513. DWORD i;
  514. ULONG_PTR offset;
  515. // Get default IME window
  516. //
  517. // Note: We do not consider user created HIMC here, because this inter-process call is intended to
  518. // support only internat.exe, and this message is passed as just a kick to IMM's def WinProc.
  519. hwnd = (HWND)NtUserQueryInputContext(hImc, InputContextDefaultImeWindow);
  520. if (hwnd == NULL || !IsWindow(hwnd)) {
  521. RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: hwnd(%lx) is not a valid window.", hwnd);
  522. return 0;
  523. }
  524. RtlEnterCriticalSection(&gcsImeDpi);
  525. // first, create memory mapped file
  526. hMemFile = CreateFileMapping((HANDLE)~0, NULL, PAGE_READWRITE,
  527. 0, IME_MENU_MAXMEM, IME_MENU_FILE_NAME);
  528. if (hMemFile == NULL) {
  529. RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: cannot allocate memory mapped file.");
  530. goto cleanup;
  531. }
  532. // then get a view of the mapped file
  533. lpMap = (LPBYTE)MapViewOfFile(hMemFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
  534. if (lpMap == NULL) {
  535. RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: cannot map view of memory mapped file.");
  536. goto cleanup;
  537. }
  538. //
  539. // shared buffer (memory mapped file) initialization
  540. //
  541. pHeader = (IMEMENU_HEADER*)lpMap;
  542. RtlZeroMemory(pHeader, sizeof *pHeader);
  543. pHeader->dwVersion = 1;
  544. pHeader->dwMemSize = IME_MENU_MAXMEM;
  545. pHeader->dwSize = dwSize / sizeof(IMEMENUITEMINFOW); // CAUTION: dwSize could be 0.
  546. RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: pHeader->dwSize=%ld", pHeader->dwSize);
  547. pHeader->dwFlags = dwFlags;
  548. pHeader->dwType = dwType;
  549. //
  550. // 1) dwSize != 0 and lpMenu != NULL means, caller requests the given buffer filled
  551. // 2) if lpParentMenu is passed, we need to put its information in shared buffer
  552. //
  553. if ((dwSize && lpMenu) || lpParentMenu) {
  554. // if parent menu is specified, copy it here
  555. if (lpParentMenu) {
  556. IMEMENU_ITEM* pPMenu =
  557. pHeader->lpImeParentMenu = (IMEMENU_ITEM*)&pHeader[1];
  558. RtlCopyMemory(pPMenu, lpParentMenu, sizeof(IMEMENUITEMINFOW));
  559. // by design, IME will receive NULL hbmpItem in parent menu.
  560. // there is no way to guarantee the same hbmpItem is returned, thus NULL is passed.
  561. pPMenu->lpBmpChecked = pPMenu->lpBmpUnchecked = pPMenu->lpBmpItem = NULL;
  562. pHeader->lpImeMenu = pHeader->lpImeParentMenu + 1;
  563. }
  564. else {
  565. pHeader->lpImeParentMenu = NULL;
  566. pHeader->lpImeMenu = (LPVOID)&pHeader[1];
  567. }
  568. // convert pointer to offset
  569. offset = (ULONG_PTR)lpMap;
  570. CONVTO_OFFSET(pHeader->lpImeParentMenu);
  571. CONVTO_OFFSET(pHeader->lpImeMenu);
  572. }
  573. ///////////////////////////////////////////////////////////////////////
  574. if (!SendMessage(hwnd, WM_IME_SYSTEM, IMS_GETIMEMENU, (LPARAM)hImc)) {
  575. // if it fails
  576. goto cleanup;
  577. }
  578. ///////////////////////////////////////////////////////////////////////
  579. // NOTE: dwSize is maximum index of menu array. not a total byte size of array.
  580. dwSize = pHeader->dwSize;
  581. if (lpMenu) {
  582. ///////////////////////////////
  583. // convert offset to pointer
  584. ///////////////////////////////
  585. pMenuItem = CONVTO_PTR(pHeader->lpImeMenu);
  586. CHK_PTR(pMenuItem);
  587. // NOTE: we don't have to handle parent menu
  588. //
  589. // pointers to BITMAP_HEADER in each menu structure
  590. //
  591. for (i = 0; i < dwSize; ++i, ++pMenuItem) {
  592. CONVTO_PTR(pMenuItem->lpBmpChecked);
  593. CONVTO_PTR(pMenuItem->lpBmpUnchecked);
  594. CONVTO_PTR(pMenuItem->lpBmpItem);
  595. //
  596. // check the pointers
  597. //
  598. CHK_PTR(pMenuItem->lpBmpChecked);
  599. CHK_PTR(pMenuItem->lpBmpUnchecked);
  600. CHK_PTR(pMenuItem->lpBmpItem);
  601. }
  602. //
  603. // pointer to first BITMAP_HEADER
  604. //
  605. pBmpHeader = CONVTO_PTR(pHeader->lpBmp);
  606. //
  607. // each BITMAP_HEADER
  608. //
  609. while (pBmpHeader) {
  610. pBmpHeader->hBitmap = NULL; // clear
  611. // pBits
  612. CONVTO_PTR(pBmpHeader->pBits);
  613. CHK_PTR(pBmpHeader->pBits);
  614. // next BITMAP_HEADER
  615. pBmpHeader = CONVTO_PTR(pBmpHeader->lpNext);
  616. CHK_PTR(pBmpHeader);
  617. }
  618. //
  619. // copy back the results
  620. //
  621. pMenuItem = pHeader->lpImeMenu;
  622. for (i = 0; i < dwSize; ++i, ++pMenuItem, ++lpMenu) {
  623. lpMenu->cbSize = pMenuItem->cbSize;
  624. lpMenu->fType = pMenuItem->fType;
  625. lpMenu->fState = pMenuItem->fState;
  626. lpMenu->wID = pMenuItem->wID;
  627. lpMenu->dwItemData = pMenuItem->dwItemData;
  628. wcsncpy(lpMenu->szString, pMenuItem->szString, ARRAY_SIZE(lpMenu->szString));
  629. // Create bitmap from memory buffer
  630. // hbmp will be NULL if no bmp is specified.
  631. if (pMenuItem->lpBmpChecked) {
  632. lpMenu->hbmpChecked = InternalImeMenuCreateBitmap(pMenuItem->lpBmpChecked);
  633. }
  634. else {
  635. lpMenu->hbmpChecked = NULL;
  636. }
  637. if (pMenuItem->lpBmpUnchecked) {
  638. lpMenu->hbmpUnchecked = InternalImeMenuCreateBitmap(pMenuItem->lpBmpUnchecked);
  639. }
  640. else {
  641. lpMenu->hbmpUnchecked = NULL;
  642. }
  643. if (pMenuItem->lpBmpItem) {
  644. lpMenu->hbmpItem = InternalImeMenuCreateBitmap(pMenuItem->lpBmpItem);
  645. }
  646. else {
  647. lpMenu->hbmpItem = NULL;
  648. }
  649. }
  650. }
  651. cleanup:
  652. if (lpMap) {
  653. UnmapViewOfFile(lpMap);
  654. }
  655. RtlLeaveCriticalSection(&gcsImeDpi);
  656. // destroy memory mapped file
  657. if (hMemFile) {
  658. CloseHandle(hMemFile);
  659. }
  660. return dwSize;
  661. }
  662. //////////////////////////////////////////////////////////////////////////////
  663. // ImmGetImeMenuItemsWorker()
  664. //
  665. // Handler of IME Menu
  666. //
  667. // if specified HIMC belongs to other process, it calls
  668. // ImmGetImeMenuItemsInterProcess()
  669. //
  670. // History:
  671. // 23-Mar-1997 HiroYama Created
  672. //////////////////////////////////////////////////////////////////////////////
  673. DWORD ImmGetImeMenuItemsWorker(HIMC hIMC,
  674. DWORD dwFlags,
  675. DWORD dwType,
  676. LPVOID lpImeParentMenu,
  677. LPVOID lpImeMenu,
  678. DWORD dwSize,
  679. BOOL bAnsiOrigin)
  680. {
  681. BOOL bAnsiIme = IsAnsiIMC(hIMC);
  682. DWORD dwRet = 0;
  683. LPINPUTCONTEXT lpInputContext;
  684. DWORD dwThreadId;
  685. PIMEDPI pImeDpi = NULL;
  686. LPVOID lpImePTemp = lpImeParentMenu; // keeps parent menu
  687. LPVOID lpImeTemp = lpImeMenu; // points menu buffer
  688. IMEMENUITEMINFOA imiiParentA;
  689. IMEMENUITEMINFOW imiiParentW;
  690. //
  691. // check if the call will be inter process
  692. //
  693. {
  694. DWORD dwProcessId = GetInputContextProcess(hIMC);
  695. if (dwProcessId == 0) {
  696. RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: dwProcessId == 0");
  697. return 0;
  698. }
  699. if (dwProcessId != GetCurrentProcessId()) {
  700. //
  701. // going to call another process' IME
  702. //
  703. TRACE(("ImmGetImeMenuItemsWorker: Inter process.\n"));
  704. if (bAnsiOrigin) {
  705. //
  706. // this inter-process thing is only allowed to internat.exe or equivalent
  707. //
  708. RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: interprocess getmenu is not allowed for ANSI caller.");
  709. return 0;
  710. }
  711. return ImmGetImeMenuItemsInterProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
  712. lpImeMenu, dwSize);
  713. }
  714. }
  715. //
  716. // within process
  717. //
  718. if (hIMC == NULL || (lpInputContext = ImmLockIMC(hIMC)) == NULL) {
  719. RIPMSG2(RIP_WARNING, "ImmGetImeMenuItemsWorker: illegal hIMC(%#lx) in L%d", hIMC, __LINE__);
  720. return 0;
  721. }
  722. dwThreadId = GetInputContextThread(hIMC);
  723. if (dwThreadId == 0) {
  724. RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsWorker: dwThreadId = 0 in L%d", __LINE__);
  725. goto cleanup;
  726. }
  727. if ((pImeDpi = ImmLockImeDpi(GetKeyboardLayout(dwThreadId))) == NULL) {
  728. RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemWorker: pImeDpi == NULL in L%d.", __LINE__);
  729. goto cleanup;
  730. }
  731. #if 0 // NT: we don't keep version info in ImeDpi
  732. if (pImeDpi->dwWinVersion <= IMEVER_0310) {
  733. RIPMSG1(RIP_WARNING, "GetImeMenuItems: OldIME does not support this. %lx", hIMC);
  734. goto cleanup;
  735. }
  736. #endif
  737. //
  738. // if IME does not support IME Menu, do nothing
  739. //
  740. if (pImeDpi->pfn.ImeGetImeMenuItems) {
  741. LPVOID lpNewBuf = NULL;
  742. TRACE(("ImmGetImeMenuItemsWorker: IME has menu callback.\n"));
  743. if (bAnsiIme != bAnsiOrigin) {
  744. //
  745. // we need A/W translation before calling IME
  746. //
  747. if (bAnsiOrigin) {
  748. // ANSI API and UNICODE IME.
  749. // A to W conversion needed here
  750. if (lpImeParentMenu) {
  751. // parent menu is specified. need conversion
  752. lpImePTemp = (LPVOID)&imiiParentW;
  753. if (! ConvertImeMenuItemInfoAtoW((LPIMEMENUITEMINFOA)lpImeParentMenu,
  754. (LPIMEMENUITEMINFOW)lpImePTemp,
  755. CP_ACP, TRUE)) { // ANSI app, UNICODE IME: let's use CP_ACP
  756. goto cleanup;
  757. }
  758. }
  759. if (lpImeMenu) {
  760. // allocate memory block for temporary storage
  761. DWORD dwNumBuffer = dwSize / sizeof(IMEMENUITEMINFOA);
  762. dwSize = dwNumBuffer * sizeof(IMEMENUITEMINFOW);
  763. if (dwSize == 0) {
  764. RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: (AtoW) dwSize is 0.");
  765. goto cleanup;
  766. }
  767. lpImeTemp = lpNewBuf = ImmLocalAlloc(0, dwSize);
  768. TRACE(("ImmGetImeMenuItemsWorker: for UNICODE IME memory allocated %d bytes. lpNewBuf=%#x\n", dwSize, lpNewBuf));
  769. if (lpNewBuf == NULL) {
  770. RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsWorker: cannot alloc lpNewBuf in L%d", __LINE__);
  771. goto cleanup;
  772. }
  773. }
  774. }
  775. else {
  776. // UNICODE API and ANSI IME.
  777. // W to A conversion needed here
  778. if (lpImeParentMenu) {
  779. // parent menu is speicified. need conversion
  780. lpImePTemp = (LPVOID)&imiiParentA;
  781. if (! ConvertImeMenuItemInfoWtoA((LPIMEMENUITEMINFOW)lpImeParentMenu,
  782. (LPIMEMENUITEMINFOA)lpImePTemp,
  783. pImeDpi->dwCodePage)) { // Note: hopefully in the future, this can be changed to IMECodePage(pImeDpi)
  784. goto cleanup;
  785. }
  786. }
  787. if (lpImeMenu) {
  788. // allocate memory block for temporary storage
  789. DWORD dwNumBuffer = dwSize / sizeof(IMEMENUITEMINFOW);
  790. dwSize = dwNumBuffer / sizeof(IMEMENUITEMINFOA);
  791. if (dwSize == 0) {
  792. RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: (WtoA) dwSize is 0.");
  793. goto cleanup;
  794. }
  795. lpImeTemp = lpNewBuf = ImmLocalAlloc(0, dwSize);
  796. RIPMSG2(RIP_WARNING, "ImmGetImeMenuItemsWorker: for ANSI IME memory allocated %d bytes. lpNewBuf=%#x", dwSize, lpNewBuf);
  797. if (lpNewBuf == NULL) {
  798. RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsWorker: cannot alloc lpNewBuf in L%d", __LINE__);
  799. goto cleanup;
  800. }
  801. }
  802. }
  803. }
  804. ////////////////////////////////////////
  805. dwRet = pImeDpi->pfn.ImeGetImeMenuItems(hIMC, dwFlags, dwType, lpImePTemp, lpImeTemp, dwSize);
  806. ////////////////////////////////////////
  807. //
  808. // back-conversion needed if:
  809. // 1) IME returns menus, and
  810. // 2) A/W is different between caller and IME, and
  811. // 3) caller wants the buffer to be filled
  812. //
  813. if (dwRet && bAnsiIme != bAnsiOrigin && lpImeTemp) {
  814. if (bAnsiOrigin) {
  815. // ANSI API and UNICODE IME.
  816. // W to A conversion needed here
  817. LPIMEMENUITEMINFOW lpW = (LPIMEMENUITEMINFOW)lpImeTemp;
  818. LPIMEMENUITEMINFOA lpA = (LPIMEMENUITEMINFOA)lpImeMenu;
  819. DWORD i;
  820. for (i = 0; i < dwRet; ++i) {
  821. if (! ConvertImeMenuItemInfoWtoA((LPIMEMENUITEMINFOW)lpW++,
  822. (LPIMEMENUITEMINFOA)lpA++,
  823. CP_ACP)) { // ANSI app and UNICODE IME: let's use CP_ACP
  824. dwRet = 0;
  825. break;
  826. }
  827. }
  828. }
  829. else {
  830. // UNICODE API and ANSI IME.
  831. // A to W conversion needed here
  832. LPIMEMENUITEMINFOA lpA = (LPIMEMENUITEMINFOA)lpImeTemp;
  833. LPIMEMENUITEMINFOW lpW = (LPIMEMENUITEMINFOW)lpImeMenu;
  834. DWORD i;
  835. for (i = 0; i < dwSize; i++) {
  836. if (! ConvertImeMenuItemInfoAtoW((LPIMEMENUITEMINFOA)lpA++,
  837. (LPIMEMENUITEMINFOW)lpW++,
  838. pImeDpi->dwCodePage, // Note: hopefully in the future, this can be changed to IMECodePage(pImeDpi)
  839. TRUE)) { // copy hbitmap also
  840. dwRet = 0;
  841. break;
  842. }
  843. }
  844. }
  845. }
  846. // free temporary buffer if we've allocated it
  847. if (lpNewBuf)
  848. ImmLocalFree(lpNewBuf);
  849. } // end if IME has menu callback
  850. cleanup:
  851. if (pImeDpi) {
  852. ImmUnlockImeDpi(pImeDpi);
  853. }
  854. if (hIMC != NULL) {
  855. ImmUnlockIMC(hIMC);
  856. }
  857. return dwRet;
  858. }
  859. DWORD WINAPI ImmGetImeMenuItemsA(
  860. HIMC hIMC,
  861. DWORD dwFlags,
  862. DWORD dwType,
  863. LPIMEMENUITEMINFOA lpImeParentMenu,
  864. LPIMEMENUITEMINFOA lpImeMenu,
  865. DWORD dwSize)
  866. {
  867. return ImmGetImeMenuItemsWorker(hIMC, dwFlags, dwType,
  868. (LPVOID)lpImeParentMenu,
  869. (LPVOID)lpImeMenu, dwSize, TRUE /* ANSI origin */);
  870. }
  871. DWORD WINAPI ImmGetImeMenuItemsW(
  872. HIMC hIMC,
  873. DWORD dwFlags,
  874. DWORD dwType,
  875. LPIMEMENUITEMINFOW lpImeParentMenu,
  876. LPIMEMENUITEMINFOW lpImeMenu,
  877. DWORD dwSize)
  878. {
  879. return ImmGetImeMenuItemsWorker(hIMC, dwFlags, dwType,
  880. (LPVOID)lpImeParentMenu,
  881. (LPVOID)lpImeMenu, dwSize, FALSE /* UNICODE origin */);
  882. }