* Sync up to trunk r55544.
[reactos.git] / subsystems / win32 / win32k / main / dllmain.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
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 NTAPI GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject);
18 BOOL NTAPI 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 void
33 NTAPI
34 DbgPreServiceHook(ULONG ulSyscallId, PULONG_PTR pulArguments)
35 {
36 GdiDbgPreServiceHook(ulSyscallId, pulArguments);
37 UserDbgPreServiceHook(ulSyscallId, pulArguments);
38 }
39
40 ULONG_PTR
41 NTAPI
42 DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
43 {
44 ulResult = GdiDbgPostServiceHook(ulSyscallId, ulResult);
45 ulResult = UserDbgPostServiceHook(ulSyscallId, ulResult);
46 return ulResult;
47 }
48
49 NTSTATUS
50 APIENTRY
51 Win32kProcessCallback(struct _EPROCESS *Process,
52 BOOLEAN Create)
53 {
54 PPROCESSINFO ppiCurrent;
55 DECLARE_RETURN(NTSTATUS);
56
57 ASSERT(Process->Peb);
58
59 DPRINT("Enter Win32kProcessCallback\n");
60 UserEnterExclusive();
61
62 if (Create)
63 {
64 SIZE_T ViewSize = 0;
65 LARGE_INTEGER Offset;
66 PVOID UserBase = NULL;
67 PRTL_USER_PROCESS_PARAMETERS pParams = Process->Peb->ProcessParameters;
68 NTSTATUS Status;
69
70 ASSERT(PsGetProcessWin32Process(Process) == NULL);
71
72 ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
73 sizeof(PROCESSINFO),
74 USERTAG_PROCESSINFO);
75
76 if (ppiCurrent == NULL)
77 RETURN( STATUS_NO_MEMORY);
78
79 RtlZeroMemory(ppiCurrent, sizeof(PROCESSINFO));
80
81 PsSetProcessWin32Process(Process, ppiCurrent);
82
83 #ifdef DBG
84 DbgInitDebugChannels();
85 #endif
86
87 TRACE_PPI(ppiCurrent, UserProcess,"Allocated ppi for PID:%d\n", Process->UniqueProcessId);
88
89 /* map the global heap into the process */
90 Offset.QuadPart = 0;
91 Status = MmMapViewOfSection(GlobalUserHeapSection,
92 PsGetCurrentProcess(),
93 &UserBase,
94 0,
95 0,
96 &Offset,
97 &ViewSize,
98 ViewUnmap,
99 SEC_NO_CHANGE,
100 PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
101 if (!NT_SUCCESS(Status))
102 {
103 DPRINT1("Failed to map the global heap! 0x%x\n", Status);
104 RETURN(Status);
105 }
106 ppiCurrent->HeapMappings.Next = NULL;
107 ppiCurrent->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
108 ppiCurrent->HeapMappings.UserMapping = UserBase;
109 ppiCurrent->HeapMappings.Count = 1;
110
111 InitializeListHead(&ppiCurrent->MenuListHead);
112
113 InitializeListHead(&ppiCurrent->GDIBrushAttrFreeList);
114 InitializeListHead(&ppiCurrent->GDIDcAttrFreeList);
115
116 InitializeListHead(&ppiCurrent->PrivateFontListHead);
117 ExInitializeFastMutex(&ppiCurrent->PrivateFontListLock);
118
119 InitializeListHead(&ppiCurrent->DriverObjListHead);
120 ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
121
122 ppiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
123 EngCreateEvent((PEVENT *)&ppiCurrent->InputIdleEvent);
124 KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
125
126
127 /* map the gdi handle table to user land */
128 Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
129 Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
130 pParams = Process->Peb->ProcessParameters;
131
132 ppiCurrent->peProcess = Process;
133 /* setup process flags */
134 ppiCurrent->W32PF_flags = W32PF_THREADCONNECTED;
135
136 if ( pParams &&
137 pParams->WindowFlags & STARTF_SCRNSAVER )
138 {
139 ppiScrnSaver = ppiCurrent;
140 ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
141 }
142
143 /* Create pools for GDI object attributes */
144 ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
145 ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
146 ppiCurrent->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
147 ASSERT(ppiCurrent->pPoolDcAttr);
148 ASSERT(ppiCurrent->pPoolBrushAttr);
149 ASSERT(ppiCurrent->pPoolRgnAttr);
150 }
151 else
152 {
153 /* Get the Win32 Process */
154 ppiCurrent = PsGetProcessWin32Process(Process);
155
156 ASSERT(ppiCurrent);
157
158 TRACE_CH(UserProcess, "Destroying W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
159 ppiCurrent->W32PF_flags |= W32PF_TERMINATED;
160
161 if (ppiScrnSaver == ppiCurrent)
162 ppiScrnSaver = NULL;
163
164 if (ppiCurrent->InputIdleEvent)
165 {
166 EngFreeMem(ppiCurrent->InputIdleEvent);
167 ppiCurrent->InputIdleEvent = NULL;
168 }
169
170 IntCleanupMenus(Process, ppiCurrent);
171 IntCleanupCurIcons(Process, ppiCurrent);
172
173 /* no process windows should exist at this point, or the function will assert! */
174 DestroyProcessClasses(ppiCurrent);
175 ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED;
176
177 GDI_CleanupForProcess(Process);
178
179 co_IntGraphicsCheck(FALSE);
180
181 /*
182 * Deregister logon application automatically
183 */
184 if(LogonProcess == ppiCurrent)
185 {
186 LogonProcess = NULL;
187 }
188
189 /* Close the startup desktop */
190 ASSERT(ppiCurrent->rpdeskStartup);
191 ASSERT(ppiCurrent->hdeskStartup);
192 ObDereferenceObject(ppiCurrent->rpdeskStartup);
193 ZwClose(ppiCurrent->hdeskStartup);
194
195 /* Close the current window station */
196 UserSetProcessWindowStation(NULL);
197
198 /* Destroy GDI pools */
199 GdiPoolDestroy(ppiCurrent->pPoolDcAttr);
200 GdiPoolDestroy(ppiCurrent->pPoolBrushAttr);
201 GdiPoolDestroy(ppiCurrent->pPoolRgnAttr);
202
203 /* Ftee the PROCESSINFO */
204 PsSetProcessWin32Process(Process, NULL);
205 ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
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 ptiCurrent;
224 int i;
225 NTSTATUS Status;
226 PTEB pTeb;
227
228 DPRINT("Enter Win32kThreadCallback\n");
229 UserEnterExclusive();
230
231 Process = Thread->ThreadsProcess;
232 pTeb = NtCurrentTeb();
233
234 ASSERT(pTeb);
235
236 if (Type == PsW32ThreadCalloutInitialize)
237 {
238 HWINSTA hWinSta = NULL;
239 PCLIENTINFO pci;
240 HDESK hDesk = NULL;
241 PUNICODE_STRING DesktopPath;
242 PDESKTOP pdesk;
243 PRTL_USER_PROCESS_PARAMETERS ProcessParams = Process->Peb->ProcessParameters;
244
245 ASSERT(PsGetThreadWin32Thread(Thread)==NULL);
246
247 ptiCurrent = ExAllocatePoolWithTag(NonPagedPool,
248 sizeof(THREADINFO),
249 USERTAG_THREADINFO);
250 if (ptiCurrent == NULL)
251 {
252 Status = STATUS_NO_MEMORY;
253 goto leave;
254 }
255
256 RtlZeroMemory(ptiCurrent, sizeof(THREADINFO));
257
258 PsSetThreadWin32Thread(Thread, ptiCurrent);
259 pTeb->Win32ThreadInfo = ptiCurrent;
260 ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
261
262 TRACE_CH(UserThread, "Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
263
264 /* Initialize the THREADINFO */
265 InitializeListHead(&ptiCurrent->WindowListHead);
266 InitializeListHead(&ptiCurrent->W32CallbackListHead);
267 InitializeListHead(&ptiCurrent->PtiLink);
268 for (i = 0; i < NB_HOOKS; i++)
269 {
270 InitializeListHead(&ptiCurrent->aphkStart[i]);
271 }
272 ptiCurrent->pEThread = Thread;
273 ptiCurrent->ppi = PsGetCurrentProcessWin32Process();
274 ptiCurrent->ptiSibling = ptiCurrent->ppi->ptiList;
275 ptiCurrent->ppi->ptiList = ptiCurrent;
276 ptiCurrent->ppi->cThreads++;
277 ptiCurrent->MessageQueue = MsqCreateMessageQueue(Thread);
278 ptiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
279 if (ptiCurrent->KeyboardLayout)
280 UserReferenceObject(ptiCurrent->KeyboardLayout);
281 ptiCurrent->TIF_flags &= ~TIF_INCLEANUP;
282
283 /* Initialize the CLIENTINFO */
284 pci = (PCLIENTINFO)pTeb->Win32ClientInfo;
285 RtlZeroMemory(pci, sizeof(CLIENTINFO));
286 pci->ppi = ptiCurrent->ppi;
287 pci->fsHooks = ptiCurrent->fsHooks;
288 pci->dwTIFlags = ptiCurrent->TIF_flags;
289 if (ptiCurrent->KeyboardLayout)
290 pci->hKL = ptiCurrent->KeyboardLayout->hkl;
291
292 /* Assign a default window station and desktop to the process */
293 /* Do not try to open a desktop or window station before winlogon initializes */
294 if(ptiCurrent->ppi->hdeskStartup == NULL && LogonProcess != NULL)
295 {
296 /*
297 * inherit the thread desktop and process window station (if not yet inherited) from the process startup
298 * info structure. See documentation of CreateProcess()
299 */
300 DesktopPath = (ProcessParams ? ((ProcessParams->DesktopInfo.Length > 0) ? &ProcessParams->DesktopInfo : NULL) : NULL);
301 Status = IntParseDesktopPath(Process,
302 DesktopPath,
303 &hWinSta,
304 &hDesk);
305 if(!NT_SUCCESS(Status))
306 {
307 ERR_CH(UserThread, "Failed to assign default dekstop and winsta to process\n");
308 goto leave;
309 }
310
311 if(!UserSetProcessWindowStation(hWinSta))
312 {
313 Status = STATUS_UNSUCCESSFUL;
314 goto leave;
315 }
316
317 /* Validate the new desktop. */
318 Status = IntValidateDesktopHandle(hDesk, UserMode, 0, &pdesk);
319 if(!NT_SUCCESS(Status))
320 {
321 goto leave;
322 }
323
324 /* Store the parsed desktop as the initial desktop */
325 ptiCurrent->ppi->hdeskStartup = hDesk;
326 ptiCurrent->ppi->rpdeskStartup = pdesk;
327 }
328
329 if (ptiCurrent->ppi->hdeskStartup != NULL)
330 {
331 if (!IntSetThreadDesktop(ptiCurrent->ppi->hdeskStartup, FALSE))
332 {
333 ERR_CH(UserThread,"Unable to set thread desktop\n");
334 Status = STATUS_UNSUCCESSFUL;
335 goto leave;
336 }
337 }
338 }
339 else
340 {
341 PTHREADINFO *ppti;
342 PSINGLE_LIST_ENTRY psle;
343 PPROCESSINFO ppiCurrent;
344
345 /* Get the Win32 Thread */
346 ptiCurrent = PsGetThreadWin32Thread(Thread);
347
348 ASSERT(ptiCurrent);
349
350 TRACE_CH(UserThread,"Destroying W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
351
352 ppiCurrent = ptiCurrent->ppi;
353 ptiCurrent->TIF_flags |= TIF_INCLEANUP;
354 ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags;
355
356 /* Find the THREADINFO in the PROCESSINFO's list */
357 ppti = &ppiCurrent->ptiList;
358 while (*ppti != NULL && *ppti != ptiCurrent)
359 {
360 ppti = &((*ppti)->ptiSibling);
361 }
362
363 /* we must have found it */
364 ASSERT(*ppti == ptiCurrent);
365
366 /* Remove it from the list */
367 *ppti = ptiCurrent->ptiSibling;
368
369 /* Decrement thread count and check if its 0 */
370 ppiCurrent->cThreads--;
371
372 /* Do now some process cleanup that requires a valid win32 thread */
373 if(ptiCurrent->ppi->cThreads == 0)
374 {
375 /* Check if we have registered the user api hook */
376 if(ptiCurrent->ppi == ppiUahServer)
377 {
378 /* Unregister the api hook without blocking */
379 UserUnregisterUserApiHook();
380 }
381
382 /* Notify logon application to restart shell if needed */
383 if(ptiCurrent->pDeskInfo)
384 {
385 if(ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent)
386 {
387 DWORD ExitCode = PsGetProcessExitStatus(Process);
388
389 TRACE_PPI(ppiCurrent, UserProcess, "Shell process is exiting (%d)\n", ExitCode);
390
391 UserPostMessage(hwndSAS,
392 WM_LOGONNOTIFY,
393 LN_SHELL_EXITED,
394 ExitCode);
395
396 ptiCurrent->pDeskInfo->ppiShellProcess = NULL;
397 }
398 }
399 }
400
401 DceFreeThreadDCE(ptiCurrent);
402 HOOK_DestroyThreadHooks(Thread);
403 EVENT_DestroyThreadEvents(Thread);
404
405 /* Cleanup timers */
406 DestroyTimersForThread(ptiCurrent);
407 KeSetEvent(ptiCurrent->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
408 UnregisterThreadHotKeys(Thread);
409
410 co_DestroyThreadWindows(Thread);
411 IntBlockInput(ptiCurrent, FALSE);
412 MsqDestroyMessageQueue(ptiCurrent->MessageQueue);
413 IntCleanupThreadCallbacks(ptiCurrent);
414 if (ptiCurrent->KeyboardLayout)
415 UserDereferenceObject(ptiCurrent->KeyboardLayout);
416
417 /* cleanup user object references stack */
418 psle = PopEntryList(&ptiCurrent->ReferencesList);
419 while (psle)
420 {
421 PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry);
422 TRACE_CH(UserThread,"thread clean: remove reference obj 0x%x\n",ref->obj);
423 UserDereferenceObject(ref->obj);
424
425 psle = PopEntryList(&ptiCurrent->ReferencesList);
426 }
427
428 IntSetThreadDesktop(NULL, TRUE);
429
430
431 /* Free the THREADINFO */
432 PsSetThreadWin32Thread(Thread, NULL);
433 ExFreePoolWithTag(ptiCurrent, USERTAG_THREADINFO);
434 }
435
436 Status = STATUS_SUCCESS;
437
438 leave:
439 UserLeave();
440 DPRINT("Leave Win32kThreadCallback, Status=0x%lx\n",Status);
441
442 return Status;
443 }
444
445 #ifdef _M_IX86
446 C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
447 #endif
448
449 // Return on failure
450 #define NT_ROF(x) \
451 Status = (x); \
452 if (!NT_SUCCESS(Status)) \
453 { \
454 DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
455 return Status; \
456 }
457
458 /*
459 * This definition doesn't work
460 */
461 INIT_FUNCTION
462 NTSTATUS
463 APIENTRY
464 DriverEntry(
465 IN PDRIVER_OBJECT DriverObject,
466 IN PUNICODE_STRING RegistryPath)
467 {
468 NTSTATUS Status;
469 BOOLEAN Result;
470 WIN32_CALLOUTS_FPNS CalloutData = {0};
471 PVOID GlobalUserHeapBase = NULL;
472
473 /*
474 * Register user mode call interface
475 * (system service table index = 1)
476 */
477 Result = KeAddSystemServiceTable(Win32kSSDT,
478 NULL,
479 Win32kNumberOfSysCalls,
480 Win32kSSPT,
481 1);
482 if (Result == FALSE)
483 {
484 DPRINT1("Adding system services failed!\n");
485 return STATUS_UNSUCCESSFUL;
486 }
487
488 hModuleWin = MmPageEntireDriver(DriverEntry);
489 DPRINT("Win32k hInstance 0x%x!\n",hModuleWin);
490
491 /* Register Object Manager Callbacks */
492 CalloutData.WindowStationParseProcedure = IntWinStaObjectParse;
493 CalloutData.WindowStationDeleteProcedure = IntWinStaObjectDelete;
494 CalloutData.DesktopDeleteProcedure = IntDesktopObjectDelete;
495 CalloutData.ProcessCallout = Win32kProcessCallback;
496 CalloutData.ThreadCallout = Win32kThreadCallback;
497 CalloutData.BatchFlushRoutine = NtGdiFlushUserBatch;
498 CalloutData.DesktopOkToCloseProcedure = IntDesktopOkToClose;
499 CalloutData.WindowStationOkToCloseProcedure = IntWinstaOkToClose;
500
501 /* Register our per-process and per-thread structures. */
502 PsEstablishWin32Callouts((PWIN32_CALLOUTS_FPNS)&CalloutData);
503
504 /* Register service hook callbacks */
505 KdSystemDebugControl('CsoR', DbgPreServiceHook, ID_Win32PreServiceHook, 0, 0, 0, 0);
506 KdSystemDebugControl('CsoR', DbgPostServiceHook, ID_Win32PostServiceHook, 0, 0, 0, 0);
507
508 /* Create the global USER heap */
509 GlobalUserHeap = UserCreateHeap(&GlobalUserHeapSection,
510 &GlobalUserHeapBase,
511 1 * 1024 * 1024); /* FIXME: 1 MB for now... */
512 if (GlobalUserHeap == NULL)
513 {
514 DPRINT1("Failed to initialize the global heap!\n");
515 return STATUS_UNSUCCESSFUL;
516 }
517
518 /* Allocate global server info structure */
519 gpsi = UserHeapAlloc(sizeof(SERVERINFO));
520 if (!gpsi)
521 {
522 DPRINT1("Failed allocate server info structure!\n");
523 return STATUS_UNSUCCESSFUL;
524 }
525
526 RtlZeroMemory(gpsi, sizeof(SERVERINFO));
527 DPRINT("Global Server Data -> %x\n", gpsi);
528
529 NT_ROF(InitGdiHandleTable());
530 NT_ROF(InitPaletteImpl());
531
532 /* Create stock objects, ie. precreated objects commonly
533 used by win32 applications */
534 CreateStockObjects();
535 CreateSysColorObjects();
536
537 NT_ROF(InitPDEVImpl());
538 NT_ROF(InitLDEVImpl());
539 NT_ROF(InitDeviceImpl());
540 NT_ROF(InitDcImpl());
541 NT_ROF(InitUserImpl());
542 NT_ROF(InitWindowStationImpl());
543 NT_ROF(InitDesktopImpl());
544 NT_ROF(InitInputImpl());
545 NT_ROF(InitKeyboardImpl());
546 NT_ROF(MsqInitializeImpl());
547 NT_ROF(InitTimerImpl());
548
549 /* Initialize FreeType library */
550 if (!InitFontSupport())
551 {
552 DPRINT1("Unable to initialize font support\n");
553 return Status;
554 }
555
556 gusLanguageID = UserGetLanguageID();
557
558 return STATUS_SUCCESS;
559 }
560
561 /* EOF */