[IMM32] Rewrite ImmInstallIMEW (#4044)

- Add Imm32StrToUInt and Imm32UIntToStr helper functions.
- Add Imm32LoadImeVerInfo, Imm32GetRegImes, Imm32WriteRegIme, Imm32GetNextHKL, Imm32CopyFile helper functions.
- Add REG_IME structure for registered IMEs.
- Rewrite ImmInstallIMEW function.
- Improve ImmLoadLayout and Imm32LoadImeInfo functions.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2021-10-21 10:28:04 +09:00 committed by GitHub
parent d26409cc34
commit a37d9a4e14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 642 additions and 124 deletions

View file

@ -152,6 +152,7 @@ BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
WCHAR szPath[MAX_PATH];
HINSTANCE hIME;
FARPROC fn;
BOOL ret = FALSE;
if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
return FALSE;
@ -172,27 +173,46 @@ BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
do { \
fn = GetProcAddress(hIME, #name); \
if (fn) pImeDpi->name = (FN_##name)fn; \
else if (!(optional)) goto Failed; \
else if (!(optional)) { \
ERR("'%s' not found in the IME module '%s'.\n", #name, debugstr_w(szPath)); \
goto Failed; \
} \
} while (0);
#include "imetable.h"
#undef DEFINE_IME_ENTRY
if (!Imm32InquireIme(pImeDpi))
if (Imm32InquireIme(pImeDpi))
{
ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n");
goto Failed;
ret = TRUE;
}
else
{
ERR("Imm32InquireIme failed\n");
Failed:
ret = FALSE;
FreeLibrary(pImeDpi->hInst);
pImeDpi->hInst = NULL;
}
if (pImeInfoEx->fLoadFlag)
return TRUE;
if (pImeInfoEx->fLoadFlag == 0)
{
if (ret)
{
C_ASSERT(sizeof(pImeInfoEx->wszUIClass) == sizeof(pImeDpi->szUIClass));
pImeInfoEx->ImeInfo = pImeDpi->ImeInfo;
RtlCopyMemory(pImeInfoEx->wszUIClass, pImeDpi->szUIClass,
sizeof(pImeInfoEx->wszUIClass));
pImeInfoEx->fLoadFlag = 2;
}
else
{
pImeInfoEx->fLoadFlag = 1;
}
NtUserSetImeOwnerWindow(pImeInfoEx, TRUE);
return TRUE;
NtUserSetImeInfoEx(pImeInfoEx);
}
Failed:
FreeLibrary(pImeDpi->hInst);
pImeDpi->hInst = NULL;
return FALSE;
return ret;
}
PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock)
@ -475,6 +495,127 @@ Quit:
return ret;
}
/***********************************************************************
* ImmInstallIMEA (IMM32.@)
*/
HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
{
HKL hKL = NULL;
LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
if (!pszFileNameW)
goto Quit;
pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
if (!pszLayoutTextW)
goto Quit;
hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
Quit:
Imm32HeapFree(pszFileNameW);
Imm32HeapFree(pszLayoutTextW);
return hKL;
}
/***********************************************************************
* ImmInstallIMEW (IMM32.@)
*/
HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
{
WCHAR szImeFileName[MAX_PATH], szImeDestPath[MAX_PATH], szImeKey[20];
IMEINFOEX InfoEx;
LPWSTR pchFilePart;
UINT iLayout, cLayouts;
HKL hNewKL;
WORD wLangID;
PREG_IME pLayouts = NULL;
TRACE("(%s, %s)\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText));
GetFullPathNameW(lpszIMEFileName, _countof(szImeFileName), szImeFileName, &pchFilePart);
CharUpperW(szImeFileName);
if (!pchFilePart)
return NULL;
/* Load the IME version info */
InfoEx.hkl = hNewKL = NULL;
StringCchCopyW(InfoEx.wszImeFile, _countof(InfoEx.wszImeFile), pchFilePart);
if (Imm32LoadImeVerInfo(&InfoEx) && InfoEx.hkl)
wLangID = LOWORD(InfoEx.hkl);
else
return NULL;
/* Get the IME layouts from registry */
cLayouts = Imm32GetRegImes(NULL, 0);
if (cLayouts)
{
pLayouts = Imm32HeapAlloc(0, cLayouts * sizeof(REG_IME));
if (!pLayouts || !Imm32GetRegImes(pLayouts, cLayouts))
{
Imm32HeapFree(pLayouts);
return NULL;
}
for (iLayout = 0; iLayout < cLayouts; ++iLayout)
{
if (lstrcmpiW(pLayouts[iLayout].szFileName, pchFilePart) == 0)
{
if (wLangID != LOWORD(pLayouts[iLayout].hKL))
goto Quit; /* The language is different */
hNewKL = pLayouts[iLayout].hKL; /* Found */
break;
}
}
}
/* If the IME for the specified filename is valid, then unload it now */
/* FIXME: ImmGetImeInfoEx is broken */
if (ImmGetImeInfoEx(&InfoEx, 3, pchFilePart) &&
!UnloadKeyboardLayout(InfoEx.hkl))
{
hNewKL = NULL;
goto Quit;
}
Imm32GetSystemLibraryPath(szImeDestPath, _countof(szImeDestPath), pchFilePart);
CharUpperW(szImeDestPath);
/* If the source and the destination pathnames were different, then copy the IME file */
if (lstrcmpiW(szImeFileName, szImeDestPath) != 0 &&
!Imm32CopyFile(szImeFileName, szImeDestPath))
{
hNewKL = NULL;
goto Quit;
}
if (hNewKL == NULL)
hNewKL = Imm32GetNextHKL(cLayouts, pLayouts, wLangID);
if (hNewKL)
{
/* Write the IME layout to registry */
if (Imm32WriteRegIme(hNewKL, pchFilePart, lpszLayoutText))
{
/* Load the keyboard layout */
Imm32UIntToStr((DWORD)(DWORD_PTR)hNewKL, 16, szImeKey, _countof(szImeKey));
hNewKL = LoadKeyboardLayoutW(szImeKey, KLF_REPLACELANG);
}
else
{
hNewKL = NULL;
}
}
Quit:
Imm32HeapFree(pLayouts);
return hNewKL;
}
/***********************************************************************
* ImmIsIME (IMM32.@)
*/
@ -482,7 +623,8 @@ BOOL WINAPI ImmIsIME(HKL hKL)
{
IMEINFOEX info;
TRACE("(%p)\n", hKL);
return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL);
/* FIXME: ImmGetImeInfoEx is broken */
return !!ImmGetImeInfoEx(&info, 1, &hKL);
}
/***********************************************************************
@ -542,6 +684,7 @@ ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearch
BOOL bDisabled = FALSE;
HKL hKL;
/* FIXME: broken */
switch (SearchType)
{
case ImeInfoExKeyboardLayout:

View file

@ -51,54 +51,64 @@ BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
/***********************************************************************
* ImmLoadLayout (IMM32.@)
*/
HKL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
{
DWORD cbData;
UNICODE_STRING UnicodeString;
HKEY hLayoutKey = NULL, hLayoutsKey = NULL;
LONG error;
NTSTATUS Status;
WCHAR szLayout[MAX_PATH];
TRACE("(%p, %p)\n", hKL, pImeInfoEx);
if (IS_IME_HKL(hKL) || !Imm32IsCiceroMode() || Imm32Is16BitMode())
{
UnicodeString.Buffer = szLayout;
UnicodeString.MaximumLength = sizeof(szLayout);
Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString);
if (!NT_SUCCESS(Status))
return NULL;
Imm32UIntToStr((DWORD)(DWORD_PTR)hKL, 16, szLayout, _countof(szLayout));
error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey);
if (error)
return NULL;
{
ERR("RegOpenKeyW: 0x%08lX\n", error);
return FALSE;
}
error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey);
if (error)
{
ERR("RegOpenKeyW: 0x%08lX\n", error);
RegCloseKey(hLayoutsKey);
return FALSE;
}
}
else
{
error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey);
if (error)
{
ERR("RegOpenKeyW: 0x%08lX\n", error);
return FALSE;
}
}
if (error)
{
ERR("RegOpenKeyW error: 0x%08lX\n", error);
hKL = NULL;
}
else
{
cbData = sizeof(pImeInfoEx->wszImeFile);
error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0,
(LPBYTE)pImeInfoEx->wszImeFile, &cbData);
if (error)
hKL = NULL;
}
cbData = sizeof(pImeInfoEx->wszImeFile);
error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0,
(LPBYTE)pImeInfoEx->wszImeFile, &cbData);
pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = 0;
RegCloseKey(hLayoutKey);
if (hLayoutsKey)
RegCloseKey(hLayoutsKey);
return hKL;
pImeInfoEx->fLoadFlag = 0;
if (error)
{
ERR("RegQueryValueExW: 0x%08lX\n", error);
pImeInfoEx->hkl = NULL;
return FALSE;
}
pImeInfoEx->hkl = hKL;
return Imm32LoadImeVerInfo(pImeInfoEx);
}
/***********************************************************************
@ -476,10 +486,6 @@ BOOL WINAPI ImmActivateLayout(HKL hKL)
return TRUE;
}
static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
static VOID APIENTRY Imm32CiceroSetActiveContext(HIMC hIMC, BOOL fActive, HWND hWnd, HKL hKL)
{
FIXME("We have to do something\n");
@ -1015,89 +1021,6 @@ BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
return Imm32IsCiceroMode();
}
/***********************************************************************
* ImmInstallIMEA (IMM32.@)
*/
HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
{
HKL hKL = NULL;
LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
if (pszFileNameW == NULL)
goto Quit;
pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
if (pszLayoutTextW == NULL)
goto Quit;
hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
Quit:
Imm32HeapFree(pszFileNameW);
Imm32HeapFree(pszLayoutTextW);
return hKL;
}
/***********************************************************************
* ImmInstallIMEW (IMM32.@)
*/
HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
{
INT lcid = GetUserDefaultLCID();
INT count;
HKL hkl;
DWORD rc;
HKEY hkey;
WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
debugstr_w(lpszLayoutText));
/* Start with 2. e001 will be blank and so default to the wine internal IME */
count = 2;
while (count < 0xfff)
{
DWORD disposition = 0;
hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
break;
else if (rc == ERROR_SUCCESS)
RegCloseKey(hkey);
count++;
}
if (count == 0xfff)
{
WARN("Unable to find slot to install IME\n");
return 0;
}
if (rc == ERROR_SUCCESS)
{
rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
(lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
(lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
RegCloseKey(hkey);
return hkl;
}
else
{
WARN("Unable to set IME registry values\n");
return 0;
}
}
/***********************************************************************
* ImmLockIMC(IMM32.@)
*

View file

@ -24,6 +24,7 @@
#include <winnls.h>
#include <winreg.h>
#include <winnls32.h>
#include <winver.h>
#include <imm.h>
#include <ddk/imm.h>
@ -61,6 +62,13 @@
#define ROUNDUP4(n) (((n) + 3) & ~3) /* DWORD alignment */
typedef struct REG_IME
{
HKL hKL;
WCHAR szImeKey[20]; /* "E0XXYYYY": "E0XX" is the device handle. "YYYY" is a LANGID. */
WCHAR szFileName[80]; /* The IME module filename */
} REG_IME, *PREG_IME;
extern HMODULE g_hImm32Inst;
extern RTL_CRITICAL_SECTION g_csImeDpi;
extern PIMEDPI g_pImeDpiList;
@ -139,3 +147,11 @@ DWORD APIENTRY
Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage);
DWORD APIENTRY
Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage);
HRESULT APIENTRY Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase);
HRESULT APIENTRY Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff);
BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx);
UINT APIENTRY Imm32GetRegImes(PREG_IME pLayouts, UINT cLayouts);
BOOL APIENTRY Imm32WriteRegIme(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayout);
HKL APIENTRY Imm32GetNextHKL(UINT cKLs, const REG_IME *pLayouts, WORD wLangID);
BOOL APIENTRY Imm32CopyFile(LPWSTR pszOldFile, LPCWSTR pszNewFile);

View file

@ -16,6 +16,48 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm);
HANDLE g_hImm32Heap = NULL;
HRESULT APIENTRY
Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase)
{
#if 1
NTSTATUS Status;
UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, pszText);
Status = RtlUnicodeStringToInteger(&UnicodeString, nBase, pdwValue);
if (!NT_SUCCESS(Status))
return E_FAIL;
return S_OK;
#else
LPWSTR endptr;
*pdwValue = wcstoul(pszText, &endptr, nBase);
return (*endptr ? E_FAIL : S_OK);
#endif
}
HRESULT APIENTRY
Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff)
{
#if 1
NTSTATUS Status;
UNICODE_STRING UnicodeString;
UnicodeString.Buffer = pszBuff;
UnicodeString.MaximumLength = cchBuff * sizeof(WCHAR);
Status = RtlIntegerToUnicodeString(dwValue, nBase, &UnicodeString);
if (!NT_SUCCESS(Status))
return E_FAIL;
return S_OK;
#else
LPCWSTR pszFormat;
if (nBase == 16)
pszFormat = L"%lX";
else if (nBase == 10)
pszFormat = L"%lu";
else
return E_INVALIDARG;
return StringCchPrintfW(pszBuff, cchBuff, pszFormat, dwValue);
#endif
}
BOOL WINAPI Imm32IsImcAnsi(HIMC hIMC)
{
BOOL ret;
@ -484,6 +526,400 @@ Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc,
return cbDest;
}
typedef BOOL (WINAPI *FN_GetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID);
typedef DWORD (WINAPI *FN_GetFileVersionInfoSizeW)(LPCWSTR, LPDWORD);
typedef BOOL (WINAPI *FN_VerQueryValueW)(LPCVOID, LPCWSTR, LPVOID*, PUINT);
static FN_GetFileVersionInfoW s_fnGetFileVersionInfoW = NULL;
static FN_GetFileVersionInfoSizeW s_fnGetFileVersionInfoSizeW = NULL;
static FN_VerQueryValueW s_fnVerQueryValueW = NULL;
static BOOL APIENTRY Imm32LoadImeFixedInfo(PIMEINFOEX pInfoEx, LPCVOID pVerInfo)
{
UINT cbFixed = 0;
VS_FIXEDFILEINFO *pFixed;
if (!s_fnVerQueryValueW(pVerInfo, L"\\", (LPVOID*)&pFixed, &cbFixed) || !cbFixed)
return FALSE;
/* NOTE: The IME module must contain a version info of input method driver. */
if (pFixed->dwFileType != VFT_DRV || pFixed->dwFileSubtype != VFT2_DRV_INPUTMETHOD)
return FALSE;
pInfoEx->dwProdVersion = pFixed->dwProductVersionMS;
pInfoEx->dwImeWinVersion = 0x40000;
return TRUE;
}
static LPWSTR APIENTRY
Imm32GetVerInfoValue(LPCVOID pVerInfo, LPWSTR pszKey, DWORD cchKey, LPCWSTR pszName)
{
size_t cchExtra;
LPWSTR pszValue;
UINT cbValue = 0;
StringCchLengthW(pszKey, cchKey, &cchExtra);
StringCchCatW(pszKey, cchKey, pszName);
s_fnVerQueryValueW(pVerInfo, pszKey, (LPVOID*)&pszValue, &cbValue);
pszKey[cchExtra] = 0;
return (cbValue ? pszValue : NULL);
}
BOOL APIENTRY Imm32LoadImeLangAndDesc(PIMEINFOEX pInfoEx, LPCVOID pVerInfo)
{
BOOL ret;
WCHAR szKey[80];
LPWSTR pszDesc;
LPWORD pw;
UINT cbData;
LANGID LangID;
/* Getting the version info. See VerQueryValue */
ret = s_fnVerQueryValueW(pVerInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&pw, &cbData);
if (!ret || !cbData)
return FALSE;
if (pInfoEx->hkl == NULL)
pInfoEx->hkl = (HKL)(DWORD_PTR)*pw; /* This is an invalid HKL */
/* Try the current language and the Unicode codepage (0x04B0) */
LangID = LANGIDFROMLCID(GetThreadLocale());
StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X04B0\\", LangID);
pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription");
if (!pszDesc)
{
/* Retry the language and codepage of the IME module */
StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X%04X\\", pw[0], pw[1]);
pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription");
}
/* The description */
if (pszDesc)
StringCchCopyW(pInfoEx->wszImeDescription, _countof(pInfoEx->wszImeDescription), pszDesc);
else
pInfoEx->wszImeDescription[0] = 0;
return TRUE;
}
BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx)
{
HINSTANCE hinstVersion;
BOOL ret = FALSE, bLoaded = FALSE;
WCHAR szPath[MAX_PATH];
LPVOID pVerInfo;
DWORD cbVerInfo, dwHandle;
/* Load version.dll to use the version info API */
Imm32GetSystemLibraryPath(szPath, _countof(szPath), L"version.dll");
hinstVersion = GetModuleHandleW(szPath);
if (!hinstVersion)
{
hinstVersion = LoadLibraryW(szPath);
if (!hinstVersion)
return FALSE;
bLoaded = TRUE;
}
#define GET_FN(name) do { \
s_fn##name = (FN_##name)GetProcAddress(hinstVersion, #name); \
if (!s_fn##name) goto Quit; \
} while (0)
GET_FN(GetFileVersionInfoW);
GET_FN(GetFileVersionInfoSizeW);
GET_FN(VerQueryValueW);
#undef GET_FN
/* The path of the IME module */
Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile);
cbVerInfo = s_fnGetFileVersionInfoSizeW(szPath, &dwHandle);
if (!cbVerInfo)
goto Quit;
pVerInfo = Imm32HeapAlloc(0, cbVerInfo);
if (!pVerInfo)
goto Quit;
/* Load the version info of the IME module */
if (s_fnGetFileVersionInfoW(szPath, dwHandle, cbVerInfo, pVerInfo) &&
Imm32LoadImeFixedInfo(pImeInfoEx, pVerInfo))
{
ret = Imm32LoadImeLangAndDesc(pImeInfoEx, pVerInfo);
}
Imm32HeapFree(pVerInfo);
Quit:
if (bLoaded)
FreeLibrary(hinstVersion);
return ret;
}
HKL APIENTRY Imm32GetNextHKL(UINT cKLs, const REG_IME *pLayouts, WORD wLangID)
{
UINT iKL, wID, wLow = 0xE0FF, wHigh = 0xE01F, wNextID = 0;
for (iKL = 0; iKL < cKLs; ++iKL)
{
wHigh = max(wHigh, HIWORD(pLayouts[iKL].hKL));
wLow = min(wLow, HIWORD(pLayouts[iKL].hKL));
}
if (wHigh < 0xE0FF)
{
wNextID = wHigh + 1;
}
else if (wLow > 0xE001)
{
wNextID = wLow - 1;
}
else
{
for (wID = 0xE020; wID <= 0xE0FF; ++wID)
{
for (iKL = 0; iKL < cKLs; ++iKL)
{
if (LOWORD(pLayouts[iKL].hKL) == wLangID &&
HIWORD(pLayouts[iKL].hKL) == wID)
{
break;
}
}
if (iKL >= cKLs)
break;
}
if (wID <= 0xE0FF)
wNextID = wID;
}
if (!wNextID)
return NULL;
return (HKL)(DWORD_PTR)MAKELONG(wLangID, wNextID);
}
UINT APIENTRY Imm32GetRegImes(PREG_IME pLayouts, UINT cLayouts)
{
HKEY hkeyLayouts, hkeyIME;
WCHAR szImeFileName[80], szImeKey[20];
UINT iKey, nCount;
DWORD cbData;
LONG lError;
ULONG Value;
HKL hKL;
/* Open the registry keyboard layouts */
lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
if (lError != ERROR_SUCCESS)
return 0;
for (iKey = nCount = 0; ; ++iKey)
{
/* Get the key name */
lError = RegEnumKeyW(hkeyLayouts, iKey, szImeKey, _countof(szImeKey));
if (lError != ERROR_SUCCESS)
break;
if (szImeKey[0] != L'E' && szImeKey[0] != L'e')
continue; /* Not an IME layout */
if (pLayouts == NULL) /* for counting only */
{
++nCount;
continue;
}
if (cLayouts <= nCount)
break;
lError = RegOpenKeyW(hkeyLayouts, szImeKey, &hkeyIME); /* Open the IME key */
if (lError != ERROR_SUCCESS)
break;
/* Load the "Ime File" value */
szImeFileName[0] = 0;
cbData = sizeof(szImeFileName);
RegQueryValueExW(hkeyIME, L"Ime File", NULL, NULL, (LPBYTE)szImeFileName, &cbData);
szImeFileName[_countof(szImeFileName) - 1] = 0;
RegCloseKey(hkeyIME);
if (!szImeFileName[0])
break;
Imm32StrToUInt(szImeKey, &Value, 16);
hKL = (HKL)(DWORD_PTR)Value;
if (!IS_IME_HKL(hKL))
break;
/* Store the IME key and the IME filename */
pLayouts[nCount].hKL = hKL;
StringCchCopyW(pLayouts[nCount].szImeKey, _countof(pLayouts[nCount].szImeKey), szImeKey);
CharUpperW(szImeFileName);
StringCchCopyW(pLayouts[nCount].szFileName, _countof(pLayouts[nCount].szFileName),
szImeFileName);
++nCount;
}
RegCloseKey(hkeyLayouts);
return nCount;
}
BOOL APIENTRY Imm32WriteRegIme(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayout)
{
UINT iPreload;
HKEY hkeyLayouts, hkeyIME, hkeyPreload;
WCHAR szImeKey[20], szPreloadNumber[20], szPreloadKey[20], szImeFileName[80];
DWORD cbData;
LANGID LangID;
LONG lError;
LPCWSTR pszLayoutFile;
/* Open the registry keyboard layouts */
lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
if (lError != ERROR_SUCCESS)
return FALSE;
/* Get the IME key from hKL */
Imm32UIntToStr((DWORD)(DWORD_PTR)hKL, 16, szImeKey, _countof(szImeKey));
/* Create a registry IME key */
lError = RegCreateKeyW(hkeyLayouts, szImeKey, &hkeyIME);
if (lError != ERROR_SUCCESS)
goto Failure;
/* Write "Ime File" */
cbData = (wcslen(pchFilePart) + 1) * sizeof(WCHAR);
lError = RegSetValueExW(hkeyIME, L"Ime File", 0, REG_SZ, (LPBYTE)pchFilePart, cbData);
if (lError != ERROR_SUCCESS)
goto Failure;
/* Write "Layout Text" */
cbData = (wcslen(pszLayout) + 1) * sizeof(WCHAR);
lError = RegSetValueExW(hkeyIME, L"Layout Text", 0, REG_SZ, (LPBYTE)pszLayout, cbData);
if (lError != ERROR_SUCCESS)
goto Failure;
/* Choose "Layout File" from hKL */
LangID = LOWORD(hKL);
switch (LOBYTE(LangID))
{
case LANG_JAPANESE: pszLayoutFile = L"kbdjpn.dll"; break;
case LANG_KOREAN: pszLayoutFile = L"kbdkor.dll"; break;
default: pszLayoutFile = L"kbdus.dll"; break;
}
StringCchCopyW(szImeFileName, _countof(szImeFileName), pszLayoutFile);
/* Write "Layout File" */
cbData = (wcslen(szImeFileName) + 1) * sizeof(WCHAR);
lError = RegSetValueExW(hkeyIME, L"Layout File", 0, REG_SZ, (LPBYTE)szImeFileName, cbData);
if (lError != ERROR_SUCCESS)
goto Failure;
RegCloseKey(hkeyIME);
RegCloseKey(hkeyLayouts);
/* Create "Preload" key */
RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkeyPreload);
#define MAX_PRELOAD 0x400
for (iPreload = 1; iPreload < MAX_PRELOAD; ++iPreload)
{
Imm32UIntToStr(iPreload, 10, szPreloadNumber, _countof(szPreloadNumber));
/* Load the key of the preload number */
cbData = sizeof(szPreloadKey);
lError = RegQueryValueExW(hkeyPreload, szPreloadNumber, NULL, NULL,
(LPBYTE)szPreloadKey, &cbData);
szPreloadKey[_countof(szPreloadKey) - 1] = 0;
if (lError != ERROR_SUCCESS || lstrcmpiW(szImeKey, szPreloadKey) == 0)
break; /* Found an empty room or the same key */
}
if (iPreload >= MAX_PRELOAD) /* Not found */
{
RegCloseKey(hkeyPreload);
return FALSE;
}
#undef MAX_PRELOAD
/* Write the IME key to the preload number */
cbData = (wcslen(szImeKey) + 1) * sizeof(WCHAR);
lError = RegSetValueExW(hkeyPreload, szPreloadNumber, 0, REG_SZ, (LPBYTE)szImeKey, cbData);
RegCloseKey(hkeyPreload);
return lError == ERROR_SUCCESS;
Failure:
RegCloseKey(hkeyIME);
RegDeleteKeyW(hkeyLayouts, szImeKey);
RegCloseKey(hkeyLayouts);
return FALSE;
}
typedef INT (WINAPI *FN_LZOpenFileW)(LPWSTR, LPOFSTRUCT, WORD);
typedef LONG (WINAPI *FN_LZCopy)(INT, INT);
typedef VOID (WINAPI *FN_LZClose)(INT);
BOOL APIENTRY Imm32CopyFile(LPWSTR pszOldFile, LPCWSTR pszNewFile)
{
BOOL ret = FALSE, bLoaded = FALSE;
HMODULE hinstLZ32;
WCHAR szLZ32Path[MAX_PATH];
CHAR szDestA[MAX_PATH];
OFSTRUCT OFStruct;
FN_LZOpenFileW fnLZOpenFileW;
FN_LZCopy fnLZCopy;
FN_LZClose fnLZClose;
HFILE hfDest, hfSrc;
/* Load LZ32.dll for copying/decompressing file */
Imm32GetSystemLibraryPath(szLZ32Path, _countof(szLZ32Path), L"LZ32");
hinstLZ32 = GetModuleHandleW(szLZ32Path);
if (!hinstLZ32)
{
hinstLZ32 = LoadLibraryW(szLZ32Path);
if (!hinstLZ32)
return FALSE;
bLoaded = TRUE;
}
#define GET_FN(name) do { \
fn##name = (FN_##name)GetProcAddress(hinstLZ32, #name); \
if (!fn##name) goto Quit; \
} while (0)
GET_FN(LZOpenFileW);
GET_FN(LZCopy);
GET_FN(LZClose);
#undef GET_FN
if (!WideCharToMultiByte(CP_ACP, 0, pszNewFile, -1, szDestA, _countof(szDestA), NULL, NULL))
goto Quit;
szDestA[_countof(szDestA) - 1] = 0;
hfSrc = fnLZOpenFileW(pszOldFile, &OFStruct, OF_READ);
if (hfSrc < 0)
goto Quit;
hfDest = OpenFile(szDestA, &OFStruct, OF_CREATE);
if (hfDest != HFILE_ERROR)
{
ret = (fnLZCopy(hfSrc, hfDest) >= 0);
_lclose(hfDest);
}
fnLZClose(hfSrc);
Quit:
if (bLoaded)
FreeLibrary(hinstLZ32);
return ret;
}
/***********************************************************************
* CtfImmIsTextFrameServiceDisabled(IMM32.@)
*/

View file

@ -1183,7 +1183,7 @@ typedef struct tagIMEINFOEX
};
} IMEINFOEX, *PIMEINFOEX;
typedef enum IMEINFOEXCLASS
typedef enum IMEINFOEXCLASS /* unconfirmed: buggy */
{
ImeInfoExKeyboardLayout,
ImeInfoExImeWindow,