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