https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a37d9a4e14115b850e00f67889ee9ee7c4be7766

commit a37d9a4e14115b850e00f67889ee9ee7c4be7766
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Thu Oct 21 10:28:04 2021 +0900
Commit:     GitHub <[email protected]>
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,

Reply via email to