mirror of
https://github.com/reactos/reactos.git
synced 2024-11-23 11:33:31 +08:00
[NTUSER][USER32] Refactor NtUserLoadKeyboardLayoutEx (#5107)
- Split some code of NtUserLoadKeyboardLayoutEx to newly-added co_IntLoadKeyboardLayoutEx helper function. - Modify NtUserLoadKeyboardLayoutEx prototype. - Move co_UserImmLoadLayout code. - Implement KLF_REORDER. - Rename UserLoadKbdLayout as co_UserLoadKbdLayout. - Improve LoadKeyboardLayoutEx. CORE-11700
This commit is contained in:
parent
0fb580a855
commit
77e6348f5f
@ -2736,12 +2736,12 @@ NtUserKillTimer(
|
||||
HKL
|
||||
NTAPI
|
||||
NtUserLoadKeyboardLayoutEx(
|
||||
IN HANDLE Handle,
|
||||
IN HANDLE hFile,
|
||||
IN DWORD offTable,
|
||||
IN PUNICODE_STRING puszKeyboardName,
|
||||
IN HKL hKL,
|
||||
IN PVOID pTables,
|
||||
IN HKL hOldKL,
|
||||
IN PUNICODE_STRING puszKLID,
|
||||
IN DWORD dwKLID,
|
||||
IN DWORD dwNewKL,
|
||||
IN UINT Flags);
|
||||
|
||||
BOOL
|
||||
|
@ -369,12 +369,12 @@ cleanup:
|
||||
}
|
||||
|
||||
/*
|
||||
* UserLoadKbdLayout
|
||||
* co_UserLoadKbdLayout
|
||||
*
|
||||
* Loads keyboard layout and creates KL object
|
||||
*/
|
||||
static PKL
|
||||
UserLoadKbdLayout(PUNICODE_STRING pustrKLID, HKL hKL)
|
||||
co_UserLoadKbdLayout(PUNICODE_STRING pustrKLID, HKL hKL)
|
||||
{
|
||||
LCID lCid;
|
||||
CHARSETINFO cs;
|
||||
@ -846,6 +846,129 @@ IntUnloadKeyboardLayout(_Inout_ PWINSTATION_OBJECT pWinSta, _In_ HKL hKL)
|
||||
return co_IntUnloadKeyboardLayoutEx(pWinSta, pKL, 0);
|
||||
}
|
||||
|
||||
PIMEINFOEX FASTCALL co_UserImmLoadLayout(_In_ HKL hKL)
|
||||
{
|
||||
PIMEINFOEX piiex;
|
||||
|
||||
if (!IS_IME_HKL(hKL) && !IS_CICERO_MODE())
|
||||
return NULL;
|
||||
|
||||
piiex = ExAllocatePoolWithTag(PagedPool, sizeof(IMEINFOEX), USERTAG_IME);
|
||||
if (!piiex)
|
||||
return NULL;
|
||||
|
||||
if (!co_ClientImmLoadLayout(hKL, piiex))
|
||||
{
|
||||
ExFreePoolWithTag(piiex, USERTAG_IME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return piiex;
|
||||
}
|
||||
|
||||
HKL APIENTRY
|
||||
co_IntLoadKeyboardLayoutEx(
|
||||
IN OUT PWINSTATION_OBJECT pWinSta,
|
||||
IN HANDLE hSafeFile,
|
||||
IN HKL hOldKL,
|
||||
IN PUNICODE_STRING puszSafeKLID,
|
||||
IN HKL hNewKL,
|
||||
IN UINT Flags)
|
||||
{
|
||||
PKL pOldKL, pNewKL;
|
||||
|
||||
UNREFERENCED_PARAMETER(hSafeFile);
|
||||
|
||||
if (hNewKL == NULL || (pWinSta->Flags & WSS_NOIO))
|
||||
return NULL;
|
||||
|
||||
/* If hOldKL is specified, unload it and load new layput as default */
|
||||
if (hOldKL && hOldKL != hNewKL)
|
||||
{
|
||||
pOldKL = UserHklToKbl(hOldKL);
|
||||
if (pOldKL)
|
||||
UserUnloadKbl(pOldKL);
|
||||
}
|
||||
|
||||
/* FIXME: It seems KLF_RESET is only supported for WINLOGON */
|
||||
|
||||
/* Let's see if layout was already loaded. */
|
||||
pNewKL = UserHklToKbl(hNewKL);
|
||||
if (!pNewKL)
|
||||
{
|
||||
/* It wasn't, so load it. */
|
||||
pNewKL = co_UserLoadKbdLayout(puszSafeKLID, hNewKL);
|
||||
if (!pNewKL)
|
||||
return NULL;
|
||||
|
||||
if (gspklBaseLayout)
|
||||
{
|
||||
/* Find last not unloaded layout */
|
||||
PKL pLastKL = gspklBaseLayout->pklPrev;
|
||||
while (pLastKL != gspklBaseLayout && (pLastKL->dwKL_Flags & KLF_UNLOAD))
|
||||
pLastKL = pLastKL->pklPrev;
|
||||
|
||||
/* Add new layout to the list */
|
||||
pNewKL->pklNext = pLastKL->pklNext;
|
||||
pNewKL->pklPrev = pLastKL;
|
||||
pNewKL->pklNext->pklPrev = pNewKL;
|
||||
pNewKL->pklPrev->pklNext = pNewKL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is the first layout */
|
||||
pNewKL->pklNext = pNewKL;
|
||||
pNewKL->pklPrev = pNewKL;
|
||||
gspklBaseLayout = pNewKL;
|
||||
}
|
||||
|
||||
pNewKL->piiex = co_UserImmLoadLayout(hNewKL);
|
||||
}
|
||||
|
||||
/* If this layout was prepared to unload, undo it */
|
||||
pNewKL->dwKL_Flags &= ~KLF_UNLOAD;
|
||||
|
||||
/* Reorder if necessary */
|
||||
if (Flags & KLF_REORDER)
|
||||
IntReorderKeyboardLayouts(pWinSta, pNewKL);
|
||||
|
||||
/* Activate this layout in current thread */
|
||||
if (Flags & KLF_ACTIVATE)
|
||||
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pNewKL, Flags);
|
||||
|
||||
/* Send shell message */
|
||||
if (!(Flags & KLF_NOTELLSHELL))
|
||||
co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hNewKL);
|
||||
|
||||
/* FIXME: KLF_REPLACELANG */
|
||||
|
||||
return hNewKL;
|
||||
}
|
||||
|
||||
HANDLE FASTCALL IntVerifyKeyboardFileHandle(HANDLE hFile)
|
||||
{
|
||||
PFILE_OBJECT FileObject;
|
||||
NTSTATUS Status;
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
Status = ObReferenceObjectByHandle(hFile, FILE_READ_DATA, NULL, UserMode,
|
||||
(PVOID*)&FileObject, NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("0x%08X\n", Status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: Is the file in the system directory? */
|
||||
|
||||
if (FileObject)
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
return hFile;
|
||||
}
|
||||
|
||||
/* EXPORTS *******************************************************************/
|
||||
|
||||
/*
|
||||
@ -1009,50 +1132,34 @@ cleanup:
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/* Win: xxxImmLoadLayout */
|
||||
PIMEINFOEX FASTCALL co_UserImmLoadLayout(_In_ HKL hKL)
|
||||
{
|
||||
PIMEINFOEX piiex;
|
||||
|
||||
if (!IS_IME_HKL(hKL) && !IS_CICERO_MODE())
|
||||
return NULL;
|
||||
|
||||
piiex = ExAllocatePoolWithTag(PagedPool, sizeof(IMEINFOEX), USERTAG_IME);
|
||||
if (!piiex)
|
||||
return NULL;
|
||||
|
||||
if (!co_ClientImmLoadLayout(hKL, piiex))
|
||||
{
|
||||
ExFreePoolWithTag(piiex, USERTAG_IME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return piiex;
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserLoadKeyboardLayoutEx
|
||||
*
|
||||
* Loads keyboard layout with given locale id
|
||||
*
|
||||
* NOTE: We adopt a different design from Microsoft's one for security reason.
|
||||
* We don't use the 1st and 3rd parameters of NtUserLoadKeyboardLayoutEx.
|
||||
* NOTE: We adopt a different design from Microsoft's one due to security reason.
|
||||
* We don't use the 3rd parameter of NtUserLoadKeyboardLayoutEx.
|
||||
* See https://bugtraq.securityfocus.com/detail/50056B96.6040306
|
||||
*/
|
||||
HKL
|
||||
APIENTRY
|
||||
NTAPI
|
||||
NtUserLoadKeyboardLayoutEx(
|
||||
IN HANDLE Handle, // hFile (See downloads.securityfocus.com/vulnerabilities/exploits/43774.c)
|
||||
IN DWORD offTable, // Offset to KbdTables
|
||||
IN PUNICODE_STRING puszKeyboardName, // Not used?
|
||||
IN HKL hklUnload,
|
||||
IN PUNICODE_STRING pustrKLID,
|
||||
IN DWORD hkl,
|
||||
IN HANDLE hFile,
|
||||
IN DWORD offTable,
|
||||
IN PVOID pTables,
|
||||
IN HKL hOldKL,
|
||||
IN PUNICODE_STRING puszKLID,
|
||||
IN DWORD dwNewKL,
|
||||
IN UINT Flags)
|
||||
{
|
||||
HKL hklRet = NULL;
|
||||
PKL pKl = NULL, pklLast;
|
||||
HKL hRetKL;
|
||||
WCHAR Buffer[KL_NAMELENGTH];
|
||||
UNICODE_STRING ustrSafeKLID;
|
||||
UNICODE_STRING uszSafeKLID;
|
||||
PWINSTATION_OBJECT pWinSta;
|
||||
HANDLE hSafeFile;
|
||||
|
||||
UNREFERENCED_PARAMETER(offTable);
|
||||
UNREFERENCED_PARAMETER(pTables);
|
||||
|
||||
if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG|
|
||||
KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS|KLF_UNLOADPREVIOUS|
|
||||
@ -1063,14 +1170,12 @@ NtUserLoadKeyboardLayoutEx(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: It seems KLF_RESET is only supported for WINLOGON */
|
||||
|
||||
RtlInitEmptyUnicodeString(&ustrSafeKLID, Buffer, sizeof(Buffer));
|
||||
RtlInitEmptyUnicodeString(&uszSafeKLID, Buffer, sizeof(Buffer));
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(pustrKLID, sizeof(*pustrKLID), 1);
|
||||
ProbeForRead(pustrKLID->Buffer, sizeof(pustrKLID->Length), 1);
|
||||
RtlCopyUnicodeString(&ustrSafeKLID, pustrKLID);
|
||||
ProbeForRead(puszKLID, sizeof(*puszKLID), 1);
|
||||
ProbeForRead(puszKLID->Buffer, sizeof(puszKLID->Length), 1);
|
||||
RtlCopyUnicodeString(&uszSafeKLID, puszKLID);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
@ -1081,67 +1186,19 @@ NtUserLoadKeyboardLayoutEx(
|
||||
|
||||
UserEnterExclusive();
|
||||
|
||||
/* If hklUnload is specified, unload it and load new layput as default */
|
||||
if (hklUnload && (hklUnload != UlongToHandle(hkl)))
|
||||
{
|
||||
pKl = UserHklToKbl(hklUnload);
|
||||
if (pKl)
|
||||
UserUnloadKbl(pKl);
|
||||
}
|
||||
hSafeFile = (hFile ? IntVerifyKeyboardFileHandle(hFile) : NULL);
|
||||
pWinSta = IntGetProcessWindowStation(NULL);
|
||||
hRetKL = co_IntLoadKeyboardLayoutEx(pWinSta,
|
||||
hSafeFile,
|
||||
hOldKL,
|
||||
&uszSafeKLID,
|
||||
(HKL)(DWORD_PTR)dwNewKL,
|
||||
Flags);
|
||||
if (hSafeFile)
|
||||
ZwClose(hSafeFile);
|
||||
|
||||
/* Let's see if layout was already loaded. */
|
||||
pKl = UserHklToKbl(UlongToHandle(hkl));
|
||||
if (!pKl)
|
||||
{
|
||||
/* It wasn't, so load it. */
|
||||
pKl = UserLoadKbdLayout(&ustrSafeKLID, UlongToHandle(hkl));
|
||||
if (!pKl)
|
||||
goto cleanup;
|
||||
|
||||
if (gspklBaseLayout)
|
||||
{
|
||||
/* Find last not unloaded layout */
|
||||
pklLast = gspklBaseLayout->pklPrev;
|
||||
while (pklLast != gspklBaseLayout && pklLast->dwKL_Flags & KLF_UNLOAD)
|
||||
pklLast = pklLast->pklPrev;
|
||||
|
||||
/* Add new layout to the list */
|
||||
pKl->pklNext = pklLast->pklNext;
|
||||
pKl->pklPrev = pklLast;
|
||||
pKl->pklNext->pklPrev = pKl;
|
||||
pKl->pklPrev->pklNext = pKl;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is the first layout */
|
||||
pKl->pklNext = pKl;
|
||||
pKl->pklPrev = pKl;
|
||||
gspklBaseLayout = pKl;
|
||||
}
|
||||
|
||||
pKl->piiex = co_UserImmLoadLayout(UlongToHandle(hkl));
|
||||
}
|
||||
|
||||
/* If this layout was prepared to unload, undo it */
|
||||
pKl->dwKL_Flags &= ~KLF_UNLOAD;
|
||||
|
||||
/* Activate this layout in current thread */
|
||||
if (Flags & KLF_ACTIVATE)
|
||||
co_UserActivateKbl(PsGetCurrentThreadWin32Thread(), pKl, Flags);
|
||||
|
||||
/* Send shell message */
|
||||
if (!(Flags & KLF_NOTELLSHELL))
|
||||
co_IntShellHookNotify(HSHELL_LANGUAGE, 0, (LPARAM)hkl);
|
||||
|
||||
/* Return hkl on success */
|
||||
hklRet = UlongToHandle(hkl);
|
||||
|
||||
/* FIXME: KLF_REPLACELANG
|
||||
KLF_REORDER */
|
||||
|
||||
cleanup:
|
||||
UserLeave();
|
||||
return hklRet;
|
||||
return hRetKL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -721,9 +721,9 @@ VOID GetSystemLibraryPath(LPWSTR pszPath, INT cchPath, LPCWSTR pszFileName)
|
||||
/*
|
||||
* @unimplemented
|
||||
*
|
||||
* NOTE: We adopt a different design from Microsoft's one for security reason.
|
||||
* NOTE: We adopt a different design from Microsoft's one due to security reason.
|
||||
* See NtUserLoadKeyboardLayoutEx.
|
||||
*/
|
||||
/* Win: LoadKeyboardLayoutWorker */
|
||||
HKL APIENTRY
|
||||
IntLoadKeyboardLayout(
|
||||
_In_ HKL hklUnload,
|
||||
@ -733,7 +733,6 @@ IntLoadKeyboardLayout(
|
||||
_In_ BOOL unknown5)
|
||||
{
|
||||
DWORD dwKLID, dwHKL, dwType, dwSize;
|
||||
UNICODE_STRING ustrKbdName;
|
||||
UNICODE_STRING ustrKLID;
|
||||
WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
|
||||
WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80];
|
||||
@ -807,7 +806,7 @@ IntLoadKeyboardLayout(
|
||||
szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL;
|
||||
GetSystemLibraryPath(szPath, _countof(szPath), szImeFileName);
|
||||
|
||||
/* We don't allow the invalid "IME File" values for security reason */
|
||||
/* We don't allow the invalid "IME File" values due to security reason */
|
||||
if (dwType != REG_SZ || szImeFileName[0] == 0 ||
|
||||
wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName) ||
|
||||
GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) /* Does not exist? */
|
||||
@ -833,9 +832,8 @@ IntLoadKeyboardLayout(
|
||||
|
||||
dwHKL = MAKELONG(wLow, wHigh);
|
||||
|
||||
ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
|
||||
RtlInitUnicodeString(&ustrKLID, pwszKLID);
|
||||
hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName, NULL, &ustrKLID, dwHKL, Flags);
|
||||
hNewKL = NtUserLoadKeyboardLayoutEx(NULL, 0, NULL, hklUnload, &ustrKLID, dwHKL, Flags);
|
||||
CliImmInitializeHotKeys(SETIMEHOTKEY_ADD, hNewKL);
|
||||
return hNewKL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user