mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 14:53:40 +00:00
[IMM32][SDK] Add install.c and move some code (#8032)
Splitting IME installation code for code readability. JIRA issue: CORE-19268 - Add win32ss/user/imm32/install.c. - Move some code to install.c. - Add SAL annotations. Use debugstr_a/_w macro. - Modify <imm32_undoc.h>. - Don't CharUpperW for IME pathname due to security reason.
This commit is contained in:
parent
b627a42898
commit
b4e471c87d
10 changed files with 672 additions and 592 deletions
|
@ -230,6 +230,14 @@ BOOL WINAPI ImmSetActiveContext(_In_ HWND hwnd, _In_ HIMC hIMC, _In_ BOOL fFlag)
|
||||||
BOOL WINAPI ImmLoadIME(_In_ HKL hKL);
|
BOOL WINAPI ImmLoadIME(_In_ HKL hKL);
|
||||||
DWORD WINAPI ImmProcessKey(_In_ HWND, _In_ HKL, _In_ UINT, _In_ LPARAM, _In_ DWORD);
|
DWORD WINAPI ImmProcessKey(_In_ HWND, _In_ HKL, _In_ UINT, _In_ LPARAM, _In_ DWORD);
|
||||||
LRESULT WINAPI ImmPutImeMenuItemsIntoMappedFile(_In_ HIMC hIMC);
|
LRESULT WINAPI ImmPutImeMenuItemsIntoMappedFile(_In_ HIMC hIMC);
|
||||||
|
BOOL WINAPI ImmWINNLSGetEnableStatus(_In_opt_ HWND hWnd);
|
||||||
|
BOOL WINAPI ImmSetActiveContextConsoleIME(_In_ HWND hwnd, _In_ BOOL fFlag);
|
||||||
|
|
||||||
|
LRESULT WINAPI
|
||||||
|
ImmSystemHandler(
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_Inout_opt_ WPARAM wParam,
|
||||||
|
_Inout_opt_ LPARAM lParam);
|
||||||
|
|
||||||
BOOL WINAPI ImmIMPGetIMEA(_In_opt_ HWND hWnd, _Out_ LPIMEPROA pImePro);
|
BOOL WINAPI ImmIMPGetIMEA(_In_opt_ HWND hWnd, _Out_ LPIMEPROA pImePro);
|
||||||
BOOL WINAPI ImmIMPGetIMEW(_In_opt_ HWND hWnd, _Out_ LPIMEPROW pImePro);
|
BOOL WINAPI ImmIMPGetIMEW(_In_opt_ HWND hWnd, _Out_ LPIMEPROW pImePro);
|
||||||
|
@ -251,9 +259,9 @@ VOID WINAPI CtfImmCoUninitialize(VOID);
|
||||||
VOID WINAPI CtfImmEnterCoInitCountSkipMode(VOID);
|
VOID WINAPI CtfImmEnterCoInitCountSkipMode(VOID);
|
||||||
BOOL WINAPI CtfImmLeaveCoInitCountSkipMode(VOID);
|
BOOL WINAPI CtfImmLeaveCoInitCountSkipMode(VOID);
|
||||||
HRESULT WINAPI CtfImmLastEnabledWndDestroy(_In_ BOOL bCreate);
|
HRESULT WINAPI CtfImmLastEnabledWndDestroy(_In_ BOOL bCreate);
|
||||||
BOOL WINAPI CtfImmIsCiceroStartedInThread(VOID);
|
|
||||||
HRESULT WINAPI CtfImmTIMActivate(_In_ HKL hKL);
|
HRESULT WINAPI CtfImmTIMActivate(_In_ HKL hKL);
|
||||||
BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID);
|
BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID);
|
||||||
|
BOOL WINAPI CtfImmIsCiceroEnabled(VOID);
|
||||||
|
|
||||||
LRESULT WINAPI
|
LRESULT WINAPI
|
||||||
CtfImmDispatchDefImeMessage(
|
CtfImmDispatchDefImeMessage(
|
||||||
|
|
|
@ -14,6 +14,7 @@ list(APPEND SOURCE
|
||||||
imemenu.c
|
imemenu.c
|
||||||
imepro.c
|
imepro.c
|
||||||
imm.c
|
imm.c
|
||||||
|
install.c
|
||||||
keymsg.c
|
keymsg.c
|
||||||
regword.c
|
regword.c
|
||||||
softkbd.c
|
softkbd.c
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||||
|
|
||||||
// Win: InternalGetCandidateListWtoA
|
#define ROUNDUP4(n) (((n) + 3) & ~3) /* DWORD alignment */
|
||||||
|
|
||||||
DWORD APIENTRY
|
DWORD APIENTRY
|
||||||
CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen,
|
CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen,
|
||||||
UINT uCodePage)
|
UINT uCodePage)
|
||||||
|
|
|
@ -1130,52 +1130,52 @@ CtfImmTIMActivate(_In_ HKL hKL)
|
||||||
{
|
{
|
||||||
TRACE("g_disable_CUAS_flag\n");
|
TRACE("g_disable_CUAS_flag\n");
|
||||||
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED)
|
if (GetWin32ClientInfo()->CI_flags & CI_TSFDISABLED)
|
||||||
{
|
{
|
||||||
TRACE("CI_TSFDISABLED\n");
|
TRACE("CI_TSFDISABLED\n");
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Imm32IsTIMDisabledInRegistry())
|
if (Imm32IsTIMDisabledInRegistry())
|
||||||
{
|
{
|
||||||
TRACE("TIM is disabled in registry\n");
|
TRACE("TIM is disabled in registry\n");
|
||||||
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Imm32IsInteractiveUserLogon() || Imm32IsRunningInMsoobe())
|
if (!Imm32IsInteractiveUserLogon() || Imm32IsRunningInMsoobe())
|
||||||
{
|
{
|
||||||
TRACE("TIM is disabled due to LOGON or MSOBE\n");
|
TRACE("TIM is disabled due to LOGON or MSOBE\n");
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Imm32IsCUASEnabledInRegistry())
|
if (!Imm32IsCUASEnabledInRegistry())
|
||||||
{
|
{
|
||||||
TRACE("CUAS is disabled in registry\n");
|
TRACE("CUAS is disabled in registry\n");
|
||||||
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NtCurrentTeb()->ProcessEnvironmentBlock->AppCompatFlags.LowPart & 0x100)
|
if (NtCurrentTeb()->ProcessEnvironmentBlock->AppCompatFlags.LowPart & 0x100)
|
||||||
{
|
{
|
||||||
TRACE("CUAS is disabled by AppCompatFlags\n");
|
TRACE("CUAS is disabled by AppCompatFlags\n");
|
||||||
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
GetWin32ClientInfo()->CI_flags |= CI_TSFDISABLED;
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RtlIsThreadWithinLoaderCallout() || Imm32InsideLoaderLock())
|
if (RtlIsThreadWithinLoaderCallout() || Imm32InsideLoaderLock())
|
||||||
{
|
{
|
||||||
TRACE("TIM is disabled by Loader\n");
|
TRACE("TIM is disabled by Loader\n");
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_CICERO_MODE() || IS_16BIT_MODE())
|
if (!IS_CICERO_MODE() || IS_16BIT_MODE())
|
||||||
{
|
{
|
||||||
TRACE("TIM is disabled because CICERO mode is unset\n");
|
TRACE("TIM is disabled because CICERO mode is unset\n");
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_IME_HKL(hKL))
|
if (IS_IME_HKL(hKL))
|
||||||
|
|
|
@ -424,138 +424,6 @@ Quit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* ImmInstallIMEA (IMM32.@)
|
|
||||||
*/
|
|
||||||
HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
|
|
||||||
{
|
|
||||||
HKL hKL = NULL;
|
|
||||||
LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
|
|
||||||
|
|
||||||
TRACE("(%s, %s)\n", lpszIMEFileName, lpszLayoutText);
|
|
||||||
|
|
||||||
pszFileNameW = Imm32WideFromAnsi(CP_ACP, lpszIMEFileName);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pszFileNameW))
|
|
||||||
goto Quit;
|
|
||||||
|
|
||||||
pszLayoutTextW = Imm32WideFromAnsi(CP_ACP, lpszLayoutText);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pszLayoutTextW))
|
|
||||||
goto Quit;
|
|
||||||
|
|
||||||
hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
ImmLocalFree(pszFileNameW);
|
|
||||||
ImmLocalFree(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", lpszIMEFileName, lpszLayoutText);
|
|
||||||
|
|
||||||
GetFullPathNameW(lpszIMEFileName, _countof(szImeFileName), szImeFileName, &pchFilePart);
|
|
||||||
CharUpperW(szImeFileName);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pchFilePart))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Load the IME version info */
|
|
||||||
InfoEx.hkl = hNewKL = NULL;
|
|
||||||
StringCchCopyW(InfoEx.wszImeFile, _countof(InfoEx.wszImeFile), pchFilePart);
|
|
||||||
if (!Imm32LoadImeVerInfo(&InfoEx) || !InfoEx.hkl)
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
wLangID = LOWORD(InfoEx.hkl);
|
|
||||||
|
|
||||||
/* Get the IME layouts from registry */
|
|
||||||
cLayouts = Imm32GetImeLayout(NULL, 0);
|
|
||||||
if (cLayouts)
|
|
||||||
{
|
|
||||||
pLayouts = ImmLocalAlloc(0, cLayouts * sizeof(REG_IME));
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(pLayouts))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!Imm32GetImeLayout(pLayouts, cLayouts))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
ImmLocalFree(pLayouts);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (iLayout = 0; iLayout < cLayouts; ++iLayout)
|
|
||||||
{
|
|
||||||
if (lstrcmpiW(pLayouts[iLayout].szFileName, pchFilePart) == 0)
|
|
||||||
{
|
|
||||||
if (wLangID != LOWORD(pLayouts[iLayout].hKL))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
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 */
|
|
||||||
if (ImmGetImeInfoEx(&InfoEx, ImeInfoExImeFileName, pchFilePart) &&
|
|
||||||
!UnloadKeyboardLayout(InfoEx.hkl))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
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 &&
|
|
||||||
!Imm32CopyImeFile(szImeFileName, szImeDestPath))
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
hNewKL = NULL;
|
|
||||||
goto Quit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hNewKL == NULL)
|
|
||||||
hNewKL = Imm32AssignNewLayout(cLayouts, pLayouts, wLangID);
|
|
||||||
|
|
||||||
if (hNewKL)
|
|
||||||
{
|
|
||||||
/* Write the IME layout to registry */
|
|
||||||
if (Imm32WriteImeLayout(hNewKL, pchFilePart, lpszLayoutText))
|
|
||||||
{
|
|
||||||
/* Load the keyboard layout */
|
|
||||||
StringCchPrintfW(szImeKey, _countof(szImeKey), L"%08X", HandleToUlong(hNewKL));
|
|
||||||
hNewKL = LoadKeyboardLayoutW(szImeKey, KLF_REPLACELANG);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
hNewKL = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
ImmLocalFree(pLayouts);
|
|
||||||
return hNewKL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmIsIME (IMM32.@)
|
* ImmIsIME (IMM32.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -54,7 +54,10 @@ static BOOL APIENTRY ImmInitializeGlobals(HMODULE hMod)
|
||||||
* ImmRegisterClient(IMM32.@)
|
* ImmRegisterClient(IMM32.@)
|
||||||
* ( Undocumented, called from user32.dll )
|
* ( Undocumented, called from user32.dll )
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
|
BOOL WINAPI
|
||||||
|
ImmRegisterClient(
|
||||||
|
_Inout_ PSHAREDINFO ptr,
|
||||||
|
_In_ HINSTANCE hMod)
|
||||||
{
|
{
|
||||||
gSharedInfo = *ptr;
|
gSharedInfo = *ptr;
|
||||||
gpsi = gSharedInfo.psi;
|
gpsi = gSharedInfo.psi;
|
||||||
|
@ -1000,8 +1003,10 @@ VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
|
||||||
ImmLocalFree(pClientImc);
|
ImmLocalFree(pClientImc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win: ImmGetSaveContext
|
static HIMC
|
||||||
static HIMC APIENTRY ImmGetSaveContext(HWND hWnd, DWORD dwContextFlags)
|
ImmGetSaveContext(
|
||||||
|
_In_opt_ HWND hWnd,
|
||||||
|
_In_ DWORD dwContextFlags)
|
||||||
{
|
{
|
||||||
HIMC hIMC;
|
HIMC hIMC;
|
||||||
PCLIENTIMC pClientImc;
|
PCLIENTIMC pClientImc;
|
||||||
|
@ -1219,8 +1224,8 @@ BOOL WINAPI ImmSetActiveContext(HWND hWnd, HIMC hIMC, BOOL fActive)
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmWINNLSGetEnableStatus (IMM32.@)
|
* ImmWINNLSGetEnableStatus (IMM32.@)
|
||||||
*/
|
*/
|
||||||
|
BOOL WINAPI
|
||||||
BOOL WINAPI ImmWINNLSGetEnableStatus(HWND hWnd)
|
ImmWINNLSGetEnableStatus(_In_opt_ HWND hWnd)
|
||||||
{
|
{
|
||||||
if (!Imm32IsSystemJapaneseOrKorean())
|
if (!Imm32IsSystemJapaneseOrKorean())
|
||||||
{
|
{
|
||||||
|
@ -1234,7 +1239,10 @@ BOOL WINAPI ImmWINNLSGetEnableStatus(HWND hWnd)
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmSetActiveContextConsoleIME(IMM32.@)
|
* ImmSetActiveContextConsoleIME(IMM32.@)
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
|
BOOL WINAPI
|
||||||
|
ImmSetActiveContextConsoleIME(
|
||||||
|
_In_ HWND hwnd,
|
||||||
|
_In_ BOOL fFlag)
|
||||||
{
|
{
|
||||||
HIMC hIMC;
|
HIMC hIMC;
|
||||||
TRACE("(%p, %d)\n", hwnd, fFlag);
|
TRACE("(%p, %d)\n", hwnd, fFlag);
|
||||||
|
|
607
win32ss/user/imm32/install.c
Normal file
607
win32ss/user/imm32/install.c
Normal file
|
@ -0,0 +1,607 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS IMM32
|
||||||
|
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||||
|
* PURPOSE: Implementing IME installation
|
||||||
|
* COPYRIGHT: Copyright 2020-2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||||
|
|
||||||
|
/* An IME layout entry in registry */
|
||||||
|
typedef struct tagREG_IME_LAYOUT
|
||||||
|
{
|
||||||
|
HKL hKL;
|
||||||
|
WCHAR szImeKey[20]; /* "E0XXYYYY": "E0XX" is the device handle. "YYYY" is a LANGID. */
|
||||||
|
WCHAR szFileName[80]; /* The IME module filename */
|
||||||
|
} REG_IME_LAYOUT, *PREG_IME_LAYOUT;
|
||||||
|
|
||||||
|
/* For using version.dll */
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Used in Imm32CopyImeFile */
|
||||||
|
typedef INT (WINAPI *FN_LZOpenFileW)(LPWSTR, LPOFSTRUCT, WORD);
|
||||||
|
typedef LONG (WINAPI *FN_LZCopy)(INT, INT);
|
||||||
|
typedef VOID (WINAPI *FN_LZClose)(INT);
|
||||||
|
|
||||||
|
/* Gets a version information entry by using version!VerQueryValueW */
|
||||||
|
static LPWSTR
|
||||||
|
Imm32GetVerInfoValue(
|
||||||
|
_In_reads_bytes_(cbVerInfo) LPCVOID pVerInfo,
|
||||||
|
_In_ DWORD cbVerInfo,
|
||||||
|
_Inout_ PWSTR pszKey,
|
||||||
|
_In_ DWORD cchKey,
|
||||||
|
_In_ PCWSTR 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] = UNICODE_NULL; /* Avoid buffer overrun */
|
||||||
|
|
||||||
|
ASSERT(cbValue <= cbVerInfo);
|
||||||
|
|
||||||
|
return (cbValue ? pszValue : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gets the language and description of an IME */
|
||||||
|
static BOOL
|
||||||
|
Imm32LoadImeLangAndDesc(
|
||||||
|
_Inout_ PIMEINFOEX pInfoEx,
|
||||||
|
_In_reads_bytes_(cbVerInfo) LPCVOID pVerInfo,
|
||||||
|
_In_ DWORD cbVerInfo)
|
||||||
|
{
|
||||||
|
/* Getting the version info. See VerQueryValue */
|
||||||
|
LPWORD pw;
|
||||||
|
UINT cbData;
|
||||||
|
BOOL ret = s_fnVerQueryValueW(pVerInfo, L"\\VarFileInfo\\Translation", (LPVOID *)&pw, &cbData);
|
||||||
|
if (!ret || !cbData)
|
||||||
|
{
|
||||||
|
ERR("Translation not available\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(cbData <= cbVerInfo);
|
||||||
|
|
||||||
|
if (pInfoEx->hkl == NULL)
|
||||||
|
pInfoEx->hkl = UlongToHandle(*pw);
|
||||||
|
|
||||||
|
/* Try the current language and the Unicode codepage (0x04B0) */
|
||||||
|
LANGID LangID = LANGIDFROMLCID(GetThreadLocale());
|
||||||
|
WCHAR szKey[80];
|
||||||
|
StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X04B0\\", LangID);
|
||||||
|
LPWSTR pszDesc = Imm32GetVerInfoValue(pVerInfo, cbVerInfo, 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, cbVerInfo, szKey, _countof(szKey), L"FileDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The description */
|
||||||
|
if (pszDesc)
|
||||||
|
StringCchCopyW(pInfoEx->wszImeDescription, _countof(pInfoEx->wszImeDescription), pszDesc);
|
||||||
|
else
|
||||||
|
pInfoEx->wszImeDescription[0] = UNICODE_NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gets the fixed version info from IME */
|
||||||
|
static BOOL
|
||||||
|
Imm32LoadImeFixedInfo(
|
||||||
|
_Out_ PIMEINFOEX pInfoEx,
|
||||||
|
_In_reads_bytes_(cbVerInfo) LPCVOID pVerInfo,
|
||||||
|
_In_ DWORD cbVerInfo)
|
||||||
|
{
|
||||||
|
UINT cbFixed = 0;
|
||||||
|
VS_FIXEDFILEINFO *pFixed;
|
||||||
|
if (!s_fnVerQueryValueW(pVerInfo, L"\\", (LPVOID *)&pFixed, &cbFixed) || !cbFixed)
|
||||||
|
{
|
||||||
|
ERR("Fixed version info not available\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(cbFixed <= cbVerInfo);
|
||||||
|
|
||||||
|
/* NOTE: The IME module must contain a version info of input method driver. */
|
||||||
|
if (pFixed->dwFileType != VFT_DRV || pFixed->dwFileSubtype != VFT2_DRV_INPUTMETHOD)
|
||||||
|
{
|
||||||
|
ERR("DLL '%s' is not an IME\n", debugstr_w(pInfoEx->wszImeFile));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pInfoEx->dwProdVersion = pFixed->dwProductVersionMS;
|
||||||
|
pInfoEx->dwImeWinVersion = IMEVER_0400;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generates a new IMM IME HKL (0xE0XXYYYY) */
|
||||||
|
static HKL
|
||||||
|
Imm32AssignNewLayout(
|
||||||
|
_In_ UINT cKLs,
|
||||||
|
_In_reads_(cKLs) const REG_IME_LAYOUT *pLayouts,
|
||||||
|
_In_ WORD wLangID)
|
||||||
|
{
|
||||||
|
#define MIN_SYSTEM_IMM_IME_ID 0xE000
|
||||||
|
#define MAX_SYSTEM_IMM_IME_ID 0xE0FF
|
||||||
|
#define MIN_USER_IMM_IME_ID 0xE020
|
||||||
|
#define MAX_USER_IMM_IME_ID MAX_SYSTEM_IMM_IME_ID
|
||||||
|
UINT iKL, wLow = MAX_USER_IMM_IME_ID, wHigh = MIN_USER_IMM_IME_ID;
|
||||||
|
|
||||||
|
for (iKL = 0; iKL < cKLs; ++iKL)
|
||||||
|
{
|
||||||
|
wHigh = max(wHigh, HIWORD(pLayouts[iKL].hKL));
|
||||||
|
wLow = min(wLow, HIWORD(pLayouts[iKL].hKL));
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT wNextImeId = 0;
|
||||||
|
if (wHigh < MAX_SYSTEM_IMM_IME_ID)
|
||||||
|
{
|
||||||
|
wNextImeId = wHigh + 1;
|
||||||
|
}
|
||||||
|
else if (wLow > MIN_SYSTEM_IMM_IME_ID)
|
||||||
|
{
|
||||||
|
wNextImeId = wLow - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UINT wID;
|
||||||
|
for (wID = MIN_USER_IMM_IME_ID; wID <= MAX_USER_IMM_IME_ID; ++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 <= MAX_SYSTEM_IMM_IME_ID)
|
||||||
|
wNextImeId = wID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wNextImeId)
|
||||||
|
{
|
||||||
|
ERR("No next IMM IME ID\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UlongToHandle(MAKELONG(wLangID, wNextImeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT
|
||||||
|
Imm32GetImeLayoutList(
|
||||||
|
_Out_writes_opt_(cLayouts) PREG_IME_LAYOUT pLayouts,
|
||||||
|
_In_ UINT cLayouts)
|
||||||
|
{
|
||||||
|
/* Open the registry keyboard layouts */
|
||||||
|
HKEY hkeyLayouts;
|
||||||
|
LSTATUS lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
UINT iKey, nCount;
|
||||||
|
WCHAR szImeFileName[80], szImeKey[20];
|
||||||
|
DWORD cbData, Value;
|
||||||
|
HKL hKL;
|
||||||
|
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;
|
||||||
|
|
||||||
|
HKEY hkeyIME;
|
||||||
|
lError = RegOpenKeyW(hkeyLayouts, szImeKey, &hkeyIME); /* Open the IME key */
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Load the "Ime File" value */
|
||||||
|
szImeFileName[0] = UNICODE_NULL;
|
||||||
|
cbData = sizeof(szImeFileName);
|
||||||
|
RegQueryValueExW(hkeyIME, L"Ime File", NULL, NULL, (LPBYTE)szImeFileName, &cbData);
|
||||||
|
szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
|
||||||
|
|
||||||
|
RegCloseKey(hkeyIME);
|
||||||
|
|
||||||
|
/* We don't allow the invalid "IME File" values for security reason */
|
||||||
|
if (!szImeFileName[0] || wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName))
|
||||||
|
{
|
||||||
|
WARN("Invalid IME Filename (%s)\n", debugstr_w(szImeFileName));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Imm32StrToUInt(szImeKey, &Value, 16);
|
||||||
|
hKL = UlongToHandle(Value);
|
||||||
|
if (!IS_IME_HKL(hKL)) /* Not an IMM IME */
|
||||||
|
{
|
||||||
|
WARN("Not IMM IME HKL: %p\n", hKL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the IME key and the IME filename */
|
||||||
|
pLayouts[nCount].hKL = hKL;
|
||||||
|
StringCchCopyW(pLayouts[nCount].szImeKey, _countof(pLayouts[nCount].szImeKey), szImeKey);
|
||||||
|
StringCchCopyW(pLayouts[nCount].szFileName, _countof(pLayouts[nCount].szFileName),
|
||||||
|
szImeFileName);
|
||||||
|
++nCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hkeyLayouts);
|
||||||
|
return nCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write an IME layout to registry */
|
||||||
|
static BOOL
|
||||||
|
Imm32WriteImeLayout(
|
||||||
|
_In_ HKL hKL,
|
||||||
|
_In_ PCWSTR pchFileTitle,
|
||||||
|
_In_ PCWSTR pszLayoutText)
|
||||||
|
{
|
||||||
|
UINT iPreload;
|
||||||
|
HKEY hkeyLayouts, hkeyIME, hkeyPreload;
|
||||||
|
WCHAR szImeKey[20], szPreloadNumber[20], szPreloadKey[20];
|
||||||
|
DWORD cbData;
|
||||||
|
LANGID LangID;
|
||||||
|
LONG lError;
|
||||||
|
LPCWSTR pszLayoutFile;
|
||||||
|
|
||||||
|
/* Open the registry keyboard layouts */
|
||||||
|
lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Get the IME key from hKL */
|
||||||
|
StringCchPrintfW(szImeKey, _countof(szImeKey), L"%08X", HandleToUlong(hKL));
|
||||||
|
|
||||||
|
/* Create a registry IME key */
|
||||||
|
lError = RegCreateKeyW(hkeyLayouts, szImeKey, &hkeyIME);
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
goto Failure;
|
||||||
|
|
||||||
|
/* Write "Ime File" */
|
||||||
|
cbData = (wcslen(pchFileTitle) + 1) * sizeof(WCHAR);
|
||||||
|
lError = RegSetValueExW(hkeyIME, L"Ime File", 0, REG_SZ, (LPBYTE)pchFileTitle, cbData);
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
goto Failure;
|
||||||
|
|
||||||
|
/* Write "Layout Text" */
|
||||||
|
cbData = (wcslen(pszLayoutText) + 1) * sizeof(WCHAR);
|
||||||
|
lError = RegSetValueExW(hkeyIME, L"Layout Text", 0, REG_SZ, (LPBYTE)pszLayoutText, cbData);
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write "Layout File" */
|
||||||
|
cbData = (wcslen(pszLayoutFile) + 1) * sizeof(WCHAR);
|
||||||
|
lError = RegSetValueExW(hkeyIME, L"Layout File", 0, REG_SZ, (LPBYTE)pszLayoutFile, cbData);
|
||||||
|
if (IS_ERROR_UNEXPECTEDLY(lError))
|
||||||
|
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] = UNICODE_NULL; /* Avoid buffer overrun */
|
||||||
|
|
||||||
|
if (lError != ERROR_SUCCESS || _wcsicmp(szImeKey, szPreloadKey) == 0)
|
||||||
|
break; /* Found an empty room or the same key */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iPreload >= MAX_PRELOAD) /* Not found */
|
||||||
|
{
|
||||||
|
ERR("iPreload: %u\n", iPreload);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy an IME file with using LZ decompression */
|
||||||
|
static BOOL
|
||||||
|
Imm32CopyImeFile(
|
||||||
|
_In_ PCWSTR pszOldFile,
|
||||||
|
_In_ PCWSTR pszNewFile)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE, bLoaded = FALSE;
|
||||||
|
|
||||||
|
/* Load LZ32.dll for copying/decompressing file */
|
||||||
|
WCHAR szLZ32Path[MAX_PATH];
|
||||||
|
Imm32GetSystemLibraryPath(szLZ32Path, _countof(szLZ32Path), L"LZ32");
|
||||||
|
HMODULE hinstLZ32 = GetModuleHandleW(szLZ32Path);
|
||||||
|
if (!hinstLZ32)
|
||||||
|
{
|
||||||
|
hinstLZ32 = LoadLibraryW(szLZ32Path);
|
||||||
|
if (IS_NULL_UNEXPECTEDLY(hinstLZ32))
|
||||||
|
return FALSE;
|
||||||
|
bLoaded = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FN_LZOpenFileW fnLZOpenFileW;
|
||||||
|
FN_LZCopy fnLZCopy;
|
||||||
|
FN_LZClose fnLZClose;
|
||||||
|
#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
|
||||||
|
|
||||||
|
CHAR szDestA[MAX_PATH];
|
||||||
|
HFILE hfDest, hfSrc;
|
||||||
|
OFSTRUCT OFStruct;
|
||||||
|
|
||||||
|
if (!WideCharToMultiByte(CP_ACP, 0, pszNewFile, -1, szDestA, _countof(szDestA), NULL, NULL))
|
||||||
|
goto Quit;
|
||||||
|
szDestA[_countof(szDestA) - 1] = ANSI_NULL; /* Avoid buffer overrun */
|
||||||
|
|
||||||
|
hfSrc = fnLZOpenFileW((PWSTR)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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loads version info of an IME by using version!{GetFileVersionInfo,VerQueryValue} etc. */
|
||||||
|
BOOL
|
||||||
|
Imm32LoadImeVerInfo(_Inout_ 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 (IS_NULL_UNEXPECTEDLY(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 (IS_ZERO_UNEXPECTEDLY(cbVerInfo))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
pVerInfo = ImmLocalAlloc(0, cbVerInfo);
|
||||||
|
if (IS_NULL_UNEXPECTEDLY(pVerInfo))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
/* Load the version info of the IME module */
|
||||||
|
if (s_fnGetFileVersionInfoW(szPath, dwHandle, cbVerInfo, pVerInfo) &&
|
||||||
|
Imm32LoadImeFixedInfo(pImeInfoEx, pVerInfo, cbVerInfo))
|
||||||
|
{
|
||||||
|
ret = Imm32LoadImeLangAndDesc(pImeInfoEx, pVerInfo, cbVerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmLocalFree(pVerInfo);
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
if (bLoaded)
|
||||||
|
FreeLibrary(hinstVersion);
|
||||||
|
TRACE("ret: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* ImmInstallIMEA (IMM32.@)
|
||||||
|
*/
|
||||||
|
HKL WINAPI
|
||||||
|
ImmInstallIMEA(
|
||||||
|
_In_ LPCSTR lpszIMEFileName,
|
||||||
|
_In_ LPCSTR lpszLayoutText)
|
||||||
|
{
|
||||||
|
HKL hKL = NULL;
|
||||||
|
LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
|
||||||
|
|
||||||
|
TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
|
||||||
|
|
||||||
|
pszFileNameW = Imm32WideFromAnsi(CP_ACP, lpszIMEFileName);
|
||||||
|
if (IS_NULL_UNEXPECTEDLY(pszFileNameW))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
pszLayoutTextW = Imm32WideFromAnsi(CP_ACP, lpszLayoutText);
|
||||||
|
if (IS_NULL_UNEXPECTEDLY(pszLayoutTextW))
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
ImmLocalFree(pszFileNameW);
|
||||||
|
ImmLocalFree(pszLayoutTextW);
|
||||||
|
return hKL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* ImmInstallIMEW (IMM32.@)
|
||||||
|
*/
|
||||||
|
HKL WINAPI
|
||||||
|
ImmInstallIMEW(
|
||||||
|
_In_ LPCWSTR lpszIMEFileName,
|
||||||
|
_In_ LPCWSTR lpszLayoutText)
|
||||||
|
{
|
||||||
|
TRACE("(%s, %s)\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText));
|
||||||
|
|
||||||
|
/* Get full pathname and file title */
|
||||||
|
WCHAR szImeFileName[MAX_PATH];
|
||||||
|
PWSTR pchFileTitle;
|
||||||
|
GetFullPathNameW(lpszIMEFileName, _countof(szImeFileName), szImeFileName, &pchFileTitle);
|
||||||
|
if (IS_NULL_UNEXPECTEDLY(pchFileTitle))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Load the IME version info */
|
||||||
|
IMEINFOEX InfoEx;
|
||||||
|
HKL hNewKL;
|
||||||
|
InfoEx.hkl = hNewKL = NULL;
|
||||||
|
StringCchCopyW(InfoEx.wszImeFile, _countof(InfoEx.wszImeFile), pchFileTitle);
|
||||||
|
if (!Imm32LoadImeVerInfo(&InfoEx) || !InfoEx.hkl)
|
||||||
|
{
|
||||||
|
ERR("Can't get version info (error: %lu)\n", GetLastError());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
WORD wLangID = LOWORD(InfoEx.hkl);
|
||||||
|
|
||||||
|
/* Get the IME layouts from registry */
|
||||||
|
PREG_IME_LAYOUT pLayouts = NULL;
|
||||||
|
UINT iLayout, cLayouts = Imm32GetImeLayoutList(NULL, 0);
|
||||||
|
if (cLayouts)
|
||||||
|
{
|
||||||
|
pLayouts = ImmLocalAlloc(0, cLayouts * sizeof(REG_IME_LAYOUT));
|
||||||
|
if (IS_NULL_UNEXPECTEDLY(pLayouts))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!Imm32GetImeLayoutList(pLayouts, cLayouts))
|
||||||
|
{
|
||||||
|
ERR("Can't get IME layouts\n");
|
||||||
|
ImmLocalFree(pLayouts);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iLayout = 0; iLayout < cLayouts; ++iLayout)
|
||||||
|
{
|
||||||
|
if (_wcsicmp(pLayouts[iLayout].szFileName, pchFileTitle) == 0)
|
||||||
|
{
|
||||||
|
if (wLangID != LOWORD(pLayouts[iLayout].hKL))
|
||||||
|
{
|
||||||
|
ERR("The language is mismatched\n");
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
hNewKL = pLayouts[iLayout].hKL; /* Found */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the IME for the specified filename is already loaded, then unload it now */
|
||||||
|
if (ImmGetImeInfoEx(&InfoEx, ImeInfoExImeFileName, pchFileTitle) &&
|
||||||
|
!UnloadKeyboardLayout(InfoEx.hkl))
|
||||||
|
{
|
||||||
|
ERR("Can't unload laybout\n");
|
||||||
|
hNewKL = NULL;
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
WCHAR szImeDestPath[MAX_PATH], szImeKey[20];
|
||||||
|
Imm32GetSystemLibraryPath(szImeDestPath, _countof(szImeDestPath), pchFileTitle);
|
||||||
|
|
||||||
|
/* If the source and the destination pathnames were different, then copy the IME file */
|
||||||
|
if (_wcsicmp(szImeFileName, szImeDestPath) != 0 &&
|
||||||
|
!Imm32CopyImeFile(szImeFileName, szImeDestPath))
|
||||||
|
{
|
||||||
|
ERR("Can't copy file (%s -> %s)\n", debugstr_w(szImeFileName), debugstr_w(szImeDestPath));
|
||||||
|
hNewKL = NULL;
|
||||||
|
goto Quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hNewKL == NULL)
|
||||||
|
hNewKL = Imm32AssignNewLayout(cLayouts, pLayouts, wLangID);
|
||||||
|
|
||||||
|
if (hNewKL)
|
||||||
|
{
|
||||||
|
/* Write the IME layout to registry */
|
||||||
|
if (Imm32WriteImeLayout(hNewKL, pchFileTitle, lpszLayoutText))
|
||||||
|
{
|
||||||
|
/* Replace the current keyboard layout */
|
||||||
|
StringCchPrintfW(szImeKey, _countof(szImeKey), L"%08X", HandleToUlong(hNewKL));
|
||||||
|
hNewKL = LoadKeyboardLayoutW(szImeKey, KLF_REPLACELANG);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("Can't write IME layout to registry\n");
|
||||||
|
hNewKL = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
ImmLocalFree(pLayouts);
|
||||||
|
return hNewKL;
|
||||||
|
}
|
|
@ -810,7 +810,11 @@ ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID)
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmSystemHandler(IMM32.@)
|
* ImmSystemHandler(IMM32.@)
|
||||||
*/
|
*/
|
||||||
LRESULT WINAPI ImmSystemHandler(HIMC hIMC, WPARAM wParam, LPARAM lParam)
|
LRESULT WINAPI
|
||||||
|
ImmSystemHandler(
|
||||||
|
_In_ HIMC hIMC,
|
||||||
|
_Inout_opt_ WPARAM wParam,
|
||||||
|
_Inout_opt_ LPARAM lParam)
|
||||||
{
|
{
|
||||||
TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam);
|
TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam);
|
||||||
|
|
||||||
|
|
|
@ -84,15 +84,6 @@
|
||||||
|
|
||||||
#define REGKEY_KEYBOARD_LAYOUTS L"System\\CurrentControlSet\\Control\\Keyboard Layouts"
|
#define REGKEY_KEYBOARD_LAYOUTS L"System\\CurrentControlSet\\Control\\Keyboard Layouts"
|
||||||
|
|
||||||
#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 ghImm32Inst;
|
extern HMODULE ghImm32Inst;
|
||||||
extern RTL_CRITICAL_SECTION gcsImeDpi;
|
extern RTL_CRITICAL_SECTION gcsImeDpi;
|
||||||
extern PIMEDPI gpImeDpiList;
|
extern PIMEDPI gpImeDpiList;
|
||||||
|
@ -124,6 +115,7 @@ BOOL Imm32IsSystemJapaneseOrKorean(VOID);
|
||||||
BOOL APIENTRY Imm32IsCrossThreadAccess(HIMC hIMC);
|
BOOL APIENTRY Imm32IsCrossThreadAccess(HIMC hIMC);
|
||||||
BOOL APIENTRY Imm32IsCrossProcessAccess(HWND hWnd);
|
BOOL APIENTRY Imm32IsCrossProcessAccess(HWND hWnd);
|
||||||
BOOL Imm32IsImcAnsi(HIMC hIMC);
|
BOOL Imm32IsImcAnsi(HIMC hIMC);
|
||||||
|
BOOL Imm32LoadImeVerInfo(_Out_ PIMEINFOEX pImeInfoEx);
|
||||||
|
|
||||||
#define ImeDpi_IsUnicode(pImeDpi) ((pImeDpi)->ImeInfo.fdwProperty & IME_PROP_UNICODE)
|
#define ImeDpi_IsUnicode(pImeDpi) ((pImeDpi)->ImeInfo.fdwProperty & IME_PROP_UNICODE)
|
||||||
|
|
||||||
|
@ -159,13 +151,19 @@ Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc,
|
||||||
DWORD APIENTRY
|
DWORD APIENTRY
|
||||||
Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage);
|
Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage);
|
||||||
|
|
||||||
HRESULT APIENTRY Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase);
|
HRESULT
|
||||||
HRESULT APIENTRY Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff);
|
Imm32StrToUInt(
|
||||||
BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx);
|
_In_ PCWSTR pszText,
|
||||||
UINT APIENTRY Imm32GetImeLayout(PREG_IME pLayouts, UINT cLayouts);
|
_Out_ PDWORD pdwValue,
|
||||||
BOOL APIENTRY Imm32WriteImeLayout(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayoutText);
|
_In_ ULONG nBase);
|
||||||
HKL APIENTRY Imm32AssignNewLayout(UINT cKLs, const REG_IME *pLayouts, WORD wLangID);
|
|
||||||
BOOL APIENTRY Imm32CopyImeFile(LPWSTR pszOldFile, LPCWSTR pszNewFile);
|
HRESULT
|
||||||
|
Imm32UIntToStr(
|
||||||
|
_In_ DWORD dwValue,
|
||||||
|
_In_ ULONG nBase,
|
||||||
|
_Out_ PWSTR pszBuff,
|
||||||
|
_In_ USHORT cchBuff);
|
||||||
|
|
||||||
PTHREADINFO FASTCALL Imm32CurrentPti(VOID);
|
PTHREADINFO FASTCALL Imm32CurrentPti(VOID);
|
||||||
|
|
||||||
HRESULT CtfImmTIMCreateInputContext(_In_ HIMC hIMC);
|
HRESULT CtfImmTIMCreateInputContext(_In_ HIMC hIMC);
|
||||||
|
|
|
@ -15,7 +15,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm);
|
||||||
|
|
||||||
HANDLE ghImmHeap = NULL; // Win: pImmHeap
|
HANDLE ghImmHeap = NULL; // Win: pImmHeap
|
||||||
|
|
||||||
/* Win: PtiCurrent */
|
|
||||||
PTHREADINFO FASTCALL Imm32CurrentPti(VOID)
|
PTHREADINFO FASTCALL Imm32CurrentPti(VOID)
|
||||||
{
|
{
|
||||||
if (NtCurrentTeb()->Win32ThreadInfo == NULL)
|
if (NtCurrentTeb()->Win32ThreadInfo == NULL)
|
||||||
|
@ -38,12 +37,15 @@ BOOL APIENTRY Imm32IsCrossProcessAccess(HWND hWnd)
|
||||||
return WndPID != CurrentPID;
|
return WndPID != CurrentPID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win: StrToUInt
|
HRESULT
|
||||||
HRESULT APIENTRY
|
Imm32StrToUInt(
|
||||||
Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase)
|
_In_ PCWSTR pszText,
|
||||||
|
_Out_ PDWORD pdwValue,
|
||||||
|
_In_ ULONG nBase)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
UNICODE_STRING UnicodeString;
|
UNICODE_STRING UnicodeString;
|
||||||
|
*pdwValue = 0;
|
||||||
RtlInitUnicodeString(&UnicodeString, pszText);
|
RtlInitUnicodeString(&UnicodeString, pszText);
|
||||||
Status = RtlUnicodeStringToInteger(&UnicodeString, nBase, pdwValue);
|
Status = RtlUnicodeStringToInteger(&UnicodeString, nBase, pdwValue);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -51,9 +53,12 @@ Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win: UIntToStr
|
HRESULT
|
||||||
HRESULT APIENTRY
|
Imm32UIntToStr(
|
||||||
Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff)
|
_In_ DWORD dwValue,
|
||||||
|
_In_ ULONG nBase,
|
||||||
|
_Out_ PWSTR pszBuff,
|
||||||
|
_In_ USHORT cchBuff)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
UNICODE_STRING UnicodeString;
|
UNICODE_STRING UnicodeString;
|
||||||
|
@ -584,426 +589,6 @@ Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc,
|
||||||
return cbDest;
|
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;
|
|
||||||
|
|
||||||
// Win: LoadFixVersionInfo
|
|
||||||
static BOOL APIENTRY Imm32LoadImeFixedInfo(PIMEINFOEX pInfoEx, LPCVOID pVerInfo)
|
|
||||||
{
|
|
||||||
UINT cbFixed = 0;
|
|
||||||
VS_FIXEDFILEINFO *pFixed;
|
|
||||||
if (!s_fnVerQueryValueW(pVerInfo, L"\\", (LPVOID*)&pFixed, &cbFixed) || !cbFixed)
|
|
||||||
{
|
|
||||||
ERR("Fixed version info not available\n");
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
ERR("DLL %S is not an IME\n", pInfoEx->wszImeFile);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pInfoEx->dwProdVersion = pFixed->dwProductVersionMS;
|
|
||||||
pInfoEx->dwImeWinVersion = 0x40000;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: GetVersionDatum
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: LoadVarVersionInfo
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
ERR("Translation not available\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pInfoEx->hkl == NULL)
|
|
||||||
pInfoEx->hkl = UlongToHandle(*pw);
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: LoadVersionInfo
|
|
||||||
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 (IS_NULL_UNEXPECTEDLY(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 (IS_ZERO_UNEXPECTEDLY(cbVerInfo))
|
|
||||||
goto Quit;
|
|
||||||
|
|
||||||
pVerInfo = ImmLocalAlloc(0, cbVerInfo);
|
|
||||||
if (IS_NULL_UNEXPECTEDLY(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImmLocalFree(pVerInfo);
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
if (bLoaded)
|
|
||||||
FreeLibrary(hinstVersion);
|
|
||||||
TRACE("ret: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: AssignNewLayout
|
|
||||||
HKL APIENTRY Imm32AssignNewLayout(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 UlongToHandle(MAKELONG(wLangID, wNextID));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: GetImeLayout
|
|
||||||
UINT APIENTRY Imm32GetImeLayout(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 (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
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 (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* 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] = UNICODE_NULL; /* Avoid buffer overrun */
|
|
||||||
|
|
||||||
RegCloseKey(hkeyIME);
|
|
||||||
|
|
||||||
/* We don't allow the invalid "IME File" values for security reason */
|
|
||||||
if (!szImeFileName[0] || wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName))
|
|
||||||
{
|
|
||||||
WARN("\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Imm32StrToUInt(szImeKey, &Value, 16);
|
|
||||||
hKL = UlongToHandle(Value);
|
|
||||||
if (!IS_IME_HKL(hKL)) /* Not an IME */
|
|
||||||
{
|
|
||||||
WARN("\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win: WriteImeLayout
|
|
||||||
BOOL APIENTRY Imm32WriteImeLayout(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayoutText)
|
|
||||||
{
|
|
||||||
UINT iPreload;
|
|
||||||
HKEY hkeyLayouts, hkeyIME, hkeyPreload;
|
|
||||||
WCHAR szImeKey[20], szPreloadNumber[20], szPreloadKey[20];
|
|
||||||
DWORD cbData;
|
|
||||||
LANGID LangID;
|
|
||||||
LONG lError;
|
|
||||||
LPCWSTR pszLayoutFile;
|
|
||||||
|
|
||||||
/* Open the registry keyboard layouts */
|
|
||||||
lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
|
|
||||||
if (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* Get the IME key from hKL */
|
|
||||||
StringCchPrintf(szImeKey, _countof(szImeKey), L"%08X", HandleToUlong(hKL));
|
|
||||||
|
|
||||||
/* Create a registry IME key */
|
|
||||||
lError = RegCreateKeyW(hkeyLayouts, szImeKey, &hkeyIME);
|
|
||||||
if (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
goto Failure;
|
|
||||||
|
|
||||||
/* Write "Ime File" */
|
|
||||||
cbData = (wcslen(pchFilePart) + 1) * sizeof(WCHAR);
|
|
||||||
lError = RegSetValueExW(hkeyIME, L"Ime File", 0, REG_SZ, (LPBYTE)pchFilePart, cbData);
|
|
||||||
if (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
goto Failure;
|
|
||||||
|
|
||||||
/* Write "Layout Text" */
|
|
||||||
cbData = (wcslen(pszLayoutText) + 1) * sizeof(WCHAR);
|
|
||||||
lError = RegSetValueExW(hkeyIME, L"Layout Text", 0, REG_SZ, (LPBYTE)pszLayoutText, cbData);
|
|
||||||
if (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write "Layout File" */
|
|
||||||
cbData = (wcslen(pszLayoutFile) + 1) * sizeof(WCHAR);
|
|
||||||
lError = RegSetValueExW(hkeyIME, L"Layout File", 0, REG_SZ, (LPBYTE)pszLayoutFile, cbData);
|
|
||||||
if (IS_ERROR_UNEXPECTEDLY(lError))
|
|
||||||
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] = UNICODE_NULL; /* Avoid buffer overrun */
|
|
||||||
|
|
||||||
if (lError != ERROR_SUCCESS || lstrcmpiW(szImeKey, szPreloadKey) == 0)
|
|
||||||
break; /* Found an empty room or the same key */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iPreload >= MAX_PRELOAD) /* Not found */
|
|
||||||
{
|
|
||||||
ERR("\n");
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Win: CopyImeFile
|
|
||||||
BOOL APIENTRY Imm32CopyImeFile(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 (IS_NULL_UNEXPECTEDLY(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ImmCreateIMCC(IMM32.@)
|
* ImmCreateIMCC(IMM32.@)
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue