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
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
);
21 HANDLE GlobalUserHeap
= NULL
;
22 PSECTION_OBJECT GlobalUserHeapSection
= NULL
;
24 PSERVERINFO gpsi
= NULL
; // Global User Server Information.
27 PPROCESSINFO ppiScrnSaver
;
29 extern ULONG_PTR Win32kSSDT
[];
30 extern UCHAR Win32kSSPT
[];
31 extern ULONG Win32kNumberOfSysCalls
;
36 DbgPreServiceHook(ULONG ulSyscallId
, PULONG_PTR pulArguments
)
38 GdiDbgPreServiceHook(ulSyscallId
, pulArguments
);
39 UserDbgPreServiceHook(ulSyscallId
, pulArguments
);
44 DbgPostServiceHook(ULONG ulSyscallId
, ULONG_PTR ulResult
)
46 ulResult
= GdiDbgPostServiceHook(ulSyscallId
, ulResult
);
47 ulResult
= UserDbgPostServiceHook(ulSyscallId
, ulResult
);
54 Win32kProcessCallback(struct _EPROCESS
*Process
,
57 PPROCESSINFO ppiCurrent
;
58 DECLARE_RETURN(NTSTATUS
);
68 PVOID UserBase
= NULL
;
69 PRTL_USER_PROCESS_PARAMETERS pParams
= Process
->Peb
->ProcessParameters
;
72 ASSERT(PsGetProcessWin32Process(Process
) == NULL
);
74 ppiCurrent
= ExAllocatePoolWithTag(NonPagedPool
,
78 if (ppiCurrent
== NULL
)
80 ERR_CH(UserProcess
, "Failed to allocate ppi for PID:0x%lx\n", HandleToUlong(Process
->UniqueProcessId
));
81 RETURN( STATUS_NO_MEMORY
);
84 RtlZeroMemory(ppiCurrent
, sizeof(PROCESSINFO
));
86 PsSetProcessWin32Process(Process
, ppiCurrent
);
89 DbgInitDebugChannels();
92 TRACE_CH(UserProcess
,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent
, HandleToUlong(Process
->UniqueProcessId
));
94 /* map the global heap into the process */
96 Status
= MmMapViewOfSection(GlobalUserHeapSection
,
97 PsGetCurrentProcess(),
105 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
106 if (!NT_SUCCESS(Status
))
108 TRACE_CH(UserProcess
,"Failed to map the global heap! 0x%x\n", Status
);
111 ppiCurrent
->HeapMappings
.Next
= NULL
;
112 ppiCurrent
->HeapMappings
.KernelMapping
= (PVOID
)GlobalUserHeap
;
113 ppiCurrent
->HeapMappings
.UserMapping
= UserBase
;
114 ppiCurrent
->HeapMappings
.Count
= 1;
116 InitializeListHead(&ppiCurrent
->MenuListHead
);
118 InitializeListHead(&ppiCurrent
->GDIBrushAttrFreeList
);
119 InitializeListHead(&ppiCurrent
->GDIDcAttrFreeList
);
121 InitializeListHead(&ppiCurrent
->PrivateFontListHead
);
122 ExInitializeFastMutex(&ppiCurrent
->PrivateFontListLock
);
124 InitializeListHead(&ppiCurrent
->DriverObjListHead
);
125 ExInitializeFastMutex(&ppiCurrent
->DriverObjListLock
);
127 ppiCurrent
->KeyboardLayout
= W32kGetDefaultKeyLayout();
128 if (!EngCreateEvent((PEVENT
*)&ppiCurrent
->InputIdleEvent
))
133 KeInitializeEvent(ppiCurrent
->InputIdleEvent
, NotificationEvent
, FALSE
);
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
;
141 ppiCurrent
->peProcess
= Process
;
142 /* setup process flags */
143 ppiCurrent
->W32PF_flags
= W32PF_THREADCONNECTED
;
146 pParams
->WindowFlags
& STARTF_SCRNSAVER
)
148 ppiScrnSaver
= ppiCurrent
;
149 ppiCurrent
->W32PF_flags
|= W32PF_SCREENSAVER
;
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
);
162 /* Get the Win32 Process */
163 ppiCurrent
= PsGetProcessWin32Process(Process
);
167 TRACE_CH(UserProcess
, "Destroying ppi 0x%p\n", ppiCurrent
);
168 ppiCurrent
->W32PF_flags
|= W32PF_TERMINATED
;
170 if (ppiScrnSaver
== ppiCurrent
)
173 if (ppiCurrent
->InputIdleEvent
)
175 EngFreeMem(ppiCurrent
->InputIdleEvent
);
176 ppiCurrent
->InputIdleEvent
= NULL
;
179 IntCleanupMenus(Process
, ppiCurrent
);
180 IntCleanupCurIcons(Process
, ppiCurrent
);
183 GDI_CleanupForProcess(Process
);
185 co_IntGraphicsCheck(FALSE
);
188 * Deregister logon application automatically
190 if(LogonProcess
== ppiCurrent
)
195 /* Close the startup desktop */
196 if(ppiCurrent
->rpdeskStartup
)
197 ObDereferenceObject(ppiCurrent
->rpdeskStartup
);
198 if(ppiCurrent
->hdeskStartup
)
199 ZwClose(ppiCurrent
->hdeskStartup
);
201 /* Close the current window station */
202 UserSetProcessWindowStation(NULL
);
204 /* Destroy GDI pools */
205 GdiPoolDestroy(ppiCurrent
->pPoolDcAttr
);
206 GdiPoolDestroy(ppiCurrent
->pPoolBrushAttr
);
207 GdiPoolDestroy(ppiCurrent
->pPoolRgnAttr
);
209 if (gppiInputProvider
== ppiCurrent
) gppiInputProvider
= NULL
;
211 TRACE_CH(UserProcess
,"Freeing ppi 0x%p\n", ppiCurrent
);
213 /* Ftee the PROCESSINFO */
214 PsSetProcessWin32Process(Process
, NULL
);
215 ExFreePoolWithTag(ppiCurrent
, USERTAG_PROCESSINFO
);
218 RETURN( STATUS_SUCCESS
);
226 UserCreateThreadInfo(struct _ETHREAD
*Thread
)
228 struct _EPROCESS
*Process
;
230 PTHREADINFO ptiCurrent
;
232 NTSTATUS Status
= STATUS_SUCCESS
;
235 Process
= Thread
->ThreadsProcess
;
237 pTeb
= NtCurrentTeb();
241 ptiCurrent
= ExAllocatePoolWithTag(NonPagedPool
,
244 if (ptiCurrent
== NULL
)
246 ERR_CH(UserThread
, "Failed to allocate pti for TID %p\n", Thread
->Cid
.UniqueThread
);
247 return STATUS_NO_MEMORY
;
250 RtlZeroMemory(ptiCurrent
, sizeof(THREADINFO
));
252 PsSetThreadWin32Thread(Thread
, ptiCurrent
);
253 pTeb
->Win32ThreadInfo
= ptiCurrent
;
254 ptiCurrent
->pClientInfo
= (PCLIENTINFO
)pTeb
->Win32ClientInfo
;
256 TRACE_CH(UserThread
, "Allocated pti 0x%p for TID %p\n", ptiCurrent
, Thread
->Cid
.UniqueThread
);
258 /* Initialize the THREADINFO */
259 InitializeListHead(&ptiCurrent
->WindowListHead
);
260 InitializeListHead(&ptiCurrent
->W32CallbackListHead
);
261 InitializeListHead(&ptiCurrent
->PtiLink
);
262 for (i
= 0; i
< NB_HOOKS
; i
++)
264 InitializeListHead(&ptiCurrent
->aphkStart
[i
]);
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
)
274 ERR_CH(UserThread
,"Failed to allocate message loop\n");
275 Status
= STATUS_NO_MEMORY
;
278 ptiCurrent
->KeyboardLayout
= W32kGetDefaultKeyLayout();
279 if (ptiCurrent
->KeyboardLayout
)
280 UserReferenceObject(ptiCurrent
->KeyboardLayout
);
281 ptiCurrent
->TIF_flags
&= ~TIF_INCLEANUP
;
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
)
291 pci
->hKL
= ptiCurrent
->KeyboardLayout
->hkl
;
292 pci
->CodePage
= ptiCurrent
->KeyboardLayout
->CodePage
;
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
)
299 HWINSTA hWinSta
= NULL
;
301 UNICODE_STRING DesktopPath
;
303 PRTL_USER_PROCESS_PARAMETERS ProcessParams
;
306 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
307 * info structure. See documentation of CreateProcess()
309 ProcessParams
= pTeb
->ProcessEnvironmentBlock
->ProcessParameters
;
311 Status
= STATUS_UNSUCCESSFUL
;
312 if(ProcessParams
&& ProcessParams
->DesktopInfo
.Length
> 0)
314 Status
= IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath
, &ProcessParams
->DesktopInfo
);
316 if(!NT_SUCCESS(Status
))
318 RtlInitUnicodeString(&DesktopPath
, NULL
);
321 Status
= IntParseDesktopPath(Process
,
326 if (DesktopPath
.Buffer
)
327 ExFreePoolWithTag(DesktopPath
.Buffer
, TAG_STRING
);
329 if(!NT_SUCCESS(Status
))
331 ERR_CH(UserThread
, "Failed to assign default dekstop and winsta to process\n");
335 if(!UserSetProcessWindowStation(hWinSta
))
337 Status
= STATUS_UNSUCCESSFUL
;
338 ERR_CH(UserThread
,"Failed to set initial process winsta\n");
342 /* Validate the new desktop. */
343 Status
= IntValidateDesktopHandle(hDesk
, UserMode
, 0, &pdesk
);
344 if(!NT_SUCCESS(Status
))
346 ERR_CH(UserThread
,"Failed to validate initial desktop handle\n");
350 /* Store the parsed desktop as the initial desktop */
351 ptiCurrent
->ppi
->hdeskStartup
= hDesk
;
352 ptiCurrent
->ppi
->rpdeskStartup
= pdesk
;
355 if (ptiCurrent
->ppi
->hdeskStartup
!= NULL
)
357 if (!IntSetThreadDesktop(ptiCurrent
->ppi
->hdeskStartup
, FALSE
))
359 ERR_CH(UserThread
,"Failed to set thread desktop\n");
360 Status
= STATUS_UNSUCCESSFUL
;
365 /* mark the thread as fully initialized */
366 ptiCurrent
->TIF_flags
|= TIF_GUITHREADINITIALIZED
;
367 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
369 return STATUS_SUCCESS
;
372 ERR_CH(UserThread
,"UserCreateThreadInfo failed! Freeing pti 0x%p for TID %p\n", ptiCurrent
, Thread
->Cid
.UniqueThread
);
373 UserDestroyThreadInfo(Thread
);
379 UserDestroyThreadInfo(struct _ETHREAD
*Thread
)
382 PSINGLE_LIST_ENTRY psle
;
383 PPROCESSINFO ppiCurrent
;
384 struct _EPROCESS
*Process
;
385 PTHREADINFO ptiCurrent
;
387 Process
= Thread
->ThreadsProcess
;
389 /* Get the Win32 Thread */
390 ptiCurrent
= PsGetThreadWin32Thread(Thread
);
394 TRACE_CH(UserThread
,"Destroying pti 0x%p\n", ptiCurrent
);
396 ptiCurrent
->TIF_flags
|= TIF_INCLEANUP
;
397 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
399 ppiCurrent
= ptiCurrent
->ppi
;
402 /* Decrement thread count and check if its 0 */
403 ppiCurrent
->cThreads
--;
405 if(ptiCurrent
->TIF_flags
& TIF_GUITHREADINITIALIZED
)
407 /* Do now some process cleanup that requires a valid win32 thread */
408 if(ptiCurrent
->ppi
->cThreads
== 0)
410 /* Check if we have registered the user api hook */
411 if(ptiCurrent
->ppi
== ppiUahServer
)
413 /* Unregister the api hook */
414 UserUnregisterUserApiHook();
417 /* Notify logon application to restart shell if needed */
418 if(ptiCurrent
->pDeskInfo
)
420 if(ptiCurrent
->pDeskInfo
->ppiShellProcess
== ppiCurrent
)
422 DWORD ExitCode
= PsGetProcessExitStatus(Process
);
424 TRACE_CH(UserProcess
, "Shell process is exiting (%lu)\n", ExitCode
);
426 UserPostMessage(hwndSAS
,
431 ptiCurrent
->pDeskInfo
->ppiShellProcess
= NULL
;
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
);
443 if (IsListEmpty(&ptiCurrent->WindowListHead))
445 ERR_CH(UserThread,"Thread Window List is Empty!\n");
448 co_DestroyThreadWindows(Thread
);
450 if (ppiCurrent
&& ppiCurrent
->ptiList
== ptiCurrent
&& !ptiCurrent
->ptiSibling
)
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
;
458 IntBlockInput(ptiCurrent
, FALSE
);
459 IntCleanupThreadCallbacks(ptiCurrent
);
461 /* cleanup user object references stack */
462 psle
= PopEntryList(&ptiCurrent
->ReferencesList
);
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
);
469 psle
= PopEntryList(&ptiCurrent
->ReferencesList
);
473 if (ptiCurrent
->pqAttach
&& ptiCurrent
->MessageQueue
)
476 ptiTo
= PsGetThreadWin32Thread(ptiCurrent
->MessageQueue
->Thread
);
477 TRACE_CH(UserThread
,"Attached Thread is getting switched!\n");
478 UserAttachThreadInput( ptiCurrent
, ptiTo
, FALSE
);
481 /* Free the message queue */
482 if(ptiCurrent
->MessageQueue
)
484 MsqDestroyMessageQueue(ptiCurrent
->MessageQueue
);
487 /* Find the THREADINFO in the PROCESSINFO's list */
488 ppti
= &ppiCurrent
->ptiList
;
489 while (*ppti
!= NULL
&& *ppti
!= ptiCurrent
)
491 ppti
= &((*ppti
)->ptiSibling
);
494 /* we must have found it */
495 ASSERT(*ppti
== ptiCurrent
);
497 /* Remove it from the list */
498 *ppti
= ptiCurrent
->ptiSibling
;
500 if (ptiCurrent
->KeyboardLayout
)
501 UserDereferenceObject(ptiCurrent
->KeyboardLayout
);
503 IntSetThreadDesktop(NULL
, TRUE
);
505 TRACE_CH(UserThread
,"Freeing pti 0x%p\n", ptiCurrent
);
507 /* Free the THREADINFO */
508 PsSetThreadWin32Thread(Thread
, NULL
);
509 ExFreePoolWithTag(ptiCurrent
, USERTAG_THREADINFO
);
511 return STATUS_SUCCESS
;
516 Win32kThreadCallback(struct _ETHREAD
*Thread
,
517 PSW32THREADCALLOUTTYPE Type
)
521 UserEnterExclusive();
523 ASSERT(NtCurrentTeb());
525 if (Type
== PsW32ThreadCalloutInitialize
)
527 ASSERT(PsGetThreadWin32Thread(Thread
) == NULL
);
528 Status
= UserCreateThreadInfo(Thread
);
532 ASSERT(PsGetThreadWin32Thread(Thread
) != NULL
);
533 Status
= UserDestroyThreadInfo(Thread
);
542 C_ASSERT(sizeof(SERVERINFO
) <= PAGE_SIZE
);
548 if (!NT_SUCCESS(Status)) \
550 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
555 * This definition doesn't work
561 IN PDRIVER_OBJECT DriverObject
,
562 IN PUNICODE_STRING RegistryPath
)
566 WIN32_CALLOUTS_FPNS CalloutData
= {0};
567 PVOID GlobalUserHeapBase
= NULL
;
570 * Register user mode call interface
571 * (system service table index = 1)
573 Result
= KeAddSystemServiceTable(Win32kSSDT
,
575 Win32kNumberOfSysCalls
,
580 DPRINT1("Adding system services failed!\n");
581 return STATUS_UNSUCCESSFUL
;
584 hModuleWin
= MmPageEntireDriver(DriverEntry
);
585 DPRINT("Win32k hInstance 0x%p!\n",hModuleWin
);
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
;
597 /* Register our per-process and per-thread structures. */
598 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS
)&CalloutData
);
600 /* Register service hook callbacks */
602 KdSystemDebugControl('CsoR', DbgPreServiceHook
, ID_Win32PreServiceHook
, 0, 0, 0, 0);
603 KdSystemDebugControl('CsoR', DbgPostServiceHook
, ID_Win32PostServiceHook
, 0, 0, 0, 0);
606 /* Create the global USER heap */
607 GlobalUserHeap
= UserCreateHeap(&GlobalUserHeapSection
,
609 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
610 if (GlobalUserHeap
== NULL
)
612 DPRINT1("Failed to initialize the global heap!\n");
613 return STATUS_UNSUCCESSFUL
;
616 /* Allocate global server info structure */
617 gpsi
= UserHeapAlloc(sizeof(SERVERINFO
));
620 DPRINT1("Failed allocate server info structure!\n");
621 return STATUS_UNSUCCESSFUL
;
624 RtlZeroMemory(gpsi
, sizeof(SERVERINFO
));
625 DPRINT("Global Server Data -> %p\n", gpsi
);
627 NT_ROF(InitGdiHandleTable());
628 NT_ROF(InitPaletteImpl());
630 /* Create stock objects, ie. precreated objects commonly
631 used by win32 applications */
632 CreateStockObjects();
633 CreateSysColorObjects();
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());
649 /* Initialize FreeType library */
650 if (!InitFontSupport())
652 DPRINT1("Unable to initialize font support\n");
656 gusLanguageID
= UserGetLanguageID();
658 return STATUS_SUCCESS
;