- Prevent kernel bug check in win32k when calling a hook proc when thread is in cleanup.
[reactos.git] / reactos / subsystems / win32 / win32k / main / dllmain.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * Entry Point for win32k.sys
21 */
22
23 #include <w32k.h>
24 #include <include/napi.h>
25
26 #define NDEBUG
27 #include <debug.h>
28
29 HANDLE hModuleWin;
30
31 PGDI_HANDLE_TABLE INTERNAL_CALL GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject);
32 BOOL INTERNAL_CALL GDI_CleanupForProcess (struct _EPROCESS *Process);
33 /* FIXME */
34 PGDI_HANDLE_TABLE GdiHandleTable = NULL;
35 PSECTION_OBJECT GdiTableSection = NULL;
36
37 LIST_ENTRY GlobalDriverListHead;
38
39 HANDLE GlobalUserHeap = NULL;
40 PSECTION_OBJECT GlobalUserHeapSection = NULL;
41
42 PSERVERINFO gpsi = NULL; // Global User Server Information.
43
44 HSEMAPHORE hsemDriverMgmt = NULL;
45
46 SHORT gusLanguageID;
47
48 extern ULONG_PTR Win32kSSDT[];
49 extern UCHAR Win32kSSPT[];
50 extern ULONG Win32kNumberOfSysCalls;
51
52 NTSTATUS
53 APIENTRY
54 Win32kProcessCallback(struct _EPROCESS *Process,
55 BOOLEAN Create)
56 {
57 PPROCESSINFO Win32Process;
58 DECLARE_RETURN(NTSTATUS);
59
60 DPRINT("Enter Win32kProcessCallback\n");
61 UserEnterExclusive();
62
63 /* Get the Win32 Process */
64 Win32Process = PsGetProcessWin32Process(Process);
65
66 /* Allocate one if needed */
67 if (!Win32Process)
68 {
69 /* FIXME - lock the process */
70 Win32Process = ExAllocatePoolWithTag(NonPagedPool,
71 sizeof(PROCESSINFO),
72 'p23W');
73
74 if (Win32Process == NULL) RETURN( STATUS_NO_MEMORY);
75
76 RtlZeroMemory(Win32Process, sizeof(PROCESSINFO));
77
78 PsSetProcessWin32Process(Process, Win32Process);
79 /* FIXME - unlock the process */
80 }
81
82 if (Create)
83 {
84 SIZE_T ViewSize = 0;
85 LARGE_INTEGER Offset;
86 PVOID UserBase = NULL;
87 NTSTATUS Status;
88 extern PSECTION_OBJECT GlobalUserHeapSection;
89 DPRINT("Creating W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
90
91 /* map the global heap into the process */
92 Offset.QuadPart = 0;
93 Status = MmMapViewOfSection(GlobalUserHeapSection,
94 PsGetCurrentProcess(),
95 &UserBase,
96 0,
97 0,
98 &Offset,
99 &ViewSize,
100 ViewUnmap,
101 SEC_NO_CHANGE,
102 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
103 if (!NT_SUCCESS(Status))
104 {
105 DPRINT1("Failed to map the global heap! 0x%x\n", Status);
106 RETURN(Status);
107 }
108 Win32Process->HeapMappings.Next = NULL;
109 Win32Process->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
110 Win32Process->HeapMappings.UserMapping = UserBase;
111 Win32Process->HeapMappings.Count = 1;
112
113 InitializeListHead(&Win32Process->ClassList);
114
115 InitializeListHead(&Win32Process->MenuListHead);
116
117 InitializeListHead(&Win32Process->PrivateFontListHead);
118 ExInitializeFastMutex(&Win32Process->PrivateFontListLock);
119
120 InitializeListHead(&Win32Process->DriverObjListHead);
121 ExInitializeFastMutex(&Win32Process->DriverObjListLock);
122
123 Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout();
124
125 if(Process->Peb != NULL)
126 {
127 /* map the gdi handle table to user land */
128 Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(GdiTableSection, Process);
129 Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
130 }
131
132 /* setup process flags */
133 Win32Process->W32PF_flags = 0;
134 }
135 else
136 {
137 DPRINT("Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
138 IntCleanupMenus(Process, Win32Process);
139 IntCleanupCurIcons(Process, Win32Process);
140 CleanupMonitorImpl();
141
142 /* no process windows should exist at this point, or the function will assert! */
143 DestroyProcessClasses(Win32Process);
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
158 RETURN( STATUS_SUCCESS);
159
160 CLEANUP:
161 UserLeave();
162 DPRINT("Leave Win32kProcessCallback, ret=%i\n",_ret_);
163 END_CLEANUP;
164 }
165
166
167 NTSTATUS
168 APIENTRY
169 Win32kThreadCallback(struct _ETHREAD *Thread,
170 PSW32THREADCALLOUTTYPE Type)
171 {
172 struct _EPROCESS *Process;
173 PTHREADINFO Win32Thread;
174 DECLARE_RETURN(NTSTATUS);
175
176 DPRINT("Enter Win32kThreadCallback\n");
177 UserEnterExclusive();
178
179 Process = Thread->ThreadsProcess;
180
181 /* Get the Win32 Thread */
182 Win32Thread = PsGetThreadWin32Thread(Thread);
183
184 /* Allocate one if needed */
185 if (!Win32Thread)
186 {
187 /* FIXME - lock the process */
188 Win32Thread = ExAllocatePoolWithTag(NonPagedPool,
189 sizeof(THREADINFO),
190 't23W');
191
192 if (Win32Thread == NULL) RETURN( STATUS_NO_MEMORY);
193
194 RtlZeroMemory(Win32Thread, sizeof(THREADINFO));
195
196 PsSetThreadWin32Thread(Thread, Win32Thread);
197 /* FIXME - unlock the process */
198 }
199 if (Type == PsW32ThreadCalloutInitialize)
200 {
201 HWINSTA hWinSta = NULL;
202 PTEB pTeb;
203 HDESK hDesk = NULL;
204 NTSTATUS Status;
205 PUNICODE_STRING DesktopPath;
206 PRTL_USER_PROCESS_PARAMETERS ProcessParams = (Process->Peb ? Process->Peb->ProcessParameters : NULL);
207
208 DPRINT("Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
209
210 InitializeListHead(&Win32Thread->WindowListHead);
211 InitializeListHead(&Win32Thread->W32CallbackListHead);
212 InitializeListHead(&Win32Thread->PtiLink);
213
214 /*
215 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
216 * info structure. See documentation of CreateProcess()
217 */
218 DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
219 Status = IntParseDesktopPath(Process,
220 DesktopPath,
221 &hWinSta,
222 &hDesk);
223 if(NT_SUCCESS(Status))
224 {
225 if(hWinSta != NULL)
226 {
227 if(Process != CsrProcess)
228 {
229 HWINSTA hProcessWinSta = (HWINSTA)InterlockedCompareExchangePointer((PVOID)&Process->Win32WindowStation, (PVOID)hWinSta, NULL);
230 if(hProcessWinSta != NULL)
231 {
232 /* our process is already assigned to a different window station, we don't need the handle anymore */
233 NtClose(hWinSta);
234 }
235 }
236 else
237 {
238 NtClose(hWinSta);
239 }
240 }
241
242 if (hDesk != NULL)
243 {
244 PDESKTOP DesktopObject;
245 Win32Thread->Desktop = NULL;
246 Status = ObReferenceObjectByHandle(hDesk,
247 0,
248 ExDesktopObjectType,
249 KernelMode,
250 (PVOID*)&DesktopObject,
251 NULL);
252 NtClose(hDesk);
253 if(NT_SUCCESS(Status))
254 {
255 if (!IntSetThreadDesktop(DesktopObject,
256 FALSE))
257 {
258 DPRINT1("Unable to set thread desktop\n");
259 }
260 }
261 else
262 {
263 DPRINT1("Unable to reference thread desktop handle 0x%x\n", hDesk);
264 }
265 }
266 }
267 Win32Thread->IsExiting = FALSE;
268 co_IntDestroyCaret(Win32Thread);
269 Win32Thread->ppi = PsGetCurrentProcessWin32Process();
270 pTeb = NtCurrentTeb();
271 if (pTeb)
272 {
273 Win32Thread->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
274 Win32Thread->pClientInfo->pClientThreadInfo = NULL;
275 }
276 Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
277 Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
278 Win32Thread->pEThread = Thread;
279 }
280 else
281 {
282 PSINGLE_LIST_ENTRY e;
283
284 DPRINT("Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
285
286 Win32Thread->IsExiting = TRUE;
287 Win32Thread->TIF_flags |= TIF_INCLEANUP;
288 HOOK_DestroyThreadHooks(Thread);
289 UnregisterThreadHotKeys(Thread);
290 /* what if this co_ func crash in umode? what will clean us up then? */
291 co_DestroyThreadWindows(Thread);
292 IntBlockInput(Win32Thread, FALSE);
293 MsqDestroyMessageQueue(Win32Thread->MessageQueue);
294 IntCleanupThreadCallbacks(Win32Thread);
295
296 /* cleanup user object references stack */
297 e = PopEntryList(&Win32Thread->ReferencesList);
298 while (e)
299 {
300 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(e, USER_REFERENCE_ENTRY, Entry);
301 DPRINT("thread clean: remove reference obj 0x%x\n",ref->obj);
302 UserDereferenceObject(ref->obj);
303
304 e = PopEntryList(&Win32Thread->ReferencesList);
305 }
306
307 IntSetThreadDesktop(NULL,
308 TRUE);
309
310 PsSetThreadWin32Thread(Thread, NULL);
311 }
312
313 RETURN( STATUS_SUCCESS);
314
315 CLEANUP:
316 UserLeave();
317 DPRINT("Leave Win32kThreadCallback, ret=%i\n",_ret_);
318 END_CLEANUP;
319 }
320
321 /* Only used in ntuser/input.c KeyboardThreadMain(). If it's
322 not called there anymore, please delete */
323 NTSTATUS
324 Win32kInitWin32Thread(PETHREAD Thread)
325 {
326 PEPROCESS Process;
327
328 Process = Thread->ThreadsProcess;
329
330 if (Process->Win32Process == NULL)
331 {
332 /* FIXME - lock the process */
333 Process->Win32Process = ExAllocatePool(NonPagedPool, sizeof(PROCESSINFO));
334
335 if (Process->Win32Process == NULL)
336 return STATUS_NO_MEMORY;
337
338 RtlZeroMemory(Process->Win32Process, sizeof(PROCESSINFO));
339 /* FIXME - unlock the process */
340
341 Win32kProcessCallback(Process, TRUE);
342 }
343
344 if (Thread->Tcb.Win32Thread == NULL)
345 {
346 Thread->Tcb.Win32Thread = ExAllocatePool (NonPagedPool, sizeof(THREADINFO));
347 if (Thread->Tcb.Win32Thread == NULL)
348 return STATUS_NO_MEMORY;
349
350 RtlZeroMemory(Thread->Tcb.Win32Thread, sizeof(THREADINFO));
351
352 Win32kThreadCallback(Thread, PsW32ThreadCalloutInitialize);
353 }
354
355 return(STATUS_SUCCESS);
356 }
357
358
359 /*
360 * This definition doesn't work
361 */
362 NTSTATUS APIENTRY
363 DriverEntry (
364 IN PDRIVER_OBJECT DriverObject,
365 IN PUNICODE_STRING RegistryPath)
366 {
367 NTSTATUS Status;
368 BOOLEAN Result;
369 WIN32_CALLOUTS_FPNS CalloutData = {0};
370 PVOID GlobalUserHeapBase = NULL;
371
372 /*
373 * Register user mode call interface
374 * (system service table index = 1)
375 */
376 Result = KeAddSystemServiceTable (Win32kSSDT,
377 NULL,
378 Win32kNumberOfSysCalls,
379 Win32kSSPT,
380 1);
381 if (Result == FALSE)
382 {
383 DPRINT1("Adding system services failed!\n");
384 return STATUS_UNSUCCESSFUL;
385 }
386
387 hModuleWin = MmPageEntireDriver(DriverEntry);
388 DPRINT("Win32k hInstance 0x%x!\n",hModuleWin);
389 /*
390 * Register Object Manager Callbacks
391 */
392 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
393 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
394 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
395 CalloutData.ProcessCallout = Win32kProcessCallback;
396 CalloutData.ThreadCallout = Win32kThreadCallback;
397 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
398
399 /*
400 * Register our per-process and per-thread structures.
401 */
402 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
403
404 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
405 &GlobalUserHeapBase,
406 1 * 1024 * 1024); /* FIXME - 1 MB for now... */
407 if (GlobalUserHeap == NULL)
408 {
409 DPRINT1("Failed to initialize the global heap!\n");
410 return STATUS_UNSUCCESSFUL;
411 }
412
413 /* Initialize a list of loaded drivers in Win32 subsystem */
414 InitializeListHead(&GlobalDriverListHead);
415
416 if(!hsemDriverMgmt) hsemDriverMgmt = EngCreateSemaphore();
417
418 GdiHandleTable = GDIOBJ_iAllocHandleTable(&GdiTableSection);
419 if (GdiHandleTable == NULL)
420 {
421 DPRINT1("Failed to initialize the GDI handle table.\n");
422 return STATUS_UNSUCCESSFUL;
423 }
424
425 Status = InitUserImpl();
426 if (!NT_SUCCESS(Status))
427 {
428 DPRINT1("Failed to initialize user implementation!\n");
429 return STATUS_UNSUCCESSFUL;
430 }
431
432 Status = InitHotkeyImpl();
433 if (!NT_SUCCESS(Status))
434 {
435 DPRINT1("Failed to initialize hotkey implementation!\n");
436 return STATUS_UNSUCCESSFUL;
437 }
438
439 Status = InitWindowStationImpl();
440 if (!NT_SUCCESS(Status))
441 {
442 DPRINT1("Failed to initialize window station implementation!\n");
443 return STATUS_UNSUCCESSFUL;
444 }
445
446 Status = InitDesktopImpl();
447 if (!NT_SUCCESS(Status))
448 {
449 DPRINT1("Failed to initialize desktop implementation!\n");
450 return STATUS_UNSUCCESSFUL;
451 }
452
453 Status = InitWindowImpl();
454 if (!NT_SUCCESS(Status))
455 {
456 DPRINT1("Failed to initialize window implementation!\n");
457 return STATUS_UNSUCCESSFUL;
458 }
459
460 Status = InitMenuImpl();
461 if (!NT_SUCCESS(Status))
462 {
463 DPRINT1("Failed to initialize menu implementation!\n");
464 return STATUS_UNSUCCESSFUL;
465 }
466
467 Status = InitInputImpl();
468 if (!NT_SUCCESS(Status))
469 {
470 DPRINT1("Failed to initialize input implementation.\n");
471 return(Status);
472 }
473
474 Status = InitKeyboardImpl();
475 if (!NT_SUCCESS(Status))
476 {
477 DPRINT1("Failed to initialize keyboard implementation.\n");
478 return(Status);
479 }
480
481 Status = InitMonitorImpl();
482 if (!NT_SUCCESS(Status))
483 {
484 DbgPrint("Failed to initialize monitor implementation!\n");
485 return STATUS_UNSUCCESSFUL;
486 }
487
488 Status = MsqInitializeImpl();
489 if (!NT_SUCCESS(Status))
490 {
491 DPRINT1("Failed to initialize message queue implementation.\n");
492 return(Status);
493 }
494
495 Status = InitTimerImpl();
496 if (!NT_SUCCESS(Status))
497 {
498 DPRINT1("Failed to initialize timer implementation.\n");
499 return(Status);
500 }
501
502 Status = InitAcceleratorImpl();
503 if (!NT_SUCCESS(Status))
504 {
505 DPRINT1("Failed to initialize accelerator implementation.\n");
506 return(Status);
507 }
508
509 Status = InitGuiCheckImpl();
510 if (!NT_SUCCESS(Status))
511 {
512 DPRINT1("Failed to initialize GUI check implementation.\n");
513 return(Status);
514 }
515
516 Status = InitDcImpl();
517 if (!NT_SUCCESS(Status))
518 {
519 DPRINT1("Failed to initialize Device context implementation!\n");
520 return STATUS_UNSUCCESSFUL;
521 }
522
523 /* Initialize FreeType library */
524 if (! InitFontSupport())
525 {
526 DPRINT1("Unable to initialize font support\n");
527 return STATUS_UNSUCCESSFUL;
528 }
529
530 InitXlateImpl();
531
532 /* Create stock objects, ie. precreated objects commonly
533 used by win32 applications */
534 CreateStockObjects();
535 CreateSysColorObjects();
536
537 gusLanguageID = IntGdiGetLanguageID();
538
539 return STATUS_SUCCESS;
540 }
541
542 /* EOF */