test: server.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# server.c

Go to the documentation of this file.

    00001 /**************************************************************************\
    00002 * Module Name: server.c
    00003 *
    00004 * Server support routines for the CSR stuff.
    00005 *
    00006 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00007 *
    00008 * Created: 10-Dec-90
    00009 *
    00010 * History:
    00011 *   10-Dec-90 created by sMeans
    00012 *
    00013 \**************************************************************************/
    00014
    00015
    00016 #include "precomp.h"
    00017 #pragma hdrstop
    00018
    00019 #include "dbt.h"
    00020 #include "ntdddisk.h"
    00021 #include "ntuser.h"
    00022 #include <regstr.h>
    00023
    00024
    00025 HANDLE hThreadNotification;
    00026 HANDLE hKeyPriority;
    00027 UNICODE_STRING PriorityValueName;
    00028 IO_STATUS_BLOCK IoStatusRegChange;
    00029 ULONG RegChangeBuffer;
    00030 HANDLE ghNlsEvent;
    00031 BOOL gfLogon;
    00032 FARPROC gpfnAttachRoutine;
    00033 HANDLE ghPowerRequestEvent;
    00034 HANDLE ghMediaRequestEvent;
    00035
    00036 #define ID_NLS              0
    00037 #define ID_POWER            1
    00038 #define ID_MEDIACHANGE      2
    00039 #define ID_NETDEVCHANGE     3
    00040
    00041 #define ID_NUM_EVENTS       4
    00042
    00043 //
    00044 // Name of event to pulse to request a device-arrival broadcast,
    00045 //
    00046 #define SC_BSM_EVENT_NAME   L"ScNetDrvMsg"
    00047
    00048 //
    00049 // What the net drive bitmask was when we last broadcast (initially 0)
    00050 //
    00051 DWORD LastNetDrives;
    00052
    00053
    00054 HANDLE CsrApiPort;
    00055 HANDLE CsrQueryApiPort(VOID);
    00056
    00057 ULONG
    00058 SrvExitWindowsEx(
    00059     IN OUT PCSR_API_MSG m,
    00060     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00061
    00062 ULONG
    00063 SrvEndTask(
    00064     IN OUT PCSR_API_MSG m,
    00065     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00066
    00067 ULONG
    00068 SrvLogon(
    00069     IN OUT PCSR_API_MSG m,
    00070     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00071
    00072 ULONG
    00073 SrvRegisterServicesProcess(
    00074     IN OUT PCSR_API_MSG m,
    00075     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00076
    00077 ULONG
    00078 SrvActivateDebugger(
    00079     IN OUT PCSR_API_MSG m,
    00080     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00081
    00082 ULONG
    00083 SrvGetThreadConsoleDesktop(
    00084     IN OUT PCSR_API_MSG m,
    00085     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00086
    00087 ULONG
    00088 SrvDeviceEvent(
    00089     IN OUT PCSR_API_MSG m,
    00090     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00091
    00092 ULONG
    00093 SrvRegisterLogonProcess(
    00094     IN OUT PCSR_API_MSG m,
    00095     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00096
    00097 ULONG
    00098 SrvWin32HeapFail(
    00099     IN OUT PCSR_API_MSG m,
    00100     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00101
    00102 ULONG
    00103 SrvWin32HeapStat(
    00104     IN OUT PCSR_API_MSG m,
    00105     IN OUT PCSR_REPLY_STATUS ReplyStatus);
    00106
    00107 PCSR_API_ROUTINE UserServerApiDispatchTable[ UserpMaxApiNumber - UserpExitWindowsEx ] = {
    00108     (PCSR_API_ROUTINE)SrvExitWindowsEx,
    00109     (PCSR_API_ROUTINE)SrvEndTask,
    00110     (PCSR_API_ROUTINE)SrvLogon,
    00111     (PCSR_API_ROUTINE)SrvRegisterServicesProcess,
    00112     (PCSR_API_ROUTINE)SrvActivateDebugger,
    00113     (PCSR_API_ROUTINE)SrvGetThreadConsoleDesktop,
    00114     (PCSR_API_ROUTINE)SrvDeviceEvent,
    00115     (PCSR_API_ROUTINE)SrvRegisterLogonProcess,
    00116     (PCSR_API_ROUTINE)SrvWin32HeapFail,
    00117     (PCSR_API_ROUTINE)SrvWin32HeapStat,
    00118 };
    00119
    00120 BOOLEAN UserServerApiServerValidTable[ UserpMaxApiNumber - UserpExitWindowsEx ] = {
    00121     FALSE,      // ExitWindowsEx
    00122     FALSE,      // EndTask
    00123     FALSE,      // Logon
    00124     FALSE,      // RegisterServicesProcess
    00125     FALSE,      // ActivateDebugger
    00126     TRUE,       // GetThreadConsoleDesktop
    00127     FALSE,      // DeviceEvent
    00128     FALSE,      // RegisterLogonProcess
    00129     FALSE,      // Win32HeapFail
    00130     FALSE,      // Win32HeapStat
    00131 };
    00132
    00133 #if DBG
    00134 PSZ UserServerApiNameTable[ UserpMaxApiNumber - UserpExitWindowsEx ] = {
    00135     "SrvExitWindowsEx",
    00136     "SrvEndTask",
    00137     "SrvLogon",
    00138     "SrvRegisterServicesProcess",
    00139     "SrvActivateDebugger",
    00140     "SrvGetThreadConsoleDesktop",
    00141     "SrvDeviceEvent",
    00142     "SrvRegisterLogonProcess",
    00143     "SrvWin32HeapFail",
    00144     "SrvWin32HeapStat"
    00145 };
    00146 #endif // DBG
    00147
    00148 NTSTATUS
    00149 UserServerDllInitialization(
    00150     PCSR_SERVER_DLL psrvdll
    00151     );
    00152
    00153 NTSTATUS UserClientConnect(PCSR_PROCESS Process, PVOID ConnectionInformation,
    00154         PULONG pulConnectionLen);
    00155 VOID     UserHardError(PCSR_THREAD pcsrt, PHARDERROR_MSG pmsg);
    00156 NTSTATUS UserClientShutdown(PCSR_PROCESS Process, ULONG dwFlags, BOOLEAN fFirstPass);
    00157
    00158 VOID GetTimeouts(VOID);
    00159 VOID StartRegReadRead(VOID);
    00160 VOID RegReadApcProcedure(PVOID RegReadApcContext, PIO_STATUS_BLOCK IoStatus);
    00161 VOID NotificationThread(PVOID);
    00162 typedef BOOL (*PFNPROCESSCREATE)(DWORD, DWORD, ULONG_PTR, DWORD);
    00163
    00164 VOID InitializeConsoleAttributes(VOID);
    00165 NTSTATUS GetThreadConsoleDesktop(DWORD dwThreadId, HDESK *phdesk);
    00166 NTSTATUS MyRegOpenKey(IN HANDLE hKey, IN LPWSTR lpSubKey, OUT PHANDLE phResult);
    00167
    00168 BOOL BaseSetProcessCreateNotify(PFNPROCESSCREATE pfn);
    00169 VOID BaseSrvNlsUpdateRegistryCache(PVOID ApcContext,
    00170                                              PIO_STATUS_BLOCK pIoStatusBlock);
    00171 NTSTATUS BaseSrvNlsLogon(BOOL);
    00172 NTSTATUS WinStationAPIInit(VOID);
    00173
    00174 /***************************************************************************\
    00175 * UserServerDllInitialization
    00176 *
    00177 * Called by the CSR stuff to allow a server DLL to initialize itself and
    00178 * provide information about the APIs it provides.
    00179 *
    00180 * Several operations are performed during this initialization:
    00181 *
    00182 * - The shared heap (client read-only) handle is initialized.
    00183 * - The Raw Input Thread (RIT) is launched.
    00184 * - GDI is initialized.
    00185 *
    00186 * History:
    00187 * 10-19-92 DarrinM      Integrated xxxUserServerDllInitialize into this rtn.
    00188 * 11-08-91 patrickh     move GDI init here from DLL init routine.
    00189 * 12-10-90 sMeans       Created.
    00190 \***************************************************************************/
    00191
    00192 NTSTATUS UserServerDllInitialization(
    00193     PCSR_SERVER_DLL psrvdll)
    00194 {
    00195     CLIENT_ID ClientId;
    00196     BOOL bAllocated;
    00197     NTSTATUS Status;
    00198
    00199     /*
    00200      * Initialize the RIP flags to default
    00201      */
    00202     gdwRIPFlags = RIPF_DEFAULT;
    00203
    00204 #if DBG
    00205     if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) {
    00206         RIPMSG0(RIP_WARNING,
    00207                 "UserServerDllInitialization: entered");
    00208     }
    00209 #endif
    00210
    00211     /*
    00212      * Initialize a critical section structure that will be used to protect
    00213      * all of the User Server's critical sections (except a few special
    00214      * cases like the RIT -- see below).
    00215      */
    00216
    00217     Status = RtlInitializeCriticalSection(&gcsUserSrv);
    00218     if (!NT_SUCCESS(Status))
    00219     {
    00220         RIPMSG1(RIP_WARNING,
    00221                 "UserServerDllInitialization: InitializeCriticalSection failed with Status %x",
    00222                 Status);
    00223         return Status;
    00224     }
    00225     EnterCrit();
    00226
    00227     /*
    00228      * Remember WINSRV.DLL's hmodule so we can grab resources from it later.
    00229      */
    00230     ghModuleWin = psrvdll->ModuleHandle;
    00231
    00232     psrvdll->ApiNumberBase = USERSRV_FIRST_API_NUMBER;
    00233     psrvdll->MaxApiNumber = UserpMaxApiNumber;
    00234     psrvdll->ApiDispatchTable = UserServerApiDispatchTable;
    00235
    00236     if (ISTS()) {
    00237         UserServerApiServerValidTable[0] = TRUE; // for ExitWindowsEx
    00238     }
    00239
    00240     psrvdll->ApiServerValidTable = UserServerApiServerValidTable;
    00241 #if DBG
    00242     psrvdll->ApiNameTable = UserServerApiNameTable;
    00243 #else
    00244     psrvdll->ApiNameTable = NULL;
    00245 #endif
    00246     psrvdll->ConnectRoutine         = UserClientConnect;
    00247     psrvdll->HardErrorRoutine       = UserHardError;
    00248     psrvdll->ShutdownProcessRoutine = UserClientShutdown;
    00249
    00250     /*
    00251      * Create these events used by shutdown
    00252      */
    00253     //BUGBUG we should test the return code of NtCreateEvent
    00254     NtCreateEvent(&gheventCancel, EVENT_ALL_ACCESS, NULL,
    00255                   NotificationEvent, FALSE);
    00256     NtCreateEvent(&gheventCancelled, EVENT_ALL_ACCESS, NULL,
    00257                   NotificationEvent, FALSE);
    00258
    00259     /*
    00260      * Create the event used by the power request code.
    00261      */
    00262     NtCreateEvent(&ghPowerRequestEvent, EVENT_ALL_ACCESS, NULL,
    00263                   SynchronizationEvent, FALSE);
    00264
    00265     /*
    00266      * Create the event used by the media change code.
    00267      */
    00268     NtCreateEvent(&ghMediaRequestEvent, EVENT_ALL_ACCESS, NULL,
    00269                   SynchronizationEvent, FALSE);
    00270
    00271     /*
    00272      * Tell the base what user address to call when it is creating a process
    00273      * (but before the process starts running).
    00274      */
    00275     BaseSetProcessCreateNotify(NtUserNotifyProcessCreate);
    00276
    00277     /*
    00278      * Load some strings.
    00279      */
    00280     gpwszaSUCCESS            = (PWSTR)RtlLoadStringOrError(ghModuleWin,
    00281                                 STR_SUCCESS, NULL, &bAllocated, FALSE);
    00282     gpwszaSYSTEM_INFORMATION = (PWSTR)RtlLoadStringOrError(ghModuleWin,
    00283                                 STR_SYSTEM_INFORMATION, NULL, &bAllocated, FALSE);
    00284     gpwszaSYSTEM_WARNING     = (PWSTR)RtlLoadStringOrError(ghModuleWin,
    00285                                 STR_SYSTEM_WARNING, NULL, &bAllocated, FALSE);
    00286     gpwszaSYSTEM_ERROR       = (PWSTR)RtlLoadStringOrError(ghModuleWin,
    00287                                 STR_SYSTEM_ERROR, NULL, &bAllocated, FALSE);
    00288     /*
    00289      * Initialize USER
    00290      */
    00291
    00292     {
    00293         HANDLE hModBase;
    00294
    00295         hModBase = GetModuleHandle(TEXT("kernel32"));
    00296         UserAssert(hModBase);
    00297         gpfnAttachRoutine = GetProcAddress(hModBase,"BaseAttachCompleteThunk");
    00298         UserAssert(gpfnAttachRoutine);
    00299
    00300         Status = NtUserInitialize(USERCURRENTVERSION, ghPowerRequestEvent, ghMediaRequestEvent);
    00301         if (!NT_SUCCESS(Status)) {
    00302             RIPMSG1(RIP_WARNING,
    00303                     "UserServerDllInitialization: NtUserInitialize failed with Status %x",
    00304                     Status);
    00305             goto ExitUserInit;
    00306         }
    00307     }
    00308
    00309     if (ISTS()) {
    00310
    00311         Status = WinStationAPIInit();
    00312         if (!NT_SUCCESS(Status)) {
    00313             RIPMSG1(RIP_WARNING,
    00314                     "UserServerDllInitialization: WinStationAPIInit failed with Status %x",
    00315                     Status);
    00316             goto ExitUserInit;
    00317         }
    00318     }
    00319
    00320     /*
    00321      * Start registry notification thread
    00322      */
    00323     Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 4*0x1000,
    00324             (PUSER_THREAD_START_ROUTINE)NotificationThread, NULL, &hThreadNotification,
    00325             &ClientId);
    00326     if (!NT_SUCCESS(Status)) {
    00327         RIPMSG1(RIP_WARNING,
    00328                 "UserServerDllInitialization: RtlCreateUserThread failed with Status %x",
    00329                 Status);
    00330     }
    00331     CsrAddStaticServerThread(hThreadNotification, &ClientId, 0);
    00332
    00333 ExitUserInit:
    00334     LeaveCrit();
    00335     return Status;
    00336 }
    00337
    00338 /**************************************************************************\
    00339 * UserClientConnect
    00340 *
    00341 * This function is called once for each client process that connects to the
    00342 * User server.  When the client dynlinks to USER.DLL, USER.DLL's init code
    00343 * is executed and calls CsrClientConnectToServer to establish the connection.
    00344 * The server portion of ConnectToServer calls out this entrypoint.
    00345 *
    00346 * UserClientConnect first verifies version numbers to make sure the client
    00347 * is compatible with this server and then completes all process-specific
    00348 * initialization.
    00349 *
    00350 * History:
    00351 * 02-??-91 SMeans       Created.
    00352 * 04-02-91 DarrinM      Added User intialization code.
    00353 \**************************************************************************/
    00354
    00355 extern WORD gDispatchTableValues;
    00356
    00357 NTSTATUS UserClientConnect(
    00358     PCSR_PROCESS Process,
    00359     PVOID ConnectionInformation,
    00360     PULONG pulConnectionLen)
    00361 {
    00362     /*
    00363      * Pass the api port to the kernel.  Do this early so the kernel
    00364      * can send a datagram to CSR to activate a debugger.
    00365      */
    00366     if (CsrApiPort == NULL) {
    00367         CsrApiPort = CsrQueryApiPort();
    00368         NtUserSetInformationThread(
    00369                 NtCurrentThread(),
    00370                 UserThreadCsrApiPort,
    00371                 &CsrApiPort,
    00372                 sizeof(HANDLE));
    00373     }
    00374
    00375     UserAssert(*pulConnectionLen == sizeof(USERCONNECT));
    00376     if (*pulConnectionLen != sizeof(USERCONNECT)) {
    00377         return STATUS_INVALID_PARAMETER;
    00378     }
    00379
    00380     ((PUSERCONNECT)ConnectionInformation)->dwDispatchCount = gDispatchTableValues;
    00381     return NtUserProcessConnect(Process->ProcessHandle,
    00382             (PUSERCONNECT)ConnectionInformation, *pulConnectionLen);
    00383 }
    00384
    00385
    00386 VOID
    00387 RegReadApcProcedure(
    00388     PVOID RegReadApcContext,
    00389     PIO_STATUS_BLOCK IoStatus
    00390     )
    00391 {
    00392     UNICODE_STRING ValueString;
    00393     LONG Status;
    00394     BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
    00395     DWORD cbSize;
    00396     ULONG l;
    00397
    00398     UNREFERENCED_PARAMETER(RegReadApcContext);
    00399     UNREFERENCED_PARAMETER(IoStatus);
    00400
    00401     RtlInitUnicodeString(&ValueString, L"Win32PrioritySeparation");
    00402     Status = NtQueryValueKey(hKeyPriority,
    00403             &ValueString,
    00404             KeyValuePartialInformation,
    00405             (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
    00406             sizeof(Buf),
    00407             &cbSize);
    00408     if (NT_SUCCESS(Status)) {
    00409         l = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
    00410     } else {
    00411         l = PROCESS_PRIORITY_SEPARATION_MAX;  // last resort default
    00412     }
    00413
    00414     NtSetSystemInformation(SystemPrioritySeperation,&l,sizeof(ULONG));
    00415
    00416     NtNotifyChangeKey(
    00417         hKeyPriority,
    00418         NULL,
    00419         (PIO_APC_ROUTINE)RegReadApcProcedure,
    00420         NULL,
    00421         &IoStatusRegChange,
    00422         REG_NOTIFY_CHANGE_LAST_SET,
    00423         FALSE,
    00424         &RegChangeBuffer,
    00425         sizeof(RegChangeBuffer),
    00426         TRUE
    00427         );
    00428 }
    00429
    00430 VOID
    00431 StartRegReadRead(VOID)
    00432 {
    00433     UNICODE_STRING UnicodeString;
    00434     OBJECT_ATTRIBUTES OA;
    00435
    00436     RtlInitUnicodeString(&UnicodeString,
    00437             L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\PriorityControl");
    00438     InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
    00439
    00440     if (!NT_SUCCESS(NtOpenKey(&hKeyPriority, KEY_READ | KEY_NOTIFY, &OA)))
    00441         UserAssert(FALSE);
    00442
    00443     RegReadApcProcedure(NULL, NULL);
    00444 }
    00445
    00446
    00447 /***************************************************************************\
    00448 * HandleMediaChangeEvent
    00449 *
    00450 * This routine is responsible for broadcasting the WM_DEVICECHANGE message
    00451 * when media arrives or is removed from a CD-ROM device.
    00452 *
    00453 * History:
    00454 * 23-Feb-96     BradG       Modified to handle event per CD-ROM device
    00455 * 23-April-96   Salimc      Some CD-ROM drives notify us that media has
    00456 *                           arrived before the drive has recognized that it had
    00457 *                           new media. The call to DeviceIoctl() will fail in
    00458 *                           this case. To fix this we made the following changes
    00459 *
    00460 *                           aDriveState is an array of tri-state global variable
    00461 *                           for each drive.Each variable starts off in an UNKNOWN
    00462 *                           state and on the first event with any drive we do the
    00463 *                           full MAX_TRIES or less CHECK_VERIFY's which then gets
    00464 *                           us into either a INSERTED or EJECTED state. From then
    00465 *                           on we know that each new event is going to be the
    00466 *                           opposite of what we currently have.
    00467 *
    00468 *                           UNKNOWN => do upto MAX_TRIES CHECK_VERIFY's with
    00469 *                           delay to get into EJECTED or INSERTED state.
    00470 *
    00471 *                           INSERTED => do 1 CHECK_VERIFY to get into
    00472 *                           EJECTED state
    00473 *
    00474 *                           EJECTED => do upto MAX_TRIES CHECK_VERIFY's with
    00475 *                           delay to get into INSERTED state
    00476 *
    00477 \***************************************************************************/
    00478
    00479 VOID HandleMediaChangeEvent(VOID)
    00480 {
    00481     /*
    00482      * Local variables
    00483      */
    00484
    00485     DWORD                   dwRecipients;
    00486     BOOL                    bResult;
    00487     NTSTATUS                Status;
    00488     DEV_BROADCAST_VOLUME    dbcvInfo;
    00489     USERTHREAD_USEDESKTOPINFO utudi;
    00490
    00491     ULONG cDrive;
    00492
    00493     while (cDrive = (ULONG)NtUserCallNoParam(SFI_GETDEVICECHANGEINFO)) {
    00494
    00495         /*
    00496          * Determine if it's an arrival or removal
    00497          */
    00498         bResult = (cDrive & 0x80000000);
    00499
    00500         /*
    00501          * Initialize the structures used for BroadcastSystemMessage
    00502          */
    00503         dbcvInfo.dbcv_size = sizeof(dbcvInfo);
    00504         dbcvInfo.dbcv_devicetype = DBT_DEVTYP_VOLUME;
    00505         dbcvInfo.dbcv_reserved = 0;
    00506         dbcvInfo.dbcv_flags = DBTF_MEDIA;
    00507         dbcvInfo.dbcv_unitmask = cDrive;
    00508
    00509         dwRecipients = BSM_ALLCOMPONENTS | BSM_ALLDESKTOPS;
    00510
    00511         /*
    00512          * Temporarily we must assign this thread to a desktop so we can
    00513          * call USER's BroascastSystemMessage() routine.  We call the
    00514          * private SetThreadDesktopToDefault() to assign ourselves to the
    00515          * desktop that is currently receiving input.
    00516          */
    00517         utudi.hThread = NULL;
    00518         utudi.drdRestore.pdeskRestore = NULL;
    00519         Status = NtUserSetInformationThread(NtCurrentThread(),
    00520                                             UserThreadUseActiveDesktop,
    00521                                             &utudi, sizeof(utudi));
    00522         if (NT_SUCCESS(Status)) {
    00523             /*
    00524              * Broadcast the message
    00525              */
    00526             BroadcastSystemMessage(BSF_FORCEIFHUNG | ((bResult) ? BSF_ALLOWSFW : 0),
    00527                                    &dwRecipients,
    00528                                    WM_DEVICECHANGE,
    00529 // HACK: need to or 0x8000 in wParam
    00530 //       because this is a flag to let
    00531 //       BSM know that lParam is a pointer
    00532 //       to a data structure.
    00533                                    0x8000 | ((bResult) ? DBT_DEVICEARRIVAL : DBT_DEVICEREMOVECOMPLETE),
    00534                                    (LPARAM)&dbcvInfo);
    00535
    00536             /*
    00537              * Set our thread's desktop back to NULL.  This will decrement
    00538              * the desktop's reference count.
    00539              */
    00540             NtUserSetInformationThread(NtCurrentThread(),
    00541                                        UserThreadUseDesktop,
    00542                                        &utudi,
    00543                                        sizeof(utudi));
    00544         }
    00545     }
    00546 }
    00547
    00548 DWORD
    00549 GetNetworkDrives(
    00550     )
    00551 /*++
    00552
    00553 Routine Description:
    00554
    00555     Returns a drive bitmask similar to GetLogicalDrives, but including
    00556     only the network drives.
    00557
    00558 Arguments:
    00559
    00560 Return Value:
    00561
    00562
    00563 --*/
    00564 {
    00565     DWORD Mask = 0;
    00566     DWORD DriveNumber;
    00567     PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
    00568
    00569     if (NT_SUCCESS(NtQueryInformationProcess( NtCurrentProcess(),
    00570                                         ProcessDeviceMap,
    00571                                         &ProcessDeviceMapInfo.Query,
    00572                                         sizeof( ProcessDeviceMapInfo.Query ),
    00573                                         NULL
    00574                                       ))) {
    00575         // For all the drives from C to Z
    00576         for (DriveNumber = 2; DriveNumber < 26; DriveNumber++)
    00577         {
    00578             if (ProcessDeviceMapInfo.Query.DriveType[DriveNumber] == DOSDEVICE_DRIVE_REMOTE)
    00579             {
    00580                 Mask |= (1 << DriveNumber);
    00581             }
    00582         }
    00583     }
    00584
    00585     return Mask;
    00586 }
    00587
    00588 VOID
    00589 HandleRemoteNetDeviceChangeEvent(
    00590     )
    00591 /*++
    00592
    00593 Routine Description:
    00594
    00595
    00596 Arguments:
    00597
    00598 Return Value:
    00599
    00600 --*/
    00601 {
    00602     DWORD    NetDrives;
    00603     DEV_BROADCAST_VOLUME dbv;
    00604     LONG status;
    00605     USERTHREAD_USEDESKTOPINFO utudi;
    00606
    00607
    00608
    00609     /*
    00610      * Temporarily we must assign this thread to a desktop so we can
    00611      * call USER's BroascastSystemMessage() routine.  We call the
    00612      * private SetThreadDesktopToDefault() to assign ourselves to the
    00613      * desktop that is currently receiving input.
    00614      */
    00615     utudi.hThread = NULL;
    00616     utudi.drdRestore.pdeskRestore = NULL;
    00617     status = NtUserSetInformationThread(NtCurrentThread(),
    00618                                         UserThreadUseActiveDesktop,
    00619                                         &utudi, sizeof(utudi));
    00620     if (!NT_SUCCESS(status)) {
    00621         return;
    00622     }
    00623
    00624     //
    00625     // Keep broadcasting until the set of net drives stops changing
    00626     //
    00627     for (;;)
    00628     {
    00629
    00630         //
    00631         // Get the current net drive bitmask and compare against the net
    00632         // drive bitmask when we last broadcast
    00633         //
    00634         NetDrives = GetNetworkDrives();
    00635
    00636         if (NetDrives == LastNetDrives)
    00637         {
    00638             break;
    00639         }
    00640
    00641         //
    00642         // Broadcast about deleted volumes
    00643         //
    00644         dbv.dbcv_size       = sizeof(dbv);
    00645         dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
    00646         dbv.dbcv_reserved   = 0;
    00647         dbv.dbcv_unitmask   = LastNetDrives & ~NetDrives;
    00648         dbv.dbcv_flags      = DBTF_NET;
    00649         if (dbv.dbcv_unitmask != 0)
    00650         {
    00651             DWORD dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
    00652             status = BroadcastSystemMessage(
    00653                         BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG,
    00654                         &dwRec,
    00655                         WM_DEVICECHANGE,
    00656                         (WPARAM) DBT_DEVICEREMOVECOMPLETE,
    00657                         (LPARAM)(DEV_BROADCAST_HDR*)(&dbv)
    00658                         );
    00659
    00660         }
    00661
    00662         //
    00663         // Broadcast about added volumes
    00664         //
    00665         dbv.dbcv_unitmask   = NetDrives & ~LastNetDrives;
    00666         if (dbv.dbcv_unitmask != 0)
    00667         {
    00668             DWORD dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
    00669
    00670             status = BroadcastSystemMessage(
    00671                         BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG,
    00672                         &dwRec,
    00673                         WM_DEVICECHANGE,
    00674                         (WPARAM) DBT_DEVICEARRIVAL,
    00675                         (LPARAM)(DEV_BROADCAST_HDR*)(&dbv)
    00676                         );
    00677
    00678
    00679         }
    00680
    00681         //
    00682         // Remember the drive set that we last broadcast about
    00683         //
    00684         LastNetDrives = NetDrives;
    00685
    00686         //
    00687         // Go around the loop again to detect changes that may have occurred
    00688         // while we were broadcasting
    00689         //
    00690     }
    00691
    00692     /*
    00693      * Set our thread's desktop back to NULL.  This will decrement
    00694      * the desktop's reference count.
    00695      */
    00696     NtUserSetInformationThread(NtCurrentThread(),
    00697                                UserThreadUseDesktop,
    00698                                &utudi,
    00699                                sizeof(utudi));
    00700
    00701     return;
    00702 }
    00703
    00704 BOOL
    00705 CreateBSMEventSD(
    00706     PSECURITY_DESCRIPTOR * SecurityDescriptor
    00707     )
    00708 /*++
    00709
    00710 Routine Description:
    00711
    00712     This function creates a security descriptor for the BSM request event.
    00713     It grants EVENT_ALL_ACCESS to local system and EVENT_MODIFY_STATE access
    00714     to the rest of the world.  This prevents principals other than local
    00715     system from waiting for the event.
    00716
    00717 Arguments:
    00718
    00719     SecurityDescriptor - Receives a pointer to the new security descriptor.
    00720         Should be freed with LocalFree.
    00721
    00722 Return Value:
    00723
    00724     TRUE - success
    00725
    00726     FALSE - failure, use GetLastError
    00727
    00728
    00729 --*/
    00730 {
    00731     NTSTATUS    Status;
    00732     ULONG       AclLength;
    00733     PACL        EventDacl;
    00734     PSID        WorldSid = NULL;
    00735     PSID        SystemSid = NULL;
    00736     SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY;
    00737     SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
    00738     BOOL        retval = TRUE;
    00739
    00740     *SecurityDescriptor = NULL;
    00741
    00742     Status = RtlAllocateAndInitializeSid( &NtSidAuthority,
    00743                                           1,
    00744                                           SECURITY_LOCAL_SYSTEM_RID,
    00745                                           0, 0, 0, 0, 0, 0, 0,
    00746                                           &SystemSid );
    00747
    00748     if (!NT_SUCCESS(Status)) {
    00749         retval = FALSE;
    00750         goto Cleanup;
    00751     }
    00752
    00753     Status = RtlAllocateAndInitializeSid( &WorldSidAuthority,
    00754                                           1,
    00755                                           SECURITY_WORLD_RID,
    00756                                           0, 0, 0, 0, 0, 0, 0,
    00757                                           &WorldSid );
    00758
    00759     if (!NT_SUCCESS(Status)) {
    00760         retval = FALSE;
    00761         goto Cleanup;
    00762     }
    00763
    00764
    00765     //
    00766     // Allocate a buffer to contain the SD followed by the DACL
    00767     // Note, the well-known SIDs are expected to have been created
    00768     // by this time
    00769     //
    00770
    00771     AclLength = (ULONG)sizeof(ACL) +
    00772                    (2*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) +
    00773                    RtlLengthSid( SystemSid ) +
    00774                    RtlLengthSid( WorldSid ) +
    00775                    8;       // 8 is for good measure
    00776
    00777     *SecurityDescriptor = (PSECURITY_DESCRIPTOR)
    00778         LocalAlloc( 0, SECURITY_DESCRIPTOR_MIN_LENGTH + AclLength );
    00779
    00780     if (*SecurityDescriptor == NULL) {
    00781         retval = FALSE;
    00782         goto Cleanup;
    00783     }
    00784
    00785     EventDacl = (PACL) ((BYTE*)(*SecurityDescriptor) + SECURITY_DESCRIPTOR_MIN_LENGTH);
    00786
    00787
    00788     //
    00789     // Set up a default ACL
    00790     //
    00791     //    Public: WORLD:EVENT_MODIFY_STATE, SYSTEM:all
    00792
    00793     Status = RtlCreateAcl( EventDacl, AclLength, ACL_REVISION2);
    00794     if (!NT_SUCCESS(Status)) {
    00795         retval = FALSE;
    00796         goto Cleanup;
    00797     }
    00798
    00799
    00800     //
    00801     // WORLD access
    00802     //
    00803
    00804     Status = RtlAddAccessAllowedAce (
    00805                  EventDacl,
    00806                  ACL_REVISION2,
    00807                  EVENT_MODIFY_STATE,
    00808                  WorldSid
    00809                  );
    00810     if (!NT_SUCCESS(Status)) {
    00811         retval = FALSE;
    00812         goto Cleanup;
    00813     }
    00814
    00815
    00816     //
    00817     // SYSTEM access
    00818     //
    00819
    00820     Status = RtlAddAccessAllowedAce (
    00821                  EventDacl,
    00822                  ACL_REVISION2,
    00823                  EVENT_ALL_ACCESS,
    00824                  SystemSid
    00825                  );
    00826     if (!NT_SUCCESS(Status)) {
    00827         retval = FALSE;
    00828         goto Cleanup;
    00829     }
    00830
    00831
    00832
    00833     //
    00834     // Now initialize security descriptors
    00835     // that export this protection
    00836     //
    00837
    00838     Status = RtlCreateSecurityDescriptor(
    00839                  *SecurityDescriptor,
    00840                  SECURITY_DESCRIPTOR_REVISION1
    00841                  );
    00842     if (!NT_SUCCESS(Status)) {
    00843         retval = FALSE;
    00844         goto Cleanup;
    00845     }
    00846
    00847     Status = RtlSetDaclSecurityDescriptor(
    00848                  *SecurityDescriptor,
    00849                  TRUE,                       // DaclPresent
    00850                  EventDacl,
    00851                  FALSE                       // DaclDefaulted
    00852                  );
    00853
    00854     if (!NT_SUCCESS(Status)) {
    00855         retval = FALSE;
    00856         goto Cleanup;
    00857     }
    00858
    00859 Cleanup:
    00860
    00861     if (WorldSid) {
    00862         RtlFreeSid(WorldSid);
    00863     }
    00864
    00865     if (SystemSid) {
    00866         RtlFreeSid(SystemSid);
    00867     }
    00868
    00869     if ((retval == FALSE) && (*SecurityDescriptor != NULL)) {
    00870         LocalFree(*SecurityDescriptor);
    00871         *SecurityDescriptor = NULL;
    00872     }
    00873
    00874
    00875     return retval;
    00876 }
    00877
    00878
    00879
    00880
    00881 VOID NotificationThread(
    00882     PVOID pJunk)
    00883 {
    00884     KPRIORITY   Priority;
    00885     NTSTATUS    Status;
    00886     HANDLE      hEvent[ID_NUM_EVENTS];
    00887     WCHAR       szObjectStr[MAX_SESSION_PATH];
    00888     OBJECT_ATTRIBUTES Attributes;
    00889     UNICODE_STRING UnicodeString;
    00890     PSECURITY_DESCRIPTOR pSD = NULL;
    00891     ULONG       NumEvents = ID_NUM_EVENTS;
    00892
    00893     UNREFERENCED_PARAMETER(pJunk);
    00894
    00895     try {
    00896
    00897         /*
    00898          * Set the priority of the RIT to 3.
    00899          */
    00900         Priority = LOW_PRIORITY + 3;
    00901         NtSetInformationThread(hThreadNotification, ThreadPriority, &Priority,
    00902                 sizeof(KPRIORITY));
    00903
    00904         /*
    00905          * Setup the NLS event
    00906          */
    00907         NtCreateEvent(&ghNlsEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
    00908         UserAssert( ghNlsEvent != NULL );
    00909         hEvent[ID_NLS] = ghNlsEvent;
    00910
    00911         /*
    00912          * Setup the power request event
    00913          */
    00914         hEvent[ID_POWER] = ghPowerRequestEvent;
    00915
    00916         /*
    00917          * Setup the MediaChangeEvent
    00918          */
    00919         hEvent[ID_MEDIACHANGE] = ghMediaRequestEvent;
    00920
    00921
    00922         /*
    00923          *  Setup the NetDeviceChange Event
    00924          */
    00925
    00926         if (gSessionId != 0) {
    00927            //
    00928            // Only on remote Session
    00929            //
    00930
    00931
    00932             swprintf(szObjectStr,L"%ws\\%ld\\BaseNamedObjects\\%ws",
    00933                                                      SESSION_ROOT,gSessionId,SC_BSM_EVENT_NAME);
    00934
    00935             RtlInitUnicodeString(&UnicodeString, szObjectStr);
    00936
    00937             if (CreateBSMEventSD(&pSD) ) {
    00938
    00939                 InitializeObjectAttributes(&Attributes,
    00940                                            &UnicodeString,
    00941                                            OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
    00942                                            NULL,
    00943                                            pSD);
    00944
    00945                 if (!NT_SUCCESS(NtCreateEvent(&hEvent[ID_NETDEVCHANGE], EVENT_ALL_ACCESS, &Attributes, SynchronizationEvent, FALSE))) {
    00946
    00947                     NumEvents--;
    00948
    00949                 }
    00950
    00951                 LocalFree(pSD);
    00952             } else {
    00953
    00954                 NumEvents--;
    00955             }
    00956
    00957         } else {
    00958             //
    00959             // On Console we don't wait for NetDeviceEvent
    00960             //
    00961             NumEvents--;
    00962         }
    00963
    00964         /*
    00965          * Only want media change events on the console.
    00966          */
    00967         if (gSessionId == 0) {
    00968         }
    00969
    00970         StartRegReadRead();
    00971
    00972         /*
    00973          * Sit and wait forever.
    00974          */
    00975         while (TRUE) {
    00976             Status = NtWaitForMultipleObjects(NumEvents,
    00977                                               hEvent,
    00978                                               WaitAny,
    00979                                               TRUE,
    00980                                               NULL);
    00981
    00982
    00983             if (Status == ID_NLS + WAIT_OBJECT_0) {
    00984
    00985                 /*
    00986                  * Handle the NLS event
    00987                  */
    00988                 if (gfLogon) {
    00989                     gfLogon = FALSE;
    00990                     BaseSrvNlsUpdateRegistryCache(NULL, NULL);
    00991                 }
    00992
    00993             }
    00994             else if (Status == ID_POWER + WAIT_OBJECT_0) {
    00995
    00996                 /*
    00997                  * Handle the power request event
    00998                  */
    00999                 NtUserCallNoParam(SFI_XXXUSERPOWERCALLOUTWORKER);
    01000
    01001             }
    01002             else if (Status == ID_MEDIACHANGE + WAIT_OBJECT_0) {
    01003
    01004                 /*
    01005                  * Handle the media change event
    01006                  */
    01007                 HandleMediaChangeEvent();
    01008
    01009                 NtResetEvent(hEvent[ID_MEDIACHANGE], NULL);
    01010             }
    01011             else if (Status == ID_NETDEVCHANGE + WAIT_OBJECT_0) {
    01012
    01013                 /*
    01014                  * Handle the NetDevice change event for remote sessions
    01015                  */
    01016                 HandleRemoteNetDeviceChangeEvent();
    01017
    01018             }
    01019
    01020
    01021         } // While (TRUE)
    01022
    01023     } except (CsrUnhandledExceptionFilter(GetExceptionInformation())) {
    01024         KdPrint(("Registry notification thread is dead, sorry.\n"));
    01025     }
    01026 }
    01027
    01028
    01029 UINT GetRegIntFromID(
    01030     HKEY hKey,
    01031     int KeyID,
    01032     UINT nDefault)
    01033 {
    01034     LPWSTR lpszValue;
    01035     BOOL fAllocated;
    01036     UNICODE_STRING Value;
    01037     DWORD cbSize;
    01038     BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 20 * sizeof(WCHAR)];
    01039     NTSTATUS Status;
    01040     UINT ReturnValue;
    01041
    01042     lpszValue = (LPWSTR)RtlLoadStringOrError(ghModuleWin,
    01043             KeyID, NULL, &fAllocated, FALSE);
    01044
    01045     RtlInitUnicodeString(&Value, lpszValue);
    01046     Status = NtQueryValueKey(hKey,
    01047             &Value,
    01048             KeyValuePartialInformation,
    01049             (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
    01050             sizeof(Buf),
    01051             &cbSize);
    01052     if (NT_SUCCESS(Status)) {
    01053
    01054         /*
    01055          * Convert string to int.
    01056          */
    01057         RtlInitUnicodeString(&Value, (LPWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
    01058         RtlUnicodeStringToInteger(&Value, 10, &ReturnValue);
    01059     } else {
    01060         ReturnValue = nDefault;
    01061     }
    01062
    01063     LocalFree(lpszValue);
    01064
    01065     return(ReturnValue);
    01066 }
    01067
    01068 VOID GetTimeouts(VOID)
    01069 {
    01070     HANDLE hCurrentUserKey;
    01071     HANDLE hKey;
    01072     NTSTATUS Status;
    01073
    01074     Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
    01075     if (NT_SUCCESS(Status)) {
    01076         Status = MyRegOpenKey(hCurrentUserKey,
    01077                 L"Control Panel\\Desktop",
    01078                 &hKey);
    01079         if (NT_SUCCESS(Status)) {
    01080             gCmsHungAppTimeout = GetRegIntFromID(
    01081                     hKey,
    01082                     STR_CMSHUNGAPPTIMEOUT,
    01083                     gCmsHungAppTimeout);
    01084             gCmsWaitToKillTimeout = GetRegIntFromID(
    01085                     hKey,
    01086                     STR_CMSWAITTOKILLTIMEOUT,
    01087                     gCmsWaitToKillTimeout);
    01088
    01089             gdwHungToKillCount = gCmsWaitToKillTimeout / gCmsHungAppTimeout;
    01090
    01091             gfAutoEndTask = GetRegIntFromID(
    01092                     hKey,
    01093                     STR_AUTOENDTASK,
    01094                     gfAutoEndTask);
    01095             NtClose(hKey);
    01096         }
    01097         NtClose(hCurrentUserKey);
    01098     }
    01099
    01100     Status = MyRegOpenKey(NULL,
    01101             L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
    01102             &hKey);
    01103     if (NT_SUCCESS(Status)) {
    01104         gdwServicesWaitToKillTimeout = GetRegIntFromID(
    01105                 hKey,
    01106                 STR_WAITTOKILLSERVICETIMEOUT,
    01107                 gCmsWaitToKillTimeout);
    01108         gdwProcessTerminateTimeout = GetRegIntFromID(
    01109                 hKey,
    01110                 STR_PROCESSTERMINATETIMEOUT,
    01111                 PROCESSTERMINATETIMEOUT);
    01112                 if (gdwProcessTerminateTimeout < CMSHUNGAPPTIMEOUT) {
    01113                         gdwProcessTerminateTimeout = CMSHUNGAPPTIMEOUT;
    01114                 }
    01115
    01116         NtClose(hKey);
    01117     }
    01118 }
    01119
    01120 ULONG
    01121 SrvLogon(
    01122     IN OUT PCSR_API_MSG m,
    01123     IN OUT PCSR_REPLY_STATUS ReplyStatus)
    01124 {
    01125     PLOGONMSG a = (PLOGONMSG)&m->u.ApiMessageData;
    01126     NTSTATUS Status;
    01127
    01128     UNREFERENCED_PARAMETER(ReplyStatus);
    01129
    01130     if (!CsrImpersonateClient(NULL))
    01131         return (ULONG)STATUS_UNSUCCESSFUL;
    01132
    01133     if (a->fLogon) {
    01134
    01135         /*
    01136          * Flush the MultiLingual UI (MUI) alternate
    01137          * resource modules from within NTDLL, so that the
    01138          * new user logging-on gets his chance to
    01139          * load his own.
    01140          */
    01141         LdrFlushAlternateResourceModules();
    01142
    01143         /*
    01144          *  Take care of NLS cache for LogON.
    01145          */
    01146         BaseSrvNlsLogon(TRUE);
    01147
    01148         /*
    01149          *  Set the cleanup event so that the RIT can handle the NLS
    01150          *  registry notification.
    01151          */
    01152         gfLogon = TRUE;
    01153         Status = NtSetEvent( ghNlsEvent, NULL );
    01154         ASSERT(NT_SUCCESS(Status));
    01155     } else {
    01156
    01157         /*
    01158          *  Take care of NLS cache for LogOFF.
    01159          */
    01160         BaseSrvNlsLogon(FALSE);
    01161     }
    01162
    01163     /*
    01164      * Get timeout values from registry
    01165      */
    01166     GetTimeouts();
    01167
    01168     CsrRevertToSelf();
    01169
    01170     /*
    01171      * Initialize console attributes
    01172      */
    01173     InitializeConsoleAttributes();
    01174
    01175     return (ULONG)STATUS_SUCCESS;
    01176 }
    01177
    01178 ULONG
    01179 SrvRegisterLogonProcess(
    01180     IN OUT PCSR_API_MSG m,
    01181     IN OUT PCSR_REPLY_STATUS ReplyStatus)
    01182 {
    01183     /*
    01184      * Fail if this is not the first call.
    01185      */
    01186     if (gIdLogon != 0) {
    01187         return (ULONG)STATUS_UNSUCCESSFUL;
    01188     }
    01189
    01190     gIdLogon = *(DWORD*)m->u.ApiMessageData;
    01191
    01192     UNREFERENCED_PARAMETER(ReplyStatus);
    01193
    01194     return (ULONG)STATUS_SUCCESS;
    01195 }
    01196
    01197 ULONG
    01198 SrvWin32HeapFail(
    01199     IN OUT PCSR_API_MSG m,
    01200     IN OUT PCSR_REPLY_STATUS ReplyStatus)
    01201 {
    01202 #if DBG
    01203     PWIN32HEAPFAILMSG a = (PWIN32HEAPFAILMSG)&m->u.ApiMessageData;
    01204
    01205     Win32HeapFailAllocations(a->bFail);
    01206
    01207 #endif
    01208     return (ULONG)STATUS_SUCCESS;
    01209     UNREFERENCED_PARAMETER(m);
    01210     UNREFERENCED_PARAMETER(ReplyStatus);
    01211 }
    01212
    01213 ULONG
    01214 SrvWin32HeapStat(
    01215     IN OUT PCSR_API_MSG m,
    01216     IN OUT PCSR_REPLY_STATUS ReplyStatus)
    01217 {
    01218 #if DBG
    01219     extern DWORD Win32HeapStat(PDBGHEAPSTAT phs, DWORD dwLen, BOOL bNeedTagShift);
    01220
    01221     PWIN32HEAPSTATMSG a = (PWIN32HEAPSTATMSG)&m->u.ApiMessageData;
    01222
    01223     if (!CsrValidateMessageBuffer(m, &a->phs, a->dwLen, sizeof(BYTE))) {
    01224         return STATUS_INVALID_PARAMETER;
    01225     }
    01226     a->dwMaxTag = Win32HeapStat(a->phs, a->dwLen, TRUE);
    01227
    01228 #endif
    01229     return (ULONG)STATUS_SUCCESS;
    01230     UNREFERENCED_PARAMETER(m);
    01231     UNREFERENCED_PARAMETER(ReplyStatus);
    01232 }
    01233
    01234 ULONG
    01235 SrvGetThreadConsoleDesktop(
    01236     IN OUT PCSR_API_MSG m,
    01237     IN OUT PCSR_REPLY_STATUS ReplyStatus)
    01238 {
    01239     PGETTHREADCONSOLEDESKTOPMSG a = (PGETTHREADCONSOLEDESKTOPMSG)&m->u.ApiMessageData;
    01240
    01241     UNREFERENCED_PARAMETER(ReplyStatus);
    01242
    01243     return GetThreadConsoleDesktop(a->dwThreadId, &a->hdeskConsole);
    01244 }
    01245
    01246 /***************************************************************************\
    01247 * FindWindowFromThread
    01248 *
    01249 * This is a callback function passed to EnumThreadWindows by
    01250 *  to find a top level window owned by a given thread;
    01251 *  ideally, we want to find a top level owner.
    01252 *
    01253 * 07/18/96  GerardoB  Created
    01254 \***************************************************************************/
    01255 BOOL CALLBACK FindWindowFromThread (HWND hwnd, LPARAM lParam)
    01256 {
    01257     BOOL fTopLevelOwner;
    01258 #ifdef FE_IME
    01259     if ( IsImeWindow(hwnd) ) {
    01260         return TRUE;
    01261     }
    01262 #endif
    01263
    01264     fTopLevelOwner = (GetWindow(hwnd, GW_OWNER) == NULL);
    01265     if ((*((HWND *)lParam) == NULL) || fTopLevelOwner) {
    01266         *((HWND *)lParam) = hwnd;
    01267     }
    01268     return !fTopLevelOwner;
    01269 }
    01270
    01271 DWORD GetRipComponent(VOID) { return RIP_USERSRV; }
    01272
    01273 DWORD GetDbgTagFlags(int tag)
    01274 {
    01275     return 0;
    01276     UNREFERENCED_PARAMETER(tag);
    01277 }
    01278
    01279 DWORD GetRipPID(VOID) { return 0; }
    01280 DWORD GetRipFlags(VOID) { return gdwRIPFlags; }
    01281
    01282 VOID SetRipFlags(DWORD dwRipFlags, DWORD dwRipPID)
    01283 {
    01284     if ((dwRipFlags != (DWORD)-1) && !(dwRipFlags & ~RIPF_VALIDUSERFLAGS)) {
    01285         gdwRIPFlags = (WORD)((gdwRIPFlags & ~RIPF_VALIDUSERFLAGS) | dwRipFlags);
    01286     }
    01287     UNREFERENCED_PARAMETER(dwRipPID);
    01288 }
    01289
    01290 VOID SetDbgTag(int tag, DWORD dwBitFlags)
    01291 {
    01292     UNREFERENCED_PARAMETER(tag);
    01293     UNREFERENCED_PARAMETER(dwBitFlags);
    01294 }
    01295
    01296 VOID UserRtlRaiseStatus(NTSTATUS Status)
    01297 {
    01298     RtlRaiseStatus(Status);
    01299 }
    01300
    01301 /*
    01302  * We get this warning if we don't explicitly initalize gZero:
    01303  *
    01304  * C4132: 'gZero' : const object should be initialized
    01305  *
    01306  * But we can't explicitly initialize it since it is a union. So
    01307  * we turn the warning off.
    01308  */
    01309 #pragma warning(disable:4132)
    01310 CONST ALWAYSZERO gZero;
    01311 #pragma warning(default:4132)