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