https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ffbdb7d39e64fb957e7ae…
commit ffbdb7d39e64fb957e7ae2b26645b3e16531bc9b
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Jul 23 05:58:17 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Jul 23 05:58:17 2022 +0900
[IMM32][USER32] ImmPutImeMenuItemsIntoMappedFile (#4588)
Implement inter-process menu item retrieving.
CORE-11700
---
dll/win32/imm32/ime.c | 184 ++++++++++++++++++++++++++++++++++++++++-
dll/win32/imm32/imm32.spec | 2 +-
dll/win32/imm32/precomp.h | 3 +
dll/win32/imm32/utils.c | 121 +++++++++++++++++++++++++++
sdk/include/ddk/immdev.h | 1 +
win32ss/user/user32/misc/imm.c | 2 +-
6 files changed, 307 insertions(+), 6 deletions(-)
diff --git a/dll/win32/imm32/ime.c b/dll/win32/imm32/ime.c
index 2703a1e3cad..21cd6810c61 100644
--- a/dll/win32/imm32/ime.c
+++ b/dll/win32/imm32/ime.c
@@ -355,13 +355,189 @@ Quit:
return ret;
}
+// We will transport the IME menu items by using a flat memory block via
+// a file mapping object beyond the boundary of a process.
+
+#define MAX_IMEMENU_BITMAP_BYTES 0xF00
+
+typedef struct tagIMEMENUITEM
+{
+ IMEMENUITEMINFOW Info;
+ BYTE abChecked[MAX_IMEMENU_BITMAP_BYTES];
+ BYTE abUnchecked[MAX_IMEMENU_BITMAP_BYTES];
+ BYTE abItem[MAX_IMEMENU_BITMAP_BYTES];
+} IMEMENUITEM, *PIMEMENUITEM;
+
+typedef struct tagIMEMENU
+{
+ DWORD dwVersion;
+ DWORD dwFlags;
+ DWORD dwType;
+ DWORD dwItemCount;
+ IMEMENUITEMINFOW Parent;
+ IMEMENUITEM Items[ANYSIZE_ARRAY];
+} IMEMENU, *PIMEMENU;
+
+/***********************************************************************
+ * ImmPutImeMenuItemsIntoMappedFile (IMM32.@)
+ *
+ * Called from user32.dll to transport the IME menu items by using a
+ * file mapping object. This function is provided for WM_IME_SYSTEM:IMS_GETIMEMENU
+ * handling.
+ */
+LRESULT WINAPI ImmPutImeMenuItemsIntoMappedFile(HIMC hIMC)
+{
+ LRESULT ret = FALSE;
+ HANDLE hMapping;
+ PIMEMENU pView;
+ LPIMEMENUITEMINFOW pParent = NULL, pItems = NULL;
+ DWORD i, cItems, cbItems = 0;
+
+ hMapping = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"ImmMenuInfo");
+ pView = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+ if (!pView || pView->dwVersion != 1)
+ {
+ ERR("hMapping %p, pView %p\n", hMapping, pView);
+ goto Quit;
+ }
+
+ if (pView->Parent.cbSize > 0)
+ pParent = &pView->Parent;
+
+ if (pView->dwItemCount > 0)
+ {
+ cbItems = pView->dwItemCount * sizeof(IMEMENUITEMINFOW);
+ pItems = ImmLocalAlloc(HEAP_ZERO_MEMORY, cbItems);
+ if (!pItems)
+ {
+ ERR("!pItems\n");
+ goto Quit;
+ }
+ }
+
+ cItems = ImmGetImeMenuItemsW(hIMC, pView->dwFlags, pView->dwType, pParent,
pItems, cbItems);
+ pView->dwItemCount = cItems;
+ if (cItems == 0)
+ goto Quit;
+
+ if (pItems)
+ {
+ for (i = 0; i < cItems; ++i)
+ {
+ pView->Items[i].Info = pItems[i];
+
+ // store bitmaps to bytes
+ if (pItems[i].hbmpChecked)
+ {
+ Imm32StoreBitmapToBytes(pItems[i].hbmpChecked,
pView->Items[i].abChecked,
+ MAX_IMEMENU_BITMAP_BYTES);
+ DeleteObject(pItems[i].hbmpChecked);
+ }
+ if (pItems[i].hbmpUnchecked)
+ {
+ Imm32StoreBitmapToBytes(pItems[i].hbmpUnchecked,
pView->Items[i].abUnchecked,
+ MAX_IMEMENU_BITMAP_BYTES);
+ DeleteObject(pItems[i].hbmpUnchecked);
+ }
+ if (pItems[i].hbmpItem)
+ {
+ Imm32StoreBitmapToBytes(pItems[i].hbmpItem, pView->Items[i].abItem,
+ MAX_IMEMENU_BITMAP_BYTES);
+ DeleteObject(pItems[i].hbmpItem);
+ }
+ }
+ }
+
+ ret = TRUE;
+
+Quit:
+ if (pItems)
+ ImmLocalFree(pItems);
+ if (pView)
+ UnmapViewOfFile(pView);
+ if (hMapping)
+ CloseHandle(hMapping);
+ return ret;
+}
+
// Win: ImmGetImeMenuItemsInterProcess
DWORD APIENTRY
-Imm32GetImeMenuItemWCrossProcess(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID
lpImeParentMenu,
+Imm32GetImeMenuItemWInterProcess(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID
lpImeParentMenu,
LPVOID lpImeMenu, DWORD dwSize)
{
- FIXME("We have to do something\n");
- return 0;
+ HANDLE hMapping;
+ PIMEMENU pView;
+ DWORD i, cbView, dwItemCount, ret = 0;
+ HWND hImeWnd;
+ PIMEMENUITEM pGotItem;
+ LPIMEMENUITEMINFOW pSetInfo;
+
+ hImeWnd = (HWND)NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME);
+ if (!hImeWnd || !IsWindow(hImeWnd))
+ {
+ ERR("hImeWnd %p\n", hImeWnd);
+ return 0;
+ }
+
+ dwItemCount = (lpImeMenu ? (dwSize / sizeof(IMEMENUITEMINFOW)) : 0);
+ cbView = sizeof(IMEMENU) + ((size_t)dwItemCount - 1) * sizeof(IMEMENUITEM);
+
+ RtlEnterCriticalSection(&gcsImeDpi);
+
+ // create a file mapping
+ hMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
+ 0, cbView, L"ImmMenuInfo");
+ pView = MapViewOfFile(hMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
+ if (!pView)
+ {
+ ERR("hMapping %p, pView %p\n", hMapping, pView);
+ goto Quit;
+ }
+
+ ZeroMemory(pView, cbView);
+ pView->dwVersion = 1;
+ pView->dwFlags = dwFlags;
+ pView->dwType = dwType;
+ pView->dwItemCount = dwItemCount;
+ pView->Parent.cbSize = (lpImeParentMenu ? sizeof(IMEMENUITEMINFOW) : 0);
+
+ if (!SendMessageW(hImeWnd, WM_IME_SYSTEM, IMS_GETIMEMENU, (LPARAM)hIMC))
+ goto Quit;
+
+ ret = pView->dwItemCount;
+
+ if (!lpImeMenu)
+ goto Quit;
+
+ for (i = 0; i < ret; ++i)
+ {
+ pGotItem = &(pView->Items[i]);
+ pSetInfo = &((LPIMEMENUITEMINFOW)lpImeMenu)[i];
+
+ *pSetInfo = pGotItem->Info;
+
+ // load bitmaps from bytes
+ if (pSetInfo->hbmpChecked)
+ {
+ pSetInfo->hbmpChecked = Imm32LoadBitmapFromBytes(pGotItem->abChecked);
+ }
+ if (pSetInfo->hbmpUnchecked)
+ {
+ pSetInfo->hbmpUnchecked =
Imm32LoadBitmapFromBytes(pGotItem->abUnchecked);
+ }
+ if (pSetInfo->hbmpItem)
+ {
+ pSetInfo->hbmpItem = Imm32LoadBitmapFromBytes(pGotItem->abItem);
+ }
+ }
+
+Quit:
+ RtlLeaveCriticalSection(&gcsImeDpi);
+ if (pView)
+ UnmapViewOfFile(pView);
+ if (hMapping)
+ CloseHandle(hMapping);
+ return ret;
}
// Win: ImmGetImeMenuItemsWorker
@@ -391,7 +567,7 @@ ImmGetImeMenuItemsAW(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID
lpImeParentM
{
if (bTargetIsAnsi)
return 0;
- return Imm32GetImeMenuItemWCrossProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
+ return Imm32GetImeMenuItemWInterProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
lpImeMenu, dwSize);
}
diff --git a/dll/win32/imm32/imm32.spec b/dll/win32/imm32/imm32.spec
index 07e85847740..0764e8dd0e5 100644
--- a/dll/win32/imm32/imm32.spec
+++ b/dll/win32/imm32/imm32.spec
@@ -81,7 +81,7 @@
@ stdcall ImmNotifyIME(ptr long long long)
@ stub ImmPenAuxInput
@ stdcall ImmProcessKey(ptr long long long long)
-@ stdcall -stub ImmPutImeMenuItemsIntoMappedFile(ptr)
+@ stdcall ImmPutImeMenuItemsIntoMappedFile(ptr)
@ stdcall ImmReSizeIMCC(ptr long)
@ stdcall ImmRegisterClient(ptr ptr)
@ stdcall ImmRegisterWordA(long str long str)
diff --git a/dll/win32/imm32/precomp.h b/dll/win32/imm32/precomp.h
index a7057be1a73..c87e6fa6e54 100644
--- a/dll/win32/imm32/precomp.h
+++ b/dll/win32/imm32/precomp.h
@@ -165,3 +165,6 @@ static inline PTHREADINFO FASTCALL Imm32CurrentPti(VOID)
NtUserGetThreadState(THREADSTATE_GETTHREADINFO);
return NtCurrentTeb()->Win32ThreadInfo;
}
+
+HBITMAP Imm32LoadBitmapFromBytes(const BYTE *pb);
+BOOL Imm32StoreBitmapToBytes(HBITMAP hbm, LPBYTE pbData, DWORD cbDataMax);
diff --git a/dll/win32/imm32/utils.c b/dll/win32/imm32/utils.c
index d135932b25a..ca9385aed14 100644
--- a/dll/win32/imm32/utils.c
+++ b/dll/win32/imm32/utils.c
@@ -50,6 +50,127 @@ BOOL APIENTRY Imm32IsSystemJapaneseOrKorean(VOID)
return (wPrimary == LANG_JAPANESE || wPrimary == LANG_KOREAN);
}
+typedef struct tagBITMAPCOREINFO256
+{
+ BITMAPCOREHEADER bmciHeader;
+ RGBTRIPLE bmciColors[256];
+} BITMAPCOREINFO256, *PBITMAPCOREINFO256;
+
+HBITMAP Imm32LoadBitmapFromBytes(const BYTE *pb)
+{
+ HBITMAP hbm = NULL;
+ const BITMAPCOREINFO256 *pbmci;
+ LPVOID pvBits;
+ DWORD ib, cbBytes, cColors;
+ BITMAP bm;
+
+ cbBytes = *(const DWORD *)pb;
+ if (cbBytes == 0)
+ return NULL;
+
+ pb += sizeof(DWORD);
+ ib = sizeof(DWORD);
+
+ pbmci = (const BITMAPCOREINFO256 *)pb;
+ hbm = CreateDIBSection(NULL, (LPBITMAPINFO)pbmci, DIB_RGB_COLORS, &pvBits, NULL,
0);
+ if (!hbm || !GetObject(hbm, sizeof(BITMAP), &bm))
+ return NULL;
+
+ switch (pbmci->bmciHeader.bcBitCount)
+ {
+ case 1: cColors = 2; break;
+ case 4: cColors = 16; break;
+ case 8: cColors = 256; break;
+ case 24: case 32:
+ cColors = 0;
+ break;
+ default:
+ DeleteObject(hbm);
+ return NULL;
+ }
+
+ ib += sizeof(BITMAPCOREHEADER);
+ pb += sizeof(BITMAPCOREHEADER);
+
+ ib += cColors * sizeof(RGBTRIPLE);
+ pb += cColors * sizeof(RGBTRIPLE);
+
+ ib += bm.bmWidthBytes * bm.bmHeight;
+ if (ib > cbBytes)
+ {
+ DeleteObject(hbm);
+ return NULL;
+ }
+ CopyMemory(pvBits, pb, bm.bmWidthBytes * bm.bmHeight);
+
+ return hbm;
+}
+
+BOOL Imm32StoreBitmapToBytes(HBITMAP hbm, LPBYTE pbData, DWORD cbDataMax)
+{
+ HDC hDC;
+ BITMAP bm;
+ DWORD cbBytes, cColors;
+ BITMAPCOREINFO256 bmci;
+ BOOL ret;
+ LPBYTE pb = pbData;
+
+ *(LPDWORD)pb = 0;
+
+ if (!GetObject(hbm, sizeof(BITMAP), &bm))
+ return FALSE;
+
+ ZeroMemory(&bmci, sizeof(bmci));
+ bmci.bmciHeader.bcSize = sizeof(BITMAPCOREHEADER);
+ bmci.bmciHeader.bcWidth = bm.bmWidth;
+ bmci.bmciHeader.bcHeight = bm.bmHeight;
+ bmci.bmciHeader.bcPlanes = 1;
+ bmci.bmciHeader.bcBitCount = bm.bmBitsPixel;
+
+ switch (bm.bmBitsPixel)
+ {
+ case 1: cColors = 2; break;
+ case 4: cColors = 16; break;
+ case 8: cColors = 256; break;
+ case 24: case 32:
+ cColors = 0;
+ break;
+ default:
+ return FALSE;
+ }
+
+ cbBytes = sizeof(DWORD);
+ cbBytes += sizeof(BITMAPCOREHEADER);
+ cbBytes += cColors * sizeof(RGBTRIPLE);
+ cbBytes += bm.bmWidthBytes * bm.bmHeight;
+ if (cbBytes > cbDataMax)
+ return FALSE;
+
+ hDC = CreateCompatibleDC(NULL);
+
+ ret = GetDIBits(hDC, hbm, 0, bm.bmHeight, NULL, (LPBITMAPINFO)&bmci,
DIB_RGB_COLORS);
+
+ if (ret)
+ {
+ *(LPDWORD)pb = cbBytes;
+ pb += sizeof(DWORD);
+
+ CopyMemory(pb, &bmci.bmciHeader, sizeof(BITMAPCOREHEADER));
+ pb += sizeof(BITMAPCOREHEADER);
+
+ CopyMemory(pb, &bmci.bmciColors, cColors * sizeof(RGBTRIPLE));
+ pb += cColors * sizeof(RGBTRIPLE);
+
+ ret = GetDIBits(hDC, hbm, 0, bm.bmHeight, pb, (LPBITMAPINFO)&bmci,
DIB_RGB_COLORS);
+ if (!ret)
+ *(LPDWORD)pbData = 0;
+ }
+
+ DeleteDC(hDC);
+
+ return ret;
+}
+
// Win: IsAnsiIMC
BOOL WINAPI Imm32IsImcAnsi(HIMC hIMC)
{
diff --git a/sdk/include/ddk/immdev.h b/sdk/include/ddk/immdev.h
index 58bbc1dc1d6..33146de3c95 100644
--- a/sdk/include/ddk/immdev.h
+++ b/sdk/include/ddk/immdev.h
@@ -28,6 +28,7 @@ extern "C" {
#define IMS_IMEACTIVATE 0x17
#define IMS_IMEDEACTIVATE 0x18
#define IMS_ACTIVATELAYOUT 0x19
+#define IMS_GETIMEMENU 0x1C
#define IMMGWL_IMC 0
#define IMMGWL_PRIVATE (sizeof(LONG))
diff --git a/win32ss/user/user32/misc/imm.c b/win32ss/user/user32/misc/imm.c
index 83b6b492777..4cfe094b066 100644
--- a/win32ss/user/user32/misc/imm.c
+++ b/win32ss/user/user32/misc/imm.c
@@ -678,7 +678,7 @@ static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM
lParam)
ret = IMM_FN(ImmActivateLayout)((HKL)lParam);
break;
- case 0x1C:
+ case IMS_GETIMEMENU:
ret = IMM_FN(ImmPutImeMenuItemsIntoMappedFile)((HIMC)lParam);
break;