[IMM32][USER32] ImmPutImeMenuItemsIntoMappedFile (#4588)

Implement inter-process menu item retrieving.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2022-07-23 05:58:17 +09:00 committed by GitHub
parent fe777bb52f
commit ffbdb7d39e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 307 additions and 6 deletions

View file

@ -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);
}

View file

@ -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)

View file

@ -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);

View file

@ -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)
{

View file

@ -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))

View file

@ -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;