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;