Windows2000/private/shell/ext/internat/dll/imemenu.c
2020-09-30 17:12:32 +02:00

768 lines
14 KiB
C

/*++
Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
Module Name:
imemenu.c
Abstract:
This module implements the dll for handling the shell hooks for the
multilingual language indicator.
Revision History:
--*/
// Include Files.
#include "indicdll.h"
#include <immp.h>
// Constant Declarations.
// Max and Min number of MENUITEM in the shared heap.
#define MAX_IMITEMS 500
#define MIN_IMITEMS 200
// Typedef Definitions.
typedef struct s_MENULIST
{
struct s_MENULIST *pPrev;
struct s_MENULIST *pNext;
DWORD dwNum;
} MENULIST, *PMENULIST;
typedef struct s_MENUITEM
{
IMEMENUITEMINFO imii;
int nMenuID;
PMENULIST pmlSubMenu;
} MENUITEM, *PMENUITEM;
// On NT, unlike Win95/98, the heap cannot be used to share data among
// processes. Instead let IMM32 handle the inter-process GetImeMenu.
HANDLE g_hHeap; // shared heap
PMENULIST g_pMenuHdr; // header of pMenuList
int g_nMenuList; // number of pMenuList items
int g_nMenuCnt; // sequence number for IME menu items
// Macro Definitions.
#define GETMENUITEM(pMenu) ((PMENUITEM)((LPBYTE)pMenu + sizeof(MENULIST)))
// Function Prototypes.
PMENULIST
IndicDll_CreateIMEMenu(
HWND hWnd,
HIMC hIMC,
LPIMEMENUITEMINFO lpImeParentMenu,
BOOL fRight);
BOOL
IndicDll_BuildIMEMenuItems(
HMENU hMenu,
PMENULIST pMenu,
BOOL fRight);
// IndicDll_AddMenuList
// Inserts the new menu after the last one in the list.
BOOL IndicDll_AddMenuList(
PMENULIST pMenu)
{
PMENULIST pMenuPrev, pMenuNext;
// Create the header if it hasn't already been created.
if (!g_pMenuHdr)
{
g_pMenuHdr = (PMENULIST)HeapAlloc( g_hHeap, HEAP_ZERO_MEMORY, sizeof(MENULIST) );
if (!g_pMenuHdr)
{
return (FALSE);
}
g_pMenuHdr->pPrev = g_pMenuHdr;
g_pMenuHdr->pNext = g_pMenuHdr;
}
// Add the new item to the end of the list.
pMenuPrev = g_pMenuHdr->pPrev;
pMenuNext = pMenuPrev->pNext;
pMenu->pNext = pMenuPrev->pNext;
pMenu->pPrev = pMenuNext->pPrev;
pMenuPrev->pNext = pMenu;
pMenuNext->pPrev = pMenu;
// Increment the count of items.
g_nMenuList++;
// See if we're at the max number of items.
if (g_nMenuList > MAX_IMITEMS)
{
return (FALSE);
}
// Return success.
return (TRUE);
}
// IndicDll_DeleteMenuList
// Deletes the given menu from the list.
void IndicDll_DeleteMenuList(
PMENULIST pMenu)
{
PMENULIST pMenuPrev, pMenuNext;
// Make sure we're not deleting the header.
if (pMenu == g_pMenuHdr)
{
return;
}
// NT only:
// Since IMM32 has created a copy of the menu bitmaps, Internat is
// responsible for deleting the GDI objects here.
if (pMenu->dwNum)
{
DWORD dwI;
PMENUITEM pMenuItem;
pMenuItem = GETMENUITEM(pMenu);
for (dwI = 0; dwI < pMenu->dwNum; dwI++)
{
if (pMenuItem[dwI].imii.hbmpChecked)
{
DeleteObject(pMenuItem[dwI].imii.hbmpChecked);
}
if (pMenuItem[dwI].imii.hbmpUnchecked)
{
DeleteObject(pMenuItem[dwI].imii.hbmpUnchecked);
}
if (pMenuItem[dwI].imii.hbmpItem)
{
DeleteObject(pMenuItem[dwI].imii.hbmpItem);
}
}
}
// Delete the item from the list.
pMenuPrev = pMenu->pPrev;
pMenuNext = pMenu->pNext;
pMenuPrev->pNext = pMenu->pNext;
pMenuNext->pPrev = pMenu->pPrev;
// Decrement the count of items.
g_nMenuList--;
if (g_nMenuList < 0)
{
g_nMenuList = 0;
}
// Free the item from the heap.
HeapFree(g_hHeap, 0, pMenu);
}
// IndicDll_DeleteAllMenuList
// Deletes all menu list items and the frees them from the heap.
void IndicDll_DeleteAllMenuList()
{
PMENULIST pMenu, pMenuNext;
// Make sure the header exists and that there is something in the list.
if ((g_pMenuHdr) &&
(pMenu = g_pMenuHdr->pNext) &&
(pMenu != g_pMenuHdr))
{
// Delete each item from the list.
while (pMenu != g_pMenuHdr)
{
pMenuNext = pMenu->pNext;
IndicDll_DeleteMenuList(pMenu);
pMenu = pMenuNext;
}
// Make sure the number of items in the list is now set to zero.
// If not, set it to zero. (this shouldn't happen)
if (g_nMenuList > 0)
{
g_nMenuList = 0;
}
}
}
// IndicDll_AllocMenuList
PMENULIST IndicDll_AllocMenuList(
DWORD dwNum)
{
PMENULIST pMenu;
pMenu = (PMENULIST)HeapAlloc( g_hHeap, HEAP_ZERO_MEMORY, sizeof(MENULIST) + sizeof(MENUITEM) * dwNum );
if (pMenu)
{
IndicDll_AddMenuList(pMenu);
}
pMenu->dwNum = dwNum;
return (pMenu);
}
// IndicDll_SetMenuItem
void IndicDll_SetMenuItem(
HWND hWnd,
HIMC hIMC,
LPIMEMENUITEMINFO lpIme,
BOOL fRight,
PMENUITEM pMenuItem)
{
FillMemory((PVOID)pMenuItem, sizeof(MENUITEM), 0);
pMenuItem->imii = *lpIme;
if (lpIme->fType & IMFT_SUBMENU)
{
// If lpIme has a SubMenu, we need to create another MENULIST.
pMenuItem->pmlSubMenu = IndicDll_CreateIMEMenu( hWnd,
hIMC,
lpIme,
fRight );
}
pMenuItem->nMenuID = IDM_IME_MENUSTART + g_nMenuCnt;
}
// IndicDll_CreateIMEMenu
PMENULIST IndicDll_CreateIMEMenu(
HWND hWnd,
HIMC hIMC,
LPIMEMENUITEMINFO lpImeParentMenu,
BOOL fRight)
{
DWORD dwSize, dwNum, dwI;
LPIMEMENUITEMINFO lpImeMenu;
PMENULIST pMenu;
PMENUITEM pMenuItem;
dwNum = ImmGetImeMenuItems( hIMC,
fRight ? IGIMIF_RIGHTMENU : 0,
IGIMII_CMODE |
IGIMII_SMODE |
IGIMII_CONFIGURE |
IGIMII_TOOLS |
IGIMII_HELP |
IGIMII_OTHER,
lpImeParentMenu,
NULL,
0 );
if (!dwNum)
{
return (0);
}
pMenu = IndicDll_AllocMenuList(dwNum);
if (!pMenu)
{
return (0);
}
pMenuItem = GETMENUITEM(pMenu);
dwSize = dwNum * sizeof(IMEMENUITEMINFO);
lpImeMenu = (LPIMEMENUITEMINFO)GlobalAlloc(GPTR, dwSize);
if (!lpImeMenu)
{
return (0);
}
dwNum = ImmGetImeMenuItems( hIMC,
fRight ? IGIMIF_RIGHTMENU : 0,
IGIMII_CMODE |
IGIMII_SMODE |
IGIMII_CONFIGURE |
IGIMII_TOOLS |
IGIMII_HELP |
IGIMII_OTHER,
lpImeParentMenu,
lpImeMenu,
dwSize );
// Set up this MENULIST.
for (dwI = 0; dwI < dwNum; dwI++)
{
IndicDll_SetMenuItem( hWnd,
hIMC,
lpImeMenu + dwI,
fRight,
pMenuItem + dwI );
g_nMenuCnt++;
}
GlobalFree((HANDLE)lpImeMenu);
return (pMenu);
}
// IndicDll_GetIMEMenu
BOOL IndicDll_GetIMEMenu(
HWND hWnd,
BOOL fRight)
{
HIMC hIMC;
HWND hwndDefIme;
// Create shared heap space.
if (!g_hHeap)
{
g_hHeap = HeapCreate( 0x04000000, MIN_IMITEMS * sizeof(MENUITEM), MAX_IMITEMS * sizeof(MENUITEM) );
}
if (!g_hHeap)
{
return (FALSE);
}
// Since we're in a different process, hIMC cannot be retrieved
// directly from hWnd.
hwndDefIme = ImmGetDefaultIMEWnd(hWnd);
if (!IsWindow(hwndDefIme))
{
return (FALSE);
}
hIMC = (HIMC)SendMessage( hwndDefIme,
WM_IME_SYSTEM,
IMS_GETCONTEXT,
(LPARAM)hWnd );
if (hIMC != NULL)
{
// Init sequence number.
g_nMenuCnt = 0;
IndicDll_CreateIMEMenu(hWnd, hIMC, NULL, fRight);
}
return (TRUE);
}
// IndicDll_FillMenuItemInfo
void IndicDll_FillMenuItemInfo(
LPMENUITEMINFO lpmii,
PMENUITEM pMenuItem,
BOOL fRight)
{
FillMemory((PVOID)lpmii, sizeof(MENUITEMINFO), 0);
lpmii->cbSize = sizeof(MENUITEMINFO);
lpmii->fMask = 0;
if (pMenuItem->imii.fType)
{
lpmii->fMask |= MIIM_FTYPE;
lpmii->fType = 0;
if (pMenuItem->imii.fType & IMFT_RADIOCHECK)
{
lpmii->fType |= MFT_RADIOCHECK;
}
if (pMenuItem->imii.fType & IMFT_SEPARATOR)
{
lpmii->fType |= MFT_SEPARATOR;
}
}
lpmii->fMask |= MIIM_ID;
lpmii->wID = pMenuItem->nMenuID;
if (pMenuItem->imii.fType & IMFT_SUBMENU)
{
// If lpIme has a SubMenu, we need to create another Popup Menu.
lpmii->fMask |= MIIM_SUBMENU;
lpmii->hSubMenu = CreatePopupMenu();
IndicDll_BuildIMEMenuItems( lpmii->hSubMenu,
pMenuItem->pmlSubMenu,
fRight );
}
lpmii->fMask |= MIIM_STATE;
lpmii->fState = pMenuItem->imii.fState;
if ((pMenuItem->imii.hbmpChecked) && (pMenuItem->imii.hbmpUnchecked))
{
lpmii->fMask |= MIIM_CHECKMARKS;
lpmii->hbmpChecked = pMenuItem->imii.hbmpChecked;
lpmii->hbmpUnchecked = pMenuItem->imii.hbmpUnchecked;
}
lpmii->fMask |= MIIM_DATA;
lpmii->dwItemData = pMenuItem->imii.dwItemData;
if (pMenuItem->imii.hbmpItem)
{
lpmii->fMask |= MIIM_BITMAP;
lpmii->hbmpItem = pMenuItem->imii.hbmpItem;
}
if (lstrlen(pMenuItem->imii.szString))
{
lpmii->fMask |= MIIM_STRING;
lpmii->dwTypeData = pMenuItem->imii.szString;
lpmii->cch = lstrlen(pMenuItem->imii.szString);
}
}
// IndicDll_GetDefaultImeMenuItem
UINT IndicDll_GetDefaultImeMenuItem(void)
{
PMENULIST pMenu;
DWORD dwI;
MENUITEMINFO mii;
PMENUITEM pMenuItem;
if (!g_pMenuHdr)
return 0;
pMenu = g_pMenuHdr->pNext;
if (pMenu == g_pMenuHdr)
return 0;
if (!pMenu->dwNum)
return 0;
pMenuItem = GETMENUITEM(pMenu);
for (dwI = 0 ; dwI < pMenu->dwNum; dwI++)
{
if (pMenuItem->imii.fState & IMFS_DEFAULT)
return pMenuItem->imii.wID;
pMenuItem++;
}
return 0;
}
// IndicDll_BuildIMEMenuItems
BOOL IndicDll_BuildIMEMenuItems(
HMENU hMenu,
PMENULIST pMenu,
BOOL fRight)
{
DWORD dwI;
MENUITEMINFO mii;
PMENUITEM pMenuItem;
if (!pMenu->dwNum)
{
return (FALSE);
}
pMenuItem = GETMENUITEM(pMenu);
for (dwI = 0; dwI < pMenu->dwNum; dwI++)
{
IndicDll_FillMenuItemInfo(&mii, pMenuItem + dwI, fRight);
VERIFY(InsertMenuItem(hMenu, dwI, TRUE, &mii));
}
return TRUE;
}
// IndicDll_BuildIMEMenu
BOOL IndicDll_BuildIMEMenu(
HMENU hMenu,
BOOL fRight)
{
PMENULIST pMenu;
if (g_pMenuHdr == NULL) {
return FALSE;
}
pMenu = g_pMenuHdr->pNext;
if (pMenu == g_pMenuHdr) {
return FALSE;
}
return IndicDll_BuildIMEMenuItems(hMenu, pMenu, fRight);
}
// IndicDll_GetIMEMenuItemID
UINT IndicDll_GetIMEMenuItemID(
int nMenuID)
{
DWORD dwI;
PMENULIST pMenu, pMenuNext;
PMENUITEM pMenuItem;
UINT uRet = 0;
if ((g_pMenuHdr) &&
(pMenu = g_pMenuHdr->pNext) &&
(pMenu != g_pMenuHdr))
{
while (pMenu != g_pMenuHdr)
{
pMenuNext = pMenu->pNext;
pMenuItem = GETMENUITEM(pMenu);
for (dwI = 0; dwI < pMenu->dwNum; dwI++)
{
if (pMenuItem->nMenuID == nMenuID)
{
uRet = pMenuItem->imii.wID;
return (uRet);
}
pMenuItem++;
}
pMenu = pMenuNext;
}
}
return (uRet);
}
// IndicDll_SearchMenuItemData
DWORD IndicDll_SearchMenuItemData(
UINT uID)
{
DWORD dwI;
PMENULIST pMenu, pMenuNext;
PMENUITEM pMenuItem;
DWORD dwRet = 0;
if ((g_pMenuHdr) &&
(pMenu = g_pMenuHdr->pNext) &&
(pMenu != g_pMenuHdr))
{
while (pMenu != g_pMenuHdr)
{
pMenuNext = pMenu->pNext;
pMenuItem = GETMENUITEM(pMenu);
for (dwI = 0; dwI < pMenu->dwNum; dwI ++)
{
if (pMenuItem->imii.wID == uID)
{
dwRet = pMenuItem->imii.dwItemData;
return (dwRet);
}
pMenuItem++;
}
pMenu = pMenuNext;
}
}
ASSERT(FALSE);
return (0);
}
// IndicDll_GetIMEMenuItemData
// Called from user32 of target application.
void IndicDll_GetIMEMenuItemData(
UINT* puID,
DWORD* pdwMenuItemData)
{
ASSERT(puID);
ASSERT(pdwMenuItemData);
ASSERT(lpvSHDataHead);
*puID = lpvSHDataHead->uMenuID;
*pdwMenuItemData = lpvSHDataHead->dwMenuItemData;
}
// IndicDll_SetIMEMenuItemData
// Called from user32 of target application.
void IndicDll_SetIMEMenuItemData(
UINT uID)
{
ASSERT(lpvSHDataHead);
lpvSHDataHead->uMenuID = uID;
lpvSHDataHead->dwMenuItemData = IndicDll_SearchMenuItemData(uID);
}
// IndicDll_DestroyIMEMenu
void IndicDll_DestroyIMEMenu()
{
IndicDll_DeleteAllMenuList();
}