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.
 
 
 
 
 
 

1155 lines
35 KiB

/**************************************************************************\
* Module Name: server.c
*
* Server support routines for the CSR stuff.
*
* Copyright (c) Microsoft Corp. 1990 All Rights Reserved
*
* Created: 10-Dec-90
*
* History:
* 10-Dec-90 created by sMeans
*
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "dbt.h"
#include "ntdddisk.h"
#include "ntuser.h"
HANDLE hThreadNotification;
HANDLE hKeyPriority;
UNICODE_STRING PriorityValueName;
IO_STATUS_BLOCK IoStatusRegChange;
ULONG RegChangeBuffer;
HANDLE ghNlsEvent;
BOOL gfLogon;
FARPROC gpfnAttachRoutine;
#define ID_NLS 0
#define ID_MEDIACHANGE 1
#define NUM_MEDIA_EVENTS 24
#define NUM_EVENTS ID_MEDIACHANGE + NUM_MEDIA_EVENTS
#define MAX_TRIES 16
static WCHAR wcDriveCache[ MAXIMUM_WAIT_OBJECTS ];
#define DS_UNKNOWN 0x0
#define DS_INSERTED 0x1
#define DS_EJECTED 0x10
static BYTE aDriveState[ MAXIMUM_WAIT_OBJECTS ];
HANDLE CsrApiPort;
HANDLE CsrQueryApiPort(VOID);
ULONG
SrvExitWindowsEx(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvEndTask(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvInitSoundDriver(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvPlaySound(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvLogon(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvServiceMessageBox(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvRegisterServicesProcess(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvActivateDebugger(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
ULONG
SrvGetThreadConsoleDesktop(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus);
PCSR_API_ROUTINE UserServerApiDispatchTable[ UserpMaxApiNumber - UserpExitWindowsEx ] = {
(PCSR_API_ROUTINE)SrvExitWindowsEx,
(PCSR_API_ROUTINE)SrvEndTask,
(PCSR_API_ROUTINE)SrvInitSoundDriver,
(PCSR_API_ROUTINE)SrvPlaySound,
(PCSR_API_ROUTINE)SrvLogon,
(PCSR_API_ROUTINE)SrvServiceMessageBox,
(PCSR_API_ROUTINE)SrvRegisterServicesProcess,
(PCSR_API_ROUTINE)SrvActivateDebugger,
(PCSR_API_ROUTINE)SrvGetThreadConsoleDesktop,
};
BOOLEAN UserServerApiServerValidTable[ UserpMaxApiNumber - UserpExitWindowsEx ] = {
FALSE, // ExitWindowsEx
FALSE, // EndTask
TRUE, // InitSoundDriver
TRUE, // PlaySound
FALSE, // Logon
FALSE, // ServiceMessageBox
FALSE, // RegisterServicesProcess
FALSE, // ActivateDebugger
TRUE, // GetThreadConsoleDesktop
};
#if DBG
PSZ UserServerApiNameTable[ UserpMaxApiNumber - UserpExitWindowsEx ] = {
"SrvExitWindowsEx",
"SrvEndTask",
"SrvInitSoundDriver",
"SrvPlaySound",
"SrvLogon",
"SrvServiceMessageBox",
"SrvRegisterServicesProcess",
"SrvActivateDebugger",
"SrvGetThreadConsoleDesktop",
};
#endif // DBG
NTSTATUS
UserServerDllInitialization(
PCSR_SERVER_DLL psrvdll
);
NTSTATUS UserClientConnect(PCSR_PROCESS Process, PVOID ConnectionInformation,
PULONG pulConnectionLen);
VOID UserClientDisconnect(PCSR_PROCESS Process);
VOID UserHardError(PCSR_THREAD pcsrt, PHARDERROR_MSG pmsg);
NTSTATUS UserClientShutdown(PCSR_PROCESS Process, ULONG dwFlags, BOOLEAN fFirstPass);
VOID SwitchStackThenTerminate(PVOID CurrentStack, PVOID NewStack, DWORD ExitCode);
VOID InitOemXlateTables();
VOID GetTimeouts(VOID);
VOID StartRegReadRead(VOID);
VOID RegReadApcProcedure(PVOID RegReadApcContext, PIO_STATUS_BLOCK IoStatus);
VOID NotificationThread(PVOID);
typedef BOOL (*PFNPROCESSCREATE)(DWORD, DWORD, DWORD, DWORD);
VOID InitializeConsoleAttributes(VOID);
NTSTATUS GetThreadConsoleDesktop(DWORD dwThreadId, HDESK *phdesk);
BOOL BaseSetProcessCreateNotify(PFNPROCESSCREATE pfn);
VOID BaseSrvNlsUpdateRegistryCache(PVOID ApcContext,
PIO_STATUS_BLOCK pIoStatusBlock);
NTSTATUS BaseSrvNlsLogon(BOOL);
/***************************************************************************\
* UserServerDllInitialization
*
* Called by the CSR stuff to allow a server DLL to initialize itself and
* provide information about the APIs it provides.
*
* Several operations are performed during this initialization:
*
* - The shared heap (client read-only) handle is initialized.
* - The Raw Input Thread (RIT) is launched.
* - GDI is initialized.
*
* History:
* 10-19-92 DarrinM Integrated xxxUserServerDllInitialize into this rtn.
* 11-08-91 patrickh move GDI init here from DLL init routine.
* 12-10-90 sMeans Created.
\***************************************************************************/
NTSTATUS UserServerDllInitialization(
PCSR_SERVER_DLL psrvdll)
{
CLIENT_ID ClientId;
DWORD cbAllocated;
NTSTATUS Status;
int i;
/*
* Initialize a critical section structure that will be used to protect
* all of the User Server's critical sections (except a few special
* cases like the RIT -- see below).
*/
RtlInitializeCriticalSection(&gcsUserSrv);
EnterCrit(); // synchronize heap calls
/*
* Remember WINSRV.DLL's hmodule so we can grab resources from it later.
*/
hModuleWin = psrvdll->ModuleHandle;
psrvdll->ApiNumberBase = USERK_FIRST_API_NUMBER;
psrvdll->MaxApiNumber = UserpMaxApiNumber;
psrvdll->ApiDispatchTable = UserServerApiDispatchTable;
psrvdll->ApiServerValidTable = UserServerApiServerValidTable;
#if DBG
psrvdll->ApiNameTable = UserServerApiNameTable;
#else
psrvdll->ApiNameTable = NULL;
#endif
psrvdll->PerProcessDataLength = CHANDLES * sizeof(HANDLE);
psrvdll->PerThreadDataLength = 0;
psrvdll->ConnectRoutine = UserClientConnect;
psrvdll->DisconnectRoutine = UserClientDisconnect;
psrvdll->HardErrorRoutine = UserHardError;
psrvdll->ShutdownProcessRoutine = UserClientShutdown;
/*
* Create these events used by shutdown
*/
NtCreateEvent(&heventCancel, EVENT_ALL_ACCESS, NULL,
NotificationEvent, FALSE);
NtCreateEvent(&heventCancelled, EVENT_ALL_ACCESS, NULL,
NotificationEvent, FALSE);
/*
* Tell the base what user address to call when it is creating a process
* (but before the process starts running).
*/
BaseSetProcessCreateNotify(NtUserNotifyProcessCreate);
/*
* Set up translation tables.
*/
InitOemXlateTables();
/*
* Get timeout values from registry
*/
GetTimeouts();
/*
* Load some strings.
*/
pszaSUCCESS = (LPSTR)RtlLoadStringOrError(hModuleWin,
STR_SUCCESS, NULL, &cbAllocated, TRUE);
pszaSYSTEM_INFORMATION = (LPSTR)RtlLoadStringOrError(hModuleWin,
STR_SYSTEM_INFORMATION, NULL, &cbAllocated, TRUE);
pszaSYSTEM_WARNING = (LPSTR)RtlLoadStringOrError(hModuleWin,
STR_SYSTEM_WARNING, NULL, &cbAllocated, TRUE);
pszaSYSTEM_ERROR = (LPSTR)RtlLoadStringOrError(hModuleWin,
STR_SYSTEM_ERROR, NULL, &cbAllocated, TRUE);
/*
* Add marlett font and make it permanent
*/
i = GdiAddFontResourceW(L"marlett.ttf", AFRW_ADD_LOCAL_FONT);
/*
* Initialize USER
*/
{
HANDLE hModBase;
LeaveCrit();
hModBase = GetModuleHandle(TEXT("kernel32"));
EnterCrit();
UserAssert(hModBase);
gpfnAttachRoutine = GetProcAddress(hModBase,"BaseAttachCompleteThunk");
UserAssert(gpfnAttachRoutine);
Status = NtUserInitialize(USERCURRENTVERSION, gpfnAttachRoutine);
if (!NT_SUCCESS(Status)) {
goto ExitUserInit;
}
}
/*
* Start registry notification thread
*/
Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 4*0x1000,
(PUSER_THREAD_START_ROUTINE)NotificationThread, NULL, &hThreadNotification,
&ClientId);
CsrAddStaticServerThread(hThreadNotification, &ClientId, 0);
ExitUserInit:
LeaveCrit();
return Status;
}
/**************************************************************************\
* UserClientConnect
*
* This function is called once for each client process that connects to the
* User server. When the client dynlinks to USER.DLL, USER.DLL's init code
* is executed and calls CsrClientConnectToServer to establish the connection.
* The server portion of ConnectToServer calls out this entrypoint.
*
* UserClientConnect first verifies version numbers to make sure the client
* is compatible with this server and then completes all process-specific
* initialization.
*
* History:
* 02-??-91 SMeans Created.
* 04-02-91 DarrinM Added User intialization code.
\**************************************************************************/
NTSTATUS UserClientConnect(
PCSR_PROCESS Process,
PVOID ConnectionInformation,
PULONG pulConnectionLen)
{
PHANDLE pHandle = Process->ServerDllPerProcessData[USERSRV_SERVERDLL_INDEX];
int i;
/*
* Pass the api port to the kernel. Do this early so the kernel
* can send a datagram to CSR to activate a debugger.
*/
if (CsrApiPort == NULL) {
CsrApiPort = CsrQueryApiPort();
NtUserSetInformationThread(
NtCurrentThread(),
UserThreadCsrApiPort,
&CsrApiPort,
sizeof(HANDLE));
}
/*
* Initialize cached handles to NULL
*/
for (i = 0; i < CHANDLES; ++i)
pHandle[i] = NULL;
return NtUserProcessConnect(Process->ProcessHandle,
(PUSERCONNECT)ConnectionInformation, *pulConnectionLen);
}
VOID UserClientDisconnect(
PCSR_PROCESS Process)
{
PHANDLE pHandle = Process->ServerDllPerProcessData[USERSRV_SERVERDLL_INDEX];
BOOL fSuccess;
/*
* Close any open handles
*/
if (pHandle[ID_HDESK]) {
fSuccess = CloseDesktop(pHandle[ID_HDESK]);
UserAssert(fSuccess);
}
if (pHandle[ID_HWINSTA]) {
fSuccess = CloseWindowStation(pHandle[ID_HWINSTA]);
UserAssert(fSuccess);
}
}
VOID
RegReadApcProcedure(
PVOID RegReadApcContext,
PIO_STATUS_BLOCK IoStatus
)
{
UNICODE_STRING ValueString;
LONG Status;
BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
DWORD cbSize;
ULONG l;
RtlInitUnicodeString(&ValueString, L"Win32PrioritySeparation");
Status = NtQueryValueKey(hKeyPriority,
&ValueString,
KeyValuePartialInformation,
(PKEY_VALUE_PARTIAL_INFORMATION)Buf,
sizeof(Buf),
&cbSize);
if (NT_SUCCESS(Status)) {
l = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
} else
l = 1; // last resort default
if ( l <= 2 ) {
CsrSetForegroundPriority((PCSR_PROCESS)(l));
}
NtNotifyChangeKey(
hKeyPriority,
NULL,
(PIO_APC_ROUTINE)RegReadApcProcedure,
NULL,
&IoStatusRegChange,
REG_NOTIFY_CHANGE_LAST_SET,
FALSE,
&RegChangeBuffer,
sizeof(RegChangeBuffer),
TRUE
);
}
VOID
StartRegReadRead(VOID)
{
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES OA;
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\PriorityControl");
InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (!NT_SUCCESS(NtOpenKey(&hKeyPriority, KEY_READ | KEY_NOTIFY, &OA)))
UserAssert(FALSE);
RegReadApcProcedure(NULL, NULL);
}
/***************************************************************************\
* GetDeviceObject
*
* This routine takes a logical drive letter and extracts the \Device\name.
*
* History:
* 24-Feb-96 BradG From Windisk for use by HandleMediChangEvent
\***************************************************************************/
BOOL GetDeviceObject(
WCHAR wcDrive, // drive letter to get info about
PUNICODE_STRING pustrLinkTarget) // Output buffer
{
BOOL bResult;
HANDLE hSymbolicLink;
#if 0
WCHAR wszLinkName[sizeof(L"\\DosDevices\\A:")];
#else
WCHAR wszLinkName[sizeof(L"A:\\")];
#endif
UNICODE_STRING ustrLinkName;
OBJECT_ATTRIBUTES LinkAttributes;
UserAssert( wcDrive >= L'A' && wcDrive <= L'Z' );
UserAssert( pustrLinkTarget != NULL );
/*
* Construct the link name by calling RtlDosPathNameToNtPathName, and
* strip of the trailing backslash. At the end of this, ustrLinkName
* should be of the form \DosDevices\X:
*/
#if 0
wsprintfW( wszLinkName, L"\\DosDevices\\%lc:", wcDrive );
RtlInitUnicodeString(&ustrLinkName, wszLinkName);
#else
wsprintfW( wszLinkName, L"%lc:\\", wcDrive);
RtlInitUnicodeString(&ustrLinkName, NULL);
bResult = RtlDosPathNameToNtPathName_U(wszLinkName, &ustrLinkName, NULL, NULL);
if (!bResult) {
goto CantDoIt;
}
ustrLinkName.Length -= sizeof(WCHAR);
#endif
/*
* Get the symbolic link object
*/
InitializeObjectAttributes(&LinkAttributes,
&ustrLinkName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
NULL);
bResult = NT_SUCCESS( NtOpenSymbolicLinkObject(&hSymbolicLink,
GENERIC_READ,
&LinkAttributes));
if (!bResult)
{
goto CantDoIt;
}
/*
* Find out if the device specified is DFS DeviceObject
*/
pustrLinkTarget->MaximumLength -= sizeof(WCHAR);
bResult = NT_SUCCESS( NtQuerySymbolicLinkObject(hSymbolicLink,
pustrLinkTarget,
NULL));
pustrLinkTarget->MaximumLength += sizeof(WCHAR);
if (bResult) {
*((WCHAR *)((PSTR)(pustrLinkTarget->Buffer) + pustrLinkTarget->Length)) = UNICODE_NULL;
}
NtClose(hSymbolicLink);
CantDoIt:
/*
* Free the string buffer that was allocated by RtlDosPathNameToNtPathName_U
*/
#if 1
if (ustrLinkName.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, ustrLinkName.Buffer);
}
#endif
return bResult;
}
/***************************************************************************\
* HandleMediaChangeEvent
*
* This routine is responsible for broadcasting the WM_DEVICECHANGE message
* when media arrives or is removed from a CD-ROM device.
*
* History:
* 23-Feb-96 BradG Modified to handle event per CD-ROM device
* 23-April-96 Salimc Some CD-ROM drives notify us that media has
* arrived before the drive has recognized that it had
* new media. The call to DeviceIoctl() will fail in
* this case. To fix this we made the following changes
*
* aDriveState is an array of tri-state global variable
* for each drive.Each variable starts off in an UNKNOWN
* state and on the first event with any drive we do the
* full MAX_TRIES or less CHECK_VERIFY's which then gets
* us into either a INSERTED or EJECTED state. From then
* on we know that each new event is going to be the
* opposite of what we currently have.
*
* UNKNOWN => do upto MAX_TRIES CHECK_VERIFY's with
* delay to get into EJECTED or INSERTED state.
*
* INSERTED => do 1 CHECK_VERIFY to get into
* EJECTED state
*
* EJECTED => do upto MAX_TRIES CHECK_VERIFY's with
* delay to get into INSERTED state
*
\***************************************************************************/
VOID HandleMediaChangeEvent( UINT uidCdRom )
{
/*
* Local variables
*/
HANDLE hDevice;
ULONG id;
DWORD cb;
DWORD dwLogicalDrives;
DWORD dwDriveMask;
DWORD dwDriveCount;
DWORD dwRecipients;
BOOL bResult;
INT nCurrentTry;
NTSTATUS Status;
UNICODE_STRING ustrCdRom;
UNICODE_STRING ustrCdRomId;
UNICODE_STRING ustrAnyCdRom;
UNICODE_STRING ustrNtPath;
DEV_BROADCAST_VOLUME dbcvInfo;
LPWSTR lpszCdRom = TEXT("\\Device\\CdRom");
WCHAR szDrive[] = TEXT("A:\\");
WCHAR szDevice[] = TEXT("\\\\.\\A:");
WCHAR wcDrive;
WCHAR szCdRom[32];
WCHAR szBuff[256];
UserAssert(uidCdRom >= 0 && uidCdRom < NUM_MEDIA_EVENTS); // at most 24 cd-rom drives in system
/*
* Some initializations
*/
RtlInitUnicodeString( &ustrAnyCdRom, lpszCdRom );
wcDrive = UNICODE_NULL;
/*
* Form the \Device\CdRomX name based on uidCdRom
*/
wsprintfW( szCdRom, L"\\Device\\CdRom%d", uidCdRom );
RtlInitUnicodeString( &ustrCdRom, szCdRom );
/*
* The uidCdRom parameter tells us which CD-ROM device generated the
* MediaChange event. We need to map this device back to it's logical
* drive letter because WM_DEVICECHANGE is based on drive letters.
*
* To avoid always searching all logical drives, we cache the last
* associated drive letter. We still need to check this every time
* we get notified because WinDisk can remap drive letters.
*/
if (wcDriveCache[uidCdRom]) {
/*
* Convert our DOS path name to a NT path name
*/
ustrNtPath.MaximumLength = sizeof(szBuff);
ustrNtPath.Length = 0;
ustrNtPath.Buffer = szBuff;
bResult = GetDeviceObject(wcDriveCache[uidCdRom], &ustrNtPath);
if (bResult) {
/*
* Check to see if this drive letter is the one that maps
* to the CD-ROM drive that just notified us.
*/
if (RtlEqualUnicodeString(&ustrCdRom, &ustrNtPath, TRUE)) {
/*
* Yes, we found a match
*/
wcDrive = wcDriveCache[uidCdRom];
}
}
}
if (!wcDrive) {
/*
* Either the cache wasn't initialized, or we had a re-mapping
* of drive letters. Scan all drive letters looking for CD-ROM
* devices and update the cache as we go.
*/
RtlZeroMemory(wcDriveCache, sizeof(wcDriveCache));
szDrive[0] = L'A';
szDevice[4] = L'A';
dwDriveCount = 26; //Max number of drive letters
dwDriveMask = 1; //Max number of drive letters
dwLogicalDrives = GetLogicalDrives();
while (dwDriveCount) {
/*
* Is this logical drive a CD-ROM?
*/
//
// JOHNC - Remove after GetDriveType() is fixed
if ((dwLogicalDrives & dwDriveMask) &&
GetDriveType(szDrive) == DRIVE_CDROM) {
/*
* For this CD-ROM drive, find it's NT path.
*/
ustrNtPath.MaximumLength = sizeof(szBuff);
ustrNtPath.Length = 0;
ustrNtPath.Buffer = szBuff;
bResult = GetDeviceObject(szDrive[0], &ustrNtPath);
if (bResult) {
/*
* Make sure the string is in the form \Device\CdRom
*/
if (RtlPrefixUnicodeString(&ustrAnyCdRom, &ustrNtPath, TRUE)) {
/*
* Now find it's id. We have a string that looks like
* \Device\CdRom??? where ??? is the unit id
*/
RtlInitUnicodeString(&ustrCdRomId,
(PWSTR)((PSTR)(ustrNtPath.Buffer)+ustrAnyCdRom.Length));
RtlUnicodeStringToInteger(&ustrCdRomId, 10, &id);
UserAssert(id >= 0 && id < NUM_MEDIA_EVENTS);
wcDriveCache[id] = szDrive[0];
//Initially set State to Unknown
aDriveState[id] = DS_UNKNOWN;
/*
* If this is the device that notified us, remember its
* drive letter so we can broadcase WM_DEVICECHANGE
*/
if (uidCdRom == id) {
wcDrive = szDrive[0];
}
}
}
}
/*
* Try the next drive
*/
szDrive[0] = szDrive[0] + 1;
szDevice[4] = szDevice[4] + 1;
dwDriveMask <<= 1;
--dwDriveCount;
}
}
/*
* If we found a logical drive, determine the media state for the drive
* and broadcast the WM_DEVICECHANGE notification.
*/
if (wcDrive) {
/*
* Get the Media status of this drive. Assume media is not
* present in the case of an error.
*/
szDevice[4] = wcDrive;
hDevice = CreateFile(szDevice,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
#ifdef DEBUG
KdPrint((" CreateFile( '%ls' ) Failed. Error %lx\n",
szDevice,GetLastError()));
#endif
return;
}
/*
* Loop and check the CD-ROM to see if media is available. We need
* this loop because some CD-ROM drives notify us that media has
* arrived before the drive has recognized that it had new media.
*/
for (nCurrentTry = 0; nCurrentTry < MAX_TRIES; nCurrentTry++) {
/*
* See if media is present
*/
bResult = (DWORD)DeviceIoControl(hDevice,
IOCTL_DISK_CHECK_VERIFY,
NULL,
0,
NULL,
0,
&cb,
NULL);
if (bResult) {
/*
* Media is present, change the state to Inserted.
*/
aDriveState[uidCdRom] = DS_INSERTED;
break;
}
/*
* Media wasn't present, so we need to look at GetLastError() to see
* if DeviceIoControl() failed. If so we may want to try again.
*/
if (GetLastError() == ERROR_NOT_READY) {
Sleep(500); // 1/2 second
/*
* We only want to retry if we the prev State was UNKNOWN or
* EJECTED. If the previous State was INSERTED it means that
* this event is the removal event
*/
if(aDriveState[uidCdRom]== DS_UNKNOWN ||
aDriveState[uidCdRom] == DS_EJECTED) {
continue;
}
}
/*
* Call failed. Assume worst case and say the media has been removed.
*/
aDriveState[uidCdRom] = DS_EJECTED;
break;
}
/*
* Close the handle to the CD-ROM device
*/
CloseHandle(hDevice);
/*
* Initialize the structures used for BroadcastSystemMessage
*/
dbcvInfo.dbcv_size = sizeof(dbcvInfo);
dbcvInfo.dbcv_devicetype = DBT_DEVTYP_VOLUME;
dbcvInfo.dbcv_reserved = 0;
dbcvInfo.dbcv_flags = DBTF_MEDIA;
dbcvInfo.dbcv_unitmask = (1 << (wcDrive - L'A'));
dwRecipients = BSM_ALLCOMPONENTS | BSM_ALLDESKTOPS;
/*
* Temporarily we must assign this thread to a desktop so we can
* call USER's BroascastSystemMessage() routine. We call the
* private SetThreadDesktopToDefault() to assign ourselves to the
* desktop that is currently receiving input.
*/
Status = NtUserSetInformationThread(NtCurrentThread(),
UserThreadUseActiveDesktop,
NULL, 0);
if (NT_SUCCESS(Status)) {
/*
* Broadcast the message
*/
BroadcastSystemMessage(BSF_FORCEIFHUNG,
&dwRecipients,
WM_DEVICECHANGE,
// HACK: need to or 0x8000 in wParam
// because this is a flag to let
// BSM know that lParam is a pointer
// to a data structure.
0x8000 | ((bResult) ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE),
(LPARAM)&dbcvInfo);
#ifdef DEBUG
KdPrint((" Message Broadcast for '%lc:'\n", wcDrive));
#endif
/*
* Set our thread's desktop back to NULL. This will decrement
* the desktop's reference count.
*/
hDevice = NULL;
NtUserSetInformationThread(NtCurrentThread(),
UserThreadUseDesktop,
&hDevice, // hDevice = NULL
sizeof(HANDLE));
}
}
}
VOID NotificationThread(
PVOID pJunk)
{
INT nEvents = ID_MEDIACHANGE;
INT nMediaEvents = 0;
KPRIORITY Priority;
NTSTATUS Status;
HANDLE hEvent[ MAXIMUM_WAIT_OBJECTS ];
try {
/*
* Set the priority of the RIT to 3.
*/
Priority = LOW_PRIORITY + 3;
NtSetInformationThread(hThreadNotification, ThreadPriority, &Priority,
sizeof(KPRIORITY));
/*
* Setup the NLS event
*/
NtCreateEvent(&ghNlsEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
UserAssert( ghNlsEvent != NULL );
hEvent[ID_NLS] = ghNlsEvent;
/*
* Setup the MediaChangeEvent
*/
RtlZeroMemory(wcDriveCache, sizeof(wcDriveCache));
Status = NtUserGetMediaChangeEvents(MAXIMUM_WAIT_OBJECTS - ID_MEDIACHANGE,
&hEvent[ID_MEDIACHANGE],
&nMediaEvents);
if (NT_SUCCESS(Status)) {
nEvents += nMediaEvents;
}
#ifdef DEBUG
else {
KdPrint(("NotificationThread: NtUserGetMediaChangeEvents failed 0x08X\n", Status));
}
#endif
StartRegReadRead();
/*
* Sit and wait forever.
*/
while (TRUE) {
Status = NtWaitForMultipleObjects(nEvents,
hEvent,
WaitAny,
TRUE,
NULL);
if (Status == ID_NLS + WAIT_OBJECT_0) {
/*
* Handle the NLS event
*/
if (gfLogon) {
gfLogon = FALSE;
BaseSrvNlsUpdateRegistryCache(NULL, NULL);
}
}
else if (Status >= ID_MEDIACHANGE + WAIT_OBJECT_0 &&
Status < (ID_MEDIACHANGE + nMediaEvents + WAIT_OBJECT_0)) {
/*
* Handle the CD-ROM \Device\MediaChangeEventX event
*/
NtResetEvent( hEvent[Status - WAIT_OBJECT_0], NULL );
HandleMediaChangeEvent( Status - WAIT_OBJECT_0 - ID_MEDIACHANGE );
}
} // While (TRUE)
} except (CsrUnhandledExceptionFilter(GetExceptionInformation())) {
KdPrint(("Registry notification thread is dead, sorry.\n"));
}
}
#define NCHARS 256
#define NCTRLS 0x20
VOID
InitOemXlateTables()
{
char ach[NCHARS];
WCHAR awch[NCHARS];
WCHAR awchCtrl[NCTRLS];
INT i;
INT cch;
PCHAR pOemToAnsi;
PCHAR pAnsiToOem;
PCSR_FAST_ANSI_OEM_TABLES Tables;
Tables = NtCurrentPeb()->ReadOnlyStaticServerData[CSRSRV_SERVERDLL_INDEX];
pOemToAnsi = Tables->OemToAnsiTable;
pAnsiToOem = Tables->AnsiToOemTable;
for (i = 0; i < NCHARS; i++) {
ach[i] = i;
}
/*
* First generate pAnsiToOem table.
*/
if (GetOEMCP() == GetACP()) {
/*
* For far east code pages using MultiByteToWideChar below
* won't work. Conveniently for these code pages the OEM
* CP equals the ANSI codepage making it trivial to compute
* pOemToAnsi and pAnsiToOem arrays
*
*/
RtlCopyMemory(pOemToAnsi, ach, NCHARS);
RtlCopyMemory(pAnsiToOem, ach, NCHARS);
}
else
{
cch = MultiByteToWideChar(
CP_ACP, // ANSI -> Unicode
MB_PRECOMPOSED, // map to precomposed
ach, NCHARS, // source & length
awch, NCHARS); // destination & length
UserAssert(cch == NCHARS);
WideCharToMultiByte(
CP_OEMCP, // Unicode -> OEM
0, // gives best visual match
awch, NCHARS, // source & length
pAnsiToOem, NCHARS, // dest & max poss. length
"_", // default char
NULL); // (don't care whether defaulted)
/*
* Now generate pOemToAnsi table.
*/
cch = MultiByteToWideChar(
CP_OEMCP, // OEM -> Unicode
MB_PRECOMPOSED | MB_USEGLYPHCHARS,// visual map to precomposed
ach, NCHARS, // source & length
awch, NCHARS); // destination
UserAssert(cch == NCHARS);
/*
* Now patch special cases for Win3.1 compatibility
*
* 0x07 BULLET (glyph 0x2022) must become 0x0007 BELL
* 0x0F WHITE STAR WITH SUN (glyph 0x263C) must become 0x00A4 CURRENCY SIGN
* 0x7F HOUSE (glyph 0x2302) must become 0x007f DELETE
*/
awch[0x07] = 0x0007;
awch[0x0F] = 0x00a4;
awch[0x7f] = 0x007f;
WideCharToMultiByte(
CP_ACP, // Unicode -> ANSI
0, // gives best visual match
awch, NCHARS, // source & length
pOemToAnsi, NCHARS, // dest & max poss. length
"_", // default char
NULL); // (don't care whether defaulted)
/*
* Now for all OEM chars < 0x20 (control chars), test whether the glyph
* we have is really in CP_ACP or not. If not, then restore the
* original control character. Note: 0x00 remains 0x00.
*/
MultiByteToWideChar(CP_ACP, 0, pOemToAnsi, NCTRLS, awchCtrl, NCTRLS);
for (i = 1; i < NCTRLS; i++) {
if (awchCtrl[i] != awch[i]) {
pOemToAnsi[i] = i;
}
}
}
}
UINT GetRegIntFromID(
HKEY hKey,
int KeyID,
UINT nDefault)
{
LPWSTR lpszValue;
BOOL fAllocated;
UNICODE_STRING Value;
DWORD cbSize;
BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 20 * sizeof(WCHAR)];
NTSTATUS Status;
UINT ReturnValue;
lpszValue = (LPWSTR)RtlLoadStringOrError(hModuleWin,
KeyID, NULL, &fAllocated, FALSE);
RtlInitUnicodeString(&Value, lpszValue);
Status = NtQueryValueKey(hKey,
&Value,
KeyValuePartialInformation,
(PKEY_VALUE_PARTIAL_INFORMATION)Buf,
sizeof(Buf),
&cbSize);
if (NT_SUCCESS(Status)) {
/*
* Convert string to int.
*/
RtlInitUnicodeString(&Value, (LPWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
RtlUnicodeStringToInteger(&Value, 10, &ReturnValue);
} else {
ReturnValue = nDefault;
}
LocalFree(lpszValue);
return(ReturnValue);
}
VOID GetTimeouts(VOID)
{
HANDLE hKey;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES OA;
NTSTATUS Status;
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\User\\.Default\\Control Panel\\Desktop");
InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey(&hKey, KEY_READ, &OA);
if (NT_SUCCESS(Status)) {
gCmsHungAppTimeout = GetRegIntFromID(
hKey,
STR_CMSHUNGAPPTIMEOUT,
CMSHUNGAPPTIMEOUT);
gCmsWaitToKillTimeout = GetRegIntFromID(
hKey,
STR_CMSWAITTOKILLTIMEOUT,
CMSWAITTOKILLTIMEOUT);
gfAutoEndTask = GetRegIntFromID(
hKey,
STR_AUTOENDTASK,
FALSE);
NtClose(hKey);
}
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey(&hKey, KEY_READ, &OA);
if (NT_SUCCESS(Status)) {
gdwServicesWaitToKillTimeout = GetRegIntFromID(
hKey,
STR_WAITTOKILLSERVICETIMEOUT,
gCmsWaitToKillTimeout);
NtClose(hKey);
}
}
ULONG
SrvLogon(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus)
{
PLOGONMSG a = (PLOGONMSG)&m->u.ApiMessageData;
NTSTATUS Status;
if (a->fLogon) {
if (!CsrImpersonateClient(NULL))
return (ULONG)STATUS_UNSUCCESSFUL;
/*
* Take care of NLS cache for LogON.
*/
BaseSrvNlsLogon(TRUE);
/*
* Set the cleanup event so that the RIT can handle the NLS
* registry notification.
*/
gfLogon = TRUE;
Status = NtSetEvent( ghNlsEvent, NULL );
ASSERT(NT_SUCCESS(Status));
/*
* Initialize console attributes
*/
InitializeConsoleAttributes();
CsrRevertToSelf();
} else {
/*
* Take care of NLS cache for LogOFF.
*/
BaseSrvNlsLogon(FALSE);
}
return (ULONG)STATUS_SUCCESS;
}
ULONG
SrvServiceMessageBox(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus)
{
PSERVICEMESSAGEBOXMSG a = (PSERVICEMESSAGEBOXMSG)&m->u.ApiMessageData;
a->hemsg.h.ClientId = m->h.ClientId;
UserHardError(NULL, &a->hemsg);
if (a->hemsg.Response == ResponseNotHandled)
a->dwLastError = GetLastError();
else
a->dwLastError = 0;
return STATUS_SUCCESS;
}
ULONG
SrvGetThreadConsoleDesktop(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus)
{
PGETTHREADCONSOLEDESKTOPMSG a = (PGETTHREADCONSOLEDESKTOPMSG)&m->u.ApiMessageData;
return GetThreadConsoleDesktop(a->dwThreadId, &a->hdeskConsole);
}