Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3236 lines
93 KiB

/****************************** Module Header ******************************\
* Module Name: init.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains all the init code for win32k.sys.
*
* History:
* 18-Sep-1990 DarrinM Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#if DBG
LIST_ENTRY gDesktopList;
#endif
PVOID gpCountTable;
//
// External references
//
extern PVOID *apObjects;
extern PKWAIT_BLOCK gWaitBlockArray;
extern PVOID UserAtomTableHandle;
extern PKTIMER gptmrWD;
extern UNICODE_STRING* gpastrSetupExe;
extern WCHAR* glpSetupPrograms;
extern PHANDLEPAGE gpHandlePages;
extern PBWL pbwlCache;
//
// Forward references
//
#if DBG
VOID InitGlobalThreadLockArray(
DWORD dwIndex);
#endif
VOID CheckLUIDDosDevicesEnabled(
PBOOL result);
/*
* Local Constants.
*/
#define GRAY_STRLEN 40
/*
* Globals local to this file only.
*/
BOOL bPermanentFontsLoaded;
/*
* Globals shared with W32
*/
CONST ULONG W32ProcessSize = sizeof(PROCESSINFO);
CONST ULONG W32ProcessTag = TAG_PROCESSINFO;
CONST ULONG W32ThreadSize = sizeof(THREADINFO);
CONST ULONG W32ThreadTag = TAG_THREADINFO;
PFAST_MUTEX gpW32FastMutex;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
#pragma alloc_text(INIT, DriverEntry)
NTSTATUS Win32UserInitialize(VOID);
#if defined(_X86_)
ULONG Win32UserProbeAddress;
#endif
/*
* holds the result of "Are LUID DosDevices maps enabled?"
* TRUE - LUID DosDevices are enabled
* FALSE - LUID DosDevices are not enabled
*/
ULONG gLUIDDeviceMapsEnabled;
VOID FreeSMS(PSMS psms);
VOID FreeImeHotKeys(VOID);
extern PPAGED_LOOKASIDE_LIST SMSLookaside;
extern PPAGED_LOOKASIDE_LIST QEntryLookaside;
/*
* Max time is 10 minutes. The count is 10 min * 60 sec * 4 for 250 ms.
*/
#define MAX_TIME_OUT (10 * 60 * 4)
/***************************************************************************\
* Win32kNtUserCleanup
*
* History:
* 5-Jan-1997 CLupu Created.
\***************************************************************************/
BOOL Win32kNtUserCleanup(
VOID)
{
int i;
TRACE_HYDAPI(("Win32kNtUserCleanup: Cleanup Resources\n"));
if (gpresUser != NULL) {
EnterCrit();
}
DbgDumpTrackedDesktops(TRUE);
/*
* Anything in this list must be cleaned up when threads go away.
*/
UserAssert(gpbwlList == NULL);
UserAssert(gpWinEventHooks == NULL);
UserAssert(gpScancodeMap == NULL);
/*
* Free IME hotkeys.
*/
FreeImeHotKeys();
/*
* Free the wallpaper name string.
*/
if (gpszWall != NULL) {
UserFreePool(gpszWall);
gpszWall = NULL;
}
/*
* Free the hung redraw stuff.
*/
if (gpvwplHungRedraw != NULL) {
UserFreePool(gpvwplHungRedraw);
gpvwplHungRedraw = NULL;
}
/*
* Free the arrary of setup app names.
*/
if (gpastrSetupExe) {
UserFreePool(gpastrSetupExe);
gpastrSetupExe = NULL;
}
if (glpSetupPrograms) {
UserFreePool(glpSetupPrograms);
glpSetupPrograms = NULL;
}
/*
* Free the cached window list.
*/
if (pbwlCache != NULL) {
UserFreePool(pbwlCache);
pbwlCache = NULL;
}
/*
* Free outstanding timers.
*/
while (gptmrFirst != NULL) {
FreeTimer(gptmrFirst);
}
if (gptmrWD) {
KeCancelTimer(gptmrWD);
UserFreePool(gptmrWD);
gptmrWD = NULL;
}
if (gptmrMaster) {
KeCancelTimer(gptmrMaster);
UserFreePool(gptmrMaster);
gptmrMaster = NULL;
}
/*
* Cleanup monitors and windows layout snapshots
*/
CleanupMonitorsAndWindowsSnapShot();
/*
* Cleanup PnP input device synchronization event.
*/
if (gpEventPnPWainting != NULL) {
FreeKernelEvent(&gpEventPnPWainting);
}
/*
* Cleanup mouse & kbd change events
*/
for (i = 0; i <= DEVICE_TYPE_MAX; i++) {
UserAssert(gptiRit == NULL);
if (aDeviceTemplate[i].pkeHidChange) {
FreeKernelEvent(&aDeviceTemplate[i].pkeHidChange);
}
}
/*
* Cleanup any system thread parameters.
*/
CSTCleanupStack(FALSE);
CSTCleanupStack(TRUE);
EnterDeviceInfoListCrit();
#ifdef GENERIC_INPUT
CleanupHidRequestList();
#endif
while (gpDeviceInfoList) {
/*
* Assert that there is no outstanding read or PnP thread waiting
* in RequestDeviceChanges() for this device.
* Clear these flags anyway, to force the free.
*/
UserAssert((gpDeviceInfoList->bFlags & GDIF_READING) == 0);
UserAssert((gpDeviceInfoList->usActions & GDIAF_PNPWAITING) == 0);
gpDeviceInfoList->bFlags &= ~GDIF_READING;
gpDeviceInfoList->usActions &= ~GDIAF_PNPWAITING;
FreeDeviceInfo(gpDeviceInfoList);
}
#ifdef TRACK_PNP_NOTIFICATION
CleanupPnpNotificationRecord();
#endif
LeaveDeviceInfoListCrit();
/*
* Cleanup object references
*/
if (gThinwireFileObject)
ObDereferenceObject(gThinwireFileObject);
if (gVideoFileObject)
ObDereferenceObject(gVideoFileObject);
if (gpRemoteBeepDevice)
ObDereferenceObject(gpRemoteBeepDevice);
/*
* Cleanup our resources. There should be no threads in here
* when we get called.
*/
if (gpresMouseEventQueue) {
ExDeleteResourceLite(gpresMouseEventQueue);
ExFreePool(gpresMouseEventQueue);
gpresMouseEventQueue = NULL;
}
if (gpresDeviceInfoList) {
ExDeleteResourceLite(gpresDeviceInfoList);
ExFreePool(gpresDeviceInfoList);
gpresDeviceInfoList = NULL;
}
if (gpkeMouseData != NULL) {
FreeKernelEvent(&gpkeMouseData);
}
if (apObjects) {
UserFreePool(apObjects);
apObjects = NULL;
}
if (gWaitBlockArray) {
UserFreePool(gWaitBlockArray);
gWaitBlockArray = NULL;
}
if (gpEventDiconnectDesktop != NULL) {
FreeKernelEvent(&gpEventDiconnectDesktop);
}
if (gpevtDesktopDestroyed != NULL) {
FreeKernelEvent(&gpevtDesktopDestroyed);
}
if (gpEventScanGhosts != NULL) {
FreeKernelEvent(&gpEventScanGhosts);
}
if (gpevtVideoportCallout != NULL) {
FreeKernelEvent(&gpevtVideoportCallout);
}
if (UserAtomTableHandle != NULL) {
RtlDestroyAtomTable(UserAtomTableHandle);
UserAtomTableHandle = NULL;
}
/*
* cleanup the SMS lookaside buffer
*/
{
PSMS psmsNext;
while (gpsmsList != NULL) {
psmsNext = gpsmsList->psmsNext;
UserAssert(gpsmsList->spwnd == NULL);
FreeSMS(gpsmsList);
gpsmsList = psmsNext;
}
if (SMSLookaside != NULL) {
ExDeletePagedLookasideList(SMSLookaside);
UserFreePool(SMSLookaside);
SMSLookaside = NULL;
}
}
/*
* Let go of the attached queue for hard error handling.
* Do this before we free the Qlookaside !
*/
if (gHardErrorHandler.pqAttach != NULL) {
UserAssert(gHardErrorHandler.pqAttach > 0);
UserAssert(gHardErrorHandler.pqAttach->QF_flags & QF_INDESTROY);
FreeQueue(gHardErrorHandler.pqAttach);
gHardErrorHandler.pqAttach = NULL;
}
/*
* Free the cached array of queues
*/
FreeCachedQueues();
/*
* cleanup the QEntry lookaside buffer
*/
if (QEntryLookaside != NULL) {
ExDeletePagedLookasideList(QEntryLookaside);
UserFreePool(QEntryLookaside);
QEntryLookaside = NULL;
}
/*
* Cleanup the keyboard layouts
*/
CleanupKeyboardLayouts();
{
PWOWTHREADINFO pwti;
/*
* Cleanup gpwtiFirst list. This list is supposed to be empty
* at this point. In one case during stress we hit the case where
* it was not empty. The assert is to catch that case in
* checked builds.
*/
while (gpwtiFirst != NULL) {
pwti = gpwtiFirst;
gpwtiFirst = pwti->pwtiNext;
UserFreePool(pwti);
}
}
/*
* Cleanup cached SMWP array
*/
if (gSMWP.acvr != NULL) {
UserFreePool(gSMWP.acvr);
}
/*
* Free gpsdInitWinSta. This is != NULL only if the session didn't
* make it to UserInitialize.
*/
if (gpsdInitWinSta != NULL) {
UserFreePool(gpsdInitWinSta);
gpsdInitWinSta = NULL;
}
if (gpHandleFlagsMutex != NULL) {
ExFreePool(gpHandleFlagsMutex);
gpHandleFlagsMutex = NULL;
}
/*
* Delete the power request structures.
*/
DeletePowerRequestList();
if (gpresUser != NULL) {
LeaveCrit();
ExDeleteResourceLite(gpresUser);
ExFreePool(gpresUser);
gpresUser = NULL;
}
#if DBG
/*
* Cleanup the global thread lock structures
*/
for (i = 0; i < gcThreadLocksArraysAllocated; i++) {
UserFreePool(gpaThreadLocksArrays[i]);
gpaThreadLocksArrays[i] = NULL;
}
#endif // DBG
#ifdef GENERIC_INPUT
#if DBG
/*
* Checkup the HID related memory leak.
*/
CheckupHidLeak();
#endif // DBG
#endif // GENERIC_INPUT
return TRUE;
}
#if DBG
/***************************************************************************\
* TrackAddDesktop
*
* Track desktops for cleanup purposes
*
* History:
* 04-Dec-1997 clupu Created.
\***************************************************************************/
VOID TrackAddDesktop(
PVOID pDesktop)
{
PLIST_ENTRY Entry;
PVOID Atom;
TRACE_HYDAPI(("TrackAddDesktop %#p\n", pDesktop));
Atom = (PVOID)UserAllocPool(sizeof(PVOID) + sizeof(LIST_ENTRY),
TAG_TRACKDESKTOP);
if (Atom) {
*(PVOID*)Atom = pDesktop;
Entry = (PLIST_ENTRY)(((PCHAR)Atom) + sizeof(PVOID));
InsertTailList(&gDesktopList, Entry);
}
}
/***************************************************************************\
* TrackRemoveDesktop
*
* Track desktops for cleanup purposes
*
* History:
* 04-Dec-1997 clupu Created.
\***************************************************************************/
VOID TrackRemoveDesktop(
PVOID pDesktop)
{
PLIST_ENTRY NextEntry;
PVOID Atom;
TRACE_HYDAPI(("TrackRemoveDesktop %#p\n", pDesktop));
NextEntry = gDesktopList.Flink;
while (NextEntry != &gDesktopList) {
Atom = (PVOID)(((PCHAR)NextEntry) - sizeof(PVOID));
if (pDesktop == *(PVOID*)Atom) {
RemoveEntryList(NextEntry);
UserFreePool(Atom);
break;
}
NextEntry = NextEntry->Flink;
}
}
/***************************************************************************\
* DumpTrackedDesktops
*
* Dumps the tracked desktops
*
* History:
* 04-Dec-1997 clupu Created.
\***************************************************************************/
VOID DumpTrackedDesktops(
BOOL bBreak)
{
PLIST_ENTRY NextEntry;
PVOID pdesk;
PVOID Atom;
int nAlive = 0;
TRACE_HYDAPI(("DumpTrackedDesktops\n"));
NextEntry = gDesktopList.Flink;
while (NextEntry != &gDesktopList) {
Atom = (PVOID)(((PCHAR)NextEntry) - sizeof(PVOID));
pdesk = *(PVOID*)Atom;
KdPrint(("pdesk %#p\n", pdesk));
/*
* Restart at the begining of the list since our
* entry got deleted
*/
NextEntry = NextEntry->Flink;
nAlive++;
}
if (bBreak && nAlive > 0) {
RIPMSG0(RIP_ERROR, "Desktop objects still around\n");
}
}
#endif // DBG
VOID DestroyRegion(
HRGN* prgn)
{
if (*prgn != NULL) {
GreSetRegionOwner(*prgn, OBJECT_OWNER_CURRENT);
GreDeleteObject(*prgn);
*prgn = NULL;
}
}
VOID DestroyBrush(
HBRUSH* pbr)
{
if (*pbr != NULL) {
//GreSetBrushOwner(*pbr, OBJECT_OWNER_CURRENT);
GreDeleteObject(*pbr);
*pbr = NULL;
}
}
VOID DestroyBitmap(
HBITMAP* pbm)
{
if (*pbm != NULL) {
GreSetBitmapOwner(*pbm, OBJECT_OWNER_CURRENT);
GreDeleteObject(*pbm);
*pbm = NULL;
}
}
VOID DestroyDC(
HDC* phdc)
{
if (*phdc != NULL) {
GreSetDCOwner(*phdc, OBJECT_OWNER_CURRENT);
GreDeleteDC(*phdc);
*phdc = NULL;
}
}
VOID DestroyFont(
HFONT* pfnt)
{
if (*pfnt != NULL) {
GreDeleteObject(*pfnt);
*pfnt = NULL;
}
}
/***************************************************************************\
* CleanupGDI
*
* Cleanup all the GDI global objects used in USERK
*
* History:
* 29-Jan-1998 clupu Created.
\***************************************************************************/
VOID CleanupGDI(
VOID)
{
int i;
/*
* Free gpDispInfo stuff
*/
DestroyDC(&gpDispInfo->hdcScreen);
DestroyDC(&gpDispInfo->hdcBits);
DestroyDC(&gpDispInfo->hdcGray);
DestroyDC(&ghdcMem);
DestroyDC(&ghdcMem2);
DestroyDC(&gfade.hdc);
/*
* Free the cache DC stuff before the GRE cleanup.
* Also notice that we call DelayedDestroyCacheDC which
* we usualy call from DestroyProcessInfo. We do it
* here because this is the last WIN32 thread.
*/
DestroyCacheDCEntries(PtiCurrent());
DestroyCacheDCEntries(NULL);
DelayedDestroyCacheDC();
UserAssert(gpDispInfo->pdceFirst == NULL);
/*
* Free bitmaps
*/
DestroyBitmap(&gpDispInfo->hbmGray);
DestroyBitmap(&ghbmBits);
DestroyBitmap(&ghbmCaption);
/*
* Cleanup brushes
*/
DestroyBrush(&ghbrHungApp);
DestroyBrush(&gpsi->hbrGray);
DestroyBrush(&ghbrWhite);
DestroyBrush(&ghbrBlack);
for (i = 0; i < COLOR_MAX; i++) {
DestroyBrush(&(SYSHBRUSH(i)));
}
/*
* Cleanup regions
*/
DestroyRegion(&gpDispInfo->hrgnScreen);
DestroyRegion(&ghrgnInvalidSum);
DestroyRegion(&ghrgnVisNew);
DestroyRegion(&ghrgnSWP1);
DestroyRegion(&ghrgnValid);
DestroyRegion(&ghrgnValidSum);
DestroyRegion(&ghrgnInvalid);
DestroyRegion(&ghrgnInv0);
DestroyRegion(&ghrgnInv1);
DestroyRegion(&ghrgnInv2);
DestroyRegion(&ghrgnGDC);
DestroyRegion(&ghrgnSCR);
DestroyRegion(&ghrgnSPB1);
DestroyRegion(&ghrgnSPB2);
DestroyRegion(&ghrgnSW);
DestroyRegion(&ghrgnScrl1);
DestroyRegion(&ghrgnScrl2);
DestroyRegion(&ghrgnScrlVis);
DestroyRegion(&ghrgnScrlSrc);
DestroyRegion(&ghrgnScrlDst);
DestroyRegion(&ghrgnScrlValid);
/*
* Cleanup fonts
*/
DestroyFont(&ghSmCaptionFont);
DestroyFont(&ghMenuFont);
DestroyFont(&ghMenuFontDef);
DestroyFont(&ghStatusFont);
DestroyFont(&ghIconFont);
DestroyFont(&ghFontSys);
#ifdef LAME_BUTTON
DestroyFont(&ghLameFont);
#endif // LAME_BUTTON
/*
* wallpaper stuff.
*/
if (ghpalWallpaper != NULL) {
GreSetPaletteOwner(ghpalWallpaper, OBJECT_OWNER_CURRENT);
GreDeleteObject(ghpalWallpaper);
ghpalWallpaper = NULL;
}
DestroyBitmap(&ghbmWallpaper);
/*
* Unload the video driver
*/
if (gpDispInfo->pmdev) {
DrvDestroyMDEV(gpDispInfo->pmdev);
GreFreePool(gpDispInfo->pmdev);
gpDispInfo->pmdev = NULL;
gpDispInfo->hDev = NULL;
}
/*
* Free the monitor stuff
*/
{
PMONITOR pMonitor;
PMONITOR pMonitorNext;
pMonitor = gpDispInfo->pMonitorFirst;
while (pMonitor != NULL) {
pMonitorNext = pMonitor->pMonitorNext;
DestroyMonitor(pMonitor);
pMonitor = pMonitorNext;
}
UserAssert(gpDispInfo->pMonitorFirst == NULL);
if (gpMonitorCached != NULL) {
DestroyMonitor(gpMonitorCached);
}
}
}
/***************************************************************************\
* DestroyHandleTableObjects
*
* Destroy any object still in the handle table.
*
\***************************************************************************/
VOID DestroyHandleFirstPass(PHE phe)
{
/*
* First pass for the handle object destruction.
* Destroy the object, when we can. Otherwise,
* links to the other handle object should be cleared
* so that there will not be a dependency issues
* in the final, second pass.
*/
if (phe->phead->cLockObj == 0) {
HMDestroyObject(phe->phead);
} else {
/*
* The object couldn't be destroyed.
*/
if (phe->bType == TYPE_KBDLAYOUT) {
PKL pkl = (PKL)phe->phead;
UINT i;
/*
* Clear out the pkf references (they will be
* destroyed cleanly in the second run anyway)
*/
pkl->spkf = NULL;
pkl->spkfPrimary = NULL;
if (pkl->pspkfExtra) {
for (i = 0; i < pkl->uNumTbl; ++i) {
pkl->pspkfExtra[i] = NULL;
}
}
pkl->uNumTbl = 0;
}
}
}
VOID DestroyHandleSecondPass(PHE phe)
{
/*
* Destroy the object.
*/
if (phe->phead->cLockObj > 0) {
RIPMSG2(RIP_WARNING, "DestroyHandleSecondPass: phe %#p still locked (%d)!", phe, phe->phead->cLockObj);
/*
* We're going to die, why bothered by the lock count?
* We're forcing the lockcount to 0, and call the destroy routine.
*/
phe->phead->cLockObj = 0;
}
HMDestroyUnlockedObject(phe);
UserAssert(phe->bType == TYPE_FREE);
}
VOID DestroyHandleTableObjects(VOID)
{
PHE pheT;
DWORD i;
VOID (*HandleDestroyer)(PHE);
#if DBG
DWORD nLeak;
#endif
/*
* Make sure the handle table was created !
*/
if (gSharedInfo.aheList == NULL) {
return;
}
/*
* Loop through the table destroying all remaining objects.
*/
#if DBG
RIPMSG0(RIP_WARNING, "==== Start handle leak check\n");
nLeak = 0;
for (i = 0; i <= giheLast; ++i) {
pheT = gSharedInfo.aheList + i;
if (pheT->bType != TYPE_FREE) {
++nLeak;
RIPMSG3(RIP_WARNING, " LEAK -- Handle %p @%p type=%x\n", pheT->phead->h, pheT, pheT->bType);
}
}
RIPMSG1(RIP_WARNING, "==== Handle leak check finished: 0n%d leaks detected.\n", nLeak);
#endif
/*
* First pass: destroy it, or cut the link to other handle based object
*/
HandleDestroyer = DestroyHandleFirstPass;
repeat:
for (i = 0; i <= giheLast; ++i) {
pheT = gSharedInfo.aheList + i;
if (pheT->bType == TYPE_FREE)
continue;
UserAssert(!(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) &&
!(gahti[pheT->bType].bObjectCreateFlags & OCF_THREADOWNED));
UserAssert(!(pheT->bFlags & HANDLEF_DESTROY));
HandleDestroyer(pheT);
}
if (HandleDestroyer == DestroyHandleFirstPass) {
/*
* Go for the second pass.
*/
HandleDestroyer = DestroyHandleSecondPass;
goto repeat;
}
}
/***************************************************************************\
* Win32KDriverUnload
*
* Exit point for win32k.sys
*
\***************************************************************************/
#ifdef TRACE_MAP_VIEWS
extern PWin32Section gpSections;
#endif
VOID Win32KDriverUnload(
IN PDRIVER_OBJECT DriverObject)
{
TRACE_HYDAPI(("Win32KDriverUnload\n"));
UNREFERENCED_PARAMETER(DriverObject);
HYDRA_HINT(HH_DRIVERUNLOAD);
/*
* Cleanup all resources in GRE
*/
MultiUserNtGreCleanup();
HYDRA_HINT(HH_GRECLEANUP);
/*
* Cleanup CSRSS
*/
if (gpepCSRSS) {
ObDereferenceObject(gpepCSRSS);
gpepCSRSS = NULL;
}
/*
* BUG 305965. There might be cases when we end up with DCEs still
* in the list. Go ahead and clean it up here.
*/
if (gpDispInfo != NULL && gpDispInfo->pdceFirst != NULL) {
PDCE pdce, pdceNext;
RIPMSG0(RIP_ERROR, "Win32KDriverUnload: the DCE list is not empty");
pdce = gpDispInfo->pdceFirst;
while (pdce != NULL) {
pdceNext = pdce->pdceNext;
UserFreePool(pdce);
pdce = pdceNext;
}
gpDispInfo->pdceFirst = NULL;
}
/*
* Cleanup all resources in ntuser
*/
Win32kNtUserCleanup();
/*
* Cleanup the handle table for any object that is neither process
* owned nor thread owned
*/
DestroyHandleTableObjects();
HYDRA_HINT(HH_USERKCLEANUP);
#if DBG || FRE_LOCK_RECORD
HMCleanUpHandleTable();
#endif
/*
* Free the handle page array
*/
if (gpHandlePages != NULL) {
UserFreePool(gpHandlePages);
gpHandlePages = NULL;
}
if (CsrApiPort != NULL) {
ObDereferenceObject(CsrApiPort);
CsrApiPort = NULL;
}
/*
* Destroy the shared memory.
*/
if (ghSectionShared != NULL) {
NTSTATUS Status;
gpsi = NULL;
if (gpvSharedBase != NULL) {
Win32HeapDestroy(gpvSharedAlloc);
Status = Win32UnmapViewInSessionSpace(gpvSharedBase);
UserAssert(NT_SUCCESS(Status));
}
Win32DestroySection(ghSectionShared);
}
CleanupWin32HeapStubs();
#ifdef TRACE_MAP_VIEWS
if (gpSections != NULL) {
FRE_RIPMSG3(RIP_ERROR, "Section being leaked; do \"d%cs 0x%p l%x\" to find stacktrace of the offender and triage against that", (sizeof(ULONG_PTR) == 8 ? 'q' : 'd'), (ULONG_PTR)gpSections + FIELD_OFFSET(Win32Section, trace), ARRAY_SIZE(gpSections->trace));
}
#endif // TRACE_MAP_VIEWS
/*
* Cleanup all the user pool allocations by hand
*/
CleanupMediaChange();
CleanupPoolAllocations();
CleanUpPoolLimitations();
CleanUpSections();
/*
* Cleanup W32 structures.
*/
if (gpW32FastMutex != NULL) {
ExFreePool(gpW32FastMutex);
gpW32FastMutex = NULL;
}
/*
* Remove and free the service vector.
*/
if (!gbRemoteSession) {
KeRemoveSystemServiceTable(W32_SERVICE_NUMBER);
if (gpCountTable != NULL) {
ExFreePool(gpCountTable);
gpCountTable = NULL;
}
}
}
/***************************************************************************\
* DriverEntry
*
* Entry point needed to initialize win32k.sys.
*
\***************************************************************************/
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES obja;
UNICODE_STRING strName;
HANDLE hEventFirstSession;
UNREFERENCED_PARAMETER(RegistryPath);
HYDRA_HINT(HH_DRIVERENTRY);
gpvWin32kImageBase = DriverObject->DriverStart;
#if DBG
/*
* Initialize the desktop tracking list.
*/
InitializeListHead(&gDesktopList);
#endif // DBG
#ifdef GENERIC_INPUT
/*
* Initialize the global HID request list.
*/
InitializeHidRequestList();
#endif
/*
* Find out if this is a remote session.
*/
RtlInitUnicodeString(&strName, L"\\UniqueSessionIdEvent");
InitializeObjectAttributes(&obja,
&strName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwCreateEvent(&hEventFirstSession,
EVENT_ALL_ACCESS,
&obja,
SynchronizationEvent,
FALSE);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_OBJECT_NAME_COLLISION) {
gbRemoteSession = TRUE;
} else {
goto Failure;
}
} else {
gbRemoteSession = FALSE;
}
/*
* Set the unload address
*/
DriverObject->DriverUnload = Win32KDriverUnload;
/*
* Initialize data used for the timers. We want to do this really early,
* before any Win32 Timer will be created. We need to be very careful to
* not do anything that will need Win32 initialized yet.
*/
gcmsLastTimer = NtGetTickCount();
/*
* Initialize the Win32 structures. We need to do this before we create
* any threads.
*/
gpW32FastMutex = ExAllocatePoolWithTag(NonPagedPool,
sizeof(FAST_MUTEX),
TAG_SYSTEM);
if (gpW32FastMutex == NULL) {
Status = STATUS_NO_MEMORY;
goto Failure;
}
ExInitializeFastMutex(gpW32FastMutex);
if (!gbRemoteSession) {
#if DBG
/*
* Allocate and zero the system service count table. Do not use
* UserAllocPool for this allocation.
*/
gpCountTable = ExAllocatePoolWithTag(NonPagedPool,
W32pServiceLimit * sizeof(ULONG),
'llac');
if (gpCountTable == NULL) {
Status = STATUS_NO_MEMORY;
goto Failure;
}
RtlZeroMemory(gpCountTable, W32pServiceLimit * sizeof(ULONG));
#endif
/*
* We only establish the system entry table once for the
* whole system, even though WIN32K.SYS is instanced on a winstation
* basis. This is because the VM changes assure that all loads of
* WIN32K.SYS are at the exact same address, even if a fixup had
* to occur.
*/
UserVerify(KeAddSystemServiceTable(W32pServiceTable,
gpCountTable,
W32pServiceLimit,
W32pArgumentTable,
W32_SERVICE_NUMBER));
}
/*
* Initialize the critical section before establishing the callouts so
* we can assume that it's always valid.
*/
if (!InitCreateUserCrit()) {
Status = STATUS_NO_MEMORY;
goto Failure;
}
if (!gbRemoteSession) {
WIN32_CALLOUTS_FPNS Win32Callouts;
Win32Callouts.ProcessCallout = W32pProcessCallout;
Win32Callouts.ThreadCallout = W32pThreadCallout;
Win32Callouts.GlobalAtomTableCallout = UserGlobalAtomTableCallout;
Win32Callouts.PowerEventCallout = UserPowerEventCallout;
Win32Callouts.PowerStateCallout = UserPowerStateCallout;
Win32Callouts.JobCallout = UserJobCallout;
Win32Callouts.BatchFlushRoutine = (PVOID)NtGdiFlushUserBatch;
Win32Callouts.DesktopOpenProcedure = (PKWIN32_OBJECT_CALLOUT)DesktopOpenProcedure;
Win32Callouts.DesktopOkToCloseProcedure = (PKWIN32_OBJECT_CALLOUT)OkayToCloseDesktop;
Win32Callouts.DesktopCloseProcedure = (PKWIN32_OBJECT_CALLOUT)UnmapDesktop;
Win32Callouts.DesktopDeleteProcedure = (PKWIN32_OBJECT_CALLOUT)FreeDesktop;
Win32Callouts.WindowStationOkToCloseProcedure = (PKWIN32_OBJECT_CALLOUT)OkayToCloseWindowStation;
Win32Callouts.WindowStationCloseProcedure = (PKWIN32_OBJECT_CALLOUT)DestroyWindowStation;
Win32Callouts.WindowStationDeleteProcedure = (PKWIN32_OBJECT_CALLOUT)FreeWindowStation;
Win32Callouts.WindowStationParseProcedure = (PKWIN32_OBJECT_CALLOUT)ParseWindowStation;
Win32Callouts.WindowStationOpenProcedure = (PKWIN32_OBJECT_CALLOUT)WindowStationOpenProcedure;
PsEstablishWin32Callouts(&Win32Callouts);
}
Status = InitSectionTrace();
if (!NT_SUCCESS(Status)) {
goto Failure;
}
if (!InitWin32HeapStubs()) {
Status = STATUS_NO_MEMORY;
goto Failure;
}
/*
* Initialize pool limitation array.
*/
Status = InitPoolLimitations();
if (!NT_SUCCESS(Status)) {
goto Failure;
}
/*
* Create the event that is signaled when a desktop does away
*/
gpevtDesktopDestroyed = CreateKernelEvent(SynchronizationEvent, FALSE);
if (gpevtDesktopDestroyed == NULL) {
RIPMSG0(RIP_WARNING, "Couldn't create gpevtDesktopDestroyed");
Status = STATUS_NO_MEMORY;
goto Failure;
}
/*
* Create the event that is signaled when no disconnect/reconnect is pending
*/
gpevtVideoportCallout = CreateKernelEvent(NotificationEvent, FALSE);
if (gpevtVideoportCallout == NULL) {
RIPMSG0(RIP_WARNING, "Couldn't create gpevtVideoportCallout");
Status = STATUS_NO_MEMORY;
goto Failure;
}
#if defined(_X86_)
/*
* Keep our own copy of this to avoid double indirections on probing
*/
Win32UserProbeAddress = *MmUserProbeAddress;
#endif
if ((hModuleWin = MmPageEntireDriver(DriverEntry)) == NULL) {
RIPMSG0(RIP_WARNING, "MmPageEntireDriver failed");
Status = STATUS_NO_MEMORY;
goto Failure;
}
#if DBG
/*
* Initialize the gpaThreadLocksArray mechanism
*/
gFreeTLList = gpaThreadLocksArrays[gcThreadLocksArraysAllocated] =
UserAllocPoolZInit(sizeof(TL)*MAX_THREAD_LOCKS, TAG_GLOBALTHREADLOCK);
if (gFreeTLList == NULL) {
Status = STATUS_NO_MEMORY;
goto Failure;
}
InitGlobalThreadLockArray(0);
gcThreadLocksArraysAllocated = 1;
#endif
if (!InitializeGre()) {
RIPMSG0(RIP_WARNING, "InitializeGre failed");
Status = STATUS_NO_MEMORY;
goto Failure;
}
Status = Win32UserInitialize();
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING, "Win32UserInitialize failed with Status %x",
Status);
goto Failure;
}
/*
* Remember Session Creation Time. This is used to decide if power
* messages need to be sent.
*/
gSessionCreationTime = KeQueryInterruptTime();
//
// Initialize rundown protection for WindowStation objects.
//
ExInitializeRundownProtection(&gWinstaRunRef);
/*
* Check if LUID DosDevices are enabled
*/
CheckLUIDDosDevicesEnabled(&gLUIDDeviceMapsEnabled);
return STATUS_SUCCESS;
Failure:
RIPMSG1(RIP_WARNING,
"Initialization of WIN32K.SYS failed with Status = 0x%x",
Status);
Win32KDriverUnload(NULL);
return Status;
}
/***************************************************************************\
* xxxAddFontResourceW
*
*
* History:
\***************************************************************************/
int xxxAddFontResourceW(
LPWSTR lpFile,
FLONG flags,
DESIGNVECTOR *pdv)
{
UNICODE_STRING strFile;
RtlInitUnicodeString(&strFile, lpFile);
return xxxClientAddFontResourceW(&strFile, flags, pdv);
}
/***************************************************************************\
* LW_DriversInit
*
*
* History:
\***************************************************************************/
VOID LW_DriversInit(VOID)
{
/*
* Initialize the keyboard typematic rate.
*/
SetKeyboardRate((UINT)gnKeyboardSpeed);
/*
* Adjust VK modification table if not default (type 4) kbd.
*/
if (gKeyboardInfo.KeyboardIdentifier.Type == 3)
gapulCvt_VK = gapulCvt_VK_84;
/*
* Adjust VK modification table for IBM 5576 002/003 keyboard.
*/
if (JAPANESE_KEYBOARD(gKeyboardInfo.KeyboardIdentifier) &&
(gKeyboardInfo.KeyboardIdentifier.Subtype == 3))
gapulCvt_VK = gapulCvt_VK_IBM02;
/*
* Initialize NLS keyboard globals.
*/
NlsKbdInitializePerSystem();
}
/***************************************************************************\
* LoadCPUserPreferences
*
* 06/07/96 GerardoB Created
\***************************************************************************/
BOOL LoadCPUserPreferences(
PUNICODE_STRING pProfileUserName,
DWORD dwPolicyOnly)
{
DWORD pdwValue[SPI_BOOLMASKDWORDSIZE], dw;
PPROFILEVALUEINFO ppvi = gpviCPUserPreferences;
UserAssert(1 + SPI_DWORDRANGECOUNT == ARRAY_SIZE(gpviCPUserPreferences));
/*
* The first value in gpviCPUserPreferences corresponds to the bit mask
*/
dw = FastGetProfileValue(pProfileUserName,
ppvi->uSection,
ppvi->pwszKeyName,
NULL,
(LPBYTE)pdwValue,
sizeof(*pdwValue),
dwPolicyOnly);
/*
* Copy only the amount of data read and no more than what we expect.
*/
if (dw != 0) {
if (dw > sizeof(gpdwCPUserPreferencesMask)) {
dw = sizeof(gpdwCPUserPreferencesMask);
}
RtlCopyMemory(gpdwCPUserPreferencesMask, pdwValue, dw);
}
ppvi++;
/*
* DWORD values
*/
for (dw = 1; dw < 1 + SPI_DWORDRANGECOUNT; dw++, ppvi++) {
if (FastGetProfileValue(pProfileUserName,
ppvi->uSection,
ppvi->pwszKeyName,
NULL,
(LPBYTE)pdwValue,
sizeof(DWORD),
dwPolicyOnly)) {
ppvi->dwValue = *pdwValue;
}
}
/*
* Propagate gpsi flags
*/
PropagetUPBOOLTogpsi(COMBOBOXANIMATION);
PropagetUPBOOLTogpsi(LISTBOXSMOOTHSCROLLING);
PropagetUPBOOLTogpsi(KEYBOARDCUES);
SET_OR_CLEAR_SRVIF(SRVIF_KEYBOARDPREF, TEST_BOOL_ACCF(ACCF_KEYBOARDPREF));
gpsi->uCaretWidth = UP(CARETWIDTH);
SYSMET(CXFOCUSBORDER) = UP(FOCUSBORDERWIDTH);
SYSMET(CYFOCUSBORDER) = UP(FOCUSBORDERHEIGHT);
PropagetUPBOOLTogpsi(UIEFFECTS);
EnforceColorDependentSettings();
return TRUE;
}
/***************************************************************************\
* LW_LoadProfileInitData
*
* Only stuff that gets initialized at boot should go here. Per user settings
* should be initialized in xxxUpdatePerUserSystemParameters.
\***************************************************************************/
VOID LW_LoadProfileInitData(
PUNICODE_STRING pProfileUserName)
{
FastGetProfileIntFromID(pProfileUserName,
PMAP_WINDOWSM,
STR_DDESENDTIMEOUT,
0,
&guDdeSendTimeout,
0);
}
/***************************************************************************\
* LW_LoadResources
*
*
* History:
\***************************************************************************/
VOID LW_LoadResources(
PUNICODE_STRING pProfileUserName)
{
WCHAR rgch[4];
/*
* See if the Mouse buttons need swapping.
*/
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_MOUSE,
STR_SWAPBUTTONS,
szN,
rgch,
ARRAY_SIZE(rgch),
0);
SYSMET(SWAPBUTTON) = (*rgch == '1' || *rgch == *szY || *rgch == *szy);
/*
* See if we should beep.
*/
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_BEEP,
STR_BEEP,
szY,
rgch,
ARRAY_SIZE(rgch),
0);
SET_OR_CLEAR_PUDF(PUDF_BEEP, (rgch[0] == *szY) || (rgch[0] == *szy));
/*
* See if we should have extended sounds.
*/
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_BEEP,
STR_EXTENDEDSOUNDS,
szN,
rgch,
ARRAY_SIZE(rgch),
0);
SET_OR_CLEAR_PUDF(PUDF_EXTENDEDSOUNDS, (rgch[0] == *szY || rgch[0] == *szy));
}
/***************************************************************************\
* xxxLoadSomeStrings
*
* This function loads a bunch of strings from the user32 resource string
* table
* This is done to keep all the localizable strings in user side to be MUI
* Manageable.
*
* History:
* 4-Mar-2000 MHamid Created.
\***************************************************************************/
VOID xxxLoadSomeStrings(
VOID)
{
int i, str, id;
/*
* MessageBox strings.
*/
for (i = 0, str = STR_OK, id = IDOK; i<MAX_MB_STRINGS; i++, str++, id++) {
gpsi->MBStrings[i].uStr = str;
gpsi->MBStrings[i].uID = id;
xxxClientLoadStringW(str,
gpsi->MBStrings[i].szName,
ARRAY_SIZE(gpsi->MBStrings[i].szName));
}
/*
* Load ToolTip strings.
*/
xxxClientLoadStringW(STR_TT_MIN, gszMIN, ARRAY_SIZE(gszMIN));
xxxClientLoadStringW(STR_TT_MAX, gszMAX, ARRAY_SIZE(gszMAX));
xxxClientLoadStringW(STR_TT_RESUP, gszRESUP, ARRAY_SIZE(gszRESUP));
xxxClientLoadStringW(STR_TT_RESDOWN, gszRESDOWN, ARRAY_SIZE(gszRESDOWN));
xxxClientLoadStringW(STR_TT_SCLOSE, gszSCLOSE, ARRAY_SIZE(gszSCLOSE));
xxxClientLoadStringW(STR_TT_HELP, gszHELP, ARRAY_SIZE(gszHELP));
}
/***************************************************************************\
* xxxInitWindowStation
*
* History:
* 6-Sep-1996 CLupu Created.
* 21-Jan-98 SamerA Renamed to xxxInitWindowStation since it may leave the
* critical section.
\***************************************************************************/
BOOL xxxInitWindowStation(
VOID)
{
TL tlName;
PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
BOOL fRet;
/*
* Load all profile data first
*/
LW_LoadProfileInitData(pProfileUserName);
/*
* Initialize User in a specific order.
*/
LW_DriversInit();
xxxLoadSomeStrings();
/*
* This is the initialization from Chicago
*/
if (!(fRet = xxxSetWindowNCMetrics(pProfileUserName, NULL, TRUE, -1))) {
RIPMSG0(RIP_WARNING, "xxxInitWindowStation failed in xxxSetWindowNCMetrics");
goto Exit;
}
SetMinMetrics(pProfileUserName, NULL);
if (!(fRet = SetIconMetrics(pProfileUserName, NULL))) {
RIPMSG0(RIP_WARNING, "xxxInitWindowStation failed in SetIconMetrics");
goto Exit;
}
if (!(fRet = FinalUserInit())) {
RIPMSG0(RIP_WARNING, "xxxInitWindowStation failed in FinalUserInit");
goto Exit;
}
/*
* Initialize the key cache index.
*/
gpsi->dwKeyCache = 1;
Exit:
FreeProfileUserName(pProfileUserName, &tlName);
return fRet;
}
/***************************************************************************\
* CreateTerminalInput
*
*
* History:
* 6-Sep-1996 CLupu Created.
\***************************************************************************/
BOOL CreateTerminalInput(
PTERMINAL pTerm)
{
UserAssert(pTerm != NULL);
/*
* call to the client side to clean up the [Fonts] section
* of the registry. This will only take significant chunk of time
* if the [Fonts] key changed during since the last boot and if
* there are lots of fonts loaded
*/
ClientFontSweep();
/*
* Load the standard fonts before we create any DCs. At this time we can
* only add the fonts that do not reside on the net. They may be needed
* by winlogon. Our winlogon needs only ms sans serif, but private
* winlogon's may need some other fonts as well. The fonts on the net
* will be added later, right after all the net connections have been
* restored.
*/
xxxLW_LoadFonts(FALSE);
/*
* Initialize the input system.
*/
if (!xxxInitInput(pTerm)) {
return FALSE;
}
return TRUE;
}
/***************************************************************************\
* CI_GetClrVal
*
* Returns the RGB value of a color string from WIN.INI.
*
* History:
\***************************************************************************/
DWORD CI_GetClrVal(
LPWSTR p,
DWORD clrDefval)
{
LPBYTE pl;
BYTE val;
int i;
DWORD clrval;
if (*p == UNICODE_NULL) {
return clrDefval;
}
/*
* Initialize the pointer to the LONG return value. Set to MSB.
*/
pl = (LPBYTE)&clrval;
/*
* Get three goups of numbers seprated by non-numeric characters.
*/
for (i = 0; i < 3; i++) {
/*
* Skip over any non-numeric characters within the string.
*/
while ((*p != UNICODE_NULL) && !(*p >= TEXT('0') && *p <= TEXT('9'))) {
p++;
}
/*
* Are we (prematurely) at the end of the string?
*/
if (*p == UNICODE_NULL) {
RIPMSG0(RIP_WARNING, "CI_GetClrVal: Color string is corrupted");
return clrDefval;
}
/*
* Get the next series of digits.
*/
val = 0;
while (*p >= TEXT('0') && *p <= TEXT('9'))
val = (BYTE)((int)val*10 + (int)*p++ - '0');
/*
* HACK! Store the group in the LONG return value.
*/
*pl++ = val;
}
/*
* Force the MSB to zero for GDI.
*/
*pl = 0;
return clrval;
}
/***************************************************************************\
* xxxODI_ColorInit
*
*
* History:
\***************************************************************************/
VOID xxxODI_ColorInit(PUNICODE_STRING pProfileUserName)
{
int i;
COLORREF colorVals[STR_COLOREND - STR_COLORSTART + 1];
INT colorIndex[STR_COLOREND - STR_COLORSTART + 1];
WCHAR rgchValue[25];
#if COLOR_MAX - (STR_COLOREND - STR_COLORSTART + 1)
#error "COLOR_MAX value conflicts with STR_COLOREND - STR_COLORSTART"
#endif
/*
* Now set up default color values.
* These are not in display drivers anymore since we just want default.
* The real values are stored in the profile.
*/
RtlCopyMemory(gpsi->argbSystem, gargbInitial, sizeof(COLORREF) * COLOR_MAX);
RtlCopyMemory(gpsi->argbSystemUnmatched, gpsi->argbSystem, sizeof(COLORREF) * COLOR_MAX);
for (i = 0; i < COLOR_MAX; i++) {
LUID luidCaller;
/*
* Try to find a WIN.INI entry for this object.
*/
*rgchValue = 0;
/*
* Special case the background color. Try using Winlogon's value
* if present. If the value doesn't exist then use USER's value.
*/
if ((COLOR_BACKGROUND == i) &&
NT_SUCCESS(GetProcessLuid(NULL, &luidCaller)) &&
RtlEqualLuid(&luidCaller, &luidSystem)) {
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_WINLOGON,
STR_COLORSTART + COLOR_BACKGROUND,
szNull,
rgchValue,
ARRAY_SIZE(rgchValue),
0);
}
if (*rgchValue == 0) {
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_COLORS,
STR_COLORSTART + i,
szNull,
rgchValue,
ARRAY_SIZE(rgchValue),
0);
}
/*
* Convert the string into an RGB value and store. Use the
* default RGB value if the profile value is missing.
*/
colorVals[i] = CI_GetClrVal(rgchValue, gpsi->argbSystem[i]);
colorIndex[i] = i;
}
xxxSetSysColors(pProfileUserName,
i,
colorIndex,
colorVals,
SSCF_FORCESOLIDCOLOR | SSCF_SETMAGICCOLORS);
}
/***********************************************************************\
* _LoadIconsAndCursors
*
* Used in parallel with the client side - LoadIconsAndCursors. This
* assumes that only the default configurable cursors and icons have
* been loaded and searches the global icon cache for them to fixup
* the default resource ids to standard ids. Also initializes the
* rgsys arrays allowing SYSCUR and SYSICO macros to work.
*
* 14-Oct-1995 SanfordS created.
\***********************************************************************/
VOID _LoadCursorsAndIcons(
VOID)
{
PCURSOR pcur;
int i;
pcur = gpcurFirst;
/*
* Only CSR can call this (and only once).
*/
if (!ISCSRSS()) {
return;
}
HYDRA_HINT(HH_LOADCURSORS);
while (pcur) {
UserAssert(!IS_PTR(pcur->strName.Buffer));
switch (pcur->rt) {
case RT_ICON:
UserAssert((LONG_PTR)pcur->strName.Buffer >= OIC_FIRST_DEFAULT);
UserAssert((LONG_PTR)pcur->strName.Buffer <
OIC_FIRST_DEFAULT + COIC_CONFIGURABLE);
i = PTR_TO_ID(pcur->strName.Buffer) - OIC_FIRST_DEFAULT;
pcur->strName.Buffer = (LPWSTR)gasysico[i].Id;
if (pcur->CURSORF_flags & CURSORF_LRSHARED) {
UserAssert(gasysico[i].spcur == NULL);
Lock(&gasysico[i].spcur, pcur);
} else {
UserAssert(gpsi->hIconSmWindows == NULL);
UserAssert((int)pcur->cx == SYSMET(CXSMICON));
/*
* The special small winlogo icon is not shared.
*/
gpsi->hIconSmWindows = PtoH(pcur);
}
break;
case RT_CURSOR:
UserAssert((LONG_PTR)pcur->strName.Buffer >= OCR_FIRST_DEFAULT);
UserAssert((LONG_PTR)pcur->strName.Buffer <
OCR_FIRST_DEFAULT + COCR_CONFIGURABLE);
i = PTR_TO_ID(pcur->strName.Buffer) - OCR_FIRST_DEFAULT;
pcur->strName.Buffer = (LPWSTR)gasyscur[i].Id;
Lock(&gasyscur[i].spcur, pcur);
break;
default:
// Should be nothing in the cache but these!
RIPMSG1(RIP_ERROR, "Bogus object in cursor list: 0x%p", pcur);
}
pcur = pcur->pcurNext;
}
/*
* copy special icon handles to global spots for later use.
*/
gpsi->hIcoWindows = PtoH(SYSICO(WINLOGO));
}
/***********************************************************************\
* UnloadCursorsAndIcons
*
* Used for cleanup of win32k.
*
* Dec-10-1997 clupu created.
\***********************************************************************/
VOID UnloadCursorsAndIcons(
VOID)
{
PCURSOR pcur;
int ind;
TRACE_HYDAPI(("UnloadCursorsAndIcons\n"));
/*
* Unlock the icons.
*/
for (ind = 0; ind < COIC_CONFIGURABLE; ind++) {
pcur = gasysico[ind].spcur;
if (pcur == NULL) {
continue;
}
pcur->head.ppi = PpiCurrent();
Unlock(&gasysico[ind].spcur);
}
/*
* Unlock the cursors.
*/
for (ind = 0; ind < COCR_CONFIGURABLE; ind++) {
pcur = gasyscur[ind].spcur;
if (pcur == NULL) {
continue;
}
pcur->head.ppi = PpiCurrent();
Unlock(&gasyscur[ind].spcur);
}
}
/***********************************************************************\
* xxxUpdateSystemCursorsFromRegistry
*
* Reloads all customizable cursors from the registry.
*
* 09-Oct-1995 SanfordS created.
\***********************************************************************/
VOID xxxUpdateSystemCursorsFromRegistry(
PUNICODE_STRING pProfileUserName)
{
int i;
UNICODE_STRING strName;
TCHAR szFilename[MAX_PATH];
PCURSOR pCursor;
UINT LR_flags;
for (i = 0; i < COCR_CONFIGURABLE; i++) {
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_CURSORS,
gasyscur[i].StrId,
TEXT(""),
szFilename,
ARRAY_SIZE(szFilename),
0);
if (*szFilename) {
RtlInitUnicodeString(&strName, szFilename);
LR_flags = LR_LOADFROMFILE | LR_ENVSUBST | LR_DEFAULTSIZE;
} else {
RtlInitUnicodeStringOrId(&strName,
MAKEINTRESOURCE(i + OCR_FIRST_DEFAULT));
LR_flags = LR_ENVSUBST | LR_DEFAULTSIZE;
}
pCursor = xxxClientLoadImage(&strName,
0,
IMAGE_CURSOR,
0,
0,
LR_flags,
FALSE);
if (pCursor) {
zzzSetSystemImage(pCursor, gasyscur[i].spcur);
} else {
RIPMSG1(RIP_WARNING, "Unable to update cursor. id=%x.", i + OCR_FIRST_DEFAULT);
}
}
}
/***********************************************************************\
* xxxUpdateSystemIconsFromRegistry
*
* Reloads all customizable icons from the registry.
*
* 09-Oct-1995 SanfordS created.
\***********************************************************************/
VOID xxxUpdateSystemIconsFromRegistry(
PUNICODE_STRING pProfileUserName)
{
int i;
UNICODE_STRING strName;
TCHAR szFilename[MAX_PATH];
PCURSOR pCursor;
UINT LR_flags;
for (i = 0; i < COIC_CONFIGURABLE; i++) {
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_ICONS,
gasysico[i].StrId,
TEXT(""),
szFilename,
ARRAY_SIZE(szFilename),
0);
if (*szFilename) {
RtlInitUnicodeString(&strName, szFilename);
LR_flags = LR_LOADFROMFILE | LR_ENVSUBST;
} else {
RtlInitUnicodeStringOrId(&strName,
MAKEINTRESOURCE(i + OIC_FIRST_DEFAULT));
LR_flags = LR_ENVSUBST;
}
pCursor = xxxClientLoadImage(&strName,
0,
IMAGE_ICON,
0,
0,
LR_flags,
FALSE);
RIPMSG3(RIP_VERBOSE,
(!IS_PTR(strName.Buffer)) ?
"%#.8lx = Loaded id %ld" :
"%#.8lx = Loaded file %ws for id %ld",
PtoH(pCursor),
strName.Buffer,
i + OIC_FIRST_DEFAULT);
if (pCursor) {
zzzSetSystemImage(pCursor, gasysico[i].spcur);
} else {
RIPMSG1(RIP_WARNING, "Unable to update icon. id=%ld", i + OIC_FIRST_DEFAULT);
}
/*
* update the small winlogo icon which is referenced by gpsi.
* Seems like we should load the small version for all configurable
* icons anyway. What is needed is for CopyImage to support
* copying of images loaded from files with LR_COPYFROMRESOURCE
* allowing a reaload of the bits. (SAS)
*/
if (i == OIC_WINLOGO_DEFAULT - OIC_FIRST_DEFAULT) {
PCURSOR pCurSys = HtoP(gpsi->hIconSmWindows);
if (pCurSys != NULL) {
pCursor = xxxClientLoadImage(&strName,
0,
IMAGE_ICON,
SYSMET(CXSMICON),
SYSMET(CYSMICON),
LR_flags,
FALSE);
if (pCursor) {
zzzSetSystemImage(pCursor, pCurSys);
} else {
RIPMSG0(RIP_WARNING, "Unable to update small winlogo icon.");
}
}
}
}
}
/***************************************************************************\
* LW_BrushInit
*
*
* History:
\***************************************************************************/
BOOL LW_BrushInit(
VOID)
{
HBITMAP hbmGray;
CONST static WORD patGray[8] = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
/*
* Create a gray brush to be used with GrayString.
*/
hbmGray = GreCreateBitmap(8, 8, 1, 1, (LPBYTE)patGray);
if (hbmGray == NULL) {
return FALSE;
}
gpsi->hbrGray = GreCreatePatternBrush(hbmGray);
ghbrWhite = GreGetStockObject(WHITE_BRUSH);
ghbrBlack = GreGetStockObject(BLACK_BRUSH);
UserAssert(ghbrWhite != NULL && ghbrBlack != NULL);
if (gpsi->hbrGray == NULL) {
return FALSE;
}
GreDeleteObject(hbmGray);
GreSetBrushOwnerPublic(gpsi->hbrGray);
ghbrHungApp = GreCreateSolidBrush(0);
if (ghbrHungApp == NULL) {
return FALSE;
}
GreSetBrushOwnerPublic(ghbrHungApp);
return TRUE;
}
/***************************************************************************\
* LW_RegisterWindows
*
*
* History:
\***************************************************************************/
BOOL LW_RegisterWindows(
VOID)
{
int i;
WNDCLASSVEREX wndcls;
PTHREADINFO ptiCurrent = PtiCurrent();
BOOL fSuccess = TRUE;
BOOL fSystem = (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) != 0;
CONST static struct {
BOOLEAN fSystem;
BOOLEAN fGlobalClass;
WORD fnid;
UINT style;
WNDPROC lpfnWndProc;
int cbWndExtra;
BOOL fNormalCursor : 1;
HBRUSH hbrBackground;
LPCTSTR lpszClassName;
} rc[] = {
{ TRUE, TRUE, FNID_DESKTOP,
CS_DBLCLKS,
(WNDPROC)xxxDesktopWndProc,
sizeof(DESKWND) - sizeof(WND),
TRUE,
(HBRUSH)(COLOR_BACKGROUND + 1),
DESKTOPCLASS},
{ TRUE, FALSE, FNID_SWITCH,
CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS,
(WNDPROC)xxxSwitchWndProc,
sizeof(SWITCHWND) - sizeof(WND),
TRUE,
NULL,
SWITCHWNDCLASS},
{ TRUE, FALSE, FNID_MENU,
CS_DBLCLKS | CS_SAVEBITS | CS_DROPSHADOW,
(WNDPROC)xxxMenuWindowProc,
sizeof(PPOPUPMENU),
FALSE,
(HBRUSH)(COLOR_MENU + 1),
MENUCLASS},
{ FALSE, FALSE, FNID_SCROLLBAR,
CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_PARENTDC,
(WNDPROC)xxxSBWndProc,
sizeof(SBWND) - sizeof(WND),
TRUE,
NULL,
L"ScrollBar"},
{ TRUE, FALSE, FNID_TOOLTIP,
CS_DBLCLKS | CS_SAVEBITS,
(WNDPROC)xxxTooltipWndProc,
sizeof(TOOLTIPWND) - sizeof(WND),
TRUE,
NULL,
TOOLTIPCLASS},
{ TRUE, TRUE, FNID_ICONTITLE,
0,
(WNDPROC)xxxDefWindowProc,
0,
TRUE,
NULL,
ICONTITLECLASS},
{ FALSE, FALSE, 0,
0,
(WNDPROC)xxxEventWndProc,
sizeof(PSVR_INSTANCE_INFO),
FALSE,
NULL,
L"DDEMLEvent"},
#ifdef HUNGAPP_GHOSTING
{ TRUE, TRUE, FNID_GHOST,
0,
(WNDPROC)xxxGhostWndProc,
0,
TRUE,
NULL,
L"Ghost"},
#endif // HUNGAPP_GHOSTING
{ TRUE, TRUE, 0,
0,
(WNDPROC)xxxDefWindowProc,
0,
TRUE,
NULL,
L"SysShadow"},
{ TRUE, TRUE, FNID_MESSAGEWND,
0,
(WNDPROC)xxxDefWindowProc,
4,
TRUE,
NULL,
szMESSAGE}
};
/*
* All other classes are registered via the table.
*/
wndcls.cbClsExtra = 0;
wndcls.hInstance = hModuleWin;
wndcls.hIcon = NULL;
wndcls.hIconSm = NULL;
wndcls.lpszMenuName = NULL;
for (i = 0; i < ARRAY_SIZE(rc); i++) {
if (fSystem && !rc[i].fSystem) {
continue;
}
wndcls.style = rc[i].style;
wndcls.lpfnWndProc = rc[i].lpfnWndProc;
wndcls.cbWndExtra = rc[i].cbWndExtra;
wndcls.hCursor = rc[i].fNormalCursor ? PtoH(SYSCUR(ARROW)) : NULL;
wndcls.hbrBackground= rc[i].hbrBackground;
wndcls.lpszClassName= rc[i].lpszClassName;
wndcls.lpszClassNameVer= rc[i].lpszClassName;
if (InternalRegisterClassEx(&wndcls,
rc[i].fnid,
CSF_SERVERSIDEPROC | CSF_WIN40COMPAT) == NULL) {
RIPMSG0(RIP_WARNING, "LW_RegisterWindows: InternalRegisterClassEx failed");
fSuccess = FALSE;
break;
}
if (fSystem && rc[i].fGlobalClass) {
if (InternalRegisterClassEx(&wndcls,
rc[i].fnid,
CSF_SERVERSIDEPROC | CSF_SYSTEMCLASS | CSF_WIN40COMPAT) == NULL) {
RIPMSG0(RIP_WARNING, "LW_RegisterWindows: InternalRegisterClassEx failed");
fSuccess = FALSE;
break;
}
}
}
if (fSuccess) {
ptiCurrent->ppi->W32PF_Flags |= W32PF_CLASSESREGISTERED;
#ifndef LAZY_CLASS_INIT
if (!fSystem && ptiCurrent->pClientInfo) {
try {
ptiCurrent->pClientInfo->CI_flags |= CI_REGISTERCLASSES;
} except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
fSuccess = FALSE;
}
}
#endif
}
return fSuccess;
}
/**********************************************************\
* VOID vCheckMMInstance
*
* History:
* Feb-06-98 Xudong Wu [TessieW]
* Wrote it.
\**********************************************************/
VOID vCheckMMInstance(
LPWSTR pchSrch,
DESIGNVECTOR *pdv)
{
LPWSTR pKeyName;
WCHAR szName[MAX_PATH], *pszName = szName;
WCHAR szCannonicalName[MAX_PATH];
ULONG NumAxes;
pdv->dvNumAxes = 0;
pKeyName = pchSrch;
while (*pKeyName && (*pKeyName++ != TEXT('('))) {
/* do nothing */;
}
if (*pKeyName){
if (!_wcsicmp(pKeyName, L"OpenType)")) {
pKeyName = pchSrch;
while(*pKeyName != TEXT('(')) {
*pszName++ = *pKeyName++;
}
*pszName = 0;
GreGetCannonicalName(szName, szCannonicalName, &NumAxes, pdv);
}
}
}
BOOL bEnumerateRegistryFonts(
BOOL bPermanent)
{
LPWSTR pchKeys, pchSrch, lpchT;
int cchReal, cFont;
WCHAR szFontFile[MAX_PATH];
FLONG flAFRW;
TL tlPool;
DESIGNVECTOR dv;
WCHAR szPreloadFontFile[MAX_PATH];
static int LastFontLoaded = -1;
/*
* if we are not just checking whether this is a registry font
*/
flAFRW = (bPermanent ? AFRW_ADD_LOCAL_FONT : AFRW_ADD_REMOTE_FONT);
cchReal = (int)FastGetProfileKeysW(NULL,
PMAP_FONTS,
TEXT("vgasys.fnt"),
&pchKeys
);
#if DBG
if (cchReal == 0) {
RIPMSG0(RIP_WARNING, "bEnumerateRegistryFonts: cchReal is 0");
}
#endif
if (!pchKeys) {
return FALSE;
}
ThreadLockPool(PtiCurrent(), pchKeys, &tlPool);
/*
* If we got here first, we load the fonts until this preload font.
* Preload fonts will be used by Winlogon UI, then we need to make sure
* the font is available when Winlogon UI comes up.
*/
if (LastFontLoaded == -1) {
FastGetProfileStringW(NULL, PMAP_WINLOGON,
TEXT("PreloadFontFile"),
TEXT("Micross.ttf"),
szPreloadFontFile,
MAX_PATH,
0);
RIPMSG1(RIP_VERBOSE, "Winlogon preload font = %ws\n",szPreloadFontFile);
}
/*
* Now we have all the key names in pchKeys.
*/
if (cchReal != 0) {
cFont = 0;
pchSrch = pchKeys;
do {
// check to see whether this is MM(OpenType) instance
vCheckMMInstance(pchSrch, &dv);
if (FastGetProfileStringW(NULL,
PMAP_FONTS,
pchSrch,
TEXT("vgasys.fon"),
szFontFile,
(MAX_PATH - 5),
0)) {
/*
* If no extension, append ".FON"
*/
for (lpchT = szFontFile; *lpchT != TEXT('.'); lpchT++) {
if (*lpchT == 0) {
wcscat(szFontFile, TEXT(".FON"));
break;
}
}
if ((cFont > LastFontLoaded) && bPermanent) {
/*
* skip if we've already loaded this local font.
*/
xxxAddFontResourceW(szFontFile, flAFRW, dv.dvNumAxes ? &dv : NULL);
}
if (!bPermanent) {
xxxAddFontResourceW(szFontFile, flAFRW, dv.dvNumAxes ? &dv : NULL);
}
if ((LastFontLoaded == -1) &&
/*
* Compare with the font file name from Registry.
*/
(!_wcsnicmp(szFontFile, szPreloadFontFile, wcslen(szPreloadFontFile))) &&
(bPermanent)) {
/*
* On the first time through only load up until
* ms sans serif for winlogon to use. Later we
* will spawn off a thread which loads the remaining
* fonts in the background.
*/
LastFontLoaded = cFont;
ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
return TRUE;
}
}
/*
* Skip to the next key.
*/
while (*pchSrch++) {
/* do nothing */;
}
cFont += 1;
} while (pchSrch < ((LPWSTR)pchKeys + cchReal));
}
/*
* signal that all the permanent fonts have been loaded
*/
bPermanentFontsLoaded = TRUE;
ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
if (!bPermanent) {
SET_PUDF(PUDF_FONTSARELOADED);
}
return TRUE;
}
extern VOID CloseFNTCache(VOID);
/***************************************************************************\
* xxxLW_LoadFonts
*
*
* History:
\***************************************************************************/
VOID xxxLW_LoadFonts(
BOOL bRemote)
{
BOOL bTimeOut = FALSE;
if (bRemote) {
LARGE_INTEGER li;
ULONG ulWaitCount = 0;
/*
* Before we can proceed we must make sure that all the permanent
* fonts have been loaded.
*/
while (!bPermanentFontsLoaded) {
if (!gbRemoteSession || ulWaitCount < MAX_TIME_OUT) {
LeaveCrit();
li.QuadPart = (LONGLONG)-10000 * CMSSLEEP;
KeDelayExecutionThread(KernelMode, FALSE, &li);
EnterCrit();
} else {
bTimeOut = TRUE;
break;
}
ulWaitCount++;
}
if (!bTimeOut) {
if (!bEnumerateRegistryFonts(FALSE)) {
return; // Nothing we can do.
}
// Add remote type 1 fonts.
ClientLoadRemoteT1Fonts();
}
} else {
xxxAddFontResourceW(L"marlett.ttf", AFRW_ADD_LOCAL_FONT,NULL);
if (!bEnumerateRegistryFonts(TRUE)) {
return; // Nothing we can do.
}
//
// Add local type 1 fonts.
// Only want to be called once, the second time after ms sans serif
// was installed
//
if (bPermanentFontsLoaded) {
ClientLoadLocalT1Fonts();
// All the fonts loaded, we can close the FNTCache.
CloseFNTCache();
}
}
}
/***************************************************************************\
* FinalUserInit
*
* History:
\***************************************************************************/
BOOL FinalUserInit(
VOID)
{
HBITMAP hbm;
PPCLS ppcls;
gpDispInfo->hdcGray = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
if (gpDispInfo->hdcGray == NULL) {
return FALSE;
}
GreSelectFont(gpDispInfo->hdcGray, ghFontSys);
GreSetDCOwner(gpDispInfo->hdcGray, OBJECT_OWNER_PUBLIC);
gpDispInfo->cxGray = gpsi->cxSysFontChar * GRAY_STRLEN;
gpDispInfo->cyGray = gpsi->cySysFontChar + 2;
gpDispInfo->hbmGray = GreCreateBitmap(gpDispInfo->cxGray, gpDispInfo->cyGray, 1, 1, 0L);
if (gpDispInfo->hbmGray == NULL) {
return FALSE;
}
GreSetBitmapOwner(gpDispInfo->hbmGray, OBJECT_OWNER_PUBLIC);
hbm = GreSelectBitmap(gpDispInfo->hdcGray, gpDispInfo->hbmGray);
GreSetTextColor(gpDispInfo->hdcGray, 0x00000000L);
GreSelectBrush(gpDispInfo->hdcGray, gpsi->hbrGray);
GreSetBkMode(gpDispInfo->hdcGray, OPAQUE);
GreSetBkColor(gpDispInfo->hdcGray, 0x00FFFFFFL);
/*
* Setup menu animation dc for global menu state
*/
if (MNSetupAnimationDC(&gMenuState)) {
GreSetDCOwner(gMenuState.hdcAni, OBJECT_OWNER_PUBLIC);
} else {
RIPMSG0(RIP_WARNING, "FinalUserInit: MNSetupAnimationDC failed");
}
/*
* Creation of the queue registers some bogus classes. Get rid
* of them and register the real ones.
*/
ppcls = &PpiCurrent()->pclsPublicList;
while ((*ppcls != NULL) && !((*ppcls)->style & CS_GLOBALCLASS)) {
DestroyClass(ppcls);
}
return TRUE;
}
/***************************************************************************\
* InitializeClientPfnArrays
*
* This routine gets called by the client to tell the kernel where
* its important functions can be located.
*
* 18-Apr-1995 JimA Created.
\***************************************************************************/
NTSTATUS InitializeClientPfnArrays(
CONST PFNCLIENT *ppfnClientA,
CONST PFNCLIENT *ppfnClientW,
CONST PFNCLIENTWORKER *ppfnClientWorker,
HANDLE hModUser)
{
static BOOL fHaveClientPfns = FALSE;
/*
* Remember client side addresses in this global structure. These are
* always constant, so this is ok. Note that if either of the pointers
* are invalid, the exception will be handled in the thunk and
* fHaveClientPfns will not be set.
*/
if (!fHaveClientPfns && ppfnClientA != NULL) {
if (!ISCSRSS()) {
RIPMSG0(RIP_WARNING, "InitializeClientPfnArrays failed !csrss");
return STATUS_ACCESS_DENIED;
}
gpsi->apfnClientA = *ppfnClientA;
gpsi->apfnClientW = *ppfnClientW;
gpsi->apfnClientWorker = *ppfnClientWorker;
gpfnwp[ICLS_BUTTON] = gpsi->apfnClientW.pfnButtonWndProc;
gpfnwp[ICLS_EDIT] = gpsi->apfnClientW.pfnDefWindowProc;
gpfnwp[ICLS_STATIC] = gpsi->apfnClientW.pfnStaticWndProc;
gpfnwp[ICLS_LISTBOX] = gpsi->apfnClientW.pfnListBoxWndProc;
gpfnwp[ICLS_SCROLLBAR] = (PROC)xxxSBWndProc;
gpfnwp[ICLS_COMBOBOX] = gpsi->apfnClientW.pfnComboBoxWndProc;
gpfnwp[ICLS_DESKTOP] = (PROC)xxxDesktopWndProc;
gpfnwp[ICLS_DIALOG] = gpsi->apfnClientW.pfnDialogWndProc;
gpfnwp[ICLS_MENU] = (PROC)xxxMenuWindowProc;
gpfnwp[ICLS_SWITCH] = (PROC)xxxSwitchWndProc;
gpfnwp[ICLS_ICONTITLE] = gpsi->apfnClientW.pfnTitleWndProc;
gpfnwp[ICLS_MDICLIENT] = gpsi->apfnClientW.pfnMDIClientWndProc;
gpfnwp[ICLS_COMBOLISTBOX] = gpsi->apfnClientW.pfnComboListBoxProc;
gpfnwp[ICLS_TOOLTIP] = (PROC)xxxTooltipWndProc;
/*
* Change this assert when new classes are added.
*/
UserAssert(ICLS_MAX == ICLS_GHOST + 1);
hModClient = hModUser;
fHaveClientPfns = TRUE;
}
/*
* Assert that user32.dll on the client side has loaded at the correct
* address.
*/
UserAssert(ppfnClientA == NULL ||
gpsi->apfnClientA.pfnButtonWndProc == ppfnClientA->pfnButtonWndProc);
return STATUS_SUCCESS;
}
/***************************************************************************\
* GetKbdLangSwitch
*
* read the kbd language hotkey setting - if any - from the registry and set
* LangToggle[] appropriately.
*
* values are:
* 1 : VK_MENU (this is the default)
* 2 : VK_CONTROL
* 3 : none
* History:
\***************************************************************************/
BOOL GetKbdLangSwitch(
PUNICODE_STRING pProfileUserName)
{
DWORD dwToggle;
LCID lcid;
FastGetProfileIntW(pProfileUserName,
PMAP_UKBDLAYOUTTOGGLE,
TEXT("Hotkey"),
1,
&dwToggle,
0);
gbGraveKeyToggle = FALSE;
switch (dwToggle) {
case 4:
/*
* Grave accent keyboard switch for thai locales
*/
ZwQueryDefaultLocale(FALSE, &lcid);
gbGraveKeyToggle = (PRIMARYLANGID(lcid) == LANG_THAI) ? TRUE : FALSE;
/*
* fall through (intentional) and disable the ctrl/alt toggle mechanism
*/
case 3:
gLangToggle[0].bVkey = 0;
gLangToggle[0].bScan = 0;
break;
case 2:
gLangToggle[0].bVkey = VK_CONTROL;
break;
default:
gLangToggle[0].bVkey = VK_MENU;
break;
}
return TRUE;
}
/***************************************************************************\
* HideMouseTrails
*
* Hide the mouse trails one by one.
*
* History:
* 04-10-00 MHamid Created.
\***************************************************************************/
VOID HideMouseTrails(
PWND pwnd,
UINT message,
UINT_PTR nID,
LPARAM lParam)
{
if (gMouseTrailsToHide > 0) {
if (InterlockedDecrement(&gMouseTrailsToHide) < gMouseTrails) {
GreMovePointer(gpDispInfo->hDev, gpsi->ptCursor.x, gpsi->ptCursor.y,
MP_PROCEDURAL);
}
}
UNREFERENCED_PARAMETER(pwnd);
UNREFERENCED_PARAMETER(message);
UNREFERENCED_PARAMETER(nID);
UNREFERENCED_PARAMETER(lParam);
}
/***************************************************************************\
*
* SetMouseTrails
*
* n = 0,1 turn off mouse trails.
* n > 1 turn on mouse trails (Trials = n-1).
*
\***************************************************************************/
VOID SetMouseTrails(
UINT n)
{
CheckCritIn();
SetPointer(FALSE);
gMouseTrails = n ? n-1 : n;
SetPointer(TRUE);
if (!IsRemoteConnection() && (!!gtmridMouseTrails ^ !!gMouseTrails)) {
if (gMouseTrails) {
/*
* Create the gtmridMouseTrails timer in the desktop thread,
* becuase if we creat it here it will get killed when the current
* thread (App thread calling SPI_SETMOUSETRAILS) get destroied.
*/
_PostMessage(gTermIO.ptiDesktop->pDeskInfo->spwnd, WM_CREATETRAILTIMER, 0, 0);
} else {
FindTimer(NULL, gtmridMouseTrails, TMRF_RIT, TRUE);
gtmridMouseTrails = 0;
}
}
}
#ifdef IMM_PER_LOGON
extern BOOL IsIMMEnabledSystem(VOID);
extern BOOL IsCTFIMEEnabledSystem(VOID);
BOOL UpdatePerUserImmEnabling(
VOID)
{
/*
* Update the IME enabling flag
*/
SET_OR_CLEAR_SRVIF(SRVIF_IME, IsIMMEnabledSystem());
RIPMSGF1(RIP_VERBOSE, "New Imm flag = %d", !!IS_IME_ENABLED());
/*
* Update the CTFIME enabling flag
*/
SET_OR_CLEAR_SRVIF(SRVIF_CTFIME_ENABLED, IsCTFIMEEnabledSystem());
RIPMSG1(RIP_VERBOSE, "_UpdatePerUserImmEnabling: new CTFIME flag = %d", !!IS_CICERO_ENABLED());
return TRUE;
}
#endif
/***************************************************************************\
* xxxUpdatePerUserSystemParameters
*
* Called by winlogon to set Window system parameters to the current user's
* profile.
*
* 18-Sep-1992 IanJa Created.
* 18-Nov-1993 SanfordS Moved more winlogon init code to here for speed.
* 31-Mar-2001 Msadek Changed parm from BOOL to flags for TS Slow Link
* Perf DCR.
* 02-Feb-2002 MMcCr Added SPI_SETBLOCKSENDINPUTRESETS feature
\***************************************************************************/
BOOL xxxUpdatePerUserSystemParameters(
DWORD dwFlags)
{
/*
* NB - Any local variables that are used in appiPolicy must be initialized.
* Otherwise, during a policy change, it is possible for them to be used w/o
* being initialized and all heck breaks loose. Windows Bug #314150.
*/
int i;
HANDLE hKey;
DWORD dwFontSmoothing = GreGetFontEnumeration();
DWORD dwFontSmoothingContrast;
DWORD dwFontSmoothingOrientation;
BOOL fDragFullWindows = TEST_PUDF(PUDF_DRAGFULLWINDOWS);
TL tlName;
PUNICODE_STRING pProfileUserName = NULL;
DWORD dwPolicyFlags = 0;
DWORD dwData;
BOOL bPolicyChange;
BOOL bUserLoggedOn;
BOOL bRemoteSettings;
SPINFO spiPolicy[] = {
{ PMAP_DESKTOP, SPI_SETBLOCKSENDINPUTRESETS, STR_BLOCKSENDINPUTRESETS, 0 },
{ PMAP_DESKTOP, SPI_SETSCREENSAVETIMEOUT, STR_SCREENSAVETIMEOUT, 0 },
{ PMAP_DESKTOP, SPI_SETSCREENSAVEACTIVE, STR_SCREENSAVEACTIVE, 0 },
{ PMAP_DESKTOP, SPI_SETDRAGHEIGHT, STR_DRAGHEIGHT, 4 },
{ PMAP_DESKTOP, SPI_SETDRAGWIDTH, STR_DRAGWIDTH, 4 },
{ PMAP_DESKTOP, SPI_SETWHEELSCROLLLINES, STR_WHEELSCROLLLINES, 3 },
};
SPINFO spiNotPolicy[] = {
{ PMAP_KEYBOARD, SPI_SETKEYBOARDDELAY, STR_KEYDELAY, 0 },
{ PMAP_KEYBOARD, SPI_SETKEYBOARDSPEED, STR_KEYSPEED, 15 },
{ PMAP_MOUSE, SPI_SETDOUBLECLICKTIME, STR_DBLCLKSPEED, 500 },
{ PMAP_MOUSE, SPI_SETDOUBLECLKWIDTH, STR_DOUBLECLICKWIDTH, 4 },
{ PMAP_MOUSE, SPI_SETDOUBLECLKHEIGHT, STR_DOUBLECLICKHEIGHT, 4 },
{ PMAP_MOUSE, SPI_SETSNAPTODEFBUTTON, STR_SNAPTO, 0 },
{ PMAP_WINDOWSU, SPI_SETMENUDROPALIGNMENT, STR_MENUDROPALIGNMENT, 0 },
{ PMAP_INPUTMETHOD, SPI_SETSHOWIMEUI, STR_SHOWIMESTATUS, 1 },
};
PROFINTINFO apiiPolicy[] = {
{ PMAP_DESKTOP, (LPWSTR)STR_MENUSHOWDELAY, 400, &gdtMNDropDown },
{ PMAP_DESKTOP, (LPWSTR)STR_DRAGFULLWINDOWS, 2, &fDragFullWindows },
{ PMAP_DESKTOP, (LPWSTR)STR_FASTALTTABROWS, 3, &gnFastAltTabRows },
{ PMAP_DESKTOP, (LPWSTR)STR_FASTALTTABCOLUMNS, 7, &gnFastAltTabColumns },
{ PMAP_DESKTOP, (LPWSTR)STR_MAXLEFTOVERLAPCHARS, 3, &(gpsi->wMaxLeftOverlapChars) },
{ PMAP_DESKTOP, (LPWSTR)STR_MAXRIGHTOVERLAPCHARS, 3, &(gpsi->wMaxRightOverlapChars) },
{ PMAP_DESKTOP, (LPWSTR)STR_FONTSMOOTHING, 0, &dwFontSmoothing },
{ 0, NULL, 0, NULL }
};
PROFINTINFO apiiNoPolicy[] = {
{ PMAP_MOUSE, (LPWSTR)STR_MOUSETHRESH1, 6, &gMouseThresh1 },
{ PMAP_MOUSE, (LPWSTR)STR_MOUSETHRESH2, 10, &gMouseThresh2 },
{ PMAP_MOUSE, (LPWSTR)STR_MOUSESPEED, 1, &gMouseSpeed },
{ PMAP_INPUTMETHOD, (LPWSTR)STR_HEXNUMPAD, 0, &gfEnableHexNumpad },
{ 0, NULL, 0, NULL }
};
UserAssert(IsWinEventNotifyDeferredOK());
bPolicyChange = dwFlags & UPUSP_POLICYCHANGE;
bUserLoggedOn = dwFlags & UPUSP_USERLOGGEDON;
bRemoteSettings = dwFlags & UPUSP_REMOTESETTINGS;
/*
* Make sure the caller is the logon process.
*/
if (PsGetCurrentProcessId() != gpidLogon) {
if (!bPolicyChange) {
RIPMSG0(RIP_WARNING, "Access denied in xxxUpdatePerUserSystemParameters");
}
return FALSE;
}
pProfileUserName = CreateProfileUserName(&tlName);
/*
* If the desktop policy hasn't changed and we came here because we
* thought it had, we're done.
*/
if (bPolicyChange && !bRemoteSettings) {
if (!CheckDesktopPolicyChange(pProfileUserName)) {
FreeProfileUserName(pProfileUserName, &tlName);
return FALSE;
}
dwPolicyFlags = POLICY_ONLY;
UserAssert(!bUserLoggedOn);
}
/*
* If new user is logging in, we need to recheck for
* user policy changes.
*/
if (bUserLoggedOn) {
gdwPolicyFlags |= POLICY_USER;
}
/*
* We don't want remote settings to be read all the time so spcify it here
* if the caller wants to.Update it here since we do not save it in
* gdwPolicyFlags [msadek].
*/
if (bRemoteSettings) {
dwPolicyFlags |= POLICY_REMOTE;
}
/*
* Get the timeout for low level hooks from the registry.
*/
dwData = 300;
FastGetProfileValue(pProfileUserName,
PMAP_DESKTOP,
(LPWSTR)STR_LLHOOKSTIMEOUT,
(LPBYTE)&dwData,
(LPBYTE)&gnllHooksTimeout,
sizeof(int),
dwPolicyFlags);
/*
* Control Panel User Preferences.
*/
LoadCPUserPreferences(pProfileUserName, dwPolicyFlags);
#ifdef LAME_BUTTON
/*
* Lame button text.
*/
FastGetProfileValue(pProfileUserName,
PMAP_DESKTOP,
(LPWSTR)STR_LAMEBUTTONENABLED,
NULL,
(LPBYTE)&gdwLameFlags,
sizeof(DWORD),
dwPolicyFlags);
#endif // LAME_BUTTON
if (!bPolicyChange) {
/*
* Set syscolors from registry.
*/
xxxODI_ColorInit(pProfileUserName);
LW_LoadResources(pProfileUserName);
/*
* This is the initialization from Chicago.
*/
xxxSetWindowNCMetrics(pProfileUserName, NULL, TRUE, -1); // Colors must be set first
SetMinMetrics(pProfileUserName, NULL);
SetIconMetrics(pProfileUserName, NULL);
/*
* Read the keyboard layout switching hot key.
*/
GetKbdLangSwitch(pProfileUserName);
/*
* Set the default thread locale for the system based on the value
* in the current user's registry profile.
*/
ZwSetDefaultLocale( TRUE, 0 );
/*
* Set the default UI language based on the value in the current
* user's registry profile.
*/
ZwSetDefaultUILanguage(0);
/*
* And then Get it.
*/
ZwQueryDefaultUILanguage(&(gpsi->UILangID));
/*
* Now load strings using the currnet UILangID.
*/
xxxLoadSomeStrings();
/*
* Destroy the desktop system menus, so that they're recreated with
* the correct UI language if the current user's UI language is
* different from the previous one. This is done by finding the
* interactive window station and destroying all its desktops's
* system menus.
*/
if (grpWinStaList != NULL) {
PDESKTOP pdesk;
PMENU pmenu;
UserAssert(!(grpWinStaList->dwWSF_Flags & WSF_NOIO));
for (pdesk = grpWinStaList->rpdeskList; pdesk != NULL; pdesk = pdesk->rpdeskNext) {
if (pdesk->spmenuSys != NULL) {
pmenu = pdesk->spmenuSys;
if (UnlockDesktopSysMenu(&pdesk->spmenuSys)) {
_DestroyMenu(pmenu);
}
}
if (pdesk->spmenuDialogSys != NULL) {
pmenu = pdesk->spmenuDialogSys;
if (UnlockDesktopSysMenu(&pdesk->spmenuDialogSys)) {
_DestroyMenu(pmenu);
}
}
}
}
xxxUpdateSystemCursorsFromRegistry(pProfileUserName);
/*
* now go set a bunch of random values from the win.ini file.
*/
for (i = 0; i < ARRAY_SIZE(spiNotPolicy); i++) {
if (FastGetProfileIntFromID(pProfileUserName,
spiNotPolicy[i].idSection,
spiNotPolicy[i].idRes,
spiNotPolicy[i].def,
&dwData,
0)) {
xxxSystemParametersInfo(spiNotPolicy[i].id, dwData, 0L, 0);
}
}
FastGetProfileIntsW(pProfileUserName, apiiNoPolicy, 0);
}
/*
* Reset desktop pattern now. Note no parameters. It just goes off
* and reads the registry and sets the desktop pattern.
*/
xxxSystemParametersInfo(SPI_SETDESKPATTERN, (UINT)-1, 0L, 0); // 265 version
/*
* Initialize IME show status
*/
if (bUserLoggedOn) {
gfIMEShowStatus = IMESHOWSTATUS_NOTINITIALIZED;
}
/*
* Now go set a bunch of random values from the registry.
*/
for (i = 0; i < ARRAY_SIZE(spiPolicy); i++) {
if (FastGetProfileIntFromID(pProfileUserName,
spiPolicy[i].idSection,
spiPolicy[i].idRes,
spiPolicy[i].def,
&dwData,
dwPolicyFlags)) {
xxxSystemParametersInfo(spiPolicy[i].id, dwData, 0L, 0);
}
}
/*
* Read profile integers and do any fixups.
*/
FastGetProfileIntsW(pProfileUserName, apiiPolicy, dwPolicyFlags);
if (gnFastAltTabColumns < 2) {
gnFastAltTabColumns = 7;
}
if (gnFastAltTabRows < 1) {
gnFastAltTabRows = 3;
}
/*
* If this is the first time the user logs on, set the DragFullWindows
* to the default. If we have an accelerated device, enable full drag.
*/
if (fDragFullWindows == 2) {
WCHAR szTemp[40], szDragFullWindows[40];
SET_OR_CLEAR_PUDF(
PUDF_DRAGFULLWINDOWS,
GreGetDeviceCaps(gpDispInfo->hdcScreen, BLTALIGNMENT) == 0);
if (bUserLoggedOn) {
swprintf(szTemp, L"%d", TEST_BOOL_PUDF(PUDF_DRAGFULLWINDOWS));
ServerLoadString(hModuleWin,
STR_DRAGFULLWINDOWS,
szDragFullWindows,
ARRAY_SIZE(szDragFullWindows));
FastWriteProfileStringW(pProfileUserName,
PMAP_DESKTOP,
szDragFullWindows,
szTemp);
}
} else {
SET_OR_CLEAR_PUDF(PUDF_DRAGFULLWINDOWS, fDragFullWindows);
}
/*
* !!!LATER!!! (adams) See if the following profile retrievals can't
* be done in the "spi" array above (e.g. SPI_SETSNAPTO).
*/
/*
* For remote connections or remote assistance, we may not want a
* blinking caret for perf reasons. So, we try to read the value from
* the registry, if there is one set. If nothing is set, we will
* default to whatever is on desktop.
*/
dwData = gpsi->dtCaretBlink;
if (FastGetProfileIntFromID(pProfileUserName,
PMAP_DESKTOP,
STR_BLINK,
500,
&dwData,
bRemoteSettings? dwPolicyFlags : bPolicyChange)) {
_SetCaretBlinkTime(dwData);
}
if (!bPolicyChange) {
/*
* Set mouse settings
*/
FastGetProfileIntFromID(pProfileUserName, PMAP_MOUSE, STR_MOUSESENSITIVITY, MOUSE_SENSITIVITY_DEFAULT, &gMouseSensitivity, 0);
if ((gMouseSensitivity < MOUSE_SENSITIVITY_MIN) || (gMouseSensitivity > MOUSE_SENSITIVITY_MAX)) {
gMouseSensitivity = MOUSE_SENSITIVITY_DEFAULT;
}
gMouseSensitivityFactor = CalculateMouseSensitivity(gMouseSensitivity);
#ifdef SUBPIXEL_MOUSE
ReadDefaultAccelerationCurves(pProfileUserName);
ResetMouseAccelerationCurves();
#endif
/*
* Set mouse trails.
*/
FastGetProfileIntFromID(pProfileUserName, PMAP_MOUSE, STR_MOUSETRAILS, 0, &dwData, 0);
SetMouseTrails(dwData);
/*
* Font Information
*/
FastGetProfileIntW(pProfileUserName, PMAP_TRUETYPE, TEXT("TTOnly"), FALSE, &dwData, 0);
GreSetFontEnumeration(dwData);
/*
* Window animation
*/
FastGetProfileIntFromID(pProfileUserName, PMAP_METRICS, STR_MINANIMATE, TRUE, &dwData, 0);
SET_OR_CLEAR_PUDF(PUDF_ANIMATE, dwData);
/*
* Mouse tracking variables
*/
FastGetProfileIntFromID(pProfileUserName, PMAP_MOUSE, STR_MOUSEHOVERWIDTH, SYSMET(CXDOUBLECLK), &gcxMouseHover, 0);
FastGetProfileIntFromID(pProfileUserName, PMAP_MOUSE, STR_MOUSEHOVERHEIGHT, SYSMET(CYDOUBLECLK), &gcyMouseHover, 0);
FastGetProfileIntFromID(pProfileUserName, PMAP_MOUSE, STR_MOUSEHOVERTIME, gdtMNDropDown, &gdtMouseHover, 0);
}
/*
* Initial Keyboard state: ScrollLock, NumLock and CapsLock state;
* global (per-user) kbd layout attributes (such as ShiftLock/CapsLock)
*/
if (!bPolicyChange) {
UpdatePerUserKeyboardIndicators(pProfileUserName);
UpdatePerUserKeyboardMappings(pProfileUserName);
FastGetProfileDwordW(pProfileUserName, PMAP_UKBDLAYOUT, L"Attributes", 0, &gdwKeyboardAttributes, 0);
gdwKeyboardAttributes = KLL_GLOBAL_ATTR_FROM_KLF(gdwKeyboardAttributes);
xxxUpdatePerUserAccessPackSettings(pProfileUserName);
}
/*
* If we successfully opened this, we assume we have a network.
*/
if (hKey = OpenCacheKeyEx(NULL, PMAP_NETWORK, KEY_READ, NULL)) {
RIPMSG0(RIP_WARNING | RIP_NONAME, "");
SYSMET(NETWORK) = RNC_NETWORKS;
ZwClose(hKey);
}
SYSMET(NETWORK) |= RNC_LOGON;
/*
* Font smoothing
*/
/* clear the flags from what could have been set for the previous user */
GreSetFontEnumeration(FE_SET_AA);
GreSetFontEnumeration(FE_SET_CT);
if (dwFontSmoothing & FE_AA_ON)
GreSetFontEnumeration( dwFontSmoothing | FE_SET_AA );
if (UPDWORDValue(SPI_GETFONTSMOOTHINGTYPE) & FE_FONTSMOOTHINGCLEARTYPE)
GreSetFontEnumeration( dwFontSmoothing | FE_SET_CT | FE_CT_ON);
dwFontSmoothingContrast = UPDWORDValue(SPI_GETFONTSMOOTHINGCONTRAST);
if (dwFontSmoothingContrast == 0)
dwFontSmoothingContrast = DEFAULT_CT_CONTRAST;
GreSetFontContrast(dwFontSmoothingContrast);
dwFontSmoothingOrientation = UPDWORDValue(SPI_GETFONTSMOOTHINGORIENTATION);
GreSetLCDOrientation(dwFontSmoothingOrientation);
/*
* Desktop Build Number Painting
*/
if (USER_SHARED_DATA->SystemExpirationDate.QuadPart || gfUnsignedDrivers) {
gdwCanPaintDesktop = 1;
} else {
FastGetProfileDwordW(pProfileUserName, PMAP_DESKTOP, L"PaintDesktopVersion", 0, &gdwCanPaintDesktop, dwPolicyFlags);
}
if (!bPolicyChange) {
FastGetProfileStringW(pProfileUserName,
PMAP_WINLOGON,
TEXT("DefaultUserName"),
TEXT("Unknown"),
gszUserName,
ARRAY_SIZE(gszUserName),
0);
FastGetProfileStringW(pProfileUserName,
PMAP_WINLOGON,
TEXT("DefaultDomainName"),
TEXT("Unknown"),
gszDomainName,
ARRAY_SIZE(gszDomainName),
0);
FastGetProfileStringW(pProfileUserName,
PMAP_COMPUTERNAME,
TEXT("ComputerName"),
TEXT("Unknown"),
gszComputerName,
ARRAY_SIZE(gszComputerName),
0);
}
FreeProfileUserName(pProfileUserName, &tlName);
/*
* Do this if we are here for real policy change
* i.e. not a remote settings policy change.
*/
if (dwFlags == UPUSP_POLICYCHANGE) {
xxxUserResetDisplayDevice();
}
return TRUE;
}
/*
* Called by InitOemXlateTables via SFI_INITANSIOEM
*/
VOID InitAnsiOem(PCHAR pOemToAnsi, PCHAR pAnsiToOem)
{
UserAssert(gpsi != NULL);
UserAssert(pOemToAnsi != NULL);
UserAssert(pAnsiToOem != NULL);
try {
ProbeForRead(pOemToAnsi, NCHARS, sizeof(BYTE));
ProbeForRead(pAnsiToOem, NCHARS, sizeof(BYTE));
RtlCopyMemory(gpsi->acOemToAnsi, pOemToAnsi, NCHARS);
RtlCopyMemory(gpsi->acAnsiToOem, pAnsiToOem, NCHARS);
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
}
}
/***************************************************************************\
* RegisterLPK
*
* Called by InitializeLpkHooks on the client side after an LPK is
* loaded for the current process.
*
* 05-Nov-1996 GregoryW Created.
\***************************************************************************/
VOID RegisterLPK(
DWORD dwLpkEntryPoints)
{
PpiCurrent()->dwLpkEntryPoints = dwLpkEntryPoints;
}
/***************************************************************************\
* Enforce color-depth dependent settings on systems with less
* then 256 colors.
*
* 2/13/1998 vadimg created
\***************************************************************************/
VOID EnforceColorDependentSettings(VOID)
{
if (gpDispInfo->fAnyPalette) {
gbDisableAlpha = TRUE;
} else if (GreGetDeviceCaps(gpDispInfo->hdcScreen, NUMCOLORS) == -1) {
gbDisableAlpha = FALSE;
} else {
gbDisableAlpha = TRUE;
}
}
#if DBG
VOID InitGlobalThreadLockArray(
DWORD dwIndex)
{
PTL pTLArray = gpaThreadLocksArrays[dwIndex];
int i;
for (i = 0; i < MAX_THREAD_LOCKS - 1; i++) {
pTLArray[i].next = &pTLArray[i + 1];
}
pTLArray[MAX_THREAD_LOCKS - 1].next = NULL;
}
#endif
/***************************************************************************\
* CheckLUIDDosDevicesEnabled
*
* Checks if LUID DosDevices are Enabled.
*
* 8/20/2000 ELi created
\***************************************************************************/
VOID CheckLUIDDosDevicesEnabled(
PBOOL pResult)
{
ULONG LUIDDeviceMapsEnabled;
NTSTATUS Status;
UserAssert(pResult != NULL);
Status = NtQueryInformationProcess(NtCurrentProcess(),
ProcessLUIDDeviceMapsEnabled,
&LUIDDeviceMapsEnabled,
sizeof(LUIDDeviceMapsEnabled),
NULL);
if (NT_SUCCESS(Status)) {
*pResult = (LUIDDeviceMapsEnabled != 0);
} else {
*pResult = FALSE;
}
}