https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ffbdb7d39e64fb957e7ae2b26645b3e16531bc9b

commit ffbdb7d39e64fb957e7ae2b26645b3e16531bc9b
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Sat Jul 23 05:58:17 2022 +0900
Commit:     GitHub <[email protected]>
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;
 

Reply via email to