caa5ee314eddaa847c6b60a521792196df3769b2
[reactos.git] / reactos / subsystems / win32 / win32k / main / dllmain.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
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 <include/napi.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 HANDLE hModuleWin;
16
17 PGDI_HANDLE_TABLE INTERNAL_CALL GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject);
18 BOOL INTERNAL_CALL GDI_CleanupForProcess (struct _EPROCESS *Process);
19
20 HANDLE GlobalUserHeap = NULL;
21 PSECTION_OBJECT GlobalUserHeapSection = NULL;
22
23 PSERVERINFO gpsi = NULL; // Global User Server Information.
24
25 SHORT gusLanguageID;
26
27 extern ULONG_PTR Win32kSSDT[];
28 extern UCHAR Win32kSSPT[];
29 extern ULONG Win32kNumberOfSysCalls;
30
31 NTSTATUS
32 APIENTRY
33 Win32kProcessCallback(struct _EPROCESS *Process,
34 BOOLEAN Create)
35 {
36 PPROCESSINFO Win32Process;
37 DECLARE_RETURN(NTSTATUS);
38
39 DPRINT("Enter Win32kProcessCallback\n");
40 UserEnterExclusive();
41
42 /* Get the Win32 Process */
43 Win32Process = PsGetProcessWin32Process(Process);
44
45 /* Allocate one if needed */
46 if (!Win32Process)
47 {
48 /* FIXME - lock the process */
49 Win32Process = ExAllocatePoolWithTag(NonPagedPool,
50 sizeof(PROCESSINFO),
51 'p23W');
52
53 if (Win32Process == NULL) RETURN( STATUS_NO_MEMORY);
54
55 RtlZeroMemory(Win32Process, sizeof(PROCESSINFO));
56
57 PsSetProcessWin32Process(Process, Win32Process);
58 /* FIXME - unlock the process */
59 }
60
61 if (Create)
62 {
63 SIZE_T ViewSize = 0;
64 LARGE_INTEGER Offset;
65 PVOID UserBase = NULL;
66 NTSTATUS Status;
67 extern PSECTION_OBJECT GlobalUserHeapSection;
68 DPRINT("Creating W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
69
70 /* map the global heap into the process */
71 Offset.QuadPart = 0;
72 Status = MmMapViewOfSection(GlobalUserHeapSection,
73 PsGetCurrentProcess(),
74 &UserBase,
75 0,
76 0,
77 &Offset,
78 &ViewSize,
79 ViewUnmap,
80 SEC_NO_CHANGE,
81 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
82 if (!NT_SUCCESS(Status))
83 {
84 DPRINT1("Failed to map the global heap! 0x%x\n", Status);
85 RETURN(Status);
86 }
87 Win32Process->HeapMappings.Next = NULL;
88 Win32Process->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
89 Win32Process->HeapMappings.UserMapping = UserBase;
90 Win32Process->HeapMappings.Count = 1;
91
92 InitializeListHead(&Win32Process->MenuListHead);
93
94 InitializeListHead(&Win32Process->GDIBrushAttrFreeList);
95 InitializeListHead(&Win32Process->GDIDcAttrFreeList);
96
97 InitializeListHead(&Win32Process->PrivateFontListHead);
98 ExInitializeFastMutex(&Win32Process->PrivateFontListLock);
99
100 InitializeListHead(&Win32Process->DriverObjListHead);
101 ExInitializeFastMutex(&Win32Process->DriverObjListLock);
102
103 Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
104 EngCreateEvent((PEVENT *)&Win32Process->InputIdleEvent);
105 KeInitializeEvent(Win32Process->InputIdleEvent, NotificationEvent, FALSE);
106
107 if(Process->Peb != NULL)
108 {
109 /* map the gdi handle table to user land */
110 Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
111 Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
112 }
113
114 Win32Process->peProcess = Process;
115 /* setup process flags */
116 Win32Process->W32PF_flags = 0;
117
118 /* Create pools for GDI object attributes */
119 Win32Process->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
120 Win32Process->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
121 Win32Process->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
122 ASSERT(Win32Process->pPoolDcAttr);
123 ASSERT(Win32Process->pPoolBrushAttr);
124 ASSERT(Win32Process->pPoolRgnAttr);
125 }
126 else
127 {
128 DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
129 Win32Process->W32PF_flags |= W32PF_TERMINATED;
130
131 /* Notify logon application to restart shell if needed */
132 if(Win32Process->rpdeskStartup->pDeskInfo)
133 {
134 if(Win32Process->rpdeskStartup->pDeskInfo->ppiShellProcess == Win32Process)
135 {
136 DWORD ExitCode;
137 ExitCode = PsGetProcessExitStatus(Win32Process->peProcess);
138
139 DPRINT1("Shell process is exiting (%d)\n", ExitCode);
140
141 UserPostMessage(hwndSAS,
142 WM_LOGONNOTIFY,
143 LN_SHELL_EXITED,
144 ExitCode);
145 }
146 }
147
148 if (Win32Process->InputIdleEvent)
149 {
150 EngFreeMem((PVOID)Win32Process->InputIdleEvent);
151 Win32Process->InputIdleEvent = NULL;
152 }
153
154 IntCleanupMenus(Process, Win32Process);
155 IntCleanupCurIcons(Process, Win32Process);
156 CleanupMonitorImpl();
157
158 /* no process windows should exist at this point, or the function will assert! */
159 DestroyProcessClasses(Win32Process);
160 Win32Process->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
161
162 GDI_CleanupForProcess(Process);
163
164 co_IntGraphicsCheck(FALSE);
165
166 /*
167 * Deregister logon application automatically
168 */
169 if(LogonProcess == Win32Process)
170 {
171 LogonProcess = NULL;
172 }
173
174 /* Close the startup desktop */
175 ASSERT(Win32Process->rpdeskStartup);
176 ASSERT(Win32Process->hdeskStartup);
177 ObDereferenceObject(Win32Process->rpdeskStartup);
178 ZwClose(Win32Process->hdeskStartup);
179
180 /* Close the current window station */
181 UserSetProcessWindowStation(NULL);
182
183 /* Destroy GDI pools */
184 GdiPoolDestroy(Win32Process->pPoolDcAttr);
185 GdiPoolDestroy(Win32Process->pPoolBrushAttr);
186 GdiPoolDestroy(Win32Process->pPoolRgnAttr);
187 }
188
189 RETURN( STATUS_SUCCESS);
190
191 CLEANUP:
192 UserLeave();
193 DPRINT("Leave Win32kProcessCallback, ret=%i\n",_ret_);
194 END_CLEANUP;
195 }
196
197
198 NTSTATUS
199 APIENTRY
200 Win32kThreadCallback(struct _ETHREAD *Thread,
201 PSW32THREADCALLOUTTYPE Type)
202 {
203 struct _EPROCESS *Process;
204 PTHREADINFO Win32Thread;
205 int i;
206 DECLARE_RETURN(NTSTATUS);
207
208 DPRINT("Enter Win32kThreadCallback\n");
209 UserEnterExclusive();
210
211 Process = Thread->ThreadsProcess;
212
213 /* Get the Win32 Thread */
214 Win32Thread = PsGetThreadWin32Thread(Thread);
215
216 /* Allocate one if needed */
217 if (!Win32Thread)
218 {
219 /* FIXME - lock the process */
220 Win32Thread = ExAllocatePoolWithTag(NonPagedPool,
221 sizeof(THREADINFO),
222 't23W');
223
224 if (Win32Thread == NULL) RETURN( STATUS_NO_MEMORY);
225
226 RtlZeroMemory(Win32Thread, sizeof(THREADINFO));
227
228 PsSetThreadWin32Thread(Thread, Win32Thread);
229 /* FIXME - unlock the process */
230 }
231 if (Type == PsW32ThreadCalloutInitialize)
232 {
233 HWINSTA hWinSta = NULL;
234 PTEB pTeb;
235 HDESK hDesk = NULL;
236 NTSTATUS Status;
237 PUNICODE_STRING DesktopPath;
238 PDESKTOP pdesk;
239 PRTL_USER_PROCESS_PARAMETERS ProcessParams = (Process->Peb ? Process->Peb->ProcessParameters : NULL);
240
241 DPRINT("Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
242
243 InitializeListHead(&Win32Thread->WindowListHead);
244 InitializeListHead(&Win32Thread->W32CallbackListHead);
245 InitializeListHead(&Win32Thread->PtiLink);
246 for (i = 0; i < NB_HOOKS; i++)
247 {
248 InitializeListHead(&Win32Thread->aphkStart[i]);
249 }
250
251 Win32Thread->TIF_flags &= ~TIF_INCLEANUP;
252 co_IntDestroyCaret(Win32Thread);
253 Win32Thread->ppi = PsGetCurrentProcessWin32Process();
254 Win32Thread->ptiSibling = Win32Thread->ppi->ptiList;
255 Win32Thread->ppi->ptiList = Win32Thread;
256 Win32Thread->ppi->cThreads++;
257 if (Win32Thread->rpdesk && !Win32Thread->pDeskInfo)
258 {
259 Win32Thread->pDeskInfo = Win32Thread->rpdesk->pDeskInfo;
260 }
261 Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
262 Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
263 Win32Thread->pEThread = Thread;
264
265 /* HAAAAAAAACK! This should go to Win32kProcessCallback */
266 if(Win32Thread->ppi->hdeskStartup == NULL)
267 {
268 /*
269 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
270 * info structure. See documentation of CreateProcess()
271 */
272 DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
273 Status = IntParseDesktopPath(Process,
274 DesktopPath,
275 &hWinSta,
276 &hDesk);
277 if(NT_SUCCESS(Status))
278 {
279 if(hWinSta != NULL)
280 {
281 if(!UserSetProcessWindowStation(hWinSta))
282 {
283 DPRINT1("Failed to set process window station\n");
284 }
285 }
286
287 if (hDesk != NULL)
288 {
289 /* Validate the new desktop. */
290 Status = IntValidateDesktopHandle(hDesk,
291 UserMode,
292 0,
293 &pdesk);
294
295 if(NT_SUCCESS(Status))
296 {
297 Win32Thread->ppi->hdeskStartup = hDesk;
298 Win32Thread->ppi->rpdeskStartup = pdesk;
299 }
300 }
301 }
302 else
303 {
304 DPRINT1("No Desktop handle for this Thread!\n");
305 }
306 }
307
308 if (Win32Thread->ppi->hdeskStartup != NULL)
309 {
310 if (!IntSetThreadDesktop(Win32Thread->ppi->hdeskStartup, FALSE))
311 {
312 DPRINT1("Unable to set thread desktop\n");
313 }
314 }
315
316 pTeb = NtCurrentTeb();
317 if (pTeb)
318 { /* Attempt to startup client support which should have been initialized in IntSetThreadDesktop. */
319 PCLIENTINFO pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
320 Win32Thread->pClientInfo = pci;
321 pci->ppi = Win32Thread->ppi;
322 pci->fsHooks = Win32Thread->fsHooks;
323 if (Win32Thread->KeyboardLayout) pci->hKL = Win32Thread->KeyboardLayout->hkl;
324 pci->dwTIFlags = Win32Thread->TIF_flags;
325 /* CI may not have been initialized. */
326 if (!pci->pDeskInfo && Win32Thread->pDeskInfo)
327 {
328 if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta();
329
330 pci->pDeskInfo = (PVOID)((ULONG_PTR)Win32Thread->pDeskInfo - pci->ulClientDelta);
331 }
332 if (Win32Thread->pcti && pci->pDeskInfo)
333 pci->pClientThreadInfo = (PVOID)((ULONG_PTR)Win32Thread->pcti - pci->ulClientDelta);
334 else
335 pci->pClientThreadInfo = NULL;
336 }
337 else
338 {
339 DPRINT1("No TEB for this Thread!\n");
340 // System thread running! Now SendMessage should be okay.
341 Win32Thread->pcti = &Win32Thread->cti;
342 }
343 GetW32ThreadInfo();
344 }
345 else
346 {
347 PTHREADINFO pti;
348 PSINGLE_LIST_ENTRY e;
349
350 DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
351
352 Win32Thread->TIF_flags |= TIF_INCLEANUP;
353 pti = Win32Thread->ppi->ptiList;
354 if (pti == Win32Thread)
355 {
356 Win32Thread->ppi->ptiList = Win32Thread->ptiSibling;
357 Win32Thread->ppi->cThreads--;
358 }
359 else
360 {
361 do
362 {
363 if (pti->ptiSibling == Win32Thread)
364 {
365 pti->ptiSibling = Win32Thread->ptiSibling;
366 Win32Thread->ppi->cThreads--;
367 break;
368 }
369 pti = pti->ptiSibling;
370 }
371 while (pti);
372 }
373 DceFreeThreadDCE(Win32Thread);
374 HOOK_DestroyThreadHooks(Thread);
375 EVENT_DestroyThreadEvents(Thread);
376 /* Cleanup timers */
377 DestroyTimersForThread(Win32Thread);
378 KeSetEvent(Win32Thread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
379 UnregisterThreadHotKeys(Thread);
380 /* what if this co_ func crash in umode? what will clean us up then? */
381 co_DestroyThreadWindows(Thread);
382 IntBlockInput(Win32Thread, FALSE);
383 MsqDestroyMessageQueue(Win32Thread->MessageQueue);
384 IntCleanupThreadCallbacks(Win32Thread);
385
386 /* cleanup user object references stack */
387 e = PopEntryList(&Win32Thread->ReferencesList);
388 while (e)
389 {
390 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(e, USER_REFERENCE_ENTRY, Entry);
391 DPRINT("thread clean: remove reference obj 0x%x\n",ref->obj);
392 UserDereferenceObject(ref->obj);
393
394 e = PopEntryList(&Win32Thread->ReferencesList);
395 }
396
397 IntSetThreadDesktop(NULL, TRUE);
398
399 PsSetThreadWin32Thread(Thread, NULL);
400 }
401
402 RETURN( STATUS_SUCCESS);
403
404 CLEANUP:
405 UserLeave();
406 DPRINT("Leave Win32kThreadCallback, ret=%i\n",_ret_);
407 END_CLEANUP;
408 }
409
410 NTSTATUS
411 Win32kInitWin32Thread(PETHREAD Thread)
412 {
413 PEPROCESS Process;
414
415 Process = Thread->ThreadsProcess;
416
417 if (Process->Win32Process == NULL)
418 {
419 /* FIXME - lock the process */
420 Process->Win32Process = ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESSINFO), USERTAG_PROCESSINFO);
421
422 if (Process->Win32Process == NULL)
423 return STATUS_NO_MEMORY;
424
425 RtlZeroMemory(Process->Win32Process, sizeof(PROCESSINFO));
426 /* FIXME - unlock the process */
427
428 Win32kProcessCallback(Process, TRUE);
429 }
430
431 if (Thread->Tcb.Win32Thread == NULL)
432 {
433 Thread->Tcb.Win32Thread = ExAllocatePoolWithTag(NonPagedPool, sizeof(THREADINFO), USERTAG_THREADINFO);
434 if (Thread->Tcb.Win32Thread == NULL)
435 return STATUS_NO_MEMORY;
436
437 RtlZeroMemory(Thread->Tcb.Win32Thread, sizeof(THREADINFO));
438
439 Win32kThreadCallback(Thread, PsW32ThreadCalloutInitialize);
440 }
441
442 return(STATUS_SUCCESS);
443 }
444
445 C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
446
447 // Return on failure
448 #define NT_ROF(x) \
449 Status = (x); \
450 if (!NT_SUCCESS(Status)) \
451 { \
452 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
453 return Status; \
454 }
455
456 /*
457 * This definition doesn't work
458 */
459 INIT_FUNCTION
460 NTSTATUS
461 APIENTRY
462 DriverEntry(
463 IN PDRIVER_OBJECT DriverObject,
464 IN PUNICODE_STRING RegistryPath)
465 {
466 NTSTATUS Status;
467 BOOLEAN Result;
468 WIN32_CALLOUTS_FPNS CalloutData = {0};
469 PVOID GlobalUserHeapBase = NULL;
470
471 /*
472 * Register user mode call interface
473 * (system service table index = 1)
474 */
475 Result = KeAddSystemServiceTable(Win32kSSDT,
476 NULL,
477 Win32kNumberOfSysCalls,
478 Win32kSSPT,
479 1);
480 if (Result == FALSE)
481 {
482 DPRINT1("Adding system services failed!\n");
483 return STATUS_UNSUCCESSFUL;
484 }
485
486 hModuleWin = MmPageEntireDriver(DriverEntry);
487 DPRINT("Win32k hInstance 0x%x!\n",hModuleWin);
488
489 /* Register Object Manager Callbacks */
490 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
491 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
492 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
493 CalloutData.ProcessCallout = Win32kProcessCallback;
494 CalloutData.ThreadCallout = Win32kThreadCallback;
495 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
496 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
497 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
498
499 /* Register our per-process and per-thread structures. */
500 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
501
502 #if DBG_ENABLE_SERVICE_HOOKS
503 /* Register service hook callbacks */
504 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
505 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
506 #endif
507
508 /* Create the global USER heap */
509 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
510 &GlobalUserHeapBase,
511 1 * 1024 * 1024); /* FIXME - 1 MB for now... */
512 if (GlobalUserHeap == NULL)
513 {
514 DPRINT1("Failed to initialize the global heap!\n");
515 return STATUS_UNSUCCESSFUL;
516 }
517
518 /* Allocate global server info structure */
519 gpsi = UserHeapAlloc(sizeof(SERVERINFO));
520 if (!gpsi)
521 {
522 DPRINT1("Failed allocate server info structure!\n");
523 return STATUS_UNSUCCESSFUL;
524 }
525
526 RtlZeroMemory(gpsi, sizeof(SERVERINFO));
527 DPRINT("Global Server Data -> %x\n", gpsi);
528
529 NT_ROF(InitGdiHandleTable());
530 NT_ROF(InitPaletteImpl());
531
532 /* Create stock objects, ie. precreated objects commonly
533 used by win32 applications */
534 CreateStockObjects();
535 CreateSysColorObjects();
536
537 NT_ROF(InitXlateImpl());
538 NT_ROF(InitPDEVImpl());
539 NT_ROF(InitLDEVImpl());
540 NT_ROF(InitDeviceImpl());
541 NT_ROF(InitDcImpl());
542 NT_ROF(InitUserImpl());
543 NT_ROF(InitHotkeyImpl());
544 NT_ROF(InitWindowStationImpl());
545 NT_ROF(InitDesktopImpl());
546 NT_ROF(InitWindowImpl());
547 NT_ROF(InitMenuImpl());
548 NT_ROF(InitInputImpl());
549 NT_ROF(InitKeyboardImpl());
550 NT_ROF(InitMonitorImpl());
551 NT_ROF(MsqInitializeImpl());
552 NT_ROF(InitTimerImpl());
553 NT_ROF(InitAcceleratorImpl());
554 NT_ROF(InitGuiCheckImpl());
555
556 /* Initialize FreeType library */
557 if (!InitFontSupport())
558 {
559 DPRINT1("Unable to initialize font support\n");
560 return Status;
561 }
562
563 gusLanguageID = IntGdiGetLanguageID();
564
565 return STATUS_SUCCESS;
566 }
567
568 /* EOF */