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