mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[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:
parent
d26409cc34
commit
a37d9a4e14
5 changed files with 642 additions and 124 deletions
|
@ -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:
|
||||
|
|
|
@ -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.@)
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -1183,7 +1183,7 @@ typedef struct tagIMEINFOEX
|
|||
};
|
||||
} IMEINFOEX, *PIMEINFOEX;
|
||||
|
||||
typedef enum IMEINFOEXCLASS
|
||||
typedef enum IMEINFOEXCLASS /* unconfirmed: buggy */
|
||||
{
|
||||
ImeInfoExKeyboardLayout,
|
||||
ImeInfoExImeWindow,
|
||||
|
|
Loading…
Reference in a new issue