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