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
18 PGDI_HANDLE_TABLE NTAPI
GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
);
19 BOOL NTAPI
GDI_CleanupForProcess (struct _EPROCESS
*Process
);
20 NTSTATUS NTAPI
UserDestroyThreadInfo(struct _ETHREAD
*Thread
);
22 HANDLE GlobalUserHeap
= NULL
;
23 PSECTION_OBJECT GlobalUserHeapSection
= NULL
;
25 PSERVERINFO gpsi
= NULL
; // Global User Server Information.
28 PPROCESSINFO ppiScrnSaver
;
30 extern ULONG_PTR Win32kSSDT
[];
31 extern UCHAR Win32kSSPT
[];
32 extern ULONG Win32kNumberOfSysCalls
;
37 DbgPreServiceHook(ULONG ulSyscallId
, PULONG_PTR pulArguments
)
39 GdiDbgPreServiceHook(ulSyscallId
, pulArguments
);
40 UserDbgPreServiceHook(ulSyscallId
, pulArguments
);
45 DbgPostServiceHook(ULONG ulSyscallId
, ULONG_PTR ulResult
)
47 ulResult
= GdiDbgPostServiceHook(ulSyscallId
, ulResult
);
48 ulResult
= UserDbgPostServiceHook(ulSyscallId
, ulResult
);
55 Win32kProcessCallback(struct _EPROCESS
*Process
,
58 PPROCESSINFO ppiCurrent
;
59 DECLARE_RETURN(NTSTATUS
);
69 PVOID UserBase
= NULL
;
70 PRTL_USER_PROCESS_PARAMETERS pParams
= Process
->Peb
->ProcessParameters
;
73 ASSERT(PsGetProcessWin32Process(Process
) == NULL
);
75 ppiCurrent
= ExAllocatePoolWithTag(NonPagedPool
,
79 if (ppiCurrent
== NULL
)
81 ERR_CH(UserProcess
, "Failed to allocate ppi for PID:0x%lx\n", HandleToUlong(Process
->UniqueProcessId
));
82 RETURN( STATUS_NO_MEMORY
);
85 RtlZeroMemory(ppiCurrent
, sizeof(PROCESSINFO
));
87 PsSetProcessWin32Process(Process
, ppiCurrent
);
90 DbgInitDebugChannels();
92 KdRosRegisterCliCallback(DbgGdiKdbgCliCallback
);
96 TRACE_CH(UserProcess
,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent
, HandleToUlong(Process
->UniqueProcessId
));
98 /* map the global heap into the process */
100 Status
= MmMapViewOfSection(GlobalUserHeapSection
,
101 PsGetCurrentProcess(),
109 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
110 if (!NT_SUCCESS(Status
))
112 TRACE_CH(UserProcess
,"Failed to map the global heap! 0x%x\n", Status
);
115 ppiCurrent
->HeapMappings
.Next
= NULL
;
116 ppiCurrent
->HeapMappings
.KernelMapping
= (PVOID
)GlobalUserHeap
;
117 ppiCurrent
->HeapMappings
.UserMapping
= UserBase
;
118 ppiCurrent
->HeapMappings
.Count
= 1;
120 InitializeListHead(&ppiCurrent
->MenuListHead
);
122 InitializeListHead(&ppiCurrent
->GDIBrushAttrFreeList
);
123 InitializeListHead(&ppiCurrent
->GDIDcAttrFreeList
);
125 InitializeListHead(&ppiCurrent
->PrivateFontListHead
);
126 ExInitializeFastMutex(&ppiCurrent
->PrivateFontListLock
);
128 InitializeListHead(&ppiCurrent
->DriverObjListHead
);
129 ExInitializeFastMutex(&ppiCurrent
->DriverObjListLock
);
131 ppiCurrent
->KeyboardLayout
= W32kGetDefaultKeyLayout();
132 if (!EngCreateEvent((PEVENT
*)&ppiCurrent
->InputIdleEvent
))
137 KeInitializeEvent(ppiCurrent
->InputIdleEvent
, NotificationEvent
, FALSE
);
140 /* map the gdi handle table to user land */
141 Process
->Peb
->GdiSharedHandleTable
= GDI_MapHandleTable(Process
);
142 Process
->Peb
->GdiDCAttributeList
= GDI_BATCH_LIMIT
;
143 pParams
= Process
->Peb
->ProcessParameters
;
145 ppiCurrent
->peProcess
= Process
;
146 /* setup process flags */
147 ppiCurrent
->W32PF_flags
= W32PF_THREADCONNECTED
;
150 pParams
->WindowFlags
& STARTF_SCRNSAVER
)
152 ppiScrnSaver
= ppiCurrent
;
153 ppiCurrent
->W32PF_flags
|= W32PF_SCREENSAVER
;
156 /* Create pools for GDI object attributes */
157 ppiCurrent
->pPoolDcAttr
= GdiPoolCreate(sizeof(DC_ATTR
), 'acdG');
158 ppiCurrent
->pPoolBrushAttr
= GdiPoolCreate(sizeof(BRUSH_ATTR
), 'arbG');
159 ppiCurrent
->pPoolRgnAttr
= GdiPoolCreate(sizeof(RGN_ATTR
), 'agrG');
160 ASSERT(ppiCurrent
->pPoolDcAttr
);
161 ASSERT(ppiCurrent
->pPoolBrushAttr
);
162 ASSERT(ppiCurrent
->pPoolRgnAttr
);
166 /* Get the Win32 Process */
167 ppiCurrent
= PsGetProcessWin32Process(Process
);
171 TRACE_CH(UserProcess
, "Destroying ppi 0x%p\n", ppiCurrent
);
172 ppiCurrent
->W32PF_flags
|= W32PF_TERMINATED
;
174 if (ppiScrnSaver
== ppiCurrent
)
177 if (ppiCurrent
->InputIdleEvent
)
179 EngFreeMem(ppiCurrent
->InputIdleEvent
);
180 ppiCurrent
->InputIdleEvent
= NULL
;
183 IntCleanupMenus(Process
, ppiCurrent
);
184 IntCleanupCurIcons(Process
, ppiCurrent
);
187 GDI_CleanupForProcess(Process
);
189 co_IntGraphicsCheck(FALSE
);
192 * Deregister logon application automatically
194 if(LogonProcess
== ppiCurrent
)
199 /* Close the startup desktop */
200 if(ppiCurrent
->rpdeskStartup
)
201 ObDereferenceObject(ppiCurrent
->rpdeskStartup
);
202 if(ppiCurrent
->hdeskStartup
)
203 ZwClose(ppiCurrent
->hdeskStartup
);
205 /* Close the current window station */
206 UserSetProcessWindowStation(NULL
);
208 /* Destroy GDI pools */
209 GdiPoolDestroy(ppiCurrent
->pPoolDcAttr
);
210 GdiPoolDestroy(ppiCurrent
->pPoolBrushAttr
);
211 GdiPoolDestroy(ppiCurrent
->pPoolRgnAttr
);
213 if (gppiInputProvider
== ppiCurrent
) gppiInputProvider
= NULL
;
215 TRACE_CH(UserProcess
,"Freeing ppi 0x%p\n", ppiCurrent
);
217 /* Ftee the PROCESSINFO */
218 PsSetProcessWin32Process(Process
, NULL
);
219 ExFreePoolWithTag(ppiCurrent
, USERTAG_PROCESSINFO
);
222 RETURN( STATUS_SUCCESS
);
230 UserCreateThreadInfo(struct _ETHREAD
*Thread
)
232 struct _EPROCESS
*Process
;
234 PTHREADINFO ptiCurrent
;
236 NTSTATUS Status
= STATUS_SUCCESS
;
239 Process
= Thread
->ThreadsProcess
;
241 pTeb
= NtCurrentTeb();
245 ptiCurrent
= ExAllocatePoolWithTag(NonPagedPool
,
248 if (ptiCurrent
== NULL
)
250 ERR_CH(UserThread
, "Failed to allocate pti for TID %p\n", Thread
->Cid
.UniqueThread
);
251 return STATUS_NO_MEMORY
;
254 TRACE_CH(UserThread
,"Create pti 0x%p eThread 0x%p\n", ptiCurrent
, Thread
);
256 RtlZeroMemory(ptiCurrent
, sizeof(THREADINFO
));
258 PsSetThreadWin32Thread(Thread
, ptiCurrent
);
259 pTeb
->Win32ThreadInfo
= ptiCurrent
;
260 ptiCurrent
->pClientInfo
= (PCLIENTINFO
)pTeb
->Win32ClientInfo
;
262 TRACE_CH(UserThread
, "Allocated pti 0x%p for TID %p\n", ptiCurrent
, Thread
->Cid
.UniqueThread
);
264 /* Initialize the THREADINFO */
265 InitializeListHead(&ptiCurrent
->WindowListHead
);
266 InitializeListHead(&ptiCurrent
->W32CallbackListHead
);
267 InitializeListHead(&ptiCurrent
->PtiLink
);
268 for (i
= 0; i
< NB_HOOKS
; i
++)
270 InitializeListHead(&ptiCurrent
->aphkStart
[i
]);
272 ptiCurrent
->pEThread
= Thread
;
273 ptiCurrent
->ppi
= PsGetCurrentProcessWin32Process();
274 ptiCurrent
->ptiSibling
= ptiCurrent
->ppi
->ptiList
;
275 ptiCurrent
->ppi
->ptiList
= ptiCurrent
;
276 ptiCurrent
->ppi
->cThreads
++;
277 ptiCurrent
->MessageQueue
= MsqCreateMessageQueue(ptiCurrent
);
278 if(ptiCurrent
->MessageQueue
== NULL
)
280 ERR_CH(UserThread
,"Failed to allocate message loop\n");
281 Status
= STATUS_NO_MEMORY
;
284 ptiCurrent
->KeyboardLayout
= W32kGetDefaultKeyLayout();
285 if (ptiCurrent
->KeyboardLayout
)
286 UserReferenceObject(ptiCurrent
->KeyboardLayout
);
287 ptiCurrent
->TIF_flags
&= ~TIF_INCLEANUP
;
289 /* Initialize the CLIENTINFO */
290 pci
= (PCLIENTINFO
)pTeb
->Win32ClientInfo
;
291 RtlZeroMemory(pci
, sizeof(CLIENTINFO
));
292 pci
->ppi
= ptiCurrent
->ppi
;
293 pci
->fsHooks
= ptiCurrent
->fsHooks
;
294 pci
->dwTIFlags
= ptiCurrent
->TIF_flags
;
295 if (ptiCurrent
->KeyboardLayout
)
297 pci
->hKL
= ptiCurrent
->KeyboardLayout
->hkl
;
298 pci
->CodePage
= ptiCurrent
->KeyboardLayout
->CodePage
;
301 /* Assign a default window station and desktop to the process */
302 /* Do not try to open a desktop or window station before winlogon initializes */
303 if(ptiCurrent
->ppi
->hdeskStartup
== NULL
&& LogonProcess
!= NULL
)
305 HWINSTA hWinSta
= NULL
;
307 UNICODE_STRING DesktopPath
;
309 PRTL_USER_PROCESS_PARAMETERS ProcessParams
;
312 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
313 * info structure. See documentation of CreateProcess()
315 ProcessParams
= pTeb
->ProcessEnvironmentBlock
->ProcessParameters
;
317 Status
= STATUS_UNSUCCESSFUL
;
318 if(ProcessParams
&& ProcessParams
->DesktopInfo
.Length
> 0)
320 Status
= IntSafeCopyUnicodeStringTerminateNULL(&DesktopPath
, &ProcessParams
->DesktopInfo
);
322 if(!NT_SUCCESS(Status
))
324 RtlInitUnicodeString(&DesktopPath
, NULL
);
327 Status
= IntParseDesktopPath(Process
,
332 if (DesktopPath
.Buffer
)
333 ExFreePoolWithTag(DesktopPath
.Buffer
, TAG_STRING
);
335 if(!NT_SUCCESS(Status
))
337 ERR_CH(UserThread
, "Failed to assign default dekstop and winsta to process\n");
341 if(!UserSetProcessWindowStation(hWinSta
))
343 Status
= STATUS_UNSUCCESSFUL
;
344 ERR_CH(UserThread
,"Failed to set initial process winsta\n");
348 /* Validate the new desktop. */
349 Status
= IntValidateDesktopHandle(hDesk
, UserMode
, 0, &pdesk
);
350 if(!NT_SUCCESS(Status
))
352 ERR_CH(UserThread
,"Failed to validate initial desktop handle\n");
356 /* Store the parsed desktop as the initial desktop */
357 ptiCurrent
->ppi
->hdeskStartup
= hDesk
;
358 ptiCurrent
->ppi
->rpdeskStartup
= pdesk
;
361 if (ptiCurrent
->ppi
->hdeskStartup
!= NULL
)
363 if (!IntSetThreadDesktop(ptiCurrent
->ppi
->hdeskStartup
, FALSE
))
365 ERR_CH(UserThread
,"Failed to set thread desktop\n");
366 Status
= STATUS_UNSUCCESSFUL
;
371 /* mark the thread as fully initialized */
372 ptiCurrent
->TIF_flags
|= TIF_GUITHREADINITIALIZED
;
373 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
375 return STATUS_SUCCESS
;
378 ERR_CH(UserThread
,"UserCreateThreadInfo failed! Freeing pti 0x%p for TID %p\n", ptiCurrent
, Thread
->Cid
.UniqueThread
);
379 UserDestroyThreadInfo(Thread
);
385 UserDestroyThreadInfo(struct _ETHREAD
*Thread
)
388 PSINGLE_LIST_ENTRY psle
;
389 PPROCESSINFO ppiCurrent
;
390 struct _EPROCESS
*Process
;
391 PTHREADINFO ptiCurrent
;
393 Process
= Thread
->ThreadsProcess
;
395 /* Get the Win32 Thread */
396 ptiCurrent
= PsGetThreadWin32Thread(Thread
);
400 TRACE_CH(UserThread
,"Destroying pti 0x%p eThread 0x%p\n", ptiCurrent
, Thread
);
402 ptiCurrent
->TIF_flags
|= TIF_INCLEANUP
;
403 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
405 ppiCurrent
= ptiCurrent
->ppi
;
409 if (IsThreadAttach(ptiCurrent
))
411 PTHREADINFO ptiFrom
= IsThreadAttach(ptiCurrent
);
412 TRACE_CH(UserThread
,"Attached Thread ptiTo is getting switched!\n");
413 UserAttachThreadInput(ptiFrom
, ptiCurrent
, FALSE
);
417 if (ptiCurrent
->pqAttach
&& ptiCurrent
->MessageQueue
)
420 ptiTo
= PsGetThreadWin32Thread(ptiCurrent
->MessageQueue
->Thread
);
421 TRACE_CH(UserThread
,"Attached Thread ptiFrom is getting switched!\n");
422 if (ptiTo
) UserAttachThreadInput( ptiCurrent
, ptiTo
, FALSE
);
425 // eThread maybe okay but Win32Thread already made NULL!
426 ERR_CH(UserThread
,"Attached Thread ptiFrom did not switch due to ptiTo is NULL!\n");
430 /* Decrement thread count and check if its 0 */
431 ppiCurrent
->cThreads
--;
433 if(ptiCurrent
->TIF_flags
& TIF_GUITHREADINITIALIZED
)
435 /* Do now some process cleanup that requires a valid win32 thread */
436 if(ptiCurrent
->ppi
->cThreads
== 0)
438 /* Check if we have registered the user api hook */
439 if(ptiCurrent
->ppi
== ppiUahServer
)
441 /* Unregister the api hook */
442 UserUnregisterUserApiHook();
445 /* Notify logon application to restart shell if needed */
446 if(ptiCurrent
->pDeskInfo
)
448 if(ptiCurrent
->pDeskInfo
->ppiShellProcess
== ppiCurrent
)
450 DWORD ExitCode
= PsGetProcessExitStatus(Process
);
452 TRACE_CH(UserProcess
, "Shell process is exiting (%lu)\n", ExitCode
);
454 UserPostMessage(hwndSAS
,
459 ptiCurrent
->pDeskInfo
->ppiShellProcess
= NULL
;
464 DceFreeThreadDCE(ptiCurrent
);
465 HOOK_DestroyThreadHooks(Thread
);
466 EVENT_DestroyThreadEvents(Thread
);
467 DestroyTimersForThread(ptiCurrent
);
468 KeSetEvent(ptiCurrent
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
469 UnregisterThreadHotKeys(Thread
);
471 if (IsListEmpty(&ptiCurrent->WindowListHead))
473 ERR_CH(UserThread,"Thread Window List is Empty!\n");
476 co_DestroyThreadWindows(Thread
);
478 if (ppiCurrent
&& ppiCurrent
->ptiList
== ptiCurrent
&& !ptiCurrent
->ptiSibling
)
480 //ERR_CH(UserThread,"DestroyProcessClasses\n");
481 /* no process windows should exist at this point, or the function will assert! */
482 DestroyProcessClasses(ppiCurrent
);
483 ppiCurrent
->W32PF_flags
&= ~W32PF_CLASSESREGISTERED
;
486 IntBlockInput(ptiCurrent
, FALSE
);
487 IntCleanupThreadCallbacks(ptiCurrent
);
489 /* cleanup user object references stack */
490 psle
= PopEntryList(&ptiCurrent
->ReferencesList
);
493 PUSER_REFERENCE_ENTRY ref
= CONTAINING_RECORD(psle
, USER_REFERENCE_ENTRY
, Entry
);
494 TRACE_CH(UserThread
,"thread clean: remove reference obj 0x%p\n",ref
->obj
);
495 UserDereferenceObject(ref
->obj
);
497 psle
= PopEntryList(&ptiCurrent
->ReferencesList
);
501 /* Free the message queue */
502 if (ptiCurrent
->MessageQueue
)
504 MsqDestroyMessageQueue(ptiCurrent
);
507 /* Find the THREADINFO in the PROCESSINFO's list */
508 ppti
= &ppiCurrent
->ptiList
;
509 while (*ppti
!= NULL
&& *ppti
!= ptiCurrent
)
511 ppti
= &((*ppti
)->ptiSibling
);
514 /* we must have found it */
515 ASSERT(*ppti
== ptiCurrent
);
517 /* Remove it from the list */
518 *ppti
= ptiCurrent
->ptiSibling
;
520 if (ptiCurrent
->KeyboardLayout
)
521 UserDereferenceObject(ptiCurrent
->KeyboardLayout
);
523 IntSetThreadDesktop(NULL
, TRUE
);
525 TRACE_CH(UserThread
,"Freeing pti 0x%p\n", ptiCurrent
);
527 /* Free the THREADINFO */
528 PsSetThreadWin32Thread(Thread
, NULL
);
529 ExFreePoolWithTag(ptiCurrent
, USERTAG_THREADINFO
);
531 return STATUS_SUCCESS
;
536 Win32kThreadCallback(struct _ETHREAD
*Thread
,
537 PSW32THREADCALLOUTTYPE Type
)
541 UserEnterExclusive();
543 ASSERT(NtCurrentTeb());
545 if (Type
== PsW32ThreadCalloutInitialize
)
547 ASSERT(PsGetThreadWin32Thread(Thread
) == NULL
);
548 Status
= UserCreateThreadInfo(Thread
);
552 ASSERT(PsGetThreadWin32Thread(Thread
) != NULL
);
553 Status
= UserDestroyThreadInfo(Thread
);
562 C_ASSERT(sizeof(SERVERINFO
) <= PAGE_SIZE
);
568 if (!NT_SUCCESS(Status)) \
570 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
575 * This definition doesn't work
581 IN PDRIVER_OBJECT DriverObject
,
582 IN PUNICODE_STRING RegistryPath
)
586 WIN32_CALLOUTS_FPNS CalloutData
= {0};
587 PVOID GlobalUserHeapBase
= NULL
;
590 * Register user mode call interface
591 * (system service table index = 1)
593 Result
= KeAddSystemServiceTable(Win32kSSDT
,
595 Win32kNumberOfSysCalls
,
600 DPRINT1("Adding system services failed!\n");
601 return STATUS_UNSUCCESSFUL
;
604 hModuleWin
= MmPageEntireDriver(DriverEntry
);
605 DPRINT("Win32k hInstance 0x%p!\n",hModuleWin
);
607 /* Register Object Manager Callbacks */
608 CalloutData
.WindowStationParseProcedure
= IntWinStaObjectParse
;
609 CalloutData
.WindowStationDeleteProcedure
= IntWinStaObjectDelete
;
610 CalloutData
.DesktopDeleteProcedure
= IntDesktopObjectDelete
;
611 CalloutData
.ProcessCallout
= Win32kProcessCallback
;
612 CalloutData
.ThreadCallout
= Win32kThreadCallback
;
613 CalloutData
.BatchFlushRoutine
= NtGdiFlushUserBatch
;
614 CalloutData
.DesktopOkToCloseProcedure
= IntDesktopOkToClose
;
615 CalloutData
.WindowStationOkToCloseProcedure
= IntWinstaOkToClose
;
617 /* Register our per-process and per-thread structures. */
618 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS
)&CalloutData
);
620 /* Register service hook callbacks */
622 KdSystemDebugControl('CsoR', DbgPreServiceHook
, ID_Win32PreServiceHook
, 0, 0, 0, 0);
623 KdSystemDebugControl('CsoR', DbgPostServiceHook
, ID_Win32PostServiceHook
, 0, 0, 0, 0);
626 /* Create the global USER heap */
627 GlobalUserHeap
= UserCreateHeap(&GlobalUserHeapSection
,
629 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
630 if (GlobalUserHeap
== NULL
)
632 DPRINT1("Failed to initialize the global heap!\n");
633 return STATUS_UNSUCCESSFUL
;
636 /* Allocate global server info structure */
637 gpsi
= UserHeapAlloc(sizeof(SERVERINFO
));
640 DPRINT1("Failed allocate server info structure!\n");
641 return STATUS_UNSUCCESSFUL
;
644 RtlZeroMemory(gpsi
, sizeof(SERVERINFO
));
645 DPRINT("Global Server Data -> %p\n", gpsi
);
647 NT_ROF(InitGdiHandleTable());
648 NT_ROF(InitPaletteImpl());
650 /* Create stock objects, ie. precreated objects commonly
651 used by win32 applications */
652 CreateStockObjects();
653 CreateSysColorObjects();
655 NT_ROF(InitBrushImpl());
656 NT_ROF(InitPDEVImpl());
657 NT_ROF(InitLDEVImpl());
658 NT_ROF(InitDeviceImpl());
659 NT_ROF(InitDcImpl());
660 NT_ROF(InitUserImpl());
661 NT_ROF(InitWindowStationImpl());
662 NT_ROF(InitDesktopImpl());
663 NT_ROF(InitInputImpl());
664 NT_ROF(InitKeyboardImpl());
665 NT_ROF(MsqInitializeImpl());
666 NT_ROF(InitTimerImpl());
667 NT_ROF(InitDCEImpl());
669 /* Initialize FreeType library */
670 if (!InitFontSupport())
672 DPRINT1("Unable to initialize font support\n");
676 gusLanguageID
= UserGetLanguageID();
678 return STATUS_SUCCESS
;