Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

908 lines
23 KiB

/**************************************************************************\
* Module Name: layout.c (corresponds to Win95 ime.c)
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* IME Keyboard Layout related functionality
*
* History:
* 03-Jan-1996 wkwok Created
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Local Defines.
*/
#define szLZOpenFileW "LZOpenFileW"
#define szLZCopy "LZCopy"
#define szLZClose "LZClose"
typedef HFILE (WINAPI *LPFNLZOPENFILEW)(LPTSTR, LPOFSTRUCT, WORD);
typedef LONG (WINAPI *LPFNLZCOPY)(INT, INT);
typedef VOID (WINAPI *LPFNLZCLOSE)(INT);
/*
* Local Routines.
*/
UINT StrToUInt(LPWSTR);
VOID UIntToStr(UINT, ULONG, LPWSTR, USHORT);
BOOL CopyImeFile(LPWSTR, LPCWSTR);
INT GetImeLayout(PIMELAYOUT, INT);
BOOL WriteImeLayout(HKL, LPCWSTR, LPCWSTR);
HKL AssignNewLayout(INT, PIMELAYOUT, HKL);
/***************************************************************************\
* ImmGetIMEFileNameW
*
* Gets the description of the IME with the specified HKL.
*
* History:
* 28-Feb-1995 wkwok Created
\***************************************************************************/
UINT WINAPI ImmGetDescriptionW(
HKL hKL,
LPWSTR lpwszDescription,
UINT uBufLen)
{
IMEINFOEX iiex;
UINT uRet;
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return 0;
#if defined(CUAS_ENABLE)
if (!IS_IME_KBDLAYOUT(hKL))
return 0;
#endif
uRet = wcslen(iiex.wszImeDescription);
/*
* ask buffer length
*/
if (uBufLen == 0)
return uRet;
if (uBufLen > uRet) {
wcscpy(lpwszDescription, iiex.wszImeDescription);
}
else {
uRet = uBufLen - 1;
wcsncpy(lpwszDescription, iiex.wszImeDescription, uRet);
lpwszDescription[uRet] = L'\0';
}
return uRet;
}
/***************************************************************************\
* ImmGetIMEFileNameA
*
* Gets the description of the IME with the specified HKL.
*
* History:
* 28-Feb-1995 wkwok Created
\***************************************************************************/
UINT WINAPI ImmGetDescriptionA(
HKL hKL,
LPSTR lpszDescription,
UINT uBufLen)
{
IMEINFOEX iiex;
INT i;
BOOL bUDC;
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return 0;
#if defined(CUAS_ENABLE)
if (!IS_IME_KBDLAYOUT(hKL))
return 0;
#endif
i = WideCharToMultiByte(CP_ACP,
(DWORD)0,
(LPWSTR)iiex.wszImeDescription, // src
wcslen(iiex.wszImeDescription),
lpszDescription, // dest
uBufLen,
(LPSTR)NULL,
(LPBOOL)&bUDC);
if (uBufLen != 0)
lpszDescription[i] = '\0';
return (UINT)i;
}
/***************************************************************************\
* ImmGetIMEFileNameW
*
* Gets the file name of the IME with the specified HKL.
*
* History:
* 28-Feb-1995 wkwok Created
\***************************************************************************/
UINT WINAPI ImmGetIMEFileNameW(
HKL hKL,
LPWSTR lpwszFile,
UINT uBufLen)
{
IMEINFOEX iiex;
UINT uRet;
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return 0;
#if defined(CUAS_ENABLE)
if (!IS_IME_KBDLAYOUT(hKL))
{
//
// #602631
//
// Ichitaro12 ATOKLIB.DLL does not check the return value of
// ImmGetIMEFileName()
//
if (uBufLen)
*lpwszFile = L'\0';
return 0;
}
#endif
uRet = wcslen(iiex.wszImeFile);
/*
* ask buffer length
*/
if (uBufLen == 0)
return uRet;
if (uBufLen > uRet) {
wcscpy(lpwszFile, iiex.wszImeFile);
}
else {
uRet = uBufLen - 1;
wcsncpy(lpwszFile, iiex.wszImeFile, uRet);
lpwszFile[uRet] = L'\0';
}
return uRet;
}
/***************************************************************************\
* ImmGetIMEFileNameA
*
* Gets the file name of the IME with the specified HKL.
*
* History:
* 28-Feb-1995 wkwok Created
\***************************************************************************/
UINT WINAPI ImmGetIMEFileNameA(
HKL hKL,
LPSTR lpszFile,
UINT uBufLen)
{
IMEINFOEX iiex;
INT i;
BOOL bUDC;
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return 0;
#if defined(CUAS_ENABLE)
if (!IS_IME_KBDLAYOUT(hKL))
{
//
// #602631
//
// Ichitaro12 ATOKLIB.DLL does not check the return value of
// ImmGetIMEFileName()
//
if (uBufLen)
*lpszFile = '\0';
return 0;
}
#endif
i = WideCharToMultiByte(CP_ACP,
(DWORD)0,
(LPWSTR)iiex.wszImeFile, // src
wcslen(iiex.wszImeFile),
lpszFile, // dest
uBufLen,
(LPSTR)NULL,
(LPBOOL)&bUDC);
if (uBufLen != 0)
lpszFile[i] = '\0';
return i;
}
/***************************************************************************\
* ImmGetProperty
*
* Gets the property and capability of the IME with the specified HKL.
*
* History:
* 28-Feb-1995 wkwok Created
\***************************************************************************/
DWORD WINAPI ImmGetProperty(
HKL hKL,
DWORD dwIndex)
{
IMEINFOEX iiex;
PIMEDPI pImeDpi = NULL;
PIMEINFO pImeInfo;
DWORD dwRet;
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return 0;
if (dwIndex == IGP_GETIMEVERSION)
return iiex.dwImeWinVersion;
if (iiex.fLoadFlag != IMEF_LOADED) {
pImeDpi = FindOrLoadImeDpi(hKL);
if (pImeDpi == NULL) {
RIPMSG0(RIP_WARNING, "ImmGetProperty: load IME failure.");
return 0;
}
pImeInfo = &pImeDpi->ImeInfo;
}
else {
pImeInfo = &iiex.ImeInfo;
}
switch (dwIndex) {
case IGP_PROPERTY:
dwRet = pImeInfo->fdwProperty;
break;
case IGP_CONVERSION:
dwRet = pImeInfo->fdwConversionCaps;
break;
case IGP_SENTENCE:
dwRet = pImeInfo->fdwSentenceCaps;
break;
case IGP_UI:
dwRet = pImeInfo->fdwUICaps;
break;
case IGP_SETCOMPSTR:
dwRet = pImeInfo->fdwSCSCaps;
break;
case IGP_SELECT:
dwRet = pImeInfo->fdwSelectCaps;
break;
default:
RIPMSG1(RIP_WARNING, "ImmGetProperty: wrong index %lx.", dwIndex);
dwRet = 0;
break;
}
ImmUnlockImeDpi(pImeDpi);
return dwRet;
}
HKL WINAPI ImmInstallIMEW(
LPCWSTR lpszIMEFileName,
LPCWSTR lpszLayoutText)
{
LPWSTR lpwszImeFileName;
LPWSTR lpwszImeFilePart;
LPWSTR lpwszImeCopiedPath;
int i, nIMEs;
PIMELAYOUT pImeLayout = NULL;
HKL hImeKL, hLangKL;
WCHAR szKeyName[HEX_ASCII_SIZE];
IMEINFOEX iiex;
lpwszImeFileName = ImmLocalAlloc(0, (MAX_PATH+1) * sizeof(WCHAR));
if (lpwszImeFileName == NULL)
return (HKL)0;
lpwszImeCopiedPath = ImmLocalAlloc(0, (MAX_PATH+1) * sizeof(WCHAR));
if (lpwszImeCopiedPath == NULL) {
ImmLocalFree(lpwszImeFileName);
return (HKL)0;
}
/*
* Get the file name only into lpwszImeFilePart
*/
GetFullPathNameW(lpszIMEFileName, MAX_PATH,
lpwszImeFileName, &lpwszImeFilePart);
CharUpper(lpwszImeFileName);
if (lpwszImeFilePart == NULL) {
ImmLocalFree(lpwszImeFileName);
ImmLocalFree(lpwszImeCopiedPath);
return (HKL)0;
}
hImeKL = hLangKL = iiex.hkl = (HKL)0;
wcsncpy(iiex.wszImeFile, lpwszImeFilePart, IM_FILE_SIZE-1);
iiex.wszImeFile[IM_FILE_SIZE - 1] = L'\0';
if (LoadVersionInfo(&iiex) && iiex.hkl != (HKL)0) {
hLangKL = iiex.hkl;
}
else {
ImmLocalFree(lpwszImeFileName);
ImmLocalFree(lpwszImeCopiedPath);
return (HKL)0;
}
nIMEs = GetImeLayout(NULL, 0);
if (nIMEs != 0) {
pImeLayout = (PIMELAYOUT)ImmLocalAlloc(0, nIMEs * sizeof(IMELAYOUT));
if (pImeLayout == NULL) {
ImmLocalFree(lpwszImeFileName);
ImmLocalFree(lpwszImeCopiedPath);
return (HKL)0;
}
GetImeLayout(pImeLayout, nIMEs);
for (i=0; i < nIMEs; i++) {
if (_wcsicmp(pImeLayout[i].szImeName, lpwszImeFilePart) == 0) {
/*
* We got the same IME name, ISV wants to upgrade.
*/
if (LOWORD(HandleToUlong(hLangKL)) != LOWORD(HandleToUlong(pImeLayout[i].hImeKL))) {
/*
* IME name conflict, blow out!
*/
RIPMSG0(RIP_WARNING, "ImmInstallIME: different language!");
goto ImmInstallIMEWFailed;
}
hImeKL = pImeLayout[i].hImeKL;
break;
}
}
}
if (ImmGetImeInfoEx(&iiex, ImeInfoExImeFileName, lpwszImeFilePart)) {
/*
* The specified IME has been activated. Unload it first.
*/
if (!UnloadKeyboardLayout(iiex.hkl)) {
hImeKL = (HKL)0;
goto ImmInstallIMEWFailed;
}
}
/*
* We will copy to system directory
*/
#if 0
i = (INT)GetSystemDirectory(lpwszImeCopiedPath, MAX_PATH);
lpwszImeCopiedPath[i] = L'\0';
AddBackslash(lpwszImeCopiedPath);
wcscat(lpwszImeCopiedPath, lpwszImeFilePart);
#else
GetSystemPathName(lpwszImeCopiedPath, lpwszImeFilePart, MAX_PATH);
#endif
CharUpper(lpwszImeCopiedPath);
if (_wcsicmp(lpwszImeFileName, lpwszImeCopiedPath) != 0) {
/*
* path is different, need to copy into system directory
*/
if (!CopyImeFile(lpwszImeFileName, lpwszImeCopiedPath)) {
hImeKL = (HKL)0;
goto ImmInstallIMEWFailed;
}
}
if (hImeKL == 0) {
hImeKL = AssignNewLayout(nIMEs, pImeLayout, hLangKL);
}
if (hImeKL != 0) {
/*
* Write HKL under "keyboard layouts"
*/
if (WriteImeLayout(hImeKL, lpwszImeFilePart, lpszLayoutText)) {
UIntToStr(HandleToUlong(hImeKL), 16, szKeyName, sizeof(szKeyName));
hImeKL = LoadKeyboardLayout(szKeyName, KLF_REPLACELANG);
}
else {
hImeKL = (HKL)0;
}
}
ImmInstallIMEWFailed:
if (pImeLayout != NULL)
ImmLocalFree(pImeLayout);
ImmLocalFree(lpwszImeFileName);
ImmLocalFree(lpwszImeCopiedPath);
return (HKL)hImeKL;
}
HKL WINAPI ImmInstallIMEA(
LPCSTR lpszIMEFileName,
LPCSTR lpszLayoutText)
{
HKL hKL;
LPWSTR lpwszIMEFileName;
LPWSTR lpwszLayoutText;
DWORD cbIMEFileName;
DWORD cbLayoutText;
INT i;
cbIMEFileName = strlen(lpszIMEFileName) + sizeof(CHAR);
cbLayoutText = strlen(lpszLayoutText) + sizeof(CHAR);
lpwszIMEFileName = ImmLocalAlloc(0, cbIMEFileName * sizeof(WCHAR));
if (lpwszIMEFileName == NULL) {
RIPMSG0(RIP_WARNING, "ImmInstallIMEA: memory failure!");
return (HKL)0;
}
lpwszLayoutText = ImmLocalAlloc(0, cbLayoutText * sizeof(WCHAR));
if (lpwszLayoutText == NULL) {
RIPMSG0(RIP_WARNING, "ImmInstallIMEA: memory failure!");
ImmLocalFree(lpwszIMEFileName);
return (HKL)0;
}
i = MultiByteToWideChar(CP_ACP,
(DWORD)MB_PRECOMPOSED,
(LPSTR)lpszIMEFileName, // src
(INT)strlen(lpszIMEFileName),
(LPWSTR)lpwszIMEFileName, // dest
(INT)cbIMEFileName);
lpwszIMEFileName[i] = L'\0';
i = MultiByteToWideChar(CP_ACP,
(DWORD)MB_PRECOMPOSED,
(LPSTR)lpszLayoutText, // src
(INT)strlen(lpszLayoutText),
(LPWSTR)lpwszLayoutText, // dest
(INT)cbLayoutText);
lpwszLayoutText[i] = L'\0';
hKL = ImmInstallIMEW(lpwszIMEFileName, lpwszLayoutText);
ImmLocalFree(lpwszLayoutText);
ImmLocalFree(lpwszIMEFileName);
return hKL;
}
/***************************************************************************\
* ImmIsIME
*
* Checks whether the specified hKL is a HKL of an IME or not.
*
* History:
* 28-Feb-1995 wkwok Created
\***************************************************************************/
BOOL WINAPI ImmIsIME(
HKL hKL)
{
IMEINFOEX iiex;
#if !defined(CUAS_ENABLE)
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return FALSE;
#else
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayoutWithCUAS, &hKL))
return FALSE;
#endif
return TRUE;
}
UINT StrToUInt(
LPWSTR lpsz)
{
UNICODE_STRING Value;
UINT ReturnValue;
Value.Length = wcslen(lpsz) * sizeof(WCHAR);
Value.Buffer = lpsz;
/*
* Convert string to int.
*/
RtlUnicodeStringToInteger(&Value, 16, &ReturnValue);
return(ReturnValue);
}
VOID UIntToStr(
UINT Value,
ULONG Base,
LPWSTR lpsz,
USHORT dwBufLen)
{
UNICODE_STRING String;
String.Length = dwBufLen;
String.MaximumLength = dwBufLen;
String.Buffer = lpsz;
/*
* Convert int to string.
*/
RtlIntegerToUnicodeString(Value, Base, &String);
}
BOOL CopyImeFile(
LPWSTR lpwszImeFileName,
LPCWSTR lpwszImeCopiedPath)
{
HMODULE hLzExpandDll;
BOOL fUnloadExpandDll;
LPFNLZOPENFILEW lpfnLZOpenFileW;
LPFNLZCOPY lpfnLZCopy;
LPFNLZCLOSE lpfnLZClose;
OFSTRUCT ofStruc;
HFILE hfSource, hfDest;
LPSTR lpszImeCopiedPath;
INT i, cbBuffer;
BOOL fRet = FALSE;
hLzExpandDll = GetModuleHandle(L"LZ32");
if (hLzExpandDll) {
fUnloadExpandDll = FALSE;
} else {
WCHAR szLzExpand[MAX_PATH];
GetSystemPathName(szLzExpand, L"LZ32", MAX_PATH);
hLzExpandDll = LoadLibrary(szLzExpand);
if (!hLzExpandDll) {
return FALSE;
}
fUnloadExpandDll = TRUE;
}
#define GET_PROC(x) \
if (!(lpfn##x = (PVOID) GetProcAddress(hLzExpandDll, sz##x))) { \
goto CopyImeFileFailed; }
GET_PROC(LZOpenFileW);
GET_PROC(LZCopy);
GET_PROC(LZClose);
#undef GET_PROC
cbBuffer = (wcslen(lpwszImeCopiedPath) + 1) * sizeof(WCHAR);
if ((lpszImeCopiedPath = ImmLocalAlloc(0, cbBuffer)) == NULL)
goto CopyImeFileFailed;
i = WideCharToMultiByte(CP_ACP,
(DWORD)0,
lpwszImeCopiedPath, // src
wcslen(lpwszImeCopiedPath),
lpszImeCopiedPath, // dest
cbBuffer,
(LPSTR)NULL,
(LPBOOL)NULL);
if (i == 0) {
ImmLocalFree(lpszImeCopiedPath);
goto CopyImeFileFailed;
}
lpszImeCopiedPath[i] = '\0';
hfSource = (*lpfnLZOpenFileW)(lpwszImeFileName, &ofStruc, OF_READ);
if (hfSource < 0) {
ImmLocalFree(lpszImeCopiedPath);
goto CopyImeFileFailed;
}
hfDest = OpenFile(lpszImeCopiedPath, &ofStruc, OF_CREATE);
if (hfDest != HFILE_ERROR) {
if ((*lpfnLZCopy)(hfSource, hfDest) >= 0) {
fRet = TRUE;
}
_lclose(hfDest);
}
(*lpfnLZClose)(hfSource);
ImmLocalFree(lpszImeCopiedPath);
CopyImeFileFailed:
if (fUnloadExpandDll)
FreeLibrary(hLzExpandDll);
return fRet;
}
INT GetImeLayout(
PIMELAYOUT pImeLayout,
INT cEntery)
{
int i, nIMEs;
HKEY hKeyKbdLayout;
HKEY hKeyOneIME;
WCHAR szKeyName[HEX_ASCII_SIZE];
WCHAR szImeFileName[IM_FILE_SIZE];
CONST DWORD dwKeyNameSize = ARRAY_SIZE(szKeyName);
DWORD dwTmp;
RegOpenKey(HKEY_LOCAL_MACHINE, gszRegKbdLayout, &hKeyKbdLayout);
for (i = 0, nIMEs = 0;
RegEnumKey(hKeyKbdLayout, i, szKeyName, dwKeyNameSize) == ERROR_SUCCESS;
i++)
{
if (szKeyName[0] != L'E' && szKeyName[0] != L'e')
continue; // this is not an IME based keyboard layout.
if (pImeLayout != NULL) {
if (nIMEs >= cEntery)
break;
RegOpenKey(hKeyKbdLayout, szKeyName, &hKeyOneIME);
dwTmp = IM_FILE_SIZE;
RegQueryValueEx(hKeyOneIME,
gszValImeFile,
NULL,
NULL,
(LPBYTE)szImeFileName,
&dwTmp);
// avoid length problem
szImeFileName[IM_FILE_SIZE - 1] = L'\0';
RegCloseKey(hKeyOneIME);
CharUpper(szImeFileName);
pImeLayout[nIMEs].hImeKL = (HKL)IntToPtr( StrToUInt(szKeyName) );
wcscpy(pImeLayout[nIMEs].szKeyName, szKeyName);
wcscpy(pImeLayout[nIMEs].szImeName, szImeFileName);
}
nIMEs++;
}
RegCloseKey(hKeyKbdLayout);
return nIMEs;
}
BOOL WriteImeLayout(
HKL hImeKL,
LPCWSTR lpwszImeFilePart,
LPCWSTR lpszLayoutText)
{
int i;
HKEY hKeyKbdLayout;
HKEY hKeyOneIME;
HKEY hKeyKbdOrder;
WCHAR szKeyName[HEX_ASCII_SIZE];
WCHAR szImeFileName[IM_FILE_SIZE];
WCHAR szOrderNum[HEX_ASCII_SIZE];
WCHAR szOrderKeyName[HEX_ASCII_SIZE];
DWORD dwTmp;
if (RegOpenKey(HKEY_LOCAL_MACHINE,
gszRegKbdLayout,
&hKeyKbdLayout) != ERROR_SUCCESS) {
RIPMSG0(RIP_WARNING, "WriteImeLayout: RegOpenKey() failed!");
return FALSE;
}
UIntToStr(HandleToUlong(hImeKL), 16, szKeyName, sizeof(szKeyName));
if (RegCreateKey(hKeyKbdLayout,
szKeyName,
&hKeyOneIME) != ERROR_SUCCESS) {
RIPMSG0(RIP_WARNING, "WriteImeLayout: RegCreateKey() failed!");
RegCloseKey(hKeyKbdLayout);
return FALSE;
}
if (RegSetValueExW(hKeyOneIME,
gszValImeFile,
0,
REG_SZ,
(CONST BYTE*)lpwszImeFilePart,
(wcslen(lpwszImeFilePart) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) {
goto WriteImeLayoutFail;
}
if (RegSetValueExW(hKeyOneIME,
gszValLayoutText,
0,
REG_SZ,
(CONST BYTE*)lpszLayoutText,
(wcslen(lpszLayoutText) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) {
goto WriteImeLayoutFail;
}
switch (LANGIDFROMHKL(hImeKL)) {
case LANG_JAPANESE:
wcscpy(szImeFileName, L"kbdjpn.dll");
break;
case LANG_KOREAN:
wcscpy(szImeFileName, L"kbdkor.dll");
break;
case LANG_CHINESE:
default:
wcscpy(szImeFileName, L"kbdus.dll");
break;
}
if (RegSetValueExW(hKeyOneIME,
gszValLayoutFile,
0,
REG_SZ,
(CONST BYTE*)szImeFileName,
(wcslen(szImeFileName) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) {
goto WriteImeLayoutFail;
}
RegCloseKey(hKeyOneIME);
RegCloseKey(hKeyKbdLayout);
/*
* Update CurrentUser's preload keyboard layout setting
*/
RegCreateKey(HKEY_CURRENT_USER, gszRegKbdOrder, &hKeyKbdOrder);
for (i = 1; i < 1024; i++) {
UIntToStr(i, 10, szOrderNum, sizeof(szOrderNum));
dwTmp = sizeof(szOrderKeyName);
if (RegQueryValueEx(hKeyKbdOrder,
szOrderNum,
NULL,
NULL,
(LPBYTE)szOrderKeyName,
&dwTmp) != ERROR_SUCCESS) {
break;
}
if (_wcsicmp(szKeyName, szOrderKeyName) == 0) {
/*
* We have the same value in the preload!
* OK, ISV is developing their IMEs
* so even it is in preload, but it can not be loaded
*/
break;
}
}
if (i < 1024) {
/*
* Write a subkey under "preload"
*/
RegSetValueExW(hKeyKbdOrder,
szOrderNum,
0,
REG_SZ,
(CONST BYTE*)szKeyName,
(lstrlen(szKeyName) + 1) * sizeof(WCHAR));
RegCloseKey(hKeyKbdOrder);
}
else {
RegCloseKey(hKeyKbdOrder);
return FALSE;
}
return TRUE;
WriteImeLayoutFail:
RegCloseKey(hKeyOneIME);
RegDeleteKey(hKeyKbdLayout, szKeyName);
RegCloseKey(hKeyKbdLayout);
return FALSE;
}
#define IMELANGID(hkl) \
LOWORD(HandleToUlong(hkl))
#define IMELAYOUTID(hkl) \
HIWORD(HandleToUlong(hkl))
HKL AssignNewLayout(
INT nIMEs,
PIMELAYOUT pImeLayout,
HKL hLangKL)
{
DWORD dwNewId = 0;
DWORD dwHighId = 0xE01F;
DWORD dwLowId = 0xE0FF;
INT i;
/*
* We prefer the value higher than E01F for ISVs, we will use
* E001 ~ E01F in Microsoft .INF file
*/
/*
* Find out the high and low one
*/
for (i = 0; i < nIMEs; ++i) {
/*
* Let's try to keep the previous behavior, not to
* have the duplicated hiword in hkl.
*/
if (IMELAYOUTID(pImeLayout[i].hImeKL) > dwHighId) {
dwHighId = IMELAYOUTID(pImeLayout[i].hImeKL);
}
if (IMELAYOUTID(pImeLayout[i].hImeKL) < dwLowId) {
dwLowId = IMELAYOUTID(pImeLayout[i].hImeKL);
}
}
if (dwHighId < 0xE0FF) {
dwNewId = dwHighId + 1;
} else if (dwLowId > 0xE001) {
dwNewId = dwLowId - 1;
} else {
/*
* Need to find out unused hKL using full search.
* Find it one by one.
*/
DWORD dwId;
for (dwId = 0xE020; dwId < 0xE100; ++dwId) {
for (i = 0; i < nIMEs; ++i) {
if (IMELAYOUTID(pImeLayout[i].hImeKL) == dwId &&
IMELANGID(pImeLayout[i].hImeKL) == IMELANGID(hLangKL)) {
// conflicts with existing IME, try the next dwLowId
break;
}
}
if (i >= nIMEs) {
break;
}
}
if (dwId < 0xE100) {
dwNewId = dwId;
}
}
if (dwNewId == 0) {
return NULL;
}
return (HKL)UIntToPtr(MAKELONG(IMELANGID(hLangKL), dwNewId));
}