mirror of
https://github.com/reactos/reactos.git
synced 2025-07-29 09:22:04 +00:00
[IMM32][SDK] Support IME menus Part 1 (#7969)
Supporting IME menus will improve Asian users' usability. IME menu is used on the IME System Pen icon. JIRA issue: CORE-20142 - Add dll/win32/imm32/imemenu.c. - Move some code to imemenu.c. - Implement IME menu transporting correctly by using file mapping and serialization.
This commit is contained in:
parent
189623614d
commit
4f84ffa118
7 changed files with 686 additions and 413 deletions
|
@ -13,6 +13,7 @@ list(APPEND SOURCE
|
||||||
ctf.c
|
ctf.c
|
||||||
guideline.c
|
guideline.c
|
||||||
ime.c
|
ime.c
|
||||||
|
imemenu.c
|
||||||
imm.c
|
imm.c
|
||||||
keymsg.c
|
keymsg.c
|
||||||
regword.c
|
regword.c
|
||||||
|
|
|
@ -415,333 +415,6 @@ Quit:
|
||||||
return ret;
|
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 (IS_NULL_UNEXPECTEDLY(pView))
|
|
||||||
goto Quit;
|
|
||||||
|
|
||||||
if (pView->dwVersion != 1)
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
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 (IS_NULL_UNEXPECTEDLY(pItems))
|
|
||||||
goto Quit;
|
|
||||||
}
|
|
||||||
|
|
||||||
cItems = ImmGetImeMenuItemsW(hIMC, pView->dwFlags, pView->dwType, pParent, pItems, cbItems);
|
|
||||||
pView->dwItemCount = cItems;
|
|
||||||
if (IS_ZERO_UNEXPECTEDLY(cItems))
|
|
||||||
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
|
|
||||||
Imm32GetImeMenuItemWInterProcess(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu,
|
|
||||||
LPVOID lpImeMenu, DWORD dwSize)
|
|
||||||
{
|
|
||||||
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("\n");
|
|
||||||
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 (IS_NULL_UNEXPECTEDLY(pView))
|
|
||||||
goto Quit;
|
|
||||||
|
|
||||||
ZeroMemory(pView, cbView);
|
|
||||||
pView->dwVersion = 1;
|
|
||||||
pView->dwFlags = dwFlags;
|
|
||||||
pView->dwType = dwType;
|
|
||||||
pView->dwItemCount = dwItemCount;
|
|
||||||
if (lpImeParentMenu)
|
|
||||||
{
|
|
||||||
pView->Parent = *(LPIMEMENUITEMINFOW)lpImeParentMenu;
|
|
||||||
pView->Parent.cbSize = sizeof(IMEMENUITEMINFOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SendMessageW(hImeWnd, WM_IME_SYSTEM, IMS_GETIMEMENU, (LPARAM)hIMC))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
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
|
|
||||||
DWORD APIENTRY
|
|
||||||
ImmGetImeMenuItemsAW(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu,
|
|
||||||
LPVOID lpImeMenu, DWORD dwSize, BOOL bTargetIsAnsi)
|
|
||||||
{
|
|
||||||
DWORD ret = 0, cbTotal, dwProcessId, dwThreadId, iItem;
|
|
||||||
LPINPUTCONTEXT pIC;
|
|
||||||
PIMEDPI pImeDpi = NULL;
|
|
||||||
IMEMENUITEMINFOA ParentA;
|
|
||||||
IMEMENUITEMINFOW ParentW;
|
|
||||||
LPIMEMENUITEMINFOA pItemA;
|
|
||||||
LPIMEMENUITEMINFOW pItemW;
|
|
||||||
LPVOID pNewItems = NULL, pNewParent = NULL;
|
|
||||||
BOOL bImcIsAnsi;
|
|
||||||
HKL hKL;
|
|
||||||
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(hIMC))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dwProcessId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTPROCESSID);
|
|
||||||
if (IS_ZERO_UNEXPECTEDLY(dwProcessId))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (dwProcessId != GetCurrentProcessId())
|
|
||||||
{
|
|
||||||
if (bTargetIsAnsi)
|
|
||||||
return 0;
|
|
||||||
return Imm32GetImeMenuItemWInterProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
|
|
||||||
lpImeMenu, dwSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
pIC = ImmLockIMC(hIMC);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pIC))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
|
|
||||||
if (IS_ZERO_UNEXPECTEDLY(dwThreadId))
|
|
||||||
{
|
|
||||||
ImmUnlockIMC(hIMC);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hKL = GetKeyboardLayout(dwThreadId);
|
|
||||||
pImeDpi = ImmLockImeDpi(hKL);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pImeDpi))
|
|
||||||
{
|
|
||||||
ImmUnlockIMC(hIMC);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bImcIsAnsi = Imm32IsImcAnsi(hIMC);
|
|
||||||
|
|
||||||
if (bImcIsAnsi != bTargetIsAnsi)
|
|
||||||
{
|
|
||||||
if (bTargetIsAnsi)
|
|
||||||
{
|
|
||||||
if (lpImeParentMenu)
|
|
||||||
pNewParent = &ParentW;
|
|
||||||
|
|
||||||
if (lpImeMenu)
|
|
||||||
{
|
|
||||||
cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOA)) * sizeof(IMEMENUITEMINFOW));
|
|
||||||
pNewItems = ImmLocalAlloc(0, cbTotal);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pNewItems))
|
|
||||||
goto Quit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lpImeParentMenu)
|
|
||||||
pNewParent = &ParentA;
|
|
||||||
|
|
||||||
if (lpImeMenu)
|
|
||||||
{
|
|
||||||
cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOW)) * sizeof(IMEMENUITEMINFOA));
|
|
||||||
pNewItems = ImmLocalAlloc(0, cbTotal);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pNewItems))
|
|
||||||
goto Quit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pNewItems = lpImeMenu;
|
|
||||||
pNewParent = lpImeParentMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = pImeDpi->ImeGetImeMenuItems(hIMC, dwFlags, dwType, pNewParent, pNewItems, dwSize);
|
|
||||||
if (IS_ZERO_UNEXPECTEDLY(ret) || !lpImeMenu)
|
|
||||||
goto Quit;
|
|
||||||
|
|
||||||
if (bImcIsAnsi != bTargetIsAnsi)
|
|
||||||
{
|
|
||||||
if (bTargetIsAnsi)
|
|
||||||
{
|
|
||||||
if (pNewParent)
|
|
||||||
Imm32ImeMenuWideToAnsi(pNewParent, lpImeParentMenu, pImeDpi->uCodePage);
|
|
||||||
|
|
||||||
pItemW = pNewItems;
|
|
||||||
pItemA = lpImeMenu;
|
|
||||||
for (iItem = 0; iItem < ret; ++iItem, ++pItemW, ++pItemA)
|
|
||||||
{
|
|
||||||
if (!Imm32ImeMenuWideToAnsi(pItemW, pItemA, pImeDpi->uCodePage))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pNewParent)
|
|
||||||
Imm32ImeMenuAnsiToWide(pNewParent, lpImeParentMenu, pImeDpi->uCodePage, TRUE);
|
|
||||||
|
|
||||||
pItemA = pNewItems;
|
|
||||||
pItemW = lpImeMenu;
|
|
||||||
for (iItem = 0; iItem < dwSize; ++iItem, ++pItemA, ++pItemW)
|
|
||||||
{
|
|
||||||
if (!Imm32ImeMenuAnsiToWide(pItemA, pItemW, pImeDpi->uCodePage, TRUE))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
if (pNewItems != lpImeMenu)
|
|
||||||
ImmLocalFree(pNewItems);
|
|
||||||
ImmUnlockImeDpi(pImeDpi);
|
|
||||||
ImmUnlockIMC(hIMC);
|
|
||||||
TRACE("ret: 0x%X\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmInstallIMEA (IMM32.@)
|
* ImmInstallIMEA (IMM32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -2102,32 +1775,6 @@ Quit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* ImmGetImeMenuItemsA (IMM32.@)
|
|
||||||
*/
|
|
||||||
DWORD WINAPI
|
|
||||||
ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType,
|
|
||||||
LPIMEMENUITEMINFOA lpImeParentMenu,
|
|
||||||
LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize)
|
|
||||||
{
|
|
||||||
TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
|
|
||||||
hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
|
|
||||||
return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* ImmGetImeMenuItemsW (IMM32.@)
|
|
||||||
*/
|
|
||||||
DWORD WINAPI
|
|
||||||
ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType,
|
|
||||||
LPIMEMENUITEMINFOW lpImeParentMenu,
|
|
||||||
LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
|
|
||||||
{
|
|
||||||
TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
|
|
||||||
hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
|
|
||||||
return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmWINNLSEnableIME (IMM32.@)
|
* ImmWINNLSEnableIME (IMM32.@)
|
||||||
*/
|
*/
|
||||||
|
|
682
dll/win32/imm32/imemenu.c
Normal file
682
dll/win32/imm32/imemenu.c
Normal file
|
@ -0,0 +1,682 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS IMM32
|
||||||
|
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||||
|
* PURPOSE: Implementing IME menus
|
||||||
|
* COPYRIGHT: Copyright 1998 Patrik Stridvall
|
||||||
|
* Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
|
||||||
|
* Copyright 2017 James Tabor <james.tabor@reactos.org>
|
||||||
|
* Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
|
||||||
|
* Copyright 2020-2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||||
|
|
||||||
|
#define IMEMENUINFO_BUFFER_SIZE 0x20000
|
||||||
|
#define IMEMENUINFO_MAGIC 0xBABEF00D /* ReactOS-specific */
|
||||||
|
|
||||||
|
/* ReactOS-specific */
|
||||||
|
typedef struct tagIMEMENUINFO
|
||||||
|
{
|
||||||
|
DWORD cbSize;
|
||||||
|
DWORD cbCapacity; /* IMEMENUINFO_BUFFER_SIZE */
|
||||||
|
DWORD dwMagic; /* IMEMENUINFO_MAGIC */
|
||||||
|
DWORD dwFlags; /* ImmGetImeMenuItems.dwFlags */
|
||||||
|
DWORD dwType; /* ImmGetImeMenuItems.dwType */
|
||||||
|
DWORD dwItemCount;
|
||||||
|
DWORD dwParentOffset;
|
||||||
|
DWORD dwItemsOffset;
|
||||||
|
DWORD dwBitmapsOffset;
|
||||||
|
} IMEMENUINFO, *PIMEMENUINFO;
|
||||||
|
|
||||||
|
typedef struct tagBITMAPINFOMAX
|
||||||
|
{
|
||||||
|
BITMAPINFOHEADER bmiHeader;
|
||||||
|
RGBQUAD bmiColors[256];
|
||||||
|
} BITMAPINFOMAX, *PBITMAPINFOMAX;
|
||||||
|
|
||||||
|
/* ReactOS-specific */
|
||||||
|
typedef struct tagIMEMENUBITMAPHEADER
|
||||||
|
{
|
||||||
|
DWORD cbSize;
|
||||||
|
DWORD dwBitsOffset;
|
||||||
|
HBITMAP hbm;
|
||||||
|
} IMEMENUBITMAPHEADER, *PIMEMENUBITMAPHEADER;
|
||||||
|
|
||||||
|
#define PTR_FROM_OFFSET(head, offset) (PVOID)((PBYTE)(head) + (SIZE_T)(offset))
|
||||||
|
|
||||||
|
/* Convert ANSI IME menu to Wide */
|
||||||
|
static BOOL
|
||||||
|
Imm32ImeMenuAnsiToWide(
|
||||||
|
_In_ const IMEMENUITEMINFOA *pItemA,
|
||||||
|
_Out_ PIMEMENUITEMINFOW pItemW,
|
||||||
|
_In_ UINT uCodePage,
|
||||||
|
_In_ BOOL bBitmap)
|
||||||
|
{
|
||||||
|
INT ret;
|
||||||
|
pItemW->cbSize = pItemA->cbSize;
|
||||||
|
pItemW->fType = pItemA->fType;
|
||||||
|
pItemW->fState = pItemA->fState;
|
||||||
|
pItemW->wID = pItemA->wID;
|
||||||
|
if (bBitmap)
|
||||||
|
{
|
||||||
|
pItemW->hbmpChecked = pItemA->hbmpChecked;
|
||||||
|
pItemW->hbmpUnchecked = pItemA->hbmpUnchecked;
|
||||||
|
pItemW->hbmpItem = pItemA->hbmpItem;
|
||||||
|
}
|
||||||
|
pItemW->dwItemData = pItemA->dwItemData;
|
||||||
|
ret = MultiByteToWideChar(uCodePage, 0, pItemA->szString, -1,
|
||||||
|
pItemW->szString, _countof(pItemW->szString));
|
||||||
|
pItemW->szString[_countof(pItemW->szString) - 1] = UNICODE_NULL;
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert Wide IME menu to ANSI */
|
||||||
|
static BOOL
|
||||||
|
Imm32ImeMenuWideToAnsi(
|
||||||
|
_In_ const IMEMENUITEMINFOW *pItemW,
|
||||||
|
_Out_ PIMEMENUITEMINFOA pItemA,
|
||||||
|
_In_ UINT uCodePage)
|
||||||
|
{
|
||||||
|
INT ret;
|
||||||
|
pItemA->cbSize = pItemW->cbSize;
|
||||||
|
pItemA->fType = pItemW->fType;
|
||||||
|
pItemA->fState = pItemW->fState;
|
||||||
|
pItemA->wID = pItemW->wID;
|
||||||
|
pItemA->hbmpChecked = pItemW->hbmpChecked;
|
||||||
|
pItemA->hbmpUnchecked = pItemW->hbmpUnchecked;
|
||||||
|
pItemA->dwItemData = pItemW->dwItemData;
|
||||||
|
pItemA->hbmpItem = pItemW->hbmpItem;
|
||||||
|
ret = WideCharToMultiByte(uCodePage, 0, pItemW->szString, -1,
|
||||||
|
pItemA->szString, _countof(pItemA->szString), NULL, NULL);
|
||||||
|
pItemA->szString[_countof(pItemA->szString) - 1] = ANSI_NULL;
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD
|
||||||
|
Imm32FindImeMenuBitmap(
|
||||||
|
_In_ const IMEMENUINFO *pView,
|
||||||
|
_In_ HBITMAP hbm)
|
||||||
|
{
|
||||||
|
const BYTE *pb = (const BYTE *)pView;
|
||||||
|
pb += pView->dwBitmapsOffset;
|
||||||
|
const IMEMENUBITMAPHEADER *pBitmap = (const IMEMENUBITMAPHEADER *)pb;
|
||||||
|
while (pBitmap->cbSize)
|
||||||
|
{
|
||||||
|
if (pBitmap->hbm == hbm)
|
||||||
|
return (PBYTE)pBitmap - (PBYTE)pView; /* Byte offset from pView */
|
||||||
|
pBitmap = PTR_FROM_OFFSET(pBitmap, pBitmap->cbSize);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
Imm32DeleteImeMenuBitmaps(_Inout_ PIMEMENUINFO pView)
|
||||||
|
{
|
||||||
|
PBYTE pb = (PBYTE)pView;
|
||||||
|
pb += pView->dwBitmapsOffset;
|
||||||
|
PIMEMENUBITMAPHEADER pBitmap = (PIMEMENUBITMAPHEADER)pb;
|
||||||
|
while (pBitmap->cbSize)
|
||||||
|
{
|
||||||
|
if (pBitmap->hbm)
|
||||||
|
{
|
||||||
|
DeleteObject(pBitmap->hbm);
|
||||||
|
pBitmap->hbm = NULL;
|
||||||
|
}
|
||||||
|
pBitmap = PTR_FROM_OFFSET(pBitmap, pBitmap->cbSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD
|
||||||
|
Imm32SerializeImeMenuBitmap(
|
||||||
|
_In_ HDC hDC,
|
||||||
|
_Inout_ PIMEMENUINFO pView,
|
||||||
|
_In_ HBITMAP hbm)
|
||||||
|
{
|
||||||
|
if (hbm == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DWORD dwOffset = Imm32FindImeMenuBitmap(pView, hbm);
|
||||||
|
if (dwOffset)
|
||||||
|
return dwOffset; /* Already serialized */
|
||||||
|
|
||||||
|
/* Get DIB info */
|
||||||
|
BITMAPINFOMAX bmi;
|
||||||
|
ZeroMemory(&bmi, sizeof(bmi));
|
||||||
|
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||||
|
if (!GetDIBits(hDC, hbm, 0, 0, NULL, (PBITMAPINFO)&bmi, DIB_RGB_COLORS))
|
||||||
|
{
|
||||||
|
ERR("!GetDIBits\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the possible color table size */
|
||||||
|
DWORD colorTableSize = 0;
|
||||||
|
if (bmi.bmiHeader.biBitCount <= 8)
|
||||||
|
colorTableSize = (1 << bmi.bmiHeader.biBitCount) * sizeof(RGBQUAD);
|
||||||
|
else if (bmi.bmiHeader.biBitCount == 16 || bmi.bmiHeader.biBitCount == 32)
|
||||||
|
colorTableSize = 3 * sizeof(DWORD);
|
||||||
|
|
||||||
|
/* Calculate the data sizes and validate them */
|
||||||
|
DWORD cbBitmapHeader = sizeof(IMEMENUBITMAPHEADER);
|
||||||
|
DWORD dibHeaderSize = sizeof(BITMAPINFOHEADER) + colorTableSize;
|
||||||
|
DWORD cbData = cbBitmapHeader + dibHeaderSize + bmi.bmiHeader.biSizeImage;
|
||||||
|
if (pView->cbSize + cbData + sizeof(DWORD) > pView->cbCapacity)
|
||||||
|
{
|
||||||
|
ERR("Too large IME menu (0x%X, 0x%X)\n", pView->cbSize, cbData);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a bitmap for getting bits */
|
||||||
|
HBITMAP hbmTmp = CreateCompatibleBitmap(hDC, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight);
|
||||||
|
if (!hbmTmp)
|
||||||
|
{
|
||||||
|
ERR("Out of memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the IMEMENUBITMAPHEADER */
|
||||||
|
PBYTE pb = (PBYTE)pView + pView->cbSize;
|
||||||
|
PIMEMENUBITMAPHEADER pBitmap = (PIMEMENUBITMAPHEADER)pb;
|
||||||
|
pBitmap->cbSize = cbData;
|
||||||
|
pBitmap->dwBitsOffset = cbBitmapHeader + dibHeaderSize;
|
||||||
|
pBitmap->hbm = hbm;
|
||||||
|
pb += cbBitmapHeader;
|
||||||
|
|
||||||
|
/* Store the BITMAPINFO */
|
||||||
|
PBITMAPINFO pbmi = (PBITMAPINFO)pb;
|
||||||
|
CopyMemory(pbmi, &bmi, dibHeaderSize);
|
||||||
|
pb += dibHeaderSize;
|
||||||
|
|
||||||
|
/* Get the bits */
|
||||||
|
HGDIOBJ hbmOld = SelectObject(hDC, hbmTmp);
|
||||||
|
BOOL ret = GetDIBits(hDC, hbm, 0, bmi.bmiHeader.biHeight, pb, pbmi, DIB_RGB_COLORS);
|
||||||
|
SelectObject(hDC, hbmOld);
|
||||||
|
|
||||||
|
DeleteObject(hbmTmp);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
ERR("!GetDIBits\n");
|
||||||
|
pBitmap->cbSize = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pView->cbSize += cbData;
|
||||||
|
return (PBYTE)pBitmap - (PBYTE)pView; /* Byte offset from pView */
|
||||||
|
}
|
||||||
|
|
||||||
|
static HBITMAP
|
||||||
|
Imm32DeserializeImeMenuBitmap(_Inout_ const IMEMENUBITMAPHEADER *pBitmap)
|
||||||
|
{
|
||||||
|
const BYTE *pb = (const BYTE *)pBitmap;
|
||||||
|
const BITMAPINFO *pbmi = (const BITMAPINFO *)(pb + sizeof(*pBitmap));
|
||||||
|
|
||||||
|
HDC hDC = GetDC(NULL);
|
||||||
|
HBITMAP hbm = CreateDIBitmap(hDC,
|
||||||
|
&pbmi->bmiHeader,
|
||||||
|
CBM_INIT,
|
||||||
|
pb + pBitmap->dwBitsOffset,
|
||||||
|
pbmi,
|
||||||
|
DIB_RGB_COLORS);
|
||||||
|
if (!hbm)
|
||||||
|
ERR("!hbm\n");
|
||||||
|
ReleaseDC(NULL, hDC);
|
||||||
|
return hbm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We transport the IME menu items by using a flat memory block via
|
||||||
|
* a file mapping object beyond boundary of process.
|
||||||
|
*/
|
||||||
|
static DWORD
|
||||||
|
Imm32SerializeImeMenu(
|
||||||
|
_Inout_ PIMEMENUINFO pView,
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_Inout_opt_ PIMEMENUITEMINFOW lpImeParentMenu,
|
||||||
|
_In_ BOOL bCountOnly)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
if (pView->dwMagic != IMEMENUINFO_MAGIC || pView->cbSize > pView->cbCapacity)
|
||||||
|
{
|
||||||
|
ERR("Invalid pView\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the count of menu items */
|
||||||
|
DWORD dwFlags = pView->dwFlags;
|
||||||
|
DWORD dwType = pView->dwType;
|
||||||
|
DWORD dwItemCount = ImmGetImeMenuItemsW(hIMC, dwFlags, dwType, lpImeParentMenu, NULL, 0);
|
||||||
|
pView->dwItemCount = dwItemCount;
|
||||||
|
if (bCountOnly)
|
||||||
|
return dwItemCount;
|
||||||
|
|
||||||
|
if (!dwItemCount)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Start of serialization */
|
||||||
|
PBYTE pb = (PBYTE)pView;
|
||||||
|
pb += sizeof(*pView);
|
||||||
|
|
||||||
|
/* Store the parent menu data */
|
||||||
|
if (lpImeParentMenu)
|
||||||
|
{
|
||||||
|
pView->dwParentOffset = pb - (PBYTE)pView;
|
||||||
|
pView->cbSize += sizeof(*lpImeParentMenu);
|
||||||
|
CopyMemory(pb, lpImeParentMenu, sizeof(*lpImeParentMenu));
|
||||||
|
pb += sizeof(*lpImeParentMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The byte size of items */
|
||||||
|
SIZE_T cbItems = dwItemCount * sizeof(IMEMENUITEMINFOW);
|
||||||
|
|
||||||
|
/* Update the offset info */
|
||||||
|
pView->dwItemsOffset = pb - (PBYTE)pView;
|
||||||
|
pView->dwBitmapsOffset = pView->dwItemsOffset + cbItems;
|
||||||
|
if (pView->dwItemsOffset + sizeof(DWORD) > pView->cbCapacity ||
|
||||||
|
pView->dwBitmapsOffset + sizeof(DWORD) > pView->cbCapacity)
|
||||||
|
{
|
||||||
|
ERR("Too large IME menu (0x%X, 0x%X)\n", pView->dwItemsOffset, pView->dwBitmapsOffset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actually get the items */
|
||||||
|
PIMEMENUITEMINFOW pItems = (PIMEMENUITEMINFOW)pb;
|
||||||
|
dwItemCount = ImmGetImeMenuItemsW(hIMC, dwFlags, dwType, lpImeParentMenu, pItems, cbItems);
|
||||||
|
pView->dwItemCount = dwItemCount;
|
||||||
|
pView->cbSize += cbItems;
|
||||||
|
|
||||||
|
/* Serialize the bitmaps */
|
||||||
|
DWORD dwOffset;
|
||||||
|
HDC hDC = CreateCompatibleDC(NULL);
|
||||||
|
for (DWORD iItem = 0; iItem < dwItemCount; ++iItem)
|
||||||
|
{
|
||||||
|
PIMEMENUITEMINFOW pItem = &pItems[iItem];
|
||||||
|
|
||||||
|
dwOffset = Imm32SerializeImeMenuBitmap(hDC, pView, pItem->hbmpChecked);
|
||||||
|
if (dwOffset)
|
||||||
|
pItem->hbmpChecked = UlongToHandle(dwOffset);
|
||||||
|
|
||||||
|
dwOffset = Imm32SerializeImeMenuBitmap(hDC, pView, pItem->hbmpUnchecked);
|
||||||
|
if (dwOffset)
|
||||||
|
pItem->hbmpUnchecked = UlongToHandle(dwOffset);
|
||||||
|
|
||||||
|
dwOffset = Imm32SerializeImeMenuBitmap(hDC, pView, pItem->hbmpItem);
|
||||||
|
if (dwOffset)
|
||||||
|
pItem->hbmpItem = UlongToHandle(dwOffset);
|
||||||
|
}
|
||||||
|
DeleteDC(hDC);
|
||||||
|
|
||||||
|
TRACE("pView->cbSize: 0x%X\n", pView->cbSize);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
Imm32DeleteImeMenuBitmaps(pView);
|
||||||
|
|
||||||
|
return dwItemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD
|
||||||
|
Imm32DeserializeImeMenu(
|
||||||
|
_Inout_ PIMEMENUINFO pView,
|
||||||
|
_Out_writes_bytes_opt_(dwSize) PIMEMENUITEMINFOW lpImeMenuItems,
|
||||||
|
_In_ DWORD dwSize)
|
||||||
|
{
|
||||||
|
/* Sanity check */
|
||||||
|
if (pView->dwMagic != IMEMENUINFO_MAGIC || pView->cbSize > pView->cbCapacity)
|
||||||
|
{
|
||||||
|
ERR("Invalid pView\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwItemCount = pView->dwItemCount;
|
||||||
|
if (lpImeMenuItems == NULL)
|
||||||
|
return dwItemCount; /* Count only */
|
||||||
|
|
||||||
|
/* Limit the item count for dwSize */
|
||||||
|
if (dwItemCount > dwSize / sizeof(IMEMENUITEMINFOW))
|
||||||
|
dwItemCount = dwSize / sizeof(IMEMENUITEMINFOW);
|
||||||
|
|
||||||
|
/* Get the items pointer */
|
||||||
|
PIMEMENUITEMINFOW pItems = PTR_FROM_OFFSET(pView, pView->dwItemsOffset);
|
||||||
|
|
||||||
|
/* Copy the items and de-serialize the bitmaps */
|
||||||
|
PIMEMENUBITMAPHEADER pBitmap;
|
||||||
|
for (DWORD iItem = 0; iItem < dwItemCount; ++iItem)
|
||||||
|
{
|
||||||
|
PIMEMENUITEMINFOW pItem = &pItems[iItem];
|
||||||
|
if (pItem->hbmpChecked)
|
||||||
|
{
|
||||||
|
pBitmap = PTR_FROM_OFFSET(pView, pItem->hbmpChecked);
|
||||||
|
pItem->hbmpChecked = Imm32DeserializeImeMenuBitmap(pBitmap);
|
||||||
|
}
|
||||||
|
if (pItem->hbmpUnchecked)
|
||||||
|
{
|
||||||
|
pBitmap = PTR_FROM_OFFSET(pView, pItem->hbmpUnchecked);
|
||||||
|
pItem->hbmpUnchecked = Imm32DeserializeImeMenuBitmap(pBitmap);
|
||||||
|
}
|
||||||
|
if (pItem->hbmpItem)
|
||||||
|
{
|
||||||
|
pBitmap = PTR_FROM_OFFSET(pView, pItem->hbmpItem);
|
||||||
|
pItem->hbmpItem = Imm32DeserializeImeMenuBitmap(pBitmap);
|
||||||
|
}
|
||||||
|
lpImeMenuItems[iItem] = *pItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dwItemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* 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(_In_ HIMC hIMC)
|
||||||
|
{
|
||||||
|
/* Open the existing file mapping */
|
||||||
|
HANDLE hMapping = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"ImmMenuInfo");
|
||||||
|
if (!hMapping)
|
||||||
|
{
|
||||||
|
ERR("!hMapping\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the view */
|
||||||
|
PIMEMENUINFO pView = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
|
if (!pView)
|
||||||
|
{
|
||||||
|
ERR("!pView\n");
|
||||||
|
CloseHandle(hMapping);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get parent menu info */
|
||||||
|
PVOID lpImeParentMenu = NULL;
|
||||||
|
if (pView->dwParentOffset)
|
||||||
|
lpImeParentMenu = PTR_FROM_OFFSET(pView, pView->dwParentOffset);
|
||||||
|
|
||||||
|
/* Serialize the IME menu */
|
||||||
|
DWORD dwItemCount = Imm32SerializeImeMenu(pView, hIMC, lpImeParentMenu, !pView->dwItemCount);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
UnmapViewOfFile(pView);
|
||||||
|
CloseHandle(hMapping);
|
||||||
|
|
||||||
|
return dwItemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD
|
||||||
|
Imm32GetImeMenuItemWInterProcess(
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_In_ DWORD dwFlags,
|
||||||
|
_In_ DWORD dwType,
|
||||||
|
_Inout_opt_ PVOID lpImeParentMenu,
|
||||||
|
_Out_writes_bytes_opt_(dwSize) PVOID lpImeMenuItems,
|
||||||
|
_In_ DWORD dwSize)
|
||||||
|
{
|
||||||
|
/* Get IME window */
|
||||||
|
HWND hwndIme = (HWND)NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME);
|
||||||
|
if (!hwndIme || !IsWindow(hwndIme))
|
||||||
|
{
|
||||||
|
ERR("!hwndIme\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock */
|
||||||
|
RtlEnterCriticalSection(&gcsImeDpi);
|
||||||
|
|
||||||
|
/* Create a file mapping */
|
||||||
|
HANDLE hMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||||||
|
0, IMEMENUINFO_BUFFER_SIZE, L"ImmMenuInfo");
|
||||||
|
if (!hMapping)
|
||||||
|
{
|
||||||
|
ERR("!pView\n");
|
||||||
|
RtlLeaveCriticalSection(&gcsImeDpi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the view */
|
||||||
|
PIMEMENUINFO pView = MapViewOfFile(hMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||||
|
if (!pView)
|
||||||
|
{
|
||||||
|
ERR("!pView\n");
|
||||||
|
CloseHandle(hMapping);
|
||||||
|
RtlLeaveCriticalSection(&gcsImeDpi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize view header */
|
||||||
|
ZeroMemory(pView, IMEMENUINFO_BUFFER_SIZE);
|
||||||
|
pView->cbSize = sizeof(*pView);
|
||||||
|
pView->cbCapacity = IMEMENUINFO_BUFFER_SIZE;
|
||||||
|
pView->dwMagic = IMEMENUINFO_MAGIC;
|
||||||
|
pView->dwFlags = dwFlags;
|
||||||
|
pView->dwType = dwType;
|
||||||
|
pView->dwItemCount = lpImeMenuItems ? (dwSize / sizeof(IMEMENUITEMINFOW)) : 0;
|
||||||
|
|
||||||
|
/* Send WM_IME_SYSTEM.IMS_GETIMEMENU message. It will call ImmPutImeMenuItemsIntoMappedFile */
|
||||||
|
DWORD ret = 0;
|
||||||
|
if (SendMessageW(hwndIme, WM_IME_SYSTEM, IMS_GETIMEMENU, (LPARAM)hIMC))
|
||||||
|
{
|
||||||
|
/* De-serialize the IME menu */
|
||||||
|
ret = Imm32DeserializeImeMenu(pView, lpImeMenuItems, dwSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
UnmapViewOfFile(pView); /* Unmap */
|
||||||
|
CloseHandle(hMapping); /* Close the file mapping */
|
||||||
|
RtlLeaveCriticalSection(&gcsImeDpi); /* Unlock */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Absorbs the differences between ANSI and Wide */
|
||||||
|
static DWORD
|
||||||
|
ImmGetImeMenuItemsAW(
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_In_ DWORD dwFlags,
|
||||||
|
_In_ DWORD dwType,
|
||||||
|
_Inout_opt_ PVOID lpImeParentMenu,
|
||||||
|
_Out_writes_bytes_opt_(dwSize) PVOID lpImeMenuItems,
|
||||||
|
_In_ DWORD dwSize,
|
||||||
|
_In_ BOOL bTargetIsAnsi)
|
||||||
|
{
|
||||||
|
DWORD ret = 0, iItem;
|
||||||
|
|
||||||
|
if (!hIMC)
|
||||||
|
{
|
||||||
|
ERR("!hIMC\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get input process ID */
|
||||||
|
DWORD dwProcessId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTPROCESSID);
|
||||||
|
if (!dwProcessId)
|
||||||
|
{
|
||||||
|
ERR("!dwProcessId\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwProcessId != GetCurrentProcessId()) /* Cross process? */
|
||||||
|
{
|
||||||
|
if (bTargetIsAnsi)
|
||||||
|
{
|
||||||
|
ERR("ImmGetImeMenuItemsA cannot cross process boundary\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transport the IME menu items, using file mapping */
|
||||||
|
return Imm32GetImeMenuItemWInterProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
|
||||||
|
lpImeMenuItems, dwSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
PINPUTCONTEXT pIC = ImmLockIMC(hIMC);
|
||||||
|
if (!pIC)
|
||||||
|
{
|
||||||
|
ERR("!pIC\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get input thread ID */
|
||||||
|
DWORD dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
|
||||||
|
if (!dwThreadId)
|
||||||
|
{
|
||||||
|
ERR("!dwThreadId\n");
|
||||||
|
ImmUnlockIMC(hIMC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get IME interface */
|
||||||
|
HKL hKL = GetKeyboardLayout(dwThreadId);
|
||||||
|
PIMEDPI pImeDpi = ImmLockImeDpi(hKL);
|
||||||
|
if (!pImeDpi)
|
||||||
|
{
|
||||||
|
ERR("!pImeDpi\n");
|
||||||
|
ImmUnlockIMC(hIMC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the IME ANSI? */
|
||||||
|
BOOL bImcIsAnsi = Imm32IsImcAnsi(hIMC);
|
||||||
|
|
||||||
|
IMEMENUITEMINFOA ParentA, *pItemA;
|
||||||
|
IMEMENUITEMINFOW ParentW, *pItemW;
|
||||||
|
PVOID pNewItems = NULL, pNewParent = NULL;
|
||||||
|
|
||||||
|
/* Are text types (ANSI/Wide) different between IME and target? */
|
||||||
|
if (bImcIsAnsi != bTargetIsAnsi)
|
||||||
|
{
|
||||||
|
DWORD cbTotal;
|
||||||
|
if (bTargetIsAnsi)
|
||||||
|
{
|
||||||
|
/* Convert the parent */
|
||||||
|
if (lpImeParentMenu)
|
||||||
|
{
|
||||||
|
Imm32ImeMenuAnsiToWide(lpImeParentMenu, &ParentW, pImeDpi->uCodePage, TRUE);
|
||||||
|
pNewParent = &ParentW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate buffer for new items */
|
||||||
|
if (lpImeMenuItems)
|
||||||
|
{
|
||||||
|
cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOA)) * sizeof(IMEMENUITEMINFOW));
|
||||||
|
pNewItems = ImmLocalAlloc(LPTR, cbTotal);
|
||||||
|
if (!pNewItems)
|
||||||
|
{
|
||||||
|
ERR("!pNewItems\n");
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Convert the parent */
|
||||||
|
if (lpImeParentMenu)
|
||||||
|
{
|
||||||
|
Imm32ImeMenuWideToAnsi(lpImeParentMenu, &ParentA, pImeDpi->uCodePage);
|
||||||
|
pNewParent = &ParentA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate buffer for new items */
|
||||||
|
if (lpImeMenuItems)
|
||||||
|
{
|
||||||
|
cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOW)) * sizeof(IMEMENUITEMINFOA));
|
||||||
|
pNewItems = ImmLocalAlloc(LPTR, cbTotal);
|
||||||
|
if (!pNewItems)
|
||||||
|
{
|
||||||
|
ERR("!pNewItems\n");
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Get the items directly */
|
||||||
|
pNewItems = lpImeMenuItems;
|
||||||
|
pNewParent = lpImeParentMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get IME menu items from the IME */
|
||||||
|
ret = pImeDpi->ImeGetImeMenuItems(hIMC, dwFlags, dwType, pNewParent, pNewItems, dwSize);
|
||||||
|
if (!ret || !lpImeMenuItems)
|
||||||
|
{
|
||||||
|
ERR("%d, %p\n", ret, lpImeMenuItems);
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bImcIsAnsi != bTargetIsAnsi) /* Are text types different? */
|
||||||
|
{
|
||||||
|
if (bTargetIsAnsi)
|
||||||
|
{
|
||||||
|
/* Convert the parent */
|
||||||
|
if (pNewParent)
|
||||||
|
Imm32ImeMenuWideToAnsi(pNewParent, lpImeParentMenu, pImeDpi->uCodePage);
|
||||||
|
|
||||||
|
/* Convert the items */
|
||||||
|
pItemW = pNewItems;
|
||||||
|
pItemA = lpImeMenuItems;
|
||||||
|
for (iItem = 0; iItem < ret; ++iItem, ++pItemW, ++pItemA)
|
||||||
|
{
|
||||||
|
Imm32ImeMenuWideToAnsi(pItemW, pItemA, pImeDpi->uCodePage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Convert the parent */
|
||||||
|
if (pNewParent)
|
||||||
|
Imm32ImeMenuAnsiToWide(pNewParent, lpImeParentMenu, pImeDpi->uCodePage, TRUE);
|
||||||
|
|
||||||
|
/* Convert the items */
|
||||||
|
pItemA = pNewItems;
|
||||||
|
pItemW = lpImeMenuItems;
|
||||||
|
for (iItem = 0; iItem < dwSize; ++iItem, ++pItemA, ++pItemW)
|
||||||
|
{
|
||||||
|
Imm32ImeMenuAnsiToWide(pItemA, pItemW, pImeDpi->uCodePage, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
if (pNewItems != lpImeMenuItems)
|
||||||
|
ImmLocalFree(pNewItems);
|
||||||
|
ImmUnlockImeDpi(pImeDpi);
|
||||||
|
ImmUnlockIMC(hIMC);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* ImmGetImeMenuItemsA (IMM32.@)
|
||||||
|
*/
|
||||||
|
DWORD WINAPI
|
||||||
|
ImmGetImeMenuItemsA(
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_In_ DWORD dwFlags,
|
||||||
|
_In_ DWORD dwType,
|
||||||
|
_Inout_opt_ PIMEMENUITEMINFOA lpImeParentMenu,
|
||||||
|
_Out_writes_bytes_opt_(dwSize) PIMEMENUITEMINFOA lpImeMenu,
|
||||||
|
_In_ DWORD dwSize)
|
||||||
|
{
|
||||||
|
TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
|
||||||
|
hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
|
||||||
|
return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* ImmGetImeMenuItemsW (IMM32.@)
|
||||||
|
*/
|
||||||
|
DWORD WINAPI
|
||||||
|
ImmGetImeMenuItemsW(
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_In_ DWORD dwFlags,
|
||||||
|
_In_ DWORD dwType,
|
||||||
|
_Inout_opt_ PIMEMENUITEMINFOW lpImeParentMenu,
|
||||||
|
_Out_writes_bytes_opt_(dwSize) PIMEMENUITEMINFOW lpImeMenu,
|
||||||
|
_In_ DWORD dwSize)
|
||||||
|
{
|
||||||
|
TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
|
||||||
|
hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
|
||||||
|
return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, FALSE);
|
||||||
|
}
|
|
@ -140,13 +140,6 @@ Imm32MakeIMENotify(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWOR
|
||||||
|
|
||||||
DWORD APIENTRY Imm32BuildHimcList(DWORD dwThreadId, HIMC **pphList);
|
DWORD APIENTRY Imm32BuildHimcList(DWORD dwThreadId, HIMC **pphList);
|
||||||
|
|
||||||
INT APIENTRY
|
|
||||||
Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA *pItemA, LPIMEMENUITEMINFOW pItemW,
|
|
||||||
UINT uCodePage, BOOL bBitmap);
|
|
||||||
INT APIENTRY
|
|
||||||
Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW *pItemW, LPIMEMENUITEMINFOA pItemA,
|
|
||||||
UINT uCodePage);
|
|
||||||
|
|
||||||
PIME_STATE APIENTRY Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL);
|
PIME_STATE APIENTRY Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL);
|
||||||
PIME_SUBSTATE APIENTRY Imm32FetchImeSubState(PIME_STATE pState, HKL hKL);
|
PIME_SUBSTATE APIENTRY Imm32FetchImeSubState(PIME_STATE pState, HKL hKL);
|
||||||
|
|
||||||
|
|
|
@ -496,57 +496,6 @@ DWORD APIENTRY Imm32BuildHimcList(DWORD dwThreadId, HIMC **pphList)
|
||||||
#undef MAX_RETRY
|
#undef MAX_RETRY
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win: ConvertImeMenuItemInfoAtoW
|
|
||||||
INT APIENTRY
|
|
||||||
Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA *pItemA, LPIMEMENUITEMINFOW pItemW,
|
|
||||||
UINT uCodePage, BOOL bBitmap)
|
|
||||||
{
|
|
||||||
INT ret;
|
|
||||||
pItemW->cbSize = pItemA->cbSize;
|
|
||||||
pItemW->fType = pItemA->fType;
|
|
||||||
pItemW->fState = pItemA->fState;
|
|
||||||
pItemW->wID = pItemA->wID;
|
|
||||||
if (bBitmap)
|
|
||||||
{
|
|
||||||
pItemW->hbmpChecked = pItemA->hbmpChecked;
|
|
||||||
pItemW->hbmpUnchecked = pItemA->hbmpUnchecked;
|
|
||||||
pItemW->hbmpItem = pItemA->hbmpItem;
|
|
||||||
}
|
|
||||||
pItemW->dwItemData = pItemA->dwItemData;
|
|
||||||
ret = MultiByteToWideChar(uCodePage, 0, pItemA->szString, -1,
|
|
||||||
pItemW->szString, _countof(pItemW->szString));
|
|
||||||
if (ret >= _countof(pItemW->szString))
|
|
||||||
{
|
|
||||||
ret = 0;
|
|
||||||
pItemW->szString[0] = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: ConvertImeMenuItemInfoWtoA
|
|
||||||
INT APIENTRY
|
|
||||||
Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW *pItemW, LPIMEMENUITEMINFOA pItemA,
|
|
||||||
UINT uCodePage)
|
|
||||||
{
|
|
||||||
INT ret;
|
|
||||||
pItemA->cbSize = pItemW->cbSize;
|
|
||||||
pItemA->fType = pItemW->fType;
|
|
||||||
pItemA->fState = pItemW->fState;
|
|
||||||
pItemA->wID = pItemW->wID;
|
|
||||||
pItemA->hbmpChecked = pItemW->hbmpChecked;
|
|
||||||
pItemA->hbmpUnchecked = pItemW->hbmpUnchecked;
|
|
||||||
pItemA->dwItemData = pItemW->dwItemData;
|
|
||||||
pItemA->hbmpItem = pItemW->hbmpItem;
|
|
||||||
ret = WideCharToMultiByte(uCodePage, 0, pItemW->szString, -1,
|
|
||||||
pItemA->szString, _countof(pItemA->szString), NULL, NULL);
|
|
||||||
if (ret >= _countof(pItemA->szString))
|
|
||||||
{
|
|
||||||
ret = 0;
|
|
||||||
pItemA->szString[0] = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: GetImeModeSaver
|
// Win: GetImeModeSaver
|
||||||
PIME_STATE APIENTRY
|
PIME_STATE APIENTRY
|
||||||
Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL)
|
Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL)
|
||||||
|
|
|
@ -658,7 +658,7 @@ ImmGetImeMenuItemsA(
|
||||||
_In_ HIMC hIMC,
|
_In_ HIMC hIMC,
|
||||||
_In_ DWORD dwFlags,
|
_In_ DWORD dwFlags,
|
||||||
_In_ DWORD dwType,
|
_In_ DWORD dwType,
|
||||||
_Out_opt_ LPIMEMENUITEMINFOA lpImeParentMenu,
|
_Inout_opt_ LPIMEMENUITEMINFOA lpImeParentMenu,
|
||||||
_Out_writes_bytes_opt_(dwSize) LPIMEMENUITEMINFOA lpImeMenu,
|
_Out_writes_bytes_opt_(dwSize) LPIMEMENUITEMINFOA lpImeMenu,
|
||||||
_In_ DWORD dwSize);
|
_In_ DWORD dwSize);
|
||||||
|
|
||||||
|
@ -668,7 +668,7 @@ ImmGetImeMenuItemsW(
|
||||||
_In_ HIMC hIMC,
|
_In_ HIMC hIMC,
|
||||||
_In_ DWORD dwFlags,
|
_In_ DWORD dwFlags,
|
||||||
_In_ DWORD dwType,
|
_In_ DWORD dwType,
|
||||||
_Out_opt_ LPIMEMENUITEMINFOW lpImeParentMenu,
|
_Inout_opt_ LPIMEMENUITEMINFOW lpImeParentMenu,
|
||||||
_Out_writes_bytes_opt_(dwSize) LPIMEMENUITEMINFOW lpImeMenu,
|
_Out_writes_bytes_opt_(dwSize) LPIMEMENUITEMINFOW lpImeMenu,
|
||||||
_In_ DWORD dwSize);
|
_In_ DWORD dwSize);
|
||||||
|
|
||||||
|
|
|
@ -228,6 +228,7 @@ DWORD WINAPI ImmGetAppCompatFlags(_In_ HIMC hIMC);
|
||||||
BOOL WINAPI ImmSetActiveContext(_In_ HWND hwnd, _In_ HIMC hIMC, _In_ BOOL fFlag);
|
BOOL WINAPI ImmSetActiveContext(_In_ HWND hwnd, _In_ HIMC hIMC, _In_ BOOL fFlag);
|
||||||
BOOL WINAPI ImmLoadIME(_In_ HKL hKL);
|
BOOL WINAPI ImmLoadIME(_In_ HKL hKL);
|
||||||
DWORD WINAPI ImmProcessKey(_In_ HWND, _In_ HKL, _In_ UINT, _In_ LPARAM, _In_ DWORD);
|
DWORD WINAPI ImmProcessKey(_In_ HWND, _In_ HKL, _In_ UINT, _In_ LPARAM, _In_ DWORD);
|
||||||
|
LRESULT WINAPI ImmPutImeMenuItemsIntoMappedFile(_In_ HIMC hIMC);
|
||||||
|
|
||||||
HRESULT WINAPI CtfAImmActivate(_Out_opt_ HINSTANCE *phinstCtfIme);
|
HRESULT WINAPI CtfAImmActivate(_Out_opt_ HINSTANCE *phinstCtfIme);
|
||||||
HRESULT WINAPI CtfAImmDeactivate(_In_ BOOL bDestroy);
|
HRESULT WINAPI CtfAImmDeactivate(_In_ BOOL bDestroy);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue