- Update to r53061
[reactos.git] / 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 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 'p23W');
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 CleanupMonitorImpl();
176
177 /* no process windows should exist at this point, or the function will assert! */
178 DestroyProcessClasses(Win32Process);
179 Win32Process->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
180
181 GDI_CleanupForProcess(Process);
182
183 co_IntGraphicsCheck(FALSE);
184
185 /*
186 * Deregister logon application automatically
187 */
188 if(LogonProcess == Win32Process)
189 {
190 LogonProcess = NULL;
191 }
192
193 /* Close the startup desktop */
194 ASSERT(Win32Process->rpdeskStartup);
195 ASSERT(Win32Process->hdeskStartup);
196 ObDereferenceObject(Win32Process->rpdeskStartup);
197 ZwClose(Win32Process->hdeskStartup);
198
199 /* Close the current window station */
200 UserSetProcessWindowStation(NULL);
201
202 /* Destroy GDI pools */
203 GdiPoolDestroy(Win32Process->pPoolDcAttr);
204 GdiPoolDestroy(Win32Process->pPoolBrushAttr);
205 GdiPoolDestroy(Win32Process->pPoolRgnAttr);
206 }
207
208 RETURN( STATUS_SUCCESS);
209
210 CLEANUP:
211 UserLeave();
212 DPRINT("Leave Win32kProcessCallback, ret=%i\n",_ret_);
213 END_CLEANUP;
214 }
215
216
217 NTSTATUS
218 APIENTRY
219 Win32kThreadCallback(struct _ETHREAD *Thread,
220 PSW32THREADCALLOUTTYPE Type)
221 {
222 struct _EPROCESS *Process;
223 PTHREADINFO Win32Thread;
224 int i;
225 DECLARE_RETURN(NTSTATUS);
226
227 DPRINT("Enter Win32kThreadCallback\n");
228 UserEnterExclusive();
229
230 Process = Thread->ThreadsProcess;
231
232 /* Get the Win32 Thread */
233 Win32Thread = PsGetThreadWin32Thread(Thread);
234
235 /* Allocate one if needed */
236 if (!Win32Thread)
237 {
238 /* FIXME - lock the process */
239 Win32Thread = ExAllocatePoolWithTag(NonPagedPool,
240 sizeof(THREADINFO),
241 't23W');
242
243 if (Win32Thread == NULL) RETURN( STATUS_NO_MEMORY);
244
245 RtlZeroMemory(Win32Thread, sizeof(THREADINFO));
246
247 PsSetThreadWin32Thread(Thread, Win32Thread);
248 /* FIXME - unlock the process */
249 }
250 if (Type == PsW32ThreadCalloutInitialize)
251 {
252 HWINSTA hWinSta = NULL;
253 PTEB pTeb;
254 HDESK hDesk = NULL;
255 NTSTATUS Status;
256 PUNICODE_STRING DesktopPath;
257 PDESKTOP pdesk;
258 PRTL_USER_PROCESS_PARAMETERS ProcessParams = (Process->Peb ? Process->Peb->ProcessParameters : NULL);
259
260 DPRINT("Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
261
262 InitializeListHead(&Win32Thread->WindowListHead);
263 InitializeListHead(&Win32Thread->W32CallbackListHead);
264 InitializeListHead(&Win32Thread->PtiLink);
265 for (i = 0; i < NB_HOOKS; i++)
266 {
267 InitializeListHead(&Win32Thread->aphkStart[i]);
268 }
269
270 Win32Thread->TIF_flags &= ~TIF_INCLEANUP;
271 co_IntDestroyCaret(Win32Thread);
272 Win32Thread->ppi = PsGetCurrentProcessWin32Process();
273 Win32Thread->ptiSibling = Win32Thread->ppi->ptiList;
274 Win32Thread->ppi->ptiList = Win32Thread;
275 Win32Thread->ppi->cThreads++;
276 if (Win32Thread->rpdesk && !Win32Thread->pDeskInfo)
277 {
278 Win32Thread->pDeskInfo = Win32Thread->rpdesk->pDeskInfo;
279 }
280 Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
281 Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
282 Win32Thread->pEThread = Thread;
283
284 /* HAAAAAAAACK! This should go to Win32kProcessCallback */
285 if(Win32Thread->ppi->hdeskStartup == NULL)
286 {
287 /*
288 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
289 * info structure. See documentation of CreateProcess()
290 */
291 DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
292 Status = IntParseDesktopPath(Process,
293 DesktopPath,
294 &hWinSta,
295 &hDesk);
296 if(NT_SUCCESS(Status))
297 {
298 if(hWinSta != NULL)
299 {
300 if(!UserSetProcessWindowStation(hWinSta))
301 {
302 DPRINT1("Failed to set process window station\n");
303 }
304 }
305
306 if (hDesk != NULL)
307 {
308 /* Validate the new desktop. */
309 Status = IntValidateDesktopHandle(hDesk,
310 UserMode,
311 0,
312 &pdesk);
313
314 if(NT_SUCCESS(Status))
315 {
316 Win32Thread->ppi->hdeskStartup = hDesk;
317 Win32Thread->ppi->rpdeskStartup = pdesk;
318 }
319 }
320 }
321 else
322 {
323 DPRINT1("No Desktop handle for this Thread!\n");
324 }
325 }
326
327 if (Win32Thread->ppi->hdeskStartup != NULL)
328 {
329 if (!IntSetThreadDesktop(Win32Thread->ppi->hdeskStartup, FALSE))
330 {
331 DPRINT1("Unable to set thread desktop\n");
332 }
333 }
334
335 pTeb = NtCurrentTeb();
336 if (pTeb)
337 { /* Attempt to startup client support which should have been initialized in IntSetThreadDesktop. */
338 PCLIENTINFO pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
339 Win32Thread->pClientInfo = pci;
340 pci->ppi = Win32Thread->ppi;
341 pci->fsHooks = Win32Thread->fsHooks;
342 if (Win32Thread->KeyboardLayout) pci->hKL = Win32Thread->KeyboardLayout->hkl;
343 pci->dwTIFlags = Win32Thread->TIF_flags;
344 /* CI may not have been initialized. */
345 if (!pci->pDeskInfo && Win32Thread->pDeskInfo)
346 {
347 if (!pci->ulClientDelta) pci->ulClientDelta = DesktopHeapGetUserDelta();
348
349 pci->pDeskInfo = (PVOID)((ULONG_PTR)Win32Thread->pDeskInfo - pci->ulClientDelta);
350 }
351 if (Win32Thread->pcti && pci->pDeskInfo)
352 pci->pClientThreadInfo = (PVOID)((ULONG_PTR)Win32Thread->pcti - pci->ulClientDelta);
353 else
354 pci->pClientThreadInfo = NULL;
355 }
356 else
357 {
358 DPRINT1("No TEB for this Thread!\n");
359 // System thread running! Now SendMessage should be okay.
360 Win32Thread->pcti = &Win32Thread->cti;
361 }
362 GetW32ThreadInfo();
363 }
364 else
365 {
366 PTHREADINFO pti;
367 PSINGLE_LIST_ENTRY e;
368
369 DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
370
371 Win32Thread->TIF_flags |= TIF_INCLEANUP;
372 pti = Win32Thread->ppi->ptiList;
373 if (pti == Win32Thread)
374 {
375 Win32Thread->ppi->ptiList = Win32Thread->ptiSibling;
376 Win32Thread->ppi->cThreads--;
377 }
378 else
379 {
380 do
381 {
382 if (pti->ptiSibling == Win32Thread)
383 {
384 pti->ptiSibling = Win32Thread->ptiSibling;
385 Win32Thread->ppi->cThreads--;
386 break;
387 }
388 pti = pti->ptiSibling;
389 }
390 while (pti);
391 }
392 DceFreeThreadDCE(Win32Thread);
393 HOOK_DestroyThreadHooks(Thread);
394 EVENT_DestroyThreadEvents(Thread);
395 /* Cleanup timers */
396 DestroyTimersForThread(Win32Thread);
397 KeSetEvent(Win32Thread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
398 UnregisterThreadHotKeys(Thread);
399 /* what if this co_ func crash in umode? what will clean us up then? */
400 co_DestroyThreadWindows(Thread);
401 IntBlockInput(Win32Thread, FALSE);
402 MsqDestroyMessageQueue(Win32Thread->MessageQueue);
403 IntCleanupThreadCallbacks(Win32Thread);
404
405 /* cleanup user object references stack */
406 e = PopEntryList(&Win32Thread->ReferencesList);
407 while (e)
408 {
409 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(e, USER_REFERENCE_ENTRY, Entry);
410 DPRINT("thread clean: remove reference obj 0x%x\n",ref->obj);
411 UserDereferenceObject(ref->obj);
412
413 e = PopEntryList(&Win32Thread->ReferencesList);
414 }
415
416 IntSetThreadDesktop(NULL, TRUE);
417
418 PsSetThreadWin32Thread(Thread, NULL);
419 }
420
421 RETURN( STATUS_SUCCESS);
422
423 CLEANUP:
424 UserLeave();
425 DPRINT("Leave Win32kThreadCallback, ret=%i\n",_ret_);
426 END_CLEANUP;
427 }
428
429 NTSTATUS
430 Win32kInitWin32Thread(PETHREAD Thread)
431 {
432 PEPROCESS Process;
433
434 Process = Thread->ThreadsProcess;
435
436 if (Process->Win32Process == NULL)
437 {
438 /* FIXME - lock the process */
439 Process->Win32Process = ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESSINFO), USERTAG_PROCESSINFO);
440
441 if (Process->Win32Process == NULL)
442 return STATUS_NO_MEMORY;
443
444 RtlZeroMemory(Process->Win32Process, sizeof(PROCESSINFO));
445 /* FIXME - unlock the process */
446
447 Win32kProcessCallback(Process, TRUE);
448 }
449
450 if (Thread->Tcb.Win32Thread == NULL)
451 {
452 Thread->Tcb.Win32Thread = ExAllocatePoolWithTag(NonPagedPool, sizeof(THREADINFO), USERTAG_THREADINFO);
453 if (Thread->Tcb.Win32Thread == NULL)
454 return STATUS_NO_MEMORY;
455
456 RtlZeroMemory(Thread->Tcb.Win32Thread, sizeof(THREADINFO));
457
458 Win32kThreadCallback(Thread, PsW32ThreadCalloutInitialize);
459 }
460
461 return(STATUS_SUCCESS);
462 }
463
464 C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
465
466 // Return on failure
467 #define NT_ROF(x) \
468 Status = (x); \
469 if (!NT_SUCCESS(Status)) \
470 { \
471 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
472 return Status; \
473 }
474
475 /*
476 * This definition doesn't work
477 */
478 INIT_FUNCTION
479 NTSTATUS
480 APIENTRY
481 DriverEntry(
482 IN PDRIVER_OBJECT DriverObject,
483 IN PUNICODE_STRING RegistryPath)
484 {
485 NTSTATUS Status;
486 BOOLEAN Result;
487 WIN32_CALLOUTS_FPNS CalloutData = {0};
488 PVOID GlobalUserHeapBase = NULL;
489
490 /*
491 * Register user mode call interface
492 * (system service table index = 1)
493 */
494 Result = KeAddSystemServiceTable(Win32kSSDT,
495 NULL,
496 Win32kNumberOfSysCalls,
497 Win32kSSPT,
498 1);
499 if (Result == FALSE)
500 {
501 DPRINT1("Adding system services failed!\n");
502 return STATUS_UNSUCCESSFUL;
503 }
504
505 hModuleWin = MmPageEntireDriver(DriverEntry);
506 DPRINT("Win32k hInstance 0x%x!\n",hModuleWin);
507
508 /* Register Object Manager Callbacks */
509 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
510 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
511 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
512 CalloutData.ProcessCallout = Win32kProcessCallback;
513 CalloutData.ThreadCallout = Win32kThreadCallback;
514 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
515 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
516 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
517
518 /* Register our per-process and per-thread structures. */
519 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
520
521 #if DBG_ENABLE_SERVICE_HOOKS
522 /* Register service hook callbacks */
523 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
524 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
525 #endif
526
527 /* Create the global USER heap */
528 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
529 &GlobalUserHeapBase,
530 1 * 1024 * 1024); /* FIXME - 1 MB for now... */
531 if (GlobalUserHeap == NULL)
532 {
533 DPRINT1("Failed to initialize the global heap!\n");
534 return STATUS_UNSUCCESSFUL;
535 }
536
537 /* Allocate global server info structure */
538 gpsi = UserHeapAlloc(sizeof(SERVERINFO));
539 if (!gpsi)
540 {
541 DPRINT1("Failed allocate server info structure!\n");
542 return STATUS_UNSUCCESSFUL;
543 }
544
545 RtlZeroMemory(gpsi, sizeof(SERVERINFO));
546 DPRINT("Global Server Data -> %x\n", gpsi);
547
548 NT_ROF(InitGdiHandleTable());
549 NT_ROF(InitPaletteImpl());
550
551 /* Create stock objects, ie. precreated objects commonly
552 used by win32 applications */
553 CreateStockObjects();
554 CreateSysColorObjects();
555
556 NT_ROF(InitXlateImpl());
557 NT_ROF(InitPDEVImpl());
558 NT_ROF(InitLDEVImpl());
559 NT_ROF(InitDeviceImpl());
560 NT_ROF(InitDcImpl());
561 NT_ROF(InitUserImpl());
562 NT_ROF(InitHotkeyImpl());
563 NT_ROF(InitWindowStationImpl());
564 NT_ROF(InitDesktopImpl());
565 NT_ROF(InitWindowImpl());
566 NT_ROF(InitMenuImpl());
567 NT_ROF(InitInputImpl());
568 NT_ROF(InitKeyboardImpl());
569 NT_ROF(InitMonitorImpl());
570 NT_ROF(MsqInitializeImpl());
571 NT_ROF(InitTimerImpl());
572 NT_ROF(InitAcceleratorImpl());
573 NT_ROF(InitGuiCheckImpl());
574
575 /* Initialize FreeType library */
576 if (!InitFontSupport())
577 {
578 DPRINT1("Unable to initialize font support\n");
579 return Status;
580 }
581
582 gusLanguageID = IntGdiGetLanguageID();
583
584 return STATUS_SUCCESS;
585 }
586
587 /* EOF */