|
|
//////////////////////////////////////////////////////////////////////////
// imemenu.c - IME Menu APIs
//
// handles IME specific menu retrieval
//
// Copyright (c) 1985 - 1999, Microsoft Corporation
//
// History:
// 23-Mar-1997 hiroyama Created
//////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#ifdef HIRO_DEBUG
#define D(x) x
#else
#define D(x)
#endif
#define IME_MENU_FILE_NAME L"ImmMenuInfo"
#define IME_MENU_MAXMEM (128 * 1024) // maximum size of mapped file
////////////////////////////////////////////////////////////
// private structurs for inter process communication
//
// NOTE for NT50: these are dedicated to internat.exe
//
// uses memory mapped file as shared buffer
// all strings expect UNICODE
// HBITMAP is de-compiled and then compiled again using
// internat.exe's context
//
////////////////////////////////////////////////////////////
typedef struct _IMEMENU_BMP_HEADER { struct _IMEMENU_BMP_HEADER* lpNext; HBITMAP hBitmap; LPBYTE pBits; BITMAPINFO bmi; } IMEMENU_BMP_HEADER;
typedef struct { UINT cbSize; UINT fType; UINT fState; UINT wID; IMEMENU_BMP_HEADER* lpBmpChecked; IMEMENU_BMP_HEADER* lpBmpUnchecked; DWORD dwItemData; WCHAR szString[IMEMENUITEM_STRING_SIZE]; // menu string: always UNICODE.
IMEMENU_BMP_HEADER* lpBmpItem; // NULL means no bitmap in this menu
} IMEMENU_ITEM;
typedef struct { DWORD dwVersion; // holds version of this memory chunk
DWORD dwMemSize; // size of memory buffer allocated
DWORD dwFlags; // flags returned from IME
DWORD dwType; IMEMENU_ITEM* lpImeParentMenu; // parent menu's offset (if any) passed from requester
IMEMENU_ITEM* lpImeMenu; // offset to first menu item (will be set by IME side)
DWORD dwSize; // number of menus to fill (not byte count)
IMEMENU_BMP_HEADER* lpBmp; // offset to first bitmap header
IMEMENU_BMP_HEADER* lpBmpNext; // points next available location for bmp buffer
} IMEMENU_HEADER;
// address conversion
#define CONVTO_OFFSET(x) ((x) = (LPVOID)((x) ? ((LPBYTE)(x) - offset) : NULL))
#define CONVTO_PTR(x) ((x) = (LPVOID)((x) ? ((LPBYTE)(x) + offset) : NULL))
#if DBG
#define CHK_OFFSET(x) if ((ULONG_PTR)(x) >= pHeader->dwMemSize) { \
RIPMSG2(RIP_WARNING, "CHK_OFFSET(%s=%lx) is out of range.", #x, (ULONG_PTR)(x)); \ } #define CHK_PTR(x) if ((LPVOID)(x) < (LPVOID)pHeader || (LPBYTE)(x) > (LPBYTE)pHeader + pHeader->dwMemSize) { \
if ((x) != NULL) { \ RIPMSG2(RIP_WARNING, "CHK_PTR(%s=%lx) is out of range.", #x, (ULONG_PTR)(x)); \ DebugBreak(); \ } \ } #else
#define CHK_OFFSET(x)
#define CHK_PTR(x) if ((x) != NULL) { \
if ((LPVOID)(x) < (LPVOID)pHeader || (LPBYTE)(x) > (LPBYTE)pHeader + pHeader->dwMemSize) { \ goto cleanup; \ } \ } #endif
int ConvertImeMenuItemInfoAtoW(LPIMEMENUITEMINFOA lpA, LPIMEMENUITEMINFOW lpW, int nCP, BOOL copyBmp) { int i;
lpW->cbSize = lpA->cbSize; lpW->fType = lpA->fType; lpW->fState = lpA->fState; lpW->wID = lpA->wID; if (copyBmp) { lpW->hbmpChecked = lpA->hbmpChecked; lpW->hbmpUnchecked = lpA->hbmpUnchecked; lpW->hbmpItem = lpA->hbmpItem; } lpW->dwItemData = lpA->dwItemData;
i = MultiByteToWideChar(nCP, 0, lpA->szString, lstrlenA(lpA->szString), lpW->szString, IMEMENUITEM_STRING_SIZE);
if (i >= IMEMENUITEM_STRING_SIZE) { return 0; } else { lpW->szString[i] = L'\0'; } return i; }
int ConvertImeMenuItemInfoWtoA(LPIMEMENUITEMINFOW lpW, LPIMEMENUITEMINFOA lpA, int nCP) { int i; BOOL bUDC;
lpA->cbSize = lpW->cbSize; lpA->fType = lpW->fType; lpA->fState = lpW->fState; lpA->wID = lpW->wID; lpA->hbmpChecked = lpW->hbmpChecked; lpA->hbmpUnchecked = lpW->hbmpUnchecked; lpA->dwItemData = lpW->dwItemData; lpA->hbmpItem = lpW->hbmpItem;
i = WideCharToMultiByte(nCP, 0, lpW->szString, wcslen(lpW->szString), lpA->szString, IMEMENUITEM_STRING_SIZE, (LPSTR)NULL, &bUDC);
if (i >= IMEMENUITEM_STRING_SIZE) { return 0; } else { lpA->szString[i] = '\0'; } return i; }
#if DBG
void DumpBytes(LPBYTE pb, UINT size) { UINT i; TRACE(("\npbmi dump:")); for (i = 0; i < size; ++i) { TRACE(("%02X ", pb[i] & 0xff)); } TRACE(("\n")); UNREFERENCED_PARAMETER(pb); // just in case
} #else
#define DumpBytes(a,b)
#endif
////////////////////////////////////////////////////////////////////
// SaveBitmapToMemory
IMEMENU_BMP_HEADER* SaveBitmapToMemory(HDC hDC, HBITMAP hBmp, IMEMENU_BMP_HEADER* lpBH, IMEMENU_HEADER* pHeader) { HBITMAP hTmpBmp, hBmpOld; IMEMENU_BMP_HEADER* lpNext = NULL; PBITMAPINFO pbmi = &lpBH->bmi; ULONG sizBMI;
if (!hBmp) { RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: hBmp == NULL"); return NULL; } UserAssert(lpBH != NULL);
//
// Let the graphics engine to retrieve the dimension of the bitmap for us
// GetDIBits uses the size to determine if it's BITMAPCOREINFO or BITMAPINFO
// if BitCount != 0, color table will be retrieved
//
pbmi->bmiHeader.biSize = sizeof pbmi->bmiHeader; pbmi->bmiHeader.biBitCount = 0; // don't get the color table
if ((GetDIBits(hDC, hBmp, 0, 0, (LPSTR)NULL, pbmi, DIB_RGB_COLORS)) == 0) { RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: failed to GetDIBits(NULL)"); return NULL; }
//
// Note: 24 bits per pixel has no color table. So, we don't have to
// allocate memory for retrieving that. Otherwise, we do.
//
switch (pbmi->bmiHeader.biBitCount) { case 24: // has color table
sizBMI = sizeof(BITMAPINFOHEADER); break; case 16: case 32: sizBMI = sizeof(BITMAPINFOHEADER) + sizeof(DWORD) * 3; break; default: sizBMI = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << pbmi->bmiHeader.biBitCount); break;
}
//
// check if the buffer has enough space to put bitmap
//
if ((LPBYTE)pHeader + pHeader->dwMemSize < (LPBYTE)lpBH + sizeof lpBH + sizBMI + pbmi->bmiHeader.biSizeImage) { RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: size of bmp image(s) exceed limit "); return FALSE; }
//
// Now that we know the size of the image, let pBits point the given buffer
//
lpBH->pBits = (LPBYTE)pbmi + sizBMI;
//
// Bitmap can't be selected into a DC when calling GetDIBits
// Assume that the hDC is the DC where the bitmap would have been selected
// if indeed it has been selected
//
if (hTmpBmp = CreateCompatibleBitmap(hDC, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight)) { hBmpOld = SelectObject(hDC, hTmpBmp); if (GetDIBits(hDC, hBmp, 0, pbmi->bmiHeader.biHeight, (LPSTR)lpBH->pBits, pbmi, DIB_RGB_COLORS) == 0){ SelectObject(hDC, hBmpOld); RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: GetDIBits() failed."); return NULL; } lpNext = (IMEMENU_BMP_HEADER*)((LPBYTE)pbmi + sizBMI + pbmi->bmiHeader.biSizeImage);
DumpBytes((LPBYTE)pbmi, sizeof *pbmi); } else { RIPMSG0(RIP_WARNING, "SaveBitmapToMemory: CreateCompatibleBitmap() failed."); return NULL; }
SelectObject(hDC, hBmpOld); DeleteObject(hTmpBmp); return lpNext; }
//////////////////////////////////////////////////////////////////////////////
// DecompileBitmap()
//
// decompile given hBitmap into IMEMENU_BMP_HEADER
// manupilate IMEMENU_BMP_HEADER links in IMEMENU_HEADER
//
// History:
// 23-Mar-1997 HiroYama Created
//////////////////////////////////////////////////////////////////////////////
IMEMENU_BMP_HEADER* DecompileBitmap(IMEMENU_HEADER* pHeader, HBITMAP hBitmap) { IMEMENU_BMP_HEADER* pBmp = pHeader->lpBmp; HDC hDC;
// first search handled bitmap
while (pBmp) { if (pBmp->hBitmap == hBitmap) { // if hBitmap is already de-compiled, return it
return pBmp; } pBmp = pBmp->lpNext; }
// not yet allocated, so prepare memory buffer
pBmp = pHeader->lpBmpNext; UserAssert(pBmp != NULL); CHK_PTR(pBmp); if (pBmp == NULL) { RIPMSG1(RIP_WARNING, "DecompileBitmap: pBmp == NULL in L%d", __LINE__); return NULL; }
// use desktop's DC
hDC = GetDC(GetDesktopWindow()); if (hDC == NULL) { RIPMSG1(RIP_WARNING, "DecompileBitmap: hDC == NULL in L%d", __LINE__); return NULL; }
//
// decompile hBitmap
//
pBmp->lpNext = pHeader->lpBmp; pHeader->lpBmpNext = SaveBitmapToMemory(hDC, hBitmap, pBmp, pHeader); if (pHeader->lpBmpNext == NULL) { RIPMSG1(RIP_WARNING, "DecompileBitmap: pHeader->lpBmpNext == NULL in L%d", __LINE__); // error case. restore bmp link, then returns NULL
pHeader->lpBmpNext = pBmp; pHeader->lpBmp = pBmp->lpNext; pBmp = NULL; goto cleanup; }
// if succeeded, mark this BITMAP_HEADER with hBitmap
pBmp->hBitmap = hBitmap;
//
// put this BITMAP_HEADER in linked list
//
pHeader->lpBmp = pBmp;
cleanup: if (hDC) ReleaseDC(GetDesktopWindow(), hDC); return pBmp; }
//////////////////////////////////////////////////////////////////////////////
// ImmPutImeMenuItemsIntoMappedFile()
//
// Interprocess IME Menu handler
//
// called from ImeSystemHandler() in user32.dll
//
// handler of WM_IME_SYSTEM:IMS_MENU_ITEM
//
// History:
// 23-Mar-1997 HiroYama Created
//////////////////////////////////////////////////////////////////////////////
LRESULT ImmPutImeMenuItemsIntoMappedFile(HIMC hImc) { HANDLE hMap = NULL; LPVOID lpMap = NULL; IMEMENU_HEADER* pHeader; LPIMEMENUITEMINFO lpBuf = NULL; IMEMENU_ITEM* pMenu; IMEMENU_BMP_HEADER* pBmp; LRESULT lRet = 0; ULONG_PTR offset; DWORD i;
// Open memory mapped file
hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, IME_MENU_FILE_NAME); if (hMap == NULL) { RIPMSG0(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: cannot open mapped file."); return 0L; }
// Map entire view of the file into the process memory space
lpMap = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (lpMap == NULL) { RIPMSG0(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: cannot map view of file."); goto cleanup; // I wish if I could use C++...
}
pHeader = (IMEMENU_HEADER*)lpMap;
///////////////////
// Version check
///////////////////
if (pHeader->dwVersion != 1) { RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: dwVersion(%d) does not match.", pHeader->dwVersion); goto cleanup; }
//////////////////////////////
// convert offset to pointer
offset = (ULONG_PTR)pHeader; CONVTO_PTR(pHeader->lpImeParentMenu); CHK_PTR(pHeader->lpImeParentMenu); pMenu = CONVTO_PTR(pHeader->lpImeMenu); CHK_PTR(pHeader->lpImeMenu); if (pHeader->dwSize) { UserAssert(pHeader->lpImeMenu); // if dwSize is specified, we need real buffer here
lpBuf = ImmLocalAlloc(HEAP_ZERO_MEMORY, pHeader->dwSize * sizeof(IMEMENUITEMINFOW)); if (lpBuf == NULL) { RIPMSG0(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: not enough memory for receiver's buffer."); goto cleanup; } }
// preparation
#if DBG
if (pHeader->lpImeParentMenu) { UserAssert(!pHeader->lpImeParentMenu->lpBmpChecked && !pHeader->lpImeParentMenu->lpBmpUnchecked && !pHeader->lpImeParentMenu->lpBmpItem); } #endif
//////////////////////////////////
// Get IME menus
pHeader->dwSize = ImmGetImeMenuItemsW(hImc, pHeader->dwFlags, pHeader->dwType, (LPIMEMENUITEMINFOW)pHeader->lpImeParentMenu, lpBuf, pHeader->dwSize * sizeof(IMEMENUITEMINFOW)); // now, pHeader->dwSize contains number of menu items rather than byte size
if (pHeader->dwSize == 0) { goto cleanup; } //////////////////////////////////
//
// Copy back the information
//
// if lpBuf != NULL, we need to copy back information
//
if (lpBuf) { LPIMEMENUITEMINFO lpMenuW = lpBuf;
pHeader->lpBmp = NULL; // lpBmpNext will point first possible memory for bmp de-compile
pHeader->lpBmpNext = (LPVOID)((LPBYTE)pHeader + (pHeader->dwSize + 1) * sizeof(IMEMENUITEMINFOW));
// copy menuinfo
for (i = 0; i < pHeader->dwSize; ++i, ++pMenu, ++lpMenuW) { RtlCopyMemory(pMenu, lpMenuW, sizeof *lpMenuW); // decompile hbitmap
if (lpMenuW->hbmpChecked) { if ((pMenu->lpBmpChecked = DecompileBitmap(pHeader, lpMenuW->hbmpChecked)) == NULL) { RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: DecompileBitmap Failed in L%d", __LINE__); goto cleanup; } } if (lpMenuW->hbmpUnchecked) { if ((pMenu->lpBmpUnchecked = DecompileBitmap(pHeader, lpMenuW->hbmpUnchecked)) == NULL) { RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: DecompileBitmap Failed in L%d", __LINE__); goto cleanup; } } if (lpMenuW->hbmpItem) { if ((pMenu->lpBmpItem = DecompileBitmap(pHeader, lpMenuW->hbmpItem)) == NULL) { RIPMSG1(RIP_WARNING, "ImmPutImeMenuItemsIntoMappedFile: DecompileBitmap Failed in L%d", __LINE__); goto cleanup; } } }
//////////////////////////////////////////////////////////////////////
//
// convert pointer to offset
//
pMenu = pHeader->lpImeMenu; CONVTO_OFFSET(pHeader->lpImeMenu); // no need to convert parent menu, so let it be NULL
D(pHeader->lpImeParentMenu = NULL);
// pointer to BITMAP_HEADER in each menu
for (i = 0; i < pHeader->dwSize; ++i, ++pMenu) { TRACE(("ImmPutImeMenuItemsIntoMappedFile: convertiong '%S'\n", pMenu->szString)); CONVTO_OFFSET(pMenu->lpBmpChecked); CONVTO_OFFSET(pMenu->lpBmpUnchecked); TRACE(("ImmPutImeMenuItemsIntoMappedFile: before conversion (%#lx)\n", pMenu->lpBmpItem)); CONVTO_OFFSET(pMenu->lpBmpItem); TRACE(("ImmPutImeMenuItemsIntoMappedFile: after conversion (%#lx)\n", pMenu->lpBmpItem));
// check them
CHK_OFFSET(pMenu->lpBmpChecked); CHK_OFFSET(pMenu->lpBmpChecked); CHK_OFFSET(pMenu->lpBmpItem); }
//
// first pointer to BITMAP_HEADER linked list
//
pBmp = pHeader->lpBmp; CONVTO_OFFSET(pHeader->lpBmp); CHK_OFFSET(pHeader->lpBmp); // pHeader->lpBmpNext will not be used, so let it be NULL
D(pHeader->lpBmpNext = NULL);
//
// pointers in BITMAP_HEADER linked list
//
while (pBmp) { IMEMENU_BMP_HEADER* ptBmp = pBmp->lpNext; CONVTO_OFFSET(pBmp->pBits); CONVTO_OFFSET(pBmp->lpNext); CHK_OFFSET(pBmp->lpNext); pBmp = ptBmp; } //
// pointer conversion finished
//
//////////////////////////////////////////////////////////////////////
} // end if (lpBuf)
//
// everything went OK
//
lRet = 1;
cleanup: if (lpBuf) ImmLocalFree(lpBuf); if (lpMap) UnmapViewOfFile(lpMap); if (hMap) CloseHandle(hMap); return lRet; }
//////////////////////////////////////////////////////////////////////////////
// InternalImeMenuCreateBitmap()
//
// create bitmap from IMEMENU_BMP_HEADER
//////////////////////////////////////////////////////////////////////////////
HBITMAP InternalImeMenuCreateBitmap(IMEMENU_BMP_HEADER* lpBH) { HDC hDC;
if (lpBH == NULL) { RIPMSG1(RIP_WARNING, "InternalImeMenuCreateBitmap: lpBH == NULL in L%d", __LINE__); return NULL; } if (lpBH->pBits == NULL) { RIPMSG1(RIP_WARNING, "InternalImeMenuCreateBitmap: lpBH->pBits == NULL in L%d", __LINE__); return NULL; }
if (lpBH->hBitmap) { TRACE(("InternalImeMenuCreateBitmap: lpBH->hBitmap != NULL. will return it.\n")); return lpBH->hBitmap; }
if (hDC = GetDC(GetDesktopWindow())) { HDC hMyDC = CreateCompatibleDC(hDC); if (hMyDC) { // (select palette) needed ?
lpBH->hBitmap = CreateDIBitmap(hDC, &lpBH->bmi.bmiHeader, CBM_INIT, lpBH->pBits, &lpBH->bmi, DIB_RGB_COLORS); if (lpBH->hBitmap == NULL) { DWORD dwErr = GetLastError(); RIPMSG1(RIP_WARNING, "InternalImeMenuCreateBitmap: CreateDIBitmap Failed. Last error=%#x\n", dwErr); } DeleteDC(hMyDC); } else { RIPMSG0(RIP_WARNING, "InternalImeMenuCreateBitmap: CreateCompatibleDC failed."); }
ReleaseDC(GetDesktopWindow(), hDC); } else { RIPMSG0(RIP_WARNING, "InternalImeMenuCreateBitmap: couldn't get Desktop DC."); } return lpBH->hBitmap; }
//////////////////////////////////////////////////////////////////////////////
// ImmGetImeMenuItemsInterProcess()
//
// Inter process IME Menu handler
// sends WM_IME_SYSTEM:IMS_GETIMEMENU
//
// History:
// 23-Mar-1997 HiroYama Created
//////////////////////////////////////////////////////////////////////////////
DWORD ImmGetImeMenuItemsInterProcess(HIMC hImc, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpParentMenu, LPIMEMENUITEMINFOW lpMenu, DWORD dwSize) { HWND hwnd; HANDLE hMemFile = NULL; DWORD dwRet = 0; LPBYTE lpMap = NULL; IMEMENU_HEADER* pHeader; IMEMENU_ITEM* pMenuItem; IMEMENU_BMP_HEADER* pBmpHeader; DWORD i; ULONG_PTR offset;
// Get default IME window
//
// Note: We do not consider user created HIMC here, because this inter-process call is intended to
// support only internat.exe, and this message is passed as just a kick to IMM's def WinProc.
hwnd = (HWND)NtUserQueryInputContext(hImc, InputContextDefaultImeWindow); if (hwnd == NULL || !IsWindow(hwnd)) { RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: hwnd(%lx) is not a valid window.", hwnd); return 0; }
RtlEnterCriticalSection(&gcsImeDpi);
// first, create memory mapped file
hMemFile = CreateFileMapping((HANDLE)~0, NULL, PAGE_READWRITE, 0, IME_MENU_MAXMEM, IME_MENU_FILE_NAME); if (hMemFile == NULL) { RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: cannot allocate memory mapped file."); goto cleanup; } // then get a view of the mapped file
lpMap = (LPBYTE)MapViewOfFile(hMemFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); if (lpMap == NULL) { RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: cannot map view of memory mapped file."); goto cleanup; }
//
// shared buffer (memory mapped file) initialization
//
pHeader = (IMEMENU_HEADER*)lpMap; RtlZeroMemory(pHeader, sizeof *pHeader); pHeader->dwVersion = 1; pHeader->dwMemSize = IME_MENU_MAXMEM; pHeader->dwSize = dwSize / sizeof(IMEMENUITEMINFOW); // CAUTION: dwSize could be 0.
RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsInterProcess: pHeader->dwSize=%ld", pHeader->dwSize); pHeader->dwFlags = dwFlags; pHeader->dwType = dwType;
//
// 1) dwSize != 0 and lpMenu != NULL means, caller requests the given buffer filled
// 2) if lpParentMenu is passed, we need to put its information in shared buffer
//
if ((dwSize && lpMenu) || lpParentMenu) { // if parent menu is specified, copy it here
if (lpParentMenu) { IMEMENU_ITEM* pPMenu = pHeader->lpImeParentMenu = (IMEMENU_ITEM*)&pHeader[1];
RtlCopyMemory(pPMenu, lpParentMenu, sizeof(IMEMENUITEMINFOW));
// by design, IME will receive NULL hbmpItem in parent menu.
// there is no way to guarantee the same hbmpItem is returned, thus NULL is passed.
pPMenu->lpBmpChecked = pPMenu->lpBmpUnchecked = pPMenu->lpBmpItem = NULL; pHeader->lpImeMenu = pHeader->lpImeParentMenu + 1; } else { pHeader->lpImeParentMenu = NULL; pHeader->lpImeMenu = (LPVOID)&pHeader[1]; } // convert pointer to offset
offset = (ULONG_PTR)lpMap; CONVTO_OFFSET(pHeader->lpImeParentMenu); CONVTO_OFFSET(pHeader->lpImeMenu); }
///////////////////////////////////////////////////////////////////////
if (!SendMessage(hwnd, WM_IME_SYSTEM, IMS_GETIMEMENU, (LPARAM)hImc)) { // if it fails
goto cleanup; } ///////////////////////////////////////////////////////////////////////
// NOTE: dwSize is maximum index of menu array. not a total byte size of array.
dwSize = pHeader->dwSize;
if (lpMenu) { ///////////////////////////////
// convert offset to pointer
///////////////////////////////
pMenuItem = CONVTO_PTR(pHeader->lpImeMenu); CHK_PTR(pMenuItem); // NOTE: we don't have to handle parent menu
//
// pointers to BITMAP_HEADER in each menu structure
//
for (i = 0; i < dwSize; ++i, ++pMenuItem) { CONVTO_PTR(pMenuItem->lpBmpChecked); CONVTO_PTR(pMenuItem->lpBmpUnchecked); CONVTO_PTR(pMenuItem->lpBmpItem); //
// check the pointers
//
CHK_PTR(pMenuItem->lpBmpChecked); CHK_PTR(pMenuItem->lpBmpUnchecked); CHK_PTR(pMenuItem->lpBmpItem); }
//
// pointer to first BITMAP_HEADER
//
pBmpHeader = CONVTO_PTR(pHeader->lpBmp);
//
// each BITMAP_HEADER
//
while (pBmpHeader) { pBmpHeader->hBitmap = NULL; // clear
// pBits
CONVTO_PTR(pBmpHeader->pBits); CHK_PTR(pBmpHeader->pBits);
// next BITMAP_HEADER
pBmpHeader = CONVTO_PTR(pBmpHeader->lpNext); CHK_PTR(pBmpHeader); }
//
// copy back the results
//
pMenuItem = pHeader->lpImeMenu; for (i = 0; i < dwSize; ++i, ++pMenuItem, ++lpMenu) { lpMenu->cbSize = pMenuItem->cbSize; lpMenu->fType = pMenuItem->fType; lpMenu->fState = pMenuItem->fState; lpMenu->wID = pMenuItem->wID; lpMenu->dwItemData = pMenuItem->dwItemData; wcsncpy(lpMenu->szString, pMenuItem->szString, ARRAY_SIZE(lpMenu->szString));
// Create bitmap from memory buffer
// hbmp will be NULL if no bmp is specified.
if (pMenuItem->lpBmpChecked) { lpMenu->hbmpChecked = InternalImeMenuCreateBitmap(pMenuItem->lpBmpChecked); } else { lpMenu->hbmpChecked = NULL; } if (pMenuItem->lpBmpUnchecked) { lpMenu->hbmpUnchecked = InternalImeMenuCreateBitmap(pMenuItem->lpBmpUnchecked); } else { lpMenu->hbmpUnchecked = NULL; } if (pMenuItem->lpBmpItem) { lpMenu->hbmpItem = InternalImeMenuCreateBitmap(pMenuItem->lpBmpItem); } else { lpMenu->hbmpItem = NULL; } } }
cleanup: if (lpMap) { UnmapViewOfFile(lpMap); } RtlLeaveCriticalSection(&gcsImeDpi); // destroy memory mapped file
if (hMemFile) { CloseHandle(hMemFile); }
return dwSize; }
//////////////////////////////////////////////////////////////////////////////
// ImmGetImeMenuItemsWorker()
//
// Handler of IME Menu
//
// if specified HIMC belongs to other process, it calls
// ImmGetImeMenuItemsInterProcess()
//
// History:
// 23-Mar-1997 HiroYama Created
//////////////////////////////////////////////////////////////////////////////
DWORD ImmGetImeMenuItemsWorker(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu, LPVOID lpImeMenu, DWORD dwSize, BOOL bAnsiOrigin) { BOOL bAnsiIme = IsAnsiIMC(hIMC); DWORD dwRet = 0; LPINPUTCONTEXT lpInputContext; DWORD dwThreadId; PIMEDPI pImeDpi = NULL; LPVOID lpImePTemp = lpImeParentMenu; // keeps parent menu
LPVOID lpImeTemp = lpImeMenu; // points menu buffer
IMEMENUITEMINFOA imiiParentA; IMEMENUITEMINFOW imiiParentW;
//
// check if the call will be inter process
//
{ DWORD dwProcessId = GetInputContextProcess(hIMC); if (dwProcessId == 0) { RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: dwProcessId == 0"); return 0; } if (dwProcessId != GetCurrentProcessId()) { //
// going to call another process' IME
//
TRACE(("ImmGetImeMenuItemsWorker: Inter process.\n")); if (bAnsiOrigin) { //
// this inter-process thing is only allowed to internat.exe or equivalent
//
RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: interprocess getmenu is not allowed for ANSI caller."); return 0; } return ImmGetImeMenuItemsInterProcess(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize); } }
//
// within process
//
if (hIMC == NULL || (lpInputContext = ImmLockIMC(hIMC)) == NULL) { RIPMSG2(RIP_WARNING, "ImmGetImeMenuItemsWorker: illegal hIMC(%#lx) in L%d", hIMC, __LINE__); return 0; }
dwThreadId = GetInputContextThread(hIMC); if (dwThreadId == 0) { RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsWorker: dwThreadId = 0 in L%d", __LINE__); goto cleanup; } if ((pImeDpi = ImmLockImeDpi(GetKeyboardLayout(dwThreadId))) == NULL) { RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemWorker: pImeDpi == NULL in L%d.", __LINE__); goto cleanup; }
#if 0 // NT: we don't keep version info in ImeDpi
if (pImeDpi->dwWinVersion <= IMEVER_0310) { RIPMSG1(RIP_WARNING, "GetImeMenuItems: OldIME does not support this. %lx", hIMC); goto cleanup; } #endif
//
// if IME does not support IME Menu, do nothing
//
if (pImeDpi->pfn.ImeGetImeMenuItems) { LPVOID lpNewBuf = NULL;
TRACE(("ImmGetImeMenuItemsWorker: IME has menu callback.\n"));
if (bAnsiIme != bAnsiOrigin) { //
// we need A/W translation before calling IME
//
if (bAnsiOrigin) { // ANSI API and UNICODE IME.
// A to W conversion needed here
if (lpImeParentMenu) { // parent menu is specified. need conversion
lpImePTemp = (LPVOID)&imiiParentW; if (! ConvertImeMenuItemInfoAtoW((LPIMEMENUITEMINFOA)lpImeParentMenu, (LPIMEMENUITEMINFOW)lpImePTemp, CP_ACP, TRUE)) { // ANSI app, UNICODE IME: let's use CP_ACP
goto cleanup; } } if (lpImeMenu) { // allocate memory block for temporary storage
DWORD dwNumBuffer = dwSize / sizeof(IMEMENUITEMINFOA); dwSize = dwNumBuffer * sizeof(IMEMENUITEMINFOW); if (dwSize == 0) { RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: (AtoW) dwSize is 0."); goto cleanup; } lpImeTemp = lpNewBuf = ImmLocalAlloc(0, dwSize); TRACE(("ImmGetImeMenuItemsWorker: for UNICODE IME memory allocated %d bytes. lpNewBuf=%#x\n", dwSize, lpNewBuf)); if (lpNewBuf == NULL) { RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsWorker: cannot alloc lpNewBuf in L%d", __LINE__); goto cleanup; } } } else { // UNICODE API and ANSI IME.
// W to A conversion needed here
if (lpImeParentMenu) { // parent menu is speicified. need conversion
lpImePTemp = (LPVOID)&imiiParentA; if (! ConvertImeMenuItemInfoWtoA((LPIMEMENUITEMINFOW)lpImeParentMenu, (LPIMEMENUITEMINFOA)lpImePTemp, pImeDpi->dwCodePage)) { // Note: hopefully in the future, this can be changed to IMECodePage(pImeDpi)
goto cleanup; } } if (lpImeMenu) { // allocate memory block for temporary storage
DWORD dwNumBuffer = dwSize / sizeof(IMEMENUITEMINFOW); dwSize = dwNumBuffer / sizeof(IMEMENUITEMINFOA); if (dwSize == 0) { RIPMSG0(RIP_WARNING, "ImmGetImeMenuItemsWorker: (WtoA) dwSize is 0."); goto cleanup; } lpImeTemp = lpNewBuf = ImmLocalAlloc(0, dwSize); RIPMSG2(RIP_WARNING, "ImmGetImeMenuItemsWorker: for ANSI IME memory allocated %d bytes. lpNewBuf=%#x", dwSize, lpNewBuf); if (lpNewBuf == NULL) { RIPMSG1(RIP_WARNING, "ImmGetImeMenuItemsWorker: cannot alloc lpNewBuf in L%d", __LINE__); goto cleanup; } } } }
////////////////////////////////////////
dwRet = pImeDpi->pfn.ImeGetImeMenuItems(hIMC, dwFlags, dwType, lpImePTemp, lpImeTemp, dwSize); ////////////////////////////////////////
//
// back-conversion needed if:
// 1) IME returns menus, and
// 2) A/W is different between caller and IME, and
// 3) caller wants the buffer to be filled
//
if (dwRet && bAnsiIme != bAnsiOrigin && lpImeTemp) { if (bAnsiOrigin) { // ANSI API and UNICODE IME.
// W to A conversion needed here
LPIMEMENUITEMINFOW lpW = (LPIMEMENUITEMINFOW)lpImeTemp; LPIMEMENUITEMINFOA lpA = (LPIMEMENUITEMINFOA)lpImeMenu; DWORD i;
for (i = 0; i < dwRet; ++i) { if (! ConvertImeMenuItemInfoWtoA((LPIMEMENUITEMINFOW)lpW++, (LPIMEMENUITEMINFOA)lpA++, CP_ACP)) { // ANSI app and UNICODE IME: let's use CP_ACP
dwRet = 0; break; } } } else { // UNICODE API and ANSI IME.
// A to W conversion needed here
LPIMEMENUITEMINFOA lpA = (LPIMEMENUITEMINFOA)lpImeTemp; LPIMEMENUITEMINFOW lpW = (LPIMEMENUITEMINFOW)lpImeMenu; DWORD i;
for (i = 0; i < dwSize; i++) { if (! ConvertImeMenuItemInfoAtoW((LPIMEMENUITEMINFOA)lpA++, (LPIMEMENUITEMINFOW)lpW++, pImeDpi->dwCodePage, // Note: hopefully in the future, this can be changed to IMECodePage(pImeDpi)
TRUE)) { // copy hbitmap also
dwRet = 0; break; } } } }
// free temporary buffer if we've allocated it
if (lpNewBuf) ImmLocalFree(lpNewBuf); } // end if IME has menu callback
cleanup: if (pImeDpi) { ImmUnlockImeDpi(pImeDpi); }
if (hIMC != NULL) { ImmUnlockIMC(hIMC); }
return dwRet; }
DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize) { return ImmGetImeMenuItemsWorker(hIMC, dwFlags, dwType, (LPVOID)lpImeParentMenu, (LPVOID)lpImeMenu, dwSize, TRUE /* ANSI origin */); }
DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize) { return ImmGetImeMenuItemsWorker(hIMC, dwFlags, dwType, (LPVOID)lpImeParentMenu, (LPVOID)lpImeMenu, dwSize, FALSE /* UNICODE origin */); }
|