https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a37d9a4e14115b850e00f…
commit a37d9a4e14115b850e00f67889ee9ee7c4be7766
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Thu Oct 21 10:28:04 2021 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Thu Oct 21 10:28:04 2021 +0900
[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
---
dll/win32/imm32/ime.c | 169 ++++++++++++++++--
dll/win32/imm32/imm.c | 143 ++++-----------
dll/win32/imm32/precomp.h | 16 ++
dll/win32/imm32/utils.c | 436 ++++++++++++++++++++++++++++++++++++++++++++++
win32ss/include/ntuser.h | 2 +-
5 files changed, 642 insertions(+), 124 deletions(-)
diff --git a/dll/win32/imm32/ime.c b/dll/win32/imm32/ime.c
index 9ae6115fe49..cfe0b66754e 100644
--- a/dll/win32/imm32/ime.c
+++ b/dll/win32/imm32/ime.c
@@ -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))
+ {
+ ret = TRUE;
+ }
+ else
{
- ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n");
- goto Failed;
+ 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:
diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c
index f4fa021b619..c21c5a23567 100644
--- a/dll/win32/imm32/imm.c
+++ b/dll/win32/imm32/imm.c
@@ -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 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;
+ {
+ ERR("RegOpenKeyW: 0x%08lX\n", error);
+ return FALSE;
+ }
}
+ 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.@)
*
diff --git a/dll/win32/imm32/precomp.h b/dll/win32/imm32/precomp.h
index 584defc5501..285ab70b8d1 100644
--- a/dll/win32/imm32/precomp.h
+++ b/dll/win32/imm32/precomp.h
@@ -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);
diff --git a/dll/win32/imm32/utils.c b/dll/win32/imm32/utils.c
index abbe5717bc9..3cf198096a6 100644
--- a/dll/win32/imm32/utils.c
+++ b/dll/win32/imm32/utils.c
@@ -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.@)
*/
diff --git a/win32ss/include/ntuser.h b/win32ss/include/ntuser.h
index eb5fb285a79..38076513db2 100644
--- a/win32ss/include/ntuser.h
+++ b/win32ss/include/ntuser.h
@@ -1183,7 +1183,7 @@ typedef struct tagIMEINFOEX
};
} IMEINFOEX, *PIMEINFOEX;
-typedef enum IMEINFOEXCLASS
+typedef enum IMEINFOEXCLASS /* unconfirmed: buggy */
{
ImeInfoExKeyboardLayout,
ImeInfoExImeWindow,