Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1001 lines
27 KiB

/**************************** Module Header ********************************\
* Copyright 1985-92, Microsoft Corporation
*
* Keyboard Layout API
*
* History:
* 04-14-92 IanJa Created
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Workers (forward declarations)
*/
BOOL xxxInternalUnloadKeyboardLayout(PWINDOWSTATION, PKL, UINT);
VOID ReorderKeyboardLayouts(PWINDOWSTATION, PKL);
/*
* Note that this only works for sections < 64K
*/
#define FIXUP_PTR(p, pBase) ((p) ? (p) = (PVOID)((PBYTE)pBase + (WORD)(p)) : 0)
/****************************************************************************\
* HKLtoPKL
*
* Given HKL_NEXT or HKL_PREV
* Finds the the next/prev LOADED layout, NULL if none.
* (Starts from the current active layout, may return pklActive itself)
*
* Given Keyboard Layout handle:
* Find the kbd layout struct (loaded or not), NULL if no match found.
*
* History:
\****************************************************************************/
PKL HKLtoPKL(
HKL hkl)
{
PKL pklActive;
PKL pkl;
if ((pklActive = PtiCurrentShared()->spklActive) == NULL) {
return NULL;
}
pkl = pklActive;
if ((DWORD)hkl == HKL_PREV) {
do {
pkl = pkl->pklPrev;
if (!(pkl->dwFlags & KL_UNLOADED)) {
return pkl;
}
} while (pkl != pklActive);
return NULL;
} else if ((DWORD)hkl == HKL_NEXT) {
do {
pkl = pkl->pklNext;
if (!(pkl->dwFlags & KL_UNLOADED)) {
return pkl;
}
} while (pkl != pklActive);
return NULL;
}
do {
if (pkl->hkl == hkl) {
return pkl;
}
pkl = pkl->pklNext;
} while (pkl != pklActive);
return NULL;
}
/***************************************************************************\
* ReadLayoutFile
*
* Maps layout file into memory and initializes layout table.
*
* History:
* 01-10-95 JimA Created.
\***************************************************************************/
PKBDTABLES ReadLayoutFile(
PKBDFILE pkf,
HANDLE hFile,
UINT offTable)
{
HANDLE hmap;
ULONG ulViewSize = 0;
NTSTATUS Status;
PIMAGE_DOS_HEADER DosHdr;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER SectionTableEntry;
ULONG NumberOfSubsections;
ULONG OffsetToSectionTable;
PBYTE pBaseDst, pBaseVirt;
PKBDTABLES pktNew = NULL;
DWORD dwDataSize;
/*
* Map the layout file into memory
*/
DosHdr = NULL;
Status = ZwCreateSection(&hmap, SECTION_ALL_ACCESS, NULL,
NULL, PAGE_READONLY, SEC_COMMIT, hFile);
if (!NT_SUCCESS(Status))
return NULL;
Status = ZwMapViewOfSection(hmap, NtCurrentProcess(), &DosHdr, 0, 0, NULL,
&ulViewSize, ViewShare, 0, PAGE_READONLY);
if (!NT_SUCCESS(Status)) {
goto exitread;
}
/*
* HACK Part 2! We find the .data section in the file header
* and by subtracting the virtual address from offTable find
* the offset in the section of the layout table.
*/
NtHeader = (PIMAGE_NT_HEADERS)((ULONG)DosHdr + (ULONG)DosHdr->e_lfanew);
/*
* Build the next subsections.
*/
NumberOfSubsections = NtHeader->FileHeader.NumberOfSections;
/*
* At this point the object table is read in (if it was not
* already read in) and may displace the image header.
*/
OffsetToSectionTable = sizeof(ULONG) +
sizeof(IMAGE_FILE_HEADER) +
NtHeader->FileHeader.SizeOfOptionalHeader;
SectionTableEntry = (PIMAGE_SECTION_HEADER)((ULONG)NtHeader +
OffsetToSectionTable);
while (NumberOfSubsections > 0) {
if (strcmp(SectionTableEntry->Name, ".data") == 0)
break;
SectionTableEntry++;
NumberOfSubsections--;
}
if (NumberOfSubsections == 0) {
goto exitread;
}
/*
* We found the section, now compute starting offset and the table size.
*/
offTable -= SectionTableEntry->VirtualAddress;
dwDataSize = SectionTableEntry->Misc.VirtualSize;
/*
* Allocate layout table and copy from file.
*/
pBaseDst = UserAllocPool(dwDataSize, TAG_KBDTABLE);
if (pBaseDst != NULL) {
VK_TO_WCHAR_TABLE *pVkToWcharTable;
VSC_LPWSTR *pKeyName;
LPWSTR *lpDeadKey;
pkf->hBase = (HANDLE)pBaseDst;
RtlMoveMemory(pBaseDst, (PBYTE)DosHdr +
SectionTableEntry->PointerToRawData, dwDataSize);
/*
* Compute table address and fixup pointers in table.
*/
pktNew = (PKBDTABLES)(pBaseDst + offTable);
/*
* The address in the data section has the virtual address
* added in, so we need to adjust the fixup pointer to
* compensate.
*/
pBaseVirt = pBaseDst - SectionTableEntry->VirtualAddress;
FIXUP_PTR(pktNew->pCharModifiers, pBaseVirt);
FIXUP_PTR(pktNew->pCharModifiers->pVkToBit, pBaseVirt);
if (FIXUP_PTR(pktNew->pVkToWcharTable, pBaseVirt)) {
for (pVkToWcharTable = pktNew->pVkToWcharTable;
pVkToWcharTable->pVkToWchars != NULL; pVkToWcharTable++)
FIXUP_PTR(pVkToWcharTable->pVkToWchars, pBaseVirt);
}
FIXUP_PTR(pktNew->pDeadKey, pBaseVirt);
if (FIXUP_PTR(pktNew->pKeyNames, pBaseVirt)) {
for (pKeyName = pktNew->pKeyNames; pKeyName->vsc != 0; pKeyName++)
FIXUP_PTR(pKeyName->pwsz, pBaseVirt);
}
if (FIXUP_PTR(pktNew->pKeyNamesExt, pBaseVirt)) {
for (pKeyName = pktNew->pKeyNamesExt; pKeyName->vsc != 0; pKeyName++)
FIXUP_PTR(pKeyName->pwsz, pBaseVirt);
}
if (FIXUP_PTR(pktNew->pKeyNamesDead, pBaseVirt)) {
for (lpDeadKey = pktNew->pKeyNamesDead; *lpDeadKey != NULL;
lpDeadKey++)
FIXUP_PTR(*lpDeadKey, pBaseVirt);
}
FIXUP_PTR(pktNew->pusVSCtoVK, pBaseVirt);
FIXUP_PTR(pktNew->pVSCtoVK_E0, pBaseVirt);
FIXUP_PTR(pktNew->pVSCtoVK_E1, pBaseVirt);
}
exitread:
/*
* Unmap and release the mapped section.
*/
ZwUnmapViewOfSection(NtCurrentProcess(), DosHdr);
ZwClose(hmap);
return pktNew;
}
/***************************************************************************\
* LoadKeyboardLayoutFile
*
* History:
* 10-29-95 GregoryW Created.
\***************************************************************************/
PKBDFILE LoadKeyboardLayoutFile(
HANDLE hFile,
UINT offTable,
LPCWSTR pwszKLID)
{
PKBDFILE pkf = gpkfList;
if (pkf) {
int iCmp;
do {
iCmp = wcscmp(pkf->awchKF, pwszKLID);
if (iCmp == 0) {
/*
* The layout is already loaded.
*/
return pkf;
}
pkf = pkf->pkfNext;
} while (pkf);
}
/*
* Allocate a new Keyboard File structure.
*/
pkf = (PKBDFILE)HMAllocObject(NULL, NULL, TYPE_KBDFILE, sizeof(KBDFILE));
if (!pkf) {
RIPMSG0(RIP_WARNING, "Keyboard Layout File: out of memory");
return (PKBDFILE)NULL;
}
/*
* Load layout table.
*/
pkf->pKbdTbl = ReadLayoutFile(pkf, hFile, offTable);
if (pkf->pKbdTbl == NULL) {
HMFreeObject(pkf);
return (PKBDFILE)NULL;
}
wcsncpycch(pkf->awchKF, pwszKLID, sizeof(pkf->awchKF) / sizeof(WCHAR));
/*
* Put keyboard layout file at front of list.
*/
pkf->pkfNext = gpkfList;
gpkfList = pkf;
return pkf;
}
/***************************************************************************\
* RemoveKeyboardLayoutFile
*
* History:
* 10-29-95 GregoryW Created.
\***************************************************************************/
VOID RemoveKeyboardLayoutFile(
PKBDFILE pkf)
{
PKBDFILE pkfPrev, pkfCur;
/*
* Good old linked list management 101
*/
if (pkf == gpkfList) {
/*
* Head of the list.
*/
gpkfList = pkf->pkfNext;
return;
}
pkfPrev = gpkfList;
pkfCur = gpkfList->pkfNext;
while (pkf != pkfCur) {
pkfPrev = pkfCur;
pkfCur = pkfCur->pkfNext;
}
/*
* Found it!
*/
pkfPrev->pkfNext = pkfCur->pkfNext;
}
VOID SetPKLinThreads(
PKL pklCurrent,
PKL pklReplace)
{
PTHREADINFO ptiT;
PEPROCESS pEProcess;
PETHREAD pEThread;
PLIST_ENTRY ProcessHead, NextProcess, NextThread;
/*
* Update pkl entries in the THREADINFO structures.
* gpepCSRSS might still be NULL if csrss process hasn't started yet.
*/
pEProcess = gpepCSRSS;
if (pEProcess != NULL) {
ProcessHead = pEProcess->ActiveProcessLinks.Flink;
NextProcess = ProcessHead;
do {
pEProcess = CONTAINING_RECORD(NextProcess, EPROCESS, ActiveProcessLinks);
if (pEProcess->Pcb.Header.Type != ProcessObject) {
/*
* We've come across PsActiveProcessHead...skip it.
*/
NextProcess = NextProcess->Flink;
continue;
}
NextProcess = pEProcess->ActiveProcessLinks.Flink;
if (pEProcess->Win32Process == NULL) {
continue;
}
NextThread = pEProcess->Pcb.ThreadListHead.Flink;
while (NextThread != &pEProcess->Pcb.ThreadListHead) {
pEThread = (PETHREAD)CONTAINING_RECORD(NextThread, KTHREAD, ThreadListEntry);
NextThread = ((PKTHREAD)pEThread)->ThreadListEntry.Flink;
ptiT = PtiFromThread(pEThread);
if (ptiT == NULL) {
continue;
}
if (!pklReplace) {
Lock(&ptiT->spklActive, pklCurrent);
} else if (pklReplace->hkl == ptiT->spklActive->hkl) {
Lock(&ptiT->spklActive, pklCurrent);
}
}
} while (NextProcess != ProcessHead);
} else {
RIPMSG0(RIP_WARNING, "gpepCSRSS not yet initialized");
}
/*
* If this is a replace, link the new layout immediately after the
* layout being replaced. This maintains ordering of layouts when
* the *replaced* layout is unloaded. The input locale panel in the
* regional settings applet depends on this.
*/
if (pklReplace) {
if (pklReplace->pklNext == pklCurrent) {
/*
* Ordering already correct. Nothing to do.
*/
return;
}
/*
* Move new layout immediately after layout being replaced.
* 1. Remove new layout from current position.
* 2. Update links in new layout.
* 3. Link new layout into desired position.
*/
pklCurrent->pklPrev->pklNext = pklCurrent->pklNext;
pklCurrent->pklNext->pklPrev = pklCurrent->pklPrev;
pklCurrent->pklNext = pklReplace->pklNext;
pklCurrent->pklPrev = pklReplace;
pklReplace->pklNext->pklPrev = pklCurrent;
pklReplace->pklNext = pklCurrent;
}
}
/***************************************************************************\
* xxxLoadKeyboardLayout
*
* History:
\***************************************************************************/
HKL xxxLoadKeyboardLayoutEx(
PWINDOWSTATION pwinsta,
HANDLE hFile,
HKL hklReplace,
UINT offTable,
LPCWSTR pwszKLID,
UINT KbdInputLocale,
UINT Flags)
{
PKL pkl, pklFirst, pklReplace;
PKBDFILE pkf;
CHARSETINFO cs;
#ifdef FE_IME
PIMEINFOEX piiex = NULL;
#endif
/*
* If the windowstation does not do I/O, don't load the
* layout.
*/
if (pwinsta->dwFlags & WSF_NOIO) {
return NULL;
}
/*
* If hklReplace is non-NULL make sure it's valid.
* NOTE: may want to verify they're not passing HKL_NEXT or HKL_PREV.
*/
if (hklReplace && !(pklReplace = HKLtoPKL(hklReplace))) {
return NULL;
}
if (KbdInputLocale == (UINT)hklReplace) {
/*
* Replacing a layout/lang pair with itself. Nothing to do.
*/
return pklReplace->hkl;
}
/*
* LATER - should not allow KLF_RESET for just any thread [ianja]
*/
if (Flags & KLF_RESET) {
xxxFreeKeyboardLayouts(pwinsta);
/*
* Make sure we don't lose track of the left-over layouts
* They have been unloaded, but are still in use by some threads)
*/
Lock(&pwinsta->spklList, gspklBaseLayout);
}
/*
* Does this hkl already exist?
*/
pkl = pklFirst = pwinsta->spklList;
if (pkl) {
do {
if (pkl->hkl == (HKL)KbdInputLocale) {
/*
* The hkl already exists.
*/
/*
* If it is unloaded (but not yet destroyed because it is
* still is use), recover it.
*/
if (pkl->dwFlags & KL_UNLOADED) {
// stop it from being destroyed if not is use.
PHE phe = HMPheFromObject(pkl);
// An unloaded layout must be marked for destroy.
UserAssert(phe->bFlags & HANDLEF_DESTROY);
phe->bFlags &= ~HANDLEF_DESTROY;
#ifdef DEBUG
phe->bFlags &= ~HANDLEF_MARKED_OK;
#endif
pkl->dwFlags &= ~KL_UNLOADED;
} else if (!(Flags & KLF_RESET)) {
/*
* If it was already loaded and we didn't change all layouts
* with KLF_RESET, there is nothing to tell the shell about
*/
Flags &= ~KLF_NOTELLSHELL;
}
goto AllPresentAndCorrectSir;
}
pkl = pkl->pklNext;
} while (pkl != pklFirst);
}
/*
* Keyboard Layout Handle object does not exist. Load keyboard layout file,
* if not already loaded.
*/
if (!(pkf = LoadKeyboardLayoutFile(hFile, offTable, pwszKLID))) {
return NULL;
}
/*
* Allocate a new Keyboard Layout structure (hkl)
*/
pkl = (PKL)HMAllocObject(NULL, NULL, TYPE_KBDLAYOUT, sizeof(KL));
if (!pkl) {
RIPMSG0(RIP_WARNING, "Keyboard Layout: out of memory");
UserFreePool(pkf->hBase);
HMMarkObjectDestroy(pkf);
HMUnlockObject(pkf);
return NULL;
}
/*
* Link to itself in case we have to DestroyKL
*/
pkl->pklNext = pkl;
pkl->pklPrev = pkl;
/*
* Init KL
*/
pkl->dwFlags = 0;
pkl->hkl = (HKL)KbdInputLocale;
Lock(&pkl->spkf, pkf);
#ifdef FE_IME
if (IS_IME_KBDLAYOUT((HKL)KbdInputLocale)) {
/*
* This is an IME keyboard layout, do a callback
* to read the extended IME information structure.
*/
piiex = xxxImmLoadLayout((HKL)KbdInputLocale);
if (!piiex) {
RIPMSG1(RIP_WARNING,
"Keyboard Layout: xxxImmLoadLayout(%lx) failed", KbdInputLocale);
DestroyKL(pkl);
return NULL;
}
}
pkl->piiex = piiex;
#endif
if (xxxClientGetCharsetInfo(HIWORD(KbdInputLocale), &cs)) {
pkl->CodePage = cs.ciACP;
pkl->bCharsets = cs.fs.fsCsb[0]; // Windows charset bitfield. These are FS_xxx values
pkl->iBaseCharset = cs.ciCharset; // charset value
} else {
pkl->CodePage = CP_ACP;
pkl->bCharsets = FS_LATIN1;
pkl->iBaseCharset = ANSI_CHARSET;
}
/*
* Get the system's codepage bitfield. These are 64-bit FS_xxx values,
* but we only need ANSI ones, so gSystemCPB is just a DWORD.
* gSystemCPB is consulted when posting WM_INPUTLANGCHANGEREQUEST (input.c)
*/
if (gSystemCPB == 0) {
LCID lcid;
ZwQueryDefaultLocale(FALSE, &lcid);
if (xxxClientGetCharsetInfo(lcid, &cs)) {
gSystemCPB = cs.fs.fsCsb[0];
} else {
gSystemCPB = 0xFFFF;
}
}
/*
* Insert KL in the double-linked circular list, at the end.
*/
pklFirst = pwinsta->spklList;
if (pklFirst == NULL) {
Lock(&pwinsta->spklList, pkl);
} else {
pkl->pklNext = pklFirst;
pkl->pklPrev = pklFirst->pklPrev;
pklFirst->pklPrev->pklNext = pkl;
pklFirst->pklPrev = pkl;
}
AllPresentAndCorrectSir:
if (hklReplace) {
SetPKLinThreads(pkl, pklReplace);
xxxInternalUnloadKeyboardLayout(pwinsta, pklReplace, KLF_INITTIME);
}
if (Flags & KLF_REORDER) {
ReorderKeyboardLayouts(pwinsta, pkl);
}
if (!(Flags & KLF_NOTELLSHELL) && IsHooked(PtiCurrent(), WHF_SHELL)) {
xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)0, WH_SHELL);
LCIDSentToShell = 0;
}
if (Flags & KLF_ACTIVATE) {
TL tlPKL;
ThreadLockAlways(pkl, &tlPKL);
xxxInternalActivateKeyboardLayout(pkl, Flags);
ThreadUnlock(&tlPKL);
}
if (Flags & KLF_RESET) {
Lock(&gspklBaseLayout, pkl);
SetPKLinThreads(pkl, NULL);
}
/*
* Use the hkl as the layout handle
*/
return (HANDLE)pkl->hkl;
}
HKL xxxActivateKeyboardLayout(
PWINDOWSTATION pwinsta,
HKL hkl,
UINT Flags)
{
PKL pkl;
TL tlPKL;
HKL hklRet;
pkl = HKLtoPKL(hkl);
if (pkl == NULL) {
return 0;
}
if (Flags & KLF_REORDER) {
ReorderKeyboardLayouts(pwinsta, pkl);
}
ThreadLockAlways(pkl, &tlPKL);
hklRet = xxxInternalActivateKeyboardLayout(pkl, Flags);
ThreadUnlock(&tlPKL);
return hklRet;
}
VOID ReorderKeyboardLayouts(
PWINDOWSTATION pwinsta,
PKL pkl)
{
PKL pklFirst = pwinsta->spklList;
UserAssert(pklFirst != NULL);
/*
* If the layout is already at the front of the list there's nothing to do.
*/
if (pkl == pklFirst) {
return;
}
/*
* Cut pkl from circular list:
*/
pkl->pklPrev->pklNext = pkl->pklNext;
pkl->pklNext->pklPrev = pkl->pklPrev;
/*
* Insert pkl at front of list
*/
pkl->pklNext = pklFirst;
pkl->pklPrev = pklFirst->pklPrev;
pklFirst->pklPrev->pklNext = pkl;
pklFirst->pklPrev = pkl;
Lock(&pwinsta->spklList, pkl);
}
HKL xxxInternalActivateKeyboardLayout(
PKL pkl,
UINT Flags)
{
HKL hklPrev;
PTHREADINFO ptiCurrent = PtiCurrent();
#if 0
TL tlpwndFocus;
#endif
CheckLock(pkl);
/*
* Remember what is about to become the "previously" active hkl
* for the return value.
*/
if (ptiCurrent->spklActive != (PKL)NULL) {
hklPrev = ptiCurrent->spklActive->hkl;
} else {
hklPrev = (HKL)0;
}
/*
* Early out
*/
if (!(Flags & KLF_SETFORPROCESS) && (pkl == ptiCurrent->spklActive)) {
return hklPrev;
}
/*
* Update the active layout in the pti. KLF_SETFORPROCESS will always be set
* when the keyboard layout switch is initiated by the keyboard hotkey.
*/
#ifdef FE_IME
/*
* For 16 bit app., only the calling thread will have its active layout updated.
*/
if ((Flags & KLF_SETFORPROCESS) && !(ptiCurrent->TIF_flags & TIF_16BIT)) {
if (!xxxImmActivateThreadsLayout(ptiCurrent->ppi->ptiList, NULL, pkl))
return hklPrev;
} else {
xxxImmActivateLayout(ptiCurrent, pkl);
}
#else
if (Flags & KLF_SETFORPROCESS) {
PTHREADINFO ptiT;
BOOL fKLChanged = FALSE;
for (ptiT = ptiCurrent->ppi->ptiList; ptiT != NULL; ptiT = ptiT->ptiSibling) {
if (ptiT->spklActive != pkl) {
Lock(&ptiT->spklActive, pkl);
fKLChanged = TRUE;
}
}
if (!fKLChanged) {
return hklPrev;
}
} else {
Lock(&ptiCurrent->spklActive, pkl);
}
#endif
UserAssert(ptiCurrent->pClientInfo != NULL);
ptiCurrent->pClientInfo->CodePage = pkl->CodePage;
if (ptiCurrent->pq && ptiCurrent->pq->spwndFocus) {
PWND pwndT;
TL tlpwndT;
if ((pwndT = GetTopLevelWindow(ptiCurrent->pq->spwndFocus)) != NULL) {
ThreadLockAlwaysWithPti( ptiCurrent, pwndT, &tlpwndT);
xxxSendMessage(pwndT, WM_INPUTLANGCHANGE, (WPARAM)pkl->iBaseCharset, (LPARAM)pkl->hkl);
ThreadUnlock(&tlpwndT);
}
}
if (gptiForeground && (gptiForeground->ppi == ptiCurrent->ppi)) {
/*
* Set gpKbdTbl so foreground thread processes AltGr appropriately
*/
gpKbdTbl = pkl->spkf->pKbdTbl;
/*
* Only call the hook if we are the foreground process, to prevent
* background apps from changing the indicator. (All console apps
* are part of the same process, but I have never seen a cmd window
* app change the layout, let alone in the background)
*/
if (LCIDSentToShell != pkl->hkl && (ptiCurrent != gptiRit)) {
if (IsHooked(ptiCurrent, WHF_SHELL)) {
xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)pkl->hkl, WH_SHELL);
LCIDSentToShell = pkl->hkl;
}
}
}
return hklPrev;
}
BOOL xxxUnloadKeyboardLayout(
PWINDOWSTATION pwinsta,
HKL hkl)
{
PKL pkl;
/*
* Validate HKL and check to make sure an app isn't attempting to unload a system
* preloaded layout.
*/
pkl = HKLtoPKL(hkl);
if (pkl == NULL) {
return FALSE;
}
return xxxInternalUnloadKeyboardLayout(pwinsta, pkl, 0);
}
BOOL _GetKeyboardLayoutName(
PUNICODE_STRING pstrKL)
{
PTHREADINFO ptiCurrent = PtiCurrentShared();
PKL pklActive;
pklActive = ptiCurrent->spklActive;
if (pklActive == NULL) {
return FALSE;
}
wcsncpycch(pstrKL->Buffer, pklActive->spkf->awchKF, pstrKL->MaximumLength / sizeof(WCHAR));
return TRUE;
}
HKL _GetKeyboardLayout(
DWORD idThread)
{
PTHREADINFO ptiT;
PLIST_ENTRY pHead, pEntry;
/*
* If idThread is NULL return hkl of the current thread
*/
if (idThread == 0) {
return PtiCurrentShared()->spklActive->hkl;
}
/*
* Look for idThread
*/
pHead = &PtiCurrent()->rpdesk->PtiList;
for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
ptiT = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink);
if (ptiT->Thread->Cid.UniqueThread == (HANDLE)idThread) {
return ptiT->spklActive->hkl;
}
}
/*
* idThread doesn't exist
*/
return (HKL)0;
}
UINT _GetKeyboardLayoutList(
PWINDOWSTATION pwinsta,
UINT nItems,
HKL *lpBuff)
{
UINT nHKL = 0;
PKL pkl, pklFirst;
pkl = pwinsta->spklList;
/*
* Windowstations that do not take input could have no layouts
*/
if (pkl == NULL) {
// SetLastError() ????
return 0;
}
/*
* The client/server thunk sets nItems to 0 if lpBuff == NULL
*/
pklFirst = pkl;
if (nItems) {
do {
if (!(pkl->dwFlags & KL_UNLOADED)) {
if (nItems-- == 0) {
break;
}
nHKL++;
*lpBuff++ = pkl->hkl;
}
pkl = pkl->pklNext;
} while (pkl != pklFirst);
} else do {
if (!(pkl->dwFlags & KL_UNLOADED)) {
nHKL++;
}
pkl = pkl->pklNext;
} while (pkl != pklFirst);
return nHKL;
}
/*
* Layouts are locked by each thread using them and possibly by:
* - pwinsta->spklList (head of windowstation's list)
* - gspklBaseLayout (default layout for new threads)
* The layout is marked for destruction when gets unloaded, so that it will be
* unlinked and freed as soon as an Unlock causes the lock count to go to 0.
* If it is reloaded before that time, it is unmarked for destruction. This
* ensures that laoded layouts stay around even when they go out of use.
*/
BOOL xxxInternalUnloadKeyboardLayout(
PWINDOWSTATION pwinsta,
PKL pkl,
UINT Flags)
{
PTHREADINFO ptiCurrent = PtiCurrent();
TL tlpkl;
/*
* Never unload the default layout, unless we are destroying the current
* windowstation or replacing one user's layouts with another's.
*/
if ((pkl == gspklBaseLayout) && !(Flags & KLF_INITTIME)) {
return FALSE;
}
/*
* Keeps pkl good, but also allows destruction when unlocked later
*/
ThreadLockAlwaysWithPti(ptiCurrent, pkl, &tlpkl);
/*
* Mark it for destruction so it gets removed when the lock count reaches 0
* Mark it KL_UNLOADED so that it appears to be gone from the toggle list
*/
HMMarkObjectDestroy(pkl);
pkl->dwFlags |= KL_UNLOADED;
/*
* If unloading this thread's active layout, helpfully activate the next one
* (Don't bother if KLF_INITTIME - unloading all previous user's layouts)
*/
if (!(Flags & KLF_INITTIME)) {
UserAssert(ptiCurrent->spklActive != NULL);
if (ptiCurrent->spklActive == pkl) {
PKL pklNext;
pklNext = HKLtoPKL((HKL)HKL_NEXT);
if (pklNext != NULL) {
TL tlPKL;
ThreadLockAlwaysWithPti(ptiCurrent, pklNext, &tlPKL);
xxxInternalActivateKeyboardLayout(pklNext, Flags);
ThreadUnlock(&tlPKL);
}
}
}
/*
* If this pkl == pwinsta->spklList, give it a chance to be destroyed by
* unlocking it from pwinsta->spklList.
*/
if (pwinsta->spklList == pkl) {
UserAssert(pkl != NULL);
if (pkl != pkl->pklNext) {
pkl = Lock(&pwinsta->spklList, pkl->pklNext);
UserAssert(pkl != NULL); // gspklBaseLayout and ThreadLocked pkl
}
}
/*
* This finally destroys the unloaded layout if it is not in use anywhere
*/
ThreadUnlock(&tlpkl);
/*
* Update keyboard list.
*/
if (IsHooked(ptiCurrent, WHF_SHELL)) {
xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)0, WH_SHELL);
LCIDSentToShell = 0;
}
return TRUE;
}
VOID xxxFreeKeyboardLayouts(
PWINDOWSTATION pwinsta)
{
PKL pkl;
/*
* Unload all of the windowstation's layouts.
* They may still be locked by some threads (eg: console), so this
* may not destroy them all, but it will mark them all KL_UNLOADED.
* Set KLF_INITTIME to ensure that the default layout (gspklBaseLayout)
* gets unloaded too.
* Note: it's much faster to unload non-active layouts, so start with
* the next loaded layout, leaving the active layout till last.
*/
while ((pkl = HKLtoPKL((HKL)HKL_NEXT)) != NULL) {
xxxInternalUnloadKeyboardLayout(pwinsta, pkl, KLF_INITTIME);
}
/*
* The WindowStation is being destroyed, or one user's layouts are being
* replaced by another user's, so it's OK to Unlock spklList.
* Any layout still in the double-linked circular KL list will still be
* pointed to by gspklBaseLayout: this is important, since we don't want
* to leak any KL or KBDFILE objects by losing pointers to them.
* There are no layouts when we first come here (during bootup).
*/
Unlock(&pwinsta->spklList);
}
VOID DestroyKL(
PKL pkl)
{
/*
* Cut it out of the pwinsta->spklList circular bidirectional list.
* We know pwinsta->spklList != pkl, since pkl is unlocked.
*/
pkl->pklPrev->pklNext = pkl->pklNext;
pkl->pklNext->pklPrev = pkl->pklPrev;
/*
* Unlock its pkf
*/
HMMarkObjectDestroy(pkl->spkf);
Unlock(&pkl->spkf);
/*
* Free the pkl itself.
*/
HMFreeObject(pkl);
}