[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / main.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Driver entry and initialization of win32k
5 * FILE: subsystems/win32/win32k/main/main.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10 #include <napi.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 HANDLE hModuleWin;
16
17 PGDI_HANDLE_TABLE NTAPI GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject);
18 BOOL NTAPI GDI_CleanupForProcess (struct _EPROCESS *Process);
19 NTSTATUS NTAPI UserDestroyThreadInfo(struct _ETHREAD *Thread);
20
21 HANDLE GlobalUserHeap = NULL;
22 PSECTION_OBJECT GlobalUserHeapSection = NULL;
23
24 PSERVERINFO gpsi = NULL; // Global User Server Information.
25
26 SHORT gusLanguageID;
27 PPROCESSINFO ppiScrnSaver;
28
29 extern ULONG_PTR Win32kSSDT[];
30 extern UCHAR Win32kSSPT[];
31 extern ULONG Win32kNumberOfSysCalls;
32
33 #if DBG
34 void
35 NTAPI
36 DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
37 {
38 GdiDbgPreServiceHook(ulSyscallId, pulArguments);
39 UserDbgPreServiceHook(ulSyscallId, pulArguments);
40 }
41
42 ULONG_PTR
43 NTAPI
44 DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
45 {
46 ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
47 ulResult = UserDbgPostServiceHook(ulSyscallId, ulResult);
48 return ulResult;
49 }
50 #endif
51
52 NTSTATUS
53 APIENTRY
54 Win32kProcessCallback(struct _EPROCESS *Process,
55 BOOLEAN Create)
56 {
57 PPROCESSINFO ppiCurrent;
58 DECLARE_RETURN(NTSTATUS);
59
60 ASSERT(Process->Peb);
61
62 UserEnterExclusive();
63
64 if (Create)
65 {
66 SIZE_T ViewSize = 0;
67 LARGE_INTEGER Offset;
68 PVOID UserBase = NULL;
69 PRTL_USER_PROCESS_PARAMETERS pParams = Process->Peb->ProcessParameters;
70 NTSTATUS Status;
71
72 ASSERT(PsGetProcessWin32Process(Process) == NULL);
73
74 ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
75 sizeof(PROCESSINFO),
76 USERTAG_PROCESSINFO);
77
78 if (ppiCurrent == NULL)
79 {
80 ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n", HandleToUlong(Process->UniqueProcessId));
81 RETURN( STATUS_NO_MEMORY);
82 }
83
84 RtlZeroMemory(ppiCurrent, sizeof(PROCESSINFO));
85
86 PsSetProcessWin32Process(Process, ppiCurrent);
87
88 #if DBG
89 DbgInitDebugChannels();
90 #endif
91
92 TRACE_CH(UserProcess,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent, HandleToUlong(Process->UniqueProcessId));
93
94 /* map the global heap into the process */
95 Offset.QuadPart = 0;
96 Status = MmMapViewOfSection(GlobalUserHeapSection,
97 PsGetCurrentProcess(),
98 &UserBase,
99 0,
100 0,
101 &Offset,
102 &ViewSize,
103 ViewUnmap,
104 SEC_NO_CHANGE,
105 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
106 if (!NT_SUCCESS(Status))
107 {
108 TRACE_CH(UserProcess,"Failed to map the global heap! 0x%x\n", Status);
109 RETURN(Status);
110 }
111 ppiCurrent->HeapMappings.Next = NULL;
112 ppiCurrent->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
113 ppiCurrent->HeapMappings.UserMapping = UserBase;
114 ppiCurrent->HeapMappings.Count = 1;
115
116 InitializeListHead(&ppiCurrent->MenuListHead);
117
118 InitializeListHead(&ppiCurrent->GDIBrushAttrFreeList);
119 InitializeListHead(&ppiCurrent->GDIDcAttrFreeList);
120
121 InitializeListHead(&ppiCurrent->PrivateFontListHead);
122 ExInitializeFastMutex(&ppiCurrent->PrivateFontListLock);
123
124 InitializeListHead(&ppiCurrent->DriverObjListHead);
125 ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
126
127 ppiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
128 if (!EngCreateEvent((PEVENT *)&ppiCurrent->InputIdleEvent))
129 {
130 KeBugCheck(0);
131 }
132
133 KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
134
135
136 /* map the gdi handle table to user land */
137 Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
138 Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
139 pParams = Process->Peb->ProcessParameters;
140
141 ppiCurrent->peProcess = Process;
142 /* setup process flags */
143 ppiCurrent->W32PF_flags = W32PF_THREADCONNECTED;
144
145 if ( pParams &&
146 pParams->WindowFlags & STARTF_SCRNSAVER )
147 {
148 ppiScrnSaver = ppiCurrent;
149 ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
150 }
151
152 /* Create pools for GDI object attributes */
153 ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
154 ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
155 ppiCurrent->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
156 ASSERT(ppiCurrent->pPoolDcAttr);
157 ASSERT(ppiCurrent->pPoolBrushAttr);
158 ASSERT(ppiCurrent->pPoolRgnAttr);
159 }
160 else
161 {
162 /* Get the Win32 Process */
163 ppiCurrent = PsGetProcessWin32Process(Process);
164
165 ASSERT(ppiCurrent);
166
167 TRACE_CH(UserProcess, "Destroying ppi 0x%p\n", ppiCurrent);
168 ppiCurrent->W32PF_flags |= W32PF_TERMINATED;
169
170 if (ppiScrnSaver == ppiCurrent)
171 ppiScrnSaver = NULL;
172
173 if (ppiCurrent->InputIdleEvent)
174 {
175 EngFreeMem(ppiCurrent->InputIdleEvent);
176 ppiCurrent->InputIdleEvent = NULL;
177 }
178
179 IntCleanupMenus(Process, ppiCurrent);
180 IntCleanupCurIcons(Process, ppiCurrent);
181
182
183 GDI_CleanupForProcess(Process);
184
185 co_IntGraphicsCheck(FALSE);
186
187 /*
188 * Deregister logon application automatically
189 */
190 if(LogonProcess == ppiCurrent)
191 {
192 LogonProcess = NULL;
193 }
194
195 /* Close the startup desktop */
196 if(ppiCurrent->rpdeskStartup)
197 ObDereferenceObject(ppiCurrent->rpdeskStartup);
198 if(ppiCurrent->hdeskStartup)
199 ZwClose(ppiCurrent->hdeskStartup);
200
201 /* Close the current window station */
202 UserSetProcessWindowStation(NULL);
203
204 /* Destroy GDI pools */
205 GdiPoolDestroy(ppiCurrent->pPoolDcAttr);
206 GdiPoolDestroy(ppiCurrent->pPoolBrushAttr);
207 GdiPoolDestroy(ppiCurrent->pPoolRgnAttr);
208
209 if (gppiInputProvider == ppiCurrent) gppiInputProvider = NULL;
210
211 TRACE_CH(UserProcess,"Freeing ppi 0x%p\n", ppiCurrent);
212
213 /* Ftee the PROCESSINFO */
214 PsSetProcessWin32Process(Process, NULL);
215 ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
216 }
217
218 RETURN( STATUS_SUCCESS);
219
220 CLEANUP:
221 UserLeave();
222 END_CLEANUP;
223 }
224
225 NTSTATUS NTAPI
226 UserCreateThreadInfo(struct _ETHREAD *Thread)
227 {
228 struct _EPROCESS *Process;
229 PCLIENTINFO pci;
230 PTHREADINFO ptiCurrent;
231 int i;
232 NTSTATUS Status = STATUS_SUCCESS;
233 PTEB pTeb;
234
235 Process = Thread->ThreadsProcess;
236
237 pTeb = NtCurrentTeb();
238
239 ASSERT(pTeb);
240
241 ptiCurrent = ExAllocatePoolWithTag(NonPagedPool,
242 sizeof(THREADINFO),
243 USERTAG_THREADINFO);
244 if (ptiCurrent == NULL)
245 {
246 ERR_CH(UserThread, "Failed to allocate pti for TID %p\n", Thread->Cid.UniqueThread);
247 return STATUS_NO_MEMORY;
248 }
249
250 RtlZeroMemory(ptiCurrent, sizeof(THREADINFO));
251
252 PsSetThreadWin32Thread(Thread, ptiCurrent);
253 pTeb->Win32ThreadInfo = ptiCurrent;
254 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
255
256 TRACE_CH(UserThread, "Allocated pti 0x%p for TID %p\n", ptiCurrent, Thread->Cid.UniqueThread);
257
258 /* Initialize the THREADINFO */
259 InitializeListHead(&ptiCurrent->WindowListHead);
260 InitializeListHead(&ptiCurrent->W32CallbackListHead);
261 InitializeListHead(&ptiCurrent->PtiLink);
262 for (i = 0; i < NB_HOOKS; i++)
263 {
264 InitializeListHead(&ptiCurrent->aphkStart[i]);
265 }
266 ptiCurrent->pEThread = Thread;
267 ptiCurrent->ppi = PsGetCurrentProcessWin32Process();
268 ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
269 ptiCurrent->ppi->ptiList = ptiCurrent;
270 ptiCurrent->ppi->cThreads++;
271 ptiCurrent->MessageQueue = MsqCreateMessageQueue(Thread);
272 if(ptiCurrent->MessageQueue == NULL)
273 {
274 ERR_CH(UserThread,"Failed to allocate message loop\n");
275 Status = STATUS_NO_MEMORY;
276 goto error;
277 }
278 ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
279 if (ptiCurrent->KeyboardLayout)
280 UserReferenceObject(ptiCurrent->KeyboardLayout);
281 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
282
283 /* Initialize the CLIENTINFO */
284 pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
285 RtlZeroMemory(pci, sizeof(CLIENTINFO));
286 pci->ppi = ptiCurrent->ppi;
287 pci->fsHooks = ptiCurrent->fsHooks;
288 pci->dwTIFlags = ptiCurrent->TIF_flags;
289 if (ptiCurrent->KeyboardLayout)
290 {
291 pci->hKL = ptiCurrent->KeyboardLayout->hkl;
292 pci->CodePage = ptiCurrent->KeyboardLayout->CodePage;
293 }
294
295 /* Assign a default window station and desktop to the process */
296 /* Do not try to open a desktop or window station before winlogon initializes */
297 if(ptiCurrent->ppi->hdeskStartup == NULL && LogonProcess != NULL)
298 {
299 HWINSTA hWinSta = NULL;
300 HDESK hDesk = NULL;
301 UNICODE_STRING DesktopPath;
302 PDESKTOP pdesk;
303 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
304
305 /*
306 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
307 * info structure. See documentation of CreateProcess()
308 */
309 ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
310
311 Status = STATUS_UNSUCCESSFUL;
312 if(ProcessParams && ProcessParams->DesktopInfo.Length > 0)
313 {
314 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
315 }
316 if(!NT_SUCCESS(Status))
317 {
318 RtlInitUnicodeString(&DesktopPath, NULL);
319 }
320
321 Status = IntParseDesktopPath(Process,
322 &DesktopPath,
323 &hWinSta,
324 &hDesk);
325
326 if (DesktopPath.Buffer)
327 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
328
329 if(!NT_SUCCESS(Status))
330 {
331 ERR_CH(UserThread, "Failed to assign default dekstop and winsta to process\n");
332 goto error;
333 }
334
335 if(!UserSetProcessWindowStation(hWinSta))
336 {
337 Status = STATUS_UNSUCCESSFUL;
338 ERR_CH(UserThread,"Failed to set initial process winsta\n");
339 goto error;
340 }
341
342 /* Validate the new desktop. */
343 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
344 if(!NT_SUCCESS(Status))
345 {
346 ERR_CH(UserThread,"Failed to validate initial desktop handle\n");
347 goto error;
348 }
349
350 /* Store the parsed desktop as the initial desktop */
351 ptiCurrent->ppi->hdeskStartup = hDesk;
352 ptiCurrent->ppi->rpdeskStartup = pdesk;
353 }
354
355 if (ptiCurrent->ppi->hdeskStartup != NULL)
356 {
357 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
358 {
359 ERR_CH(UserThread,"Failed to set thread desktop\n");
360 Status = STATUS_UNSUCCESSFUL;
361 goto error;
362 }
363 }
364
365 /* mark the thread as fully initialized */
366 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
367 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
368
369 return STATUS_SUCCESS;
370
371 error:
372 ERR_CH(UserThread,"UserCreateThreadInfo failed! Freeing pti 0x%p for TID %p\n", ptiCurrent, Thread->Cid.UniqueThread);
373 UserDestroyThreadInfo(Thread);
374 return Status;
375 }
376
377 NTSTATUS
378 NTAPI
379 UserDestroyThreadInfo(struct _ETHREAD *Thread)
380 {
381 PTHREADINFO *ppti;
382 PSINGLE_LIST_ENTRY psle;
383 PPROCESSINFO ppiCurrent;
384 struct _EPROCESS *Process;
385 PTHREADINFO ptiCurrent;
386
387 Process = Thread->ThreadsProcess;
388
389 /* Get the Win32 Thread */
390 ptiCurrent = PsGetThreadWin32Thread(Thread);
391
392 ASSERT(ptiCurrent);
393
394 TRACE_CH(UserThread,"Destroying pti 0x%p\n", ptiCurrent);
395
396 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
397 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
398
399 ppiCurrent = ptiCurrent->ppi;
400 ASSERT(ppiCurrent);
401
402 /* Decrement thread count and check if its 0 */
403 ppiCurrent->cThreads--;
404
405 if(ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
406 {
407 /* Do now some process cleanup that requires a valid win32 thread */
408 if(ptiCurrent->ppi->cThreads == 0)
409 {
410 /* Check if we have registered the user api hook */
411 if(ptiCurrent->ppi == ppiUahServer)
412 {
413 /* Unregister the api hook */
414 UserUnregisterUserApiHook();
415 }
416
417 /* Notify logon application to restart shell if needed */
418 if(ptiCurrent->pDeskInfo)
419 {
420 if(ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
421 {
422 DWORD ExitCode = PsGetProcessExitStatus(Process);
423
424 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
425
426 UserPostMessage(hwndSAS,
427 WM_LOGONNOTIFY,
428 LN_SHELL_EXITED,
429 ExitCode);
430
431 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
432 }
433 }
434 }
435
436 DceFreeThreadDCE(ptiCurrent);
437 HOOK_DestroyThreadHooks(Thread);
438 EVENT_DestroyThreadEvents(Thread);
439 DestroyTimersForThread(ptiCurrent);
440 KeSetEvent(ptiCurrent->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
441 UnregisterThreadHotKeys(Thread);
442 /*
443 if (IsListEmpty(&ptiCurrent->WindowListHead))
444 {
445 ERR_CH(UserThread,"Thread Window List is Empty!\n");
446 }
447 */
448 co_DestroyThreadWindows(Thread);
449
450 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling)
451 {
452 //ERR_CH(UserThread,"DestroyProcessClasses\n");
453 /* no process windows should exist at this point, or the function will assert! */
454 DestroyProcessClasses(ppiCurrent);
455 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
456 }
457
458 IntBlockInput(ptiCurrent, FALSE);
459 IntCleanupThreadCallbacks(ptiCurrent);
460
461 /* cleanup user object references stack */
462 psle = PopEntryList(&ptiCurrent->ReferencesList);
463 while (psle)
464 {
465 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
466 TRACE_CH(UserThread,"thread clean: remove reference obj 0x%p\n",ref->obj);
467 UserDereferenceObject(ref->obj);
468
469 psle = PopEntryList(&ptiCurrent->ReferencesList);
470 }
471 }
472
473 if (ptiCurrent->pqAttach && ptiCurrent->MessageQueue)
474 {
475 PTHREADINFO ptiTo;
476 ptiTo = PsGetThreadWin32Thread(ptiCurrent->MessageQueue->Thread);
477 TRACE_CH(UserThread,"Attached Thread is getting switched!\n");
478 UserAttachThreadInput( ptiCurrent, ptiTo, FALSE);
479 }
480
481 /* Free the message queue */
482 if(ptiCurrent->MessageQueue)
483 {
484 MsqDestroyMessageQueue(ptiCurrent->MessageQueue);
485 }
486
487 /* Find the THREADINFO in the PROCESSINFO's list */
488 ppti = &ppiCurrent->ptiList;
489 while (*ppti != NULL && *ppti != ptiCurrent)
490 {
491 ppti = &((*ppti)->ptiSibling);
492 }
493
494 /* we must have found it */
495 ASSERT(*ppti == ptiCurrent);
496
497 /* Remove it from the list */
498 *ppti = ptiCurrent->ptiSibling;
499
500 if (ptiCurrent->KeyboardLayout)
501 UserDereferenceObject(ptiCurrent->KeyboardLayout);
502
503 IntSetThreadDesktop(NULL, TRUE);
504
505 TRACE_CH(UserThread,"Freeing pti 0x%p\n", ptiCurrent);
506
507 /* Free the THREADINFO */
508 PsSetThreadWin32Thread(Thread, NULL);
509 ExFreePoolWithTag(ptiCurrent, USERTAG_THREADINFO);
510
511 return STATUS_SUCCESS;
512 }
513
514 NTSTATUS
515 APIENTRY
516 Win32kThreadCallback(struct _ETHREAD *Thread,
517 PSW32THREADCALLOUTTYPE Type)
518 {
519 NTSTATUS Status;
520
521 UserEnterExclusive();
522
523 ASSERT(NtCurrentTeb());
524
525 if (Type == PsW32ThreadCalloutInitialize)
526 {
527 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
528 Status = UserCreateThreadInfo(Thread);
529 }
530 else
531 {
532 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
533 Status = UserDestroyThreadInfo(Thread);
534 }
535
536 UserLeave();
537
538 return Status;
539 }
540
541 #ifdef _M_IX86
542 C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
543 #endif
544
545 // Return on failure
546 #define NT_ROF(x) \
547 Status = (x); \
548 if (!NT_SUCCESS(Status)) \
549 { \
550 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
551 return Status; \
552 }
553
554 /*
555 * This definition doesn't work
556 */
557 INIT_FUNCTION
558 NTSTATUS
559 APIENTRY
560 DriverEntry(
561 IN PDRIVER_OBJECT DriverObject,
562 IN PUNICODE_STRING RegistryPath)
563 {
564 NTSTATUS Status;
565 BOOLEAN Result;
566 WIN32_CALLOUTS_FPNS CalloutData = {0};
567 PVOID GlobalUserHeapBase = NULL;
568
569 /*
570 * Register user mode call interface
571 * (system service table index = 1)
572 */
573 Result = KeAddSystemServiceTable(Win32kSSDT,
574 NULL,
575 Win32kNumberOfSysCalls,
576 Win32kSSPT,
577 1);
578 if (Result == FALSE)
579 {
580 DPRINT1("Adding system services failed!\n");
581 return STATUS_UNSUCCESSFUL;
582 }
583
584 hModuleWin = MmPageEntireDriver(DriverEntry);
585 DPRINT("Win32k hInstance 0x%p!\n",hModuleWin);
586
587 /* Register Object Manager Callbacks */
588 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
589 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
590 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
591 CalloutData.ProcessCallout = Win32kProcessCallback;
592 CalloutData.ThreadCallout = Win32kThreadCallback;
593 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
594 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
595 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
596
597 /* Register our per-process and per-thread structures. */
598 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
599
600 /* Register service hook callbacks */
601 #if DBG
602 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
603 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
604 #endif
605
606 /* Create the global USER heap */
607 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
608 &GlobalUserHeapBase,
609 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
610 if (GlobalUserHeap == NULL)
611 {
612 DPRINT1("Failed to initialize the global heap!\n");
613 return STATUS_UNSUCCESSFUL;
614 }
615
616 /* Allocate global server info structure */
617 gpsi = UserHeapAlloc(sizeof(SERVERINFO));
618 if (!gpsi)
619 {
620 DPRINT1("Failed allocate server info structure!\n");
621 return STATUS_UNSUCCESSFUL;
622 }
623
624 RtlZeroMemory(gpsi, sizeof(SERVERINFO));
625 DPRINT("Global Server Data -> %p\n", gpsi);
626
627 NT_ROF(InitGdiHandleTable());
628 NT_ROF(InitPaletteImpl());
629
630 /* Create stock objects, ie. precreated objects commonly
631 used by win32 applications */
632 CreateStockObjects();
633 CreateSysColorObjects();
634
635 NT_ROF(InitBrushImpl());
636 NT_ROF(InitPDEVImpl());
637 NT_ROF(InitLDEVImpl());
638 NT_ROF(InitDeviceImpl());
639 NT_ROF(InitDcImpl());
640 NT_ROF(InitUserImpl());
641 NT_ROF(InitWindowStationImpl());
642 NT_ROF(InitDesktopImpl());
643 NT_ROF(InitInputImpl());
644 NT_ROF(InitKeyboardImpl());
645 NT_ROF(MsqInitializeImpl());
646 NT_ROF(InitTimerImpl());
647 NT_ROF(InitDCEImpl());
648
649 /* Initialize FreeType library */
650 if (!InitFontSupport())
651 {
652 DPRINT1("Unable to initialize font support\n");
653 return Status;
654 }
655
656 gusLanguageID = UserGetLanguageID();
657
658 return STATUS_SUCCESS;
659 }
660
661 /* EOF */