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