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)) { - 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: 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: 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.@) * 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 #include #include +#include #include #include @@ -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,