[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 TRACE_CH(UserThread,"Create pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
251
252 RtlZeroMemory(ptiCurrent, sizeof(THREADINFO));
253
254 PsSetThreadWin32Thread(Thread, ptiCurrent);
255 pTeb->Win32ThreadInfo = ptiCurrent;
256 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
257
258 TRACE_CH(UserThread, "Allocated pti 0x%p for TID %p\n", ptiCurrent, Thread->Cid.UniqueThread);
259
260 /* Initialize the THREADINFO */
261 InitializeListHead(&ptiCurrent->WindowListHead);
262 InitializeListHead(&ptiCurrent->W32CallbackListHead);
263 InitializeListHead(&ptiCurrent->PtiLink);
264 for (i = 0; i < NB_HOOKS; i++)
265 {
266 InitializeListHead(&ptiCurrent->aphkStart[i]);
267 }
268 ptiCurrent->pEThread = Thread;
269 ptiCurrent->ppi = PsGetCurrentProcessWin32Process();
270 ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
271 ptiCurrent->ppi->ptiList = ptiCurrent;
272 ptiCurrent->ppi->cThreads++;
273 ptiCurrent->MessageQueue = MsqCreateMessageQueue(ptiCurrent);
274 if(ptiCurrent->MessageQueue == NULL)
275 {
276 ERR_CH(UserThread,"Failed to allocate message loop\n");
277 Status = STATUS_NO_MEMORY;
278 goto error;
279 }
280 ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
281 if (ptiCurrent->KeyboardLayout)
282 UserReferenceObject(ptiCurrent->KeyboardLayout);
283 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
284
285 /* Initialize the CLIENTINFO */
286 pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
287 RtlZeroMemory(pci, sizeof(CLIENTINFO));
288 pci->ppi = ptiCurrent->ppi;
289 pci->fsHooks = ptiCurrent->fsHooks;
290 pci->dwTIFlags = ptiCurrent->TIF_flags;
291 if (ptiCurrent->KeyboardLayout)
292 {
293 pci->hKL = ptiCurrent->KeyboardLayout->hkl;
294 pci->CodePage = ptiCurrent->KeyboardLayout->CodePage;
295 }
296
297 /* Assign a default window station and desktop to the process */
298 /* Do not try to open a desktop or window station before winlogon initializes */
299 if(ptiCurrent->ppi->hdeskStartup == NULL && LogonProcess != NULL)
300 {
301 HWINSTA hWinSta = NULL;
302 HDESK hDesk = NULL;
303 UNICODE_STRING DesktopPath;
304 PDESKTOP pdesk;
305 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
306
307 /*
308 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
309 * info structure. See documentation of CreateProcess()
310 */
311 ProcessParams = pTeb->ProcessEnvironmentBlock->ProcessParameters;
312
313 Status = STATUS_UNSUCCESSFUL;
314 if(ProcessParams && ProcessParams->DesktopInfo.Length > 0)
315 {
316 Status = IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath, &ProcessParams->DesktopInfo);
317 }
318 if(!NT_SUCCESS(Status))
319 {
320 RtlInitUnicodeString(&DesktopPath, NULL);
321 }
322
323 Status = IntParseDesktopPath(Process,
324 &DesktopPath,
325 &hWinSta,
326 &hDesk);
327
328 if (DesktopPath.Buffer)
329 ExFreePoolWithTag(DesktopPath.Buffer, TAG_STRING);
330
331 if(!NT_SUCCESS(Status))
332 {
333 ERR_CH(UserThread, "Failed to assign default dekstop and winsta to process\n");
334 goto error;
335 }
336
337 if(!UserSetProcessWindowStation(hWinSta))
338 {
339 Status = STATUS_UNSUCCESSFUL;
340 ERR_CH(UserThread,"Failed to set initial process winsta\n");
341 goto error;
342 }
343
344 /* Validate the new desktop. */
345 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
346 if(!NT_SUCCESS(Status))
347 {
348 ERR_CH(UserThread,"Failed to validate initial desktop handle\n");
349 goto error;
350 }
351
352 /* Store the parsed desktop as the initial desktop */
353 ptiCurrent->ppi->hdeskStartup = hDesk;
354 ptiCurrent->ppi->rpdeskStartup = pdesk;
355 }
356
357 if (ptiCurrent->ppi->hdeskStartup != NULL)
358 {
359 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
360 {
361 ERR_CH(UserThread,"Failed to set thread desktop\n");
362 Status = STATUS_UNSUCCESSFUL;
363 goto error;
364 }
365 }
366
367 /* mark the thread as fully initialized */
368 ptiCurrent->TIF_flags |= TIF_GUITHREADINITIALIZED;
369 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
370
371 return STATUS_SUCCESS;
372
373 error:
374 ERR_CH(UserThread,"UserCreateThreadInfo failed! Freeing pti 0x%p for TID %p\n", ptiCurrent, Thread->Cid.UniqueThread);
375 UserDestroyThreadInfo(Thread);
376 return Status;
377 }
378
379 NTSTATUS
380 NTAPI
381 UserDestroyThreadInfo(struct _ETHREAD *Thread)
382 {
383 PTHREADINFO *ppti;
384 PSINGLE_LIST_ENTRY psle;
385 PPROCESSINFO ppiCurrent;
386 struct _EPROCESS *Process;
387 PTHREADINFO ptiCurrent;
388
389 Process = Thread->ThreadsProcess;
390
391 /* Get the Win32 Thread */
392 ptiCurrent = PsGetThreadWin32Thread(Thread);
393
394 ASSERT(ptiCurrent);
395
396 TRACE_CH(UserThread,"Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread);
397
398 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
399 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
400
401 ppiCurrent = ptiCurrent->ppi;
402 ASSERT(ppiCurrent);
403
404 // ptiTo
405 if (IsThreadAttach(ptiCurrent))
406 {
407 PTHREADINFO ptiFrom = IsThreadAttach(ptiCurrent);
408 TRACE_CH(UserThread,"Attached Thread ptiTo is getting switched!\n");
409 UserAttachThreadInput(ptiFrom, ptiCurrent, FALSE);
410 }
411
412 // ptiFrom
413 if (ptiCurrent->pqAttach && ptiCurrent->MessageQueue)
414 {
415 PTHREADINFO ptiTo;
416 ptiTo = PsGetThreadWin32Thread(ptiCurrent->MessageQueue->Thread);
417 TRACE_CH(UserThread,"Attached Thread ptiFrom is getting switched!\n");
418 if (ptiTo) UserAttachThreadInput( ptiCurrent, ptiTo, FALSE);
419 else
420 {
421 // eThread maybe okay but Win32Thread already made NULL!
422 ERR_CH(UserThread,"Attached Thread ptiFrom did not switch due to ptiTo is NULL!\n");
423 }
424 }
425
426 /* Decrement thread count and check if its 0 */
427 ppiCurrent->cThreads--;
428
429 if(ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
430 {
431 /* Do now some process cleanup that requires a valid win32 thread */
432 if(ptiCurrent->ppi->cThreads == 0)
433 {
434 /* Check if we have registered the user api hook */
435 if(ptiCurrent->ppi == ppiUahServer)
436 {
437 /* Unregister the api hook */
438 UserUnregisterUserApiHook();
439 }
440
441 /* Notify logon application to restart shell if needed */
442 if(ptiCurrent->pDeskInfo)
443 {
444 if(ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
445 {
446 DWORD ExitCode = PsGetProcessExitStatus(Process);
447
448 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
449
450 UserPostMessage(hwndSAS,
451 WM_LOGONNOTIFY,
452 LN_SHELL_EXITED,
453 ExitCode);
454
455 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
456 }
457 }
458 }
459
460 DceFreeThreadDCE(ptiCurrent);
461 HOOK_DestroyThreadHooks(Thread);
462 EVENT_DestroyThreadEvents(Thread);
463 DestroyTimersForThread(ptiCurrent);
464 KeSetEvent(ptiCurrent->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
465 UnregisterThreadHotKeys(Thread);
466 /*
467 if (IsListEmpty(&ptiCurrent->WindowListHead))
468 {
469 ERR_CH(UserThread,"Thread Window List is Empty!\n");
470 }
471 */
472 co_DestroyThreadWindows(Thread);
473
474 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling)
475 {
476 //ERR_CH(UserThread,"DestroyProcessClasses\n");
477 /* no process windows should exist at this point, or the function will assert! */
478 DestroyProcessClasses(ppiCurrent);
479 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
480 }
481
482 IntBlockInput(ptiCurrent, FALSE);
483 IntCleanupThreadCallbacks(ptiCurrent);
484
485 /* cleanup user object references stack */
486 psle = PopEntryList(&ptiCurrent->ReferencesList);
487 while (psle)
488 {
489 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
490 TRACE_CH(UserThread,"thread clean: remove reference obj 0x%p\n",ref->obj);
491 UserDereferenceObject(ref->obj);
492
493 psle = PopEntryList(&ptiCurrent->ReferencesList);
494 }
495 }
496
497 /* Free the message queue */
498 if (ptiCurrent->MessageQueue)
499 {
500 MsqDestroyMessageQueue(ptiCurrent);
501 }
502
503 /* Find the THREADINFO in the PROCESSINFO's list */
504 ppti = &ppiCurrent->ptiList;
505 while (*ppti != NULL && *ppti != ptiCurrent)
506 {
507 ppti = &((*ppti)->ptiSibling);
508 }
509
510 /* we must have found it */
511 ASSERT(*ppti == ptiCurrent);
512
513 /* Remove it from the list */
514 *ppti = ptiCurrent->ptiSibling;
515
516 if (ptiCurrent->KeyboardLayout)
517 UserDereferenceObject(ptiCurrent->KeyboardLayout);
518
519 IntSetThreadDesktop(NULL, TRUE);
520
521 TRACE_CH(UserThread,"Freeing pti 0x%p\n", ptiCurrent);
522
523 /* Free the THREADINFO */
524 PsSetThreadWin32Thread(Thread, NULL);
525 ExFreePoolWithTag(ptiCurrent, USERTAG_THREADINFO);
526
527 return STATUS_SUCCESS;
528 }
529
530 NTSTATUS
531 APIENTRY
532 Win32kThreadCallback(struct _ETHREAD *Thread,
533 PSW32THREADCALLOUTTYPE Type)
534 {
535 NTSTATUS Status;
536
537 UserEnterExclusive();
538
539 ASSERT(NtCurrentTeb());
540
541 if (Type == PsW32ThreadCalloutInitialize)
542 {
543 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
544 Status = UserCreateThreadInfo(Thread);
545 }
546 else
547 {
548 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
549 Status = UserDestroyThreadInfo(Thread);
550 }
551
552 UserLeave();
553
554 return Status;
555 }
556
557 #ifdef _M_IX86
558 C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
559 #endif
560
561 // Return on failure
562 #define NT_ROF(x) \
563 Status = (x); \
564 if (!NT_SUCCESS(Status)) \
565 { \
566 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
567 return Status; \
568 }
569
570 /*
571 * This definition doesn't work
572 */
573 INIT_FUNCTION
574 NTSTATUS
575 APIENTRY
576 DriverEntry(
577 IN PDRIVER_OBJECT DriverObject,
578 IN PUNICODE_STRING RegistryPath)
579 {
580 NTSTATUS Status;
581 BOOLEAN Result;
582 WIN32_CALLOUTS_FPNS CalloutData = {0};
583 PVOID GlobalUserHeapBase = NULL;
584
585 /*
586 * Register user mode call interface
587 * (system service table index = 1)
588 */
589 Result = KeAddSystemServiceTable(Win32kSSDT,
590 NULL,
591 Win32kNumberOfSysCalls,
592 Win32kSSPT,
593 1);
594 if (Result == FALSE)
595 {
596 DPRINT1("Adding system services failed!\n");
597 return STATUS_UNSUCCESSFUL;
598 }
599
600 hModuleWin = MmPageEntireDriver(DriverEntry);
601 DPRINT("Win32k hInstance 0x%p!\n",hModuleWin);
602
603 /* Register Object Manager Callbacks */
604 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
605 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
606 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
607 CalloutData.ProcessCallout = Win32kProcessCallback;
608 CalloutData.ThreadCallout = Win32kThreadCallback;
609 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
610 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
611 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
612
613 /* Register our per-process and per-thread structures. */
614 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
615
616 /* Register service hook callbacks */
617 #if DBG
618 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
619 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
620 #endif
621
622 /* Create the global USER heap */
623 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
624 &GlobalUserHeapBase,
625 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
626 if (GlobalUserHeap == NULL)
627 {
628 DPRINT1("Failed to initialize the global heap!\n");
629 return STATUS_UNSUCCESSFUL;
630 }
631
632 /* Allocate global server info structure */
633 gpsi = UserHeapAlloc(sizeof(SERVERINFO));
634 if (!gpsi)
635 {
636 DPRINT1("Failed allocate server info structure!\n");
637 return STATUS_UNSUCCESSFUL;
638 }
639
640 RtlZeroMemory(gpsi, sizeof(SERVERINFO));
641 DPRINT("Global Server Data -> %p\n", gpsi);
642
643 NT_ROF(InitGdiHandleTable());
644 NT_ROF(InitPaletteImpl());
645
646 /* Create stock objects, ie. precreated objects commonly
647 used by win32 applications */
648 CreateStockObjects();
649 CreateSysColorObjects();
650
651 NT_ROF(InitBrushImpl());
652 NT_ROF(InitPDEVImpl());
653 NT_ROF(InitLDEVImpl());
654 NT_ROF(InitDeviceImpl());
655 NT_ROF(InitDcImpl());
656 NT_ROF(InitUserImpl());
657 NT_ROF(InitWindowStationImpl());
658 NT_ROF(InitDesktopImpl());
659 NT_ROF(InitInputImpl());
660 NT_ROF(InitKeyboardImpl());
661 NT_ROF(MsqInitializeImpl());
662 NT_ROF(InitTimerImpl());
663 NT_ROF(InitDCEImpl());
664
665 /* Initialize FreeType library */
666 if (!InitFontSupport())
667 {
668 DPRINT1("Unable to initialize font support\n");
669 return Status;
670 }
671
672 gusLanguageID = UserGetLanguageID();
673
674 return STATUS_SUCCESS;
675 }
676
677 /* EOF */