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
10 #include <include/napi.h>
17 PGDI_HANDLE_TABLE NTAPI
GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT
*SectionObject
);
18 BOOL NTAPI
GDI_CleanupForProcess (struct _EPROCESS
*Process
);
20 HANDLE GlobalUserHeap
= NULL
;
21 PSECTION_OBJECT GlobalUserHeapSection
= NULL
;
23 PSERVERINFO gpsi
= NULL
; // Global User Server Information.
26 PPROCESSINFO ppiScrnSaver
;
28 extern ULONG_PTR Win32kSSDT
[];
29 extern UCHAR Win32kSSPT
[];
30 extern ULONG Win32kNumberOfSysCalls
;
34 DbgPreServiceHook(ULONG ulSyscallId
, PULONG_PTR pulArguments
)
36 GdiDbgPreServiceHook(ulSyscallId
, pulArguments
);
37 UserDbgPreServiceHook(ulSyscallId
, pulArguments
);
42 DbgPostServiceHook(ULONG ulSyscallId
, ULONG_PTR ulResult
)
44 ulResult
= GdiDbgPostServiceHook(ulSyscallId
, ulResult
);
45 ulResult
= UserDbgPostServiceHook(ulSyscallId
, ulResult
);
51 Win32kProcessCallback(struct _EPROCESS
*Process
,
54 PPROCESSINFO ppiCurrent
;
55 DECLARE_RETURN(NTSTATUS
);
59 DPRINT("Enter Win32kProcessCallback\n");
66 PVOID UserBase
= NULL
;
67 PRTL_USER_PROCESS_PARAMETERS pParams
= Process
->Peb
->ProcessParameters
;
70 ASSERT(PsGetProcessWin32Process(Process
) == NULL
);
72 ppiCurrent
= ExAllocatePoolWithTag(NonPagedPool
,
76 if (ppiCurrent
== NULL
)
77 RETURN( STATUS_NO_MEMORY
);
79 RtlZeroMemory(ppiCurrent
, sizeof(PROCESSINFO
));
81 PsSetProcessWin32Process(Process
, ppiCurrent
);
84 DbgInitDebugChannels();
87 TRACE_PPI(ppiCurrent
, UserProcess
,"Allocated ppi for PID:%d\n", Process
->UniqueProcessId
);
89 /* map the global heap into the process */
91 Status
= MmMapViewOfSection(GlobalUserHeapSection
,
92 PsGetCurrentProcess(),
100 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
101 if (!NT_SUCCESS(Status
))
103 DPRINT1("Failed to map the global heap! 0x%x\n", Status
);
106 ppiCurrent
->HeapMappings
.Next
= NULL
;
107 ppiCurrent
->HeapMappings
.KernelMapping
= (PVOID
)GlobalUserHeap
;
108 ppiCurrent
->HeapMappings
.UserMapping
= UserBase
;
109 ppiCurrent
->HeapMappings
.Count
= 1;
111 InitializeListHead(&ppiCurrent
->MenuListHead
);
113 InitializeListHead(&ppiCurrent
->GDIBrushAttrFreeList
);
114 InitializeListHead(&ppiCurrent
->GDIDcAttrFreeList
);
116 InitializeListHead(&ppiCurrent
->PrivateFontListHead
);
117 ExInitializeFastMutex(&ppiCurrent
->PrivateFontListLock
);
119 InitializeListHead(&ppiCurrent
->DriverObjListHead
);
120 ExInitializeFastMutex(&ppiCurrent
->DriverObjListLock
);
122 ppiCurrent
->KeyboardLayout
= W32kGetDefaultKeyLayout();
123 EngCreateEvent((PEVENT
*)&ppiCurrent
->InputIdleEvent
);
124 KeInitializeEvent(ppiCurrent
->InputIdleEvent
, NotificationEvent
, FALSE
);
127 /* map the gdi handle table to user land */
128 Process
->Peb
->GdiSharedHandleTable
= GDI_MapHandleTable(Process
);
129 Process
->Peb
->GdiDCAttributeList
= GDI_BATCH_LIMIT
;
130 pParams
= Process
->Peb
->ProcessParameters
;
132 ppiCurrent
->peProcess
= Process
;
133 /* setup process flags */
134 ppiCurrent
->W32PF_flags
= W32PF_THREADCONNECTED
;
137 pParams
->WindowFlags
& STARTF_SCRNSAVER
)
139 ppiScrnSaver
= ppiCurrent
;
140 ppiCurrent
->W32PF_flags
|= W32PF_SCREENSAVER
;
143 /* Create pools for GDI object attributes */
144 ppiCurrent
->pPoolDcAttr
= GdiPoolCreate(sizeof(DC_ATTR
), 'acdG');
145 ppiCurrent
->pPoolBrushAttr
= GdiPoolCreate(sizeof(BRUSH_ATTR
), 'arbG');
146 ppiCurrent
->pPoolRgnAttr
= GdiPoolCreate(sizeof(RGN_ATTR
), 'agrG');
147 ASSERT(ppiCurrent
->pPoolDcAttr
);
148 ASSERT(ppiCurrent
->pPoolBrushAttr
);
149 ASSERT(ppiCurrent
->pPoolRgnAttr
);
153 /* Get the Win32 Process */
154 ppiCurrent
= PsGetProcessWin32Process(Process
);
158 TRACE_CH(UserProcess
, "Destroying W32 process PID:%d at IRQ level: %lu\n", Process
->UniqueProcessId
, KeGetCurrentIrql());
159 ppiCurrent
->W32PF_flags
|= W32PF_TERMINATED
;
161 if (ppiScrnSaver
== ppiCurrent
)
164 if (ppiCurrent
->InputIdleEvent
)
166 EngFreeMem(ppiCurrent
->InputIdleEvent
);
167 ppiCurrent
->InputIdleEvent
= NULL
;
170 IntCleanupMenus(Process
, ppiCurrent
);
171 IntCleanupCurIcons(Process
, ppiCurrent
);
173 /* no process windows should exist at this point, or the function will assert! */
174 DestroyProcessClasses(ppiCurrent
);
175 ppiCurrent
->W32PF_flags
&= ~W32PF_CLASSESREGISTERED
;
177 GDI_CleanupForProcess(Process
);
179 co_IntGraphicsCheck(FALSE
);
182 * Deregister logon application automatically
184 if(LogonProcess
== ppiCurrent
)
189 /* Close the startup desktop */
190 ASSERT(ppiCurrent
->rpdeskStartup
);
191 ASSERT(ppiCurrent
->hdeskStartup
);
192 ObDereferenceObject(ppiCurrent
->rpdeskStartup
);
193 ZwClose(ppiCurrent
->hdeskStartup
);
195 /* Close the current window station */
196 UserSetProcessWindowStation(NULL
);
198 /* Destroy GDI pools */
199 GdiPoolDestroy(ppiCurrent
->pPoolDcAttr
);
200 GdiPoolDestroy(ppiCurrent
->pPoolBrushAttr
);
201 GdiPoolDestroy(ppiCurrent
->pPoolRgnAttr
);
203 /* Ftee the PROCESSINFO */
204 PsSetProcessWin32Process(Process
, NULL
);
205 ExFreePoolWithTag(ppiCurrent
, USERTAG_PROCESSINFO
);
208 RETURN( STATUS_SUCCESS
);
212 DPRINT("Leave Win32kProcessCallback, ret=%i\n",_ret_
);
219 Win32kThreadCallback(struct _ETHREAD
*Thread
,
220 PSW32THREADCALLOUTTYPE Type
)
222 struct _EPROCESS
*Process
;
223 PTHREADINFO ptiCurrent
;
228 DPRINT("Enter Win32kThreadCallback\n");
229 UserEnterExclusive();
231 Process
= Thread
->ThreadsProcess
;
232 pTeb
= NtCurrentTeb();
236 if (Type
== PsW32ThreadCalloutInitialize
)
238 HWINSTA hWinSta
= NULL
;
241 PUNICODE_STRING DesktopPath
;
243 PRTL_USER_PROCESS_PARAMETERS ProcessParams
= Process
->Peb
->ProcessParameters
;
245 ASSERT(PsGetThreadWin32Thread(Thread
)==NULL
);
247 ptiCurrent
= ExAllocatePoolWithTag(NonPagedPool
,
250 if (ptiCurrent
== NULL
)
252 Status
= STATUS_NO_MEMORY
;
256 RtlZeroMemory(ptiCurrent
, sizeof(THREADINFO
));
258 PsSetThreadWin32Thread(Thread
, ptiCurrent
);
259 pTeb
->Win32ThreadInfo
= ptiCurrent
;
260 ptiCurrent
->pClientInfo
= (PCLIENTINFO
)pTeb
->Win32ClientInfo
;
262 TRACE_CH(UserThread
, "Creating W32 thread TID:%d at IRQ level: %lu\n", Thread
->Cid
.UniqueThread
, KeGetCurrentIrql());
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(Thread
);
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
)
290 pci
->hKL
= ptiCurrent
->KeyboardLayout
->hkl
;
292 /* Assign a default window station and desktop to the process */
293 /* Do not try to open a desktop or window station before winlogon initializes */
294 if(ptiCurrent
->ppi
->hdeskStartup
== NULL
&& LogonProcess
!= NULL
)
297 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
298 * info structure. See documentation of CreateProcess()
300 DesktopPath
= (ProcessParams
? ((ProcessParams
->DesktopInfo
.Length
> 0) ? &ProcessParams
->DesktopInfo
: NULL
) : NULL
);
301 Status
= IntParseDesktopPath(Process
,
305 if(!NT_SUCCESS(Status
))
307 ERR_CH(UserThread
, "Failed to assign default dekstop and winsta to process\n");
311 if(!UserSetProcessWindowStation(hWinSta
))
313 Status
= STATUS_UNSUCCESSFUL
;
317 /* Validate the new desktop. */
318 Status
= IntValidateDesktopHandle(hDesk
, UserMode
, 0, &pdesk
);
319 if(!NT_SUCCESS(Status
))
324 /* Store the parsed desktop as the initial desktop */
325 ptiCurrent
->ppi
->hdeskStartup
= hDesk
;
326 ptiCurrent
->ppi
->rpdeskStartup
= pdesk
;
329 if (ptiCurrent
->ppi
->hdeskStartup
!= NULL
)
331 if (!IntSetThreadDesktop(ptiCurrent
->ppi
->hdeskStartup
, FALSE
))
333 ERR_CH(UserThread
,"Unable to set thread desktop\n");
334 Status
= STATUS_UNSUCCESSFUL
;
342 PSINGLE_LIST_ENTRY psle
;
343 PPROCESSINFO ppiCurrent
;
345 /* Get the Win32 Thread */
346 ptiCurrent
= PsGetThreadWin32Thread(Thread
);
350 TRACE_CH(UserThread
,"Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread
->Cid
.UniqueThread
, KeGetCurrentIrql());
352 ppiCurrent
= ptiCurrent
->ppi
;
353 ptiCurrent
->TIF_flags
|= TIF_INCLEANUP
;
354 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
356 /* Find the THREADINFO in the PROCESSINFO's list */
357 ppti
= &ppiCurrent
->ptiList
;
358 while (*ppti
!= NULL
&& *ppti
!= ptiCurrent
)
360 ppti
= &((*ppti
)->ptiSibling
);
363 /* we must have found it */
364 ASSERT(*ppti
== ptiCurrent
);
366 /* Remove it from the list */
367 *ppti
= ptiCurrent
->ptiSibling
;
369 /* Decrement thread count and check if its 0 */
370 ppiCurrent
->cThreads
--;
372 /* Do now some process cleanup that requires a valid win32 thread */
373 if(ptiCurrent
->ppi
->cThreads
== 0)
375 /* Check if we have registered the user api hook */
376 if(ptiCurrent
->ppi
== ppiUahServer
)
378 /* Unregister the api hook without blocking */
379 UserUnregisterUserApiHook();
382 /* Notify logon application to restart shell if needed */
383 if(ptiCurrent
->pDeskInfo
)
385 if(ptiCurrent
->pDeskInfo
->ppiShellProcess
== ppiCurrent
)
387 DWORD ExitCode
= PsGetProcessExitStatus(Process
);
389 TRACE_PPI(ppiCurrent
, UserProcess
, "Shell process is exiting (%d)\n", ExitCode
);
391 UserPostMessage(hwndSAS
,
396 ptiCurrent
->pDeskInfo
->ppiShellProcess
= NULL
;
401 DceFreeThreadDCE(ptiCurrent
);
402 HOOK_DestroyThreadHooks(Thread
);
403 EVENT_DestroyThreadEvents(Thread
);
406 DestroyTimersForThread(ptiCurrent
);
407 KeSetEvent(ptiCurrent
->MessageQueue
->NewMessages
, IO_NO_INCREMENT
, FALSE
);
408 UnregisterThreadHotKeys(Thread
);
410 co_DestroyThreadWindows(Thread
);
411 IntBlockInput(ptiCurrent
, FALSE
);
412 MsqDestroyMessageQueue(ptiCurrent
->MessageQueue
);
413 IntCleanupThreadCallbacks(ptiCurrent
);
414 if (ptiCurrent
->KeyboardLayout
)
415 UserDereferenceObject(ptiCurrent
->KeyboardLayout
);
417 /* cleanup user object references stack */
418 psle
= PopEntryList(&ptiCurrent
->ReferencesList
);
421 PUSER_REFERENCE_ENTRY ref
= CONTAINING_RECORD(psle
, USER_REFERENCE_ENTRY
, Entry
);
422 TRACE_CH(UserThread
,"thread clean: remove reference obj 0x%x\n",ref
->obj
);
423 UserDereferenceObject(ref
->obj
);
425 psle
= PopEntryList(&ptiCurrent
->ReferencesList
);
428 IntSetThreadDesktop(NULL
, TRUE
);
431 /* Free the THREADINFO */
432 PsSetThreadWin32Thread(Thread
, NULL
);
433 ExFreePoolWithTag(ptiCurrent
, USERTAG_THREADINFO
);
436 Status
= STATUS_SUCCESS
;
440 DPRINT("Leave Win32kThreadCallback, Status=0x%lx\n",Status
);
446 C_ASSERT(sizeof(SERVERINFO
) <= PAGE_SIZE
);
452 if (!NT_SUCCESS(Status)) \
454 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
459 * This definition doesn't work
465 IN PDRIVER_OBJECT DriverObject
,
466 IN PUNICODE_STRING RegistryPath
)
470 WIN32_CALLOUTS_FPNS CalloutData
= {0};
471 PVOID GlobalUserHeapBase
= NULL
;
474 * Register user mode call interface
475 * (system service table index = 1)
477 Result
= KeAddSystemServiceTable(Win32kSSDT
,
479 Win32kNumberOfSysCalls
,
484 DPRINT1("Adding system services failed!\n");
485 return STATUS_UNSUCCESSFUL
;
488 hModuleWin
= MmPageEntireDriver(DriverEntry
);
489 DPRINT("Win32k hInstance 0x%x!\n",hModuleWin
);
491 /* Register Object Manager Callbacks */
492 CalloutData
.WindowStationParseProcedure
= IntWinStaObjectParse
;
493 CalloutData
.WindowStationDeleteProcedure
= IntWinStaObjectDelete
;
494 CalloutData
.DesktopDeleteProcedure
= IntDesktopObjectDelete
;
495 CalloutData
.ProcessCallout
= Win32kProcessCallback
;
496 CalloutData
.ThreadCallout
= Win32kThreadCallback
;
497 CalloutData
.BatchFlushRoutine
= NtGdiFlushUserBatch
;
498 CalloutData
.DesktopOkToCloseProcedure
= IntDesktopOkToClose
;
499 CalloutData
.WindowStationOkToCloseProcedure
= IntWinstaOkToClose
;
501 /* Register our per-process and per-thread structures. */
502 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS
)&CalloutData
);
504 /* Register service hook callbacks */
505 KdSystemDebugControl('CsoR', DbgPreServiceHook
, ID_Win32PreServiceHook
, 0, 0, 0, 0);
506 KdSystemDebugControl('CsoR', DbgPostServiceHook
, ID_Win32PostServiceHook
, 0, 0, 0, 0);
508 /* Create the global USER heap */
509 GlobalUserHeap
= UserCreateHeap(&GlobalUserHeapSection
,
511 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
512 if (GlobalUserHeap
== NULL
)
514 DPRINT1("Failed to initialize the global heap!\n");
515 return STATUS_UNSUCCESSFUL
;
518 /* Allocate global server info structure */
519 gpsi
= UserHeapAlloc(sizeof(SERVERINFO
));
522 DPRINT1("Failed allocate server info structure!\n");
523 return STATUS_UNSUCCESSFUL
;
526 RtlZeroMemory(gpsi
, sizeof(SERVERINFO
));
527 DPRINT("Global Server Data -> %x\n", gpsi
);
529 NT_ROF(InitGdiHandleTable());
530 NT_ROF(InitPaletteImpl());
532 /* Create stock objects, ie. precreated objects commonly
533 used by win32 applications */
534 CreateStockObjects();
535 CreateSysColorObjects();
537 NT_ROF(InitPDEVImpl());
538 NT_ROF(InitLDEVImpl());
539 NT_ROF(InitDeviceImpl());
540 NT_ROF(InitDcImpl());
541 NT_ROF(InitUserImpl());
542 NT_ROF(InitWindowStationImpl());
543 NT_ROF(InitDesktopImpl());
544 NT_ROF(InitInputImpl());
545 NT_ROF(InitKeyboardImpl());
546 NT_ROF(MsqInitializeImpl());
547 NT_ROF(InitTimerImpl());
549 /* Initialize FreeType library */
550 if (!InitFontSupport())
552 DPRINT1("Unable to initialize font support\n");
556 gusLanguageID
= UserGetLanguageID();
558 return STATUS_SUCCESS
;