[NtUser]
[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 /* Decrement thread count and check if its 0 */
405 ppiCurrent->cThreads--;
406
407 if(ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED)
408 {
409 /* Do now some process cleanup that requires a valid win32 thread */
410 if(ptiCurrent->ppi->cThreads == 0)
411 {
412 /* Check if we have registered the user api hook */
413 if(ptiCurrent->ppi == ppiUahServer)
414 {
415 /* Unregister the api hook */
416 UserUnregisterUserApiHook();
417 }
418
419 /* Notify logon application to restart shell if needed */
420 if(ptiCurrent->pDeskInfo)
421 {
422 if(ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
423 {
424 DWORD ExitCode = PsGetProcessExitStatus(Process);
425
426 TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode);
427
428 UserPostMessage(hwndSAS,
429 WM_LOGONNOTIFY,
430 LN_SHELL_EXITED,
431 ExitCode);
432
433 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
434 }
435 }
436 }
437
438 DceFreeThreadDCE(ptiCurrent);
439 HOOK_DestroyThreadHooks(Thread);
440 EVENT_DestroyThreadEvents(Thread);
441 DestroyTimersForThread(ptiCurrent);
442 KeSetEvent(ptiCurrent->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
443 UnregisterThreadHotKeys(Thread);
444 /*
445 if (IsListEmpty(&ptiCurrent->WindowListHead))
446 {
447 ERR_CH(UserThread,"Thread Window List is Empty!\n");
448 }
449 */
450 co_DestroyThreadWindows(Thread);
451
452 if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling)
453 {
454 //ERR_CH(UserThread,"DestroyProcessClasses\n");
455 /* no process windows should exist at this point, or the function will assert! */
456 DestroyProcessClasses(ppiCurrent);
457 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
458 }
459
460 IntBlockInput(ptiCurrent, FALSE);
461 IntCleanupThreadCallbacks(ptiCurrent);
462
463 /* cleanup user object references stack */
464 psle = PopEntryList(&ptiCurrent->ReferencesList);
465 while (psle)
466 {
467 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
468 TRACE_CH(UserThread,"thread clean: remove reference obj 0x%p\n",ref->obj);
469 UserDereferenceObject(ref->obj);
470
471 psle = PopEntryList(&ptiCurrent->ReferencesList);
472 }
473 }
474
475 // ptiTo
476 if (IsThreadAttach(ptiCurrent))
477 {
478 PTHREADINFO ptiFrom = IsThreadAttach(ptiCurrent);
479 TRACE_CH(UserThread,"Attached Thread ptiTo is getting switched!\n");
480 UserAttachThreadInput(ptiFrom, ptiCurrent, FALSE);
481 }
482
483 // ptiFrom
484 if (ptiCurrent->pqAttach && ptiCurrent->MessageQueue)
485 {
486 PTHREADINFO ptiTo;
487 ptiTo = PsGetThreadWin32Thread(ptiCurrent->MessageQueue->Thread);
488 TRACE_CH(UserThread,"Attached Thread ptiFrom is getting switched!\n");
489 UserAttachThreadInput( ptiCurrent, ptiTo, FALSE);
490 }
491
492 /* Free the message queue */
493 if (ptiCurrent->MessageQueue)
494 {
495 MsqDestroyMessageQueue(ptiCurrent);
496 }
497
498 /* Find the THREADINFO in the PROCESSINFO's list */
499 ppti = &ppiCurrent->ptiList;
500 while (*ppti != NULL && *ppti != ptiCurrent)
501 {
502 ppti = &((*ppti)->ptiSibling);
503 }
504
505 /* we must have found it */
506 ASSERT(*ppti == ptiCurrent);
507
508 /* Remove it from the list */
509 *ppti = ptiCurrent->ptiSibling;
510
511 if (ptiCurrent->KeyboardLayout)
512 UserDereferenceObject(ptiCurrent->KeyboardLayout);
513
514 IntSetThreadDesktop(NULL, TRUE);
515
516 TRACE_CH(UserThread,"Freeing pti 0x%p\n", ptiCurrent);
517
518 /* Free the THREADINFO */
519 PsSetThreadWin32Thread(Thread, NULL);
520 ExFreePoolWithTag(ptiCurrent, USERTAG_THREADINFO);
521
522 return STATUS_SUCCESS;
523 }
524
525 NTSTATUS
526 APIENTRY
527 Win32kThreadCallback(struct _ETHREAD *Thread,
528 PSW32THREADCALLOUTTYPE Type)
529 {
530 NTSTATUS Status;
531
532 UserEnterExclusive();
533
534 ASSERT(NtCurrentTeb());
535
536 if (Type == PsW32ThreadCalloutInitialize)
537 {
538 ASSERT(PsGetThreadWin32Thread(Thread) == NULL);
539 Status = UserCreateThreadInfo(Thread);
540 }
541 else
542 {
543 ASSERT(PsGetThreadWin32Thread(Thread) != NULL);
544 Status = UserDestroyThreadInfo(Thread);
545 }
546
547 UserLeave();
548
549 return Status;
550 }
551
552 #ifdef _M_IX86
553 C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
554 #endif
555
556 // Return on failure
557 #define NT_ROF(x) \
558 Status = (x); \
559 if (!NT_SUCCESS(Status)) \
560 { \
561 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
562 return Status; \
563 }
564
565 /*
566 * This definition doesn't work
567 */
568 INIT_FUNCTION
569 NTSTATUS
570 APIENTRY
571 DriverEntry(
572 IN PDRIVER_OBJECT DriverObject,
573 IN PUNICODE_STRING RegistryPath)
574 {
575 NTSTATUS Status;
576 BOOLEAN Result;
577 WIN32_CALLOUTS_FPNS CalloutData = {0};
578 PVOID GlobalUserHeapBase = NULL;
579
580 /*
581 * Register user mode call interface
582 * (system service table index = 1)
583 */
584 Result = KeAddSystemServiceTable(Win32kSSDT,
585 NULL,
586 Win32kNumberOfSysCalls,
587 Win32kSSPT,
588 1);
589 if (Result == FALSE)
590 {
591 DPRINT1("Adding system services failed!\n");
592 return STATUS_UNSUCCESSFUL;
593 }
594
595 hModuleWin = MmPageEntireDriver(DriverEntry);
596 DPRINT("Win32k hInstance 0x%p!\n",hModuleWin);
597
598 /* Register Object Manager Callbacks */
599 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
600 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
601 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
602 CalloutData.ProcessCallout = Win32kProcessCallback;
603 CalloutData.ThreadCallout = Win32kThreadCallback;
604 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
605 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
606 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
607
608 /* Register our per-process and per-thread structures. */
609 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
610
611 /* Register service hook callbacks */
612 #if DBG
613 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
614 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
615 #endif
616
617 /* Create the global USER heap */
618 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
619 &GlobalUserHeapBase,
620 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
621 if (GlobalUserHeap == NULL)
622 {
623 DPRINT1("Failed to initialize the global heap!\n");
624 return STATUS_UNSUCCESSFUL;
625 }
626
627 /* Allocate global server info structure */
628 gpsi = UserHeapAlloc(sizeof(SERVERINFO));
629 if (!gpsi)
630 {
631 DPRINT1("Failed allocate server info structure!\n");
632 return STATUS_UNSUCCESSFUL;
633 }
634
635 RtlZeroMemory(gpsi, sizeof(SERVERINFO));
636 DPRINT("Global Server Data -> %p\n", gpsi);
637
638 NT_ROF(InitGdiHandleTable());
639 NT_ROF(InitPaletteImpl());
640
641 /* Create stock objects, ie. precreated objects commonly
642 used by win32 applications */
643 CreateStockObjects();
644 CreateSysColorObjects();
645
646 NT_ROF(InitBrushImpl());
647 NT_ROF(InitPDEVImpl());
648 NT_ROF(InitLDEVImpl());
649 NT_ROF(InitDeviceImpl());
650 NT_ROF(InitDcImpl());
651 NT_ROF(InitUserImpl());
652 NT_ROF(InitWindowStationImpl());
653 NT_ROF(InitDesktopImpl());
654 NT_ROF(InitInputImpl());
655 NT_ROF(InitKeyboardImpl());
656 NT_ROF(MsqInitializeImpl());
657 NT_ROF(InitTimerImpl());
658 NT_ROF(InitDCEImpl());
659
660 /* Initialize FreeType library */
661 if (!InitFontSupport())
662 {
663 DPRINT1("Unable to initialize font support\n");
664 return Status;
665 }
666
667 gusLanguageID = UserGetLanguageID();
668
669 return STATUS_SUCCESS;
670 }
671
672 /* EOF */