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