58e3ec076484645892cc4b8fdc0402cafb209dcd
[reactos.git] / reactos / win32ss / user / user32 / misc / dllmain.c
1 #include <user32.h>
2
3 #include <ndk/cmfuncs.h>
4
5 #include <wine/debug.h>
6 WINE_DEFAULT_DEBUG_CHANNEL(user32);
7
8 #define KEY_LENGTH 1024
9
10 static ULONG User32TlsIndex;
11 HINSTANCE User32Instance;
12
13 PPROCESSINFO g_ppi = NULL;
14 PUSER_HANDLE_TABLE gHandleTable = NULL;
15 PUSER_HANDLE_ENTRY gHandleEntries = NULL;
16 PSERVERINFO gpsi = NULL;
17 ULONG_PTR g_ulSharedDelta;
18 BOOLEAN gfLogonProcess = FALSE;
19 BOOLEAN gfServerProcess = FALSE;
20 HICON hIconSmWindows = NULL, hIconWindows = NULL;
21
22 WCHAR szAppInit[KEY_LENGTH];
23
24 BOOL
25 GetDllList()
26 {
27 NTSTATUS Status;
28 OBJECT_ATTRIBUTES Attributes;
29 BOOL bRet = FALSE;
30 BOOL bLoad;
31 HANDLE hKey = NULL;
32 DWORD dwSize;
33 PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = NULL;
34
35 UNICODE_STRING szKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows");
36 UNICODE_STRING szLoadName = RTL_CONSTANT_STRING(L"LoadAppInit_DLLs");
37 UNICODE_STRING szDllsName = RTL_CONSTANT_STRING(L"AppInit_DLLs");
38
39 InitializeObjectAttributes(&Attributes, &szKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
40 Status = NtOpenKey(&hKey, KEY_READ, &Attributes);
41 if (NT_SUCCESS(Status))
42 {
43 dwSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD);
44 kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize);
45 if (!kvpInfo)
46 goto end;
47
48 Status = NtQueryValueKey(hKey,
49 &szLoadName,
50 KeyValuePartialInformation,
51 kvpInfo,
52 dwSize,
53 &dwSize);
54 if (!NT_SUCCESS(Status))
55 goto end;
56
57 RtlMoveMemory(&bLoad,
58 kvpInfo->Data,
59 kvpInfo->DataLength);
60
61 HeapFree(GetProcessHeap(), 0, kvpInfo);
62 kvpInfo = NULL;
63
64 if (bLoad)
65 {
66 Status = NtQueryValueKey(hKey,
67 &szDllsName,
68 KeyValuePartialInformation,
69 NULL,
70 0,
71 &dwSize);
72 if (Status != STATUS_BUFFER_TOO_SMALL)
73 goto end;
74
75 kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize);
76 if (!kvpInfo)
77 goto end;
78
79 Status = NtQueryValueKey(hKey,
80 &szDllsName,
81 KeyValuePartialInformation,
82 kvpInfo,
83 dwSize,
84 &dwSize);
85 if (NT_SUCCESS(Status))
86 {
87 LPWSTR lpBuffer = (LPWSTR)kvpInfo->Data;
88 if (*lpBuffer != UNICODE_NULL)
89 {
90 INT bytesToCopy, nullPos;
91
92 bytesToCopy = min(kvpInfo->DataLength, KEY_LENGTH * sizeof(WCHAR));
93
94 if (bytesToCopy != 0)
95 {
96 RtlMoveMemory(szAppInit,
97 kvpInfo->Data,
98 bytesToCopy);
99
100 nullPos = (bytesToCopy / sizeof(WCHAR)) - 1;
101
102 /* ensure string is terminated */
103 szAppInit[nullPos] = UNICODE_NULL;
104
105 bRet = TRUE;
106 }
107 }
108 }
109 }
110 }
111
112 end:
113 if (hKey)
114 NtClose(hKey);
115
116 if (kvpInfo)
117 HeapFree(GetProcessHeap(), 0, kvpInfo);
118
119 return bRet;
120 }
121
122
123 VOID
124 LoadAppInitDlls()
125 {
126 szAppInit[0] = UNICODE_NULL;
127
128 if (GetDllList())
129 {
130 WCHAR buffer[KEY_LENGTH];
131 LPWSTR ptr;
132 size_t i;
133
134 RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR) );
135
136 for (i = 0; i < KEY_LENGTH; ++ i)
137 {
138 if(buffer[i] == L' ' || buffer[i] == L',')
139 buffer[i] = 0;
140 }
141
142 for (i = 0; i < KEY_LENGTH; )
143 {
144 if(buffer[i] == 0)
145 ++ i;
146 else
147 {
148 ptr = buffer + i;
149 i += wcslen(ptr);
150 LoadLibraryW(ptr);
151 }
152 }
153 }
154 }
155
156 VOID
157 UnloadAppInitDlls()
158 {
159 if (szAppInit[0] != UNICODE_NULL)
160 {
161 WCHAR buffer[KEY_LENGTH];
162 HMODULE hModule;
163 LPWSTR ptr;
164 size_t i;
165
166 RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR));
167
168 for (i = 0; i < KEY_LENGTH; ++ i)
169 {
170 if(buffer[i] == L' ' || buffer[i] == L',')
171 buffer[i] = 0;
172 }
173
174 for (i = 0; i < KEY_LENGTH; )
175 {
176 if(buffer[i] == 0)
177 ++ i;
178 else
179 {
180 ptr = buffer + i;
181 i += wcslen(ptr);
182 hModule = GetModuleHandleW(ptr);
183 FreeLibrary(hModule);
184 }
185 }
186 }
187 }
188
189 PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
190 {
191 User32CallWindowProcFromKernel,
192 User32CallSendAsyncProcForKernel,
193 User32LoadSysMenuTemplateForKernel,
194 User32SetupDefaultCursors,
195 User32CallHookProcFromKernel,
196 User32CallEventProcFromKernel,
197 User32CallLoadMenuFromKernel,
198 User32CallClientThreadSetupFromKernel,
199 User32CallClientLoadLibraryFromKernel,
200 User32CallGetCharsetInfo,
201 User32CallCopyImageFromKernel,
202 User32CallSetWndIconsFromKernel,
203 User32DeliverUserAPC,
204 };
205
206 /*
207 * @unimplemented
208 */
209 BOOL
210 WINAPI
211 ClientThreadSetup(VOID)
212 {
213 //
214 // This routine, in Windows, does a lot of what Init does, but in a radically
215 // different way.
216 //
217 // In Windows, because CSRSS's threads have TIF_CSRSSTHREAD set (we have this
218 // flag in ROS but not sure if we use it), the xxxClientThreadSetup callback
219 // isn't made when CSRSS first loads WINSRV.DLL (which loads USER32.DLL).
220 //
221 // However, all the other calls are made as normal, and WINSRV.DLL loads
222 // USER32.dll, the DllMain runs, and eventually the first NtUser system call is
223 // made which initializes Win32k (and initializes the thread, but as mentioned
224 // above, the thread is marked as TIF_CSRSSTHREAD.
225 //
226 // In the DllMain of User32, there is also a CsrClientConnectToServer call to
227 // server 2 (winsrv). When this is done from CSRSS, the "InServer" flag is set,
228 // so user32 will remember that it's running inside of CSRSS. Also, another
229 // flag, called "FirstThread" is manually set by DllMain.
230 //
231 // Then, WINSRV finishes loading, and CSRSRV starts the API thread/loop. This
232 // code then calls CsrConnectToUser, which calls... ClientThreadStartup. Now
233 // this routine detects that it's in the server process, which means it's CSRSS
234 // and that the callback never happened. It does some first-time-Win32k connection
235 // initialization and caches a bunch of things -- if it's the first thread. It also
236 // acquires a critical section to initialize GDI -- and then resets the first thread
237 // flag.
238 //
239 // For now, we'll do none of this, but to support Windows' CSRSRV.DLL which calls
240 // CsrConnectToUser, we'll pretend we "did something" here. Then the rest will
241 // continue as normal.
242 //
243
244 // GetConnected();
245
246 UNIMPLEMENTED;
247 return TRUE;
248 }
249
250 BOOL
251 Init(VOID)
252 {
253 NTSTATUS Status;
254 USERCONNECT UserCon;
255
256 TRACE("user32::Init()\n");
257
258 /* Set PEB data */
259 NtCurrentPeb()->KernelCallbackTable = apfnDispatch;
260 NtCurrentPeb()->PostProcessInitRoutine = NULL;
261
262 /* Minimal setup of the connect info structure */
263 UserCon.ulVersion = USER_VERSION;
264
265 /* Connect to win32k */
266 Status = NtUserProcessConnect(NtCurrentProcess(),
267 &UserCon,
268 sizeof(UserCon));
269 if (!NT_SUCCESS(Status)) return FALSE;
270
271 /* Retrieve data */
272 g_ppi = GetWin32ClientInfo()->ppi; // Snapshot PI, used as pointer only!
273 g_ulSharedDelta = UserCon.siClient.ulSharedDelta;
274 gpsi = SharedPtrToUser(UserCon.siClient.psi);
275 gHandleTable = SharedPtrToUser(UserCon.siClient.aheList);
276 gHandleEntries = SharedPtrToUser(gHandleTable->handles);
277
278 RtlInitializeCriticalSection(&gcsUserApiHook);
279
280 //ERR("1 SI 0x%x : HT 0x%x : D 0x%x\n", UserCon.siClient.psi, UserCon.siClient.aheList, g_ulSharedDelta);
281
282 /* Allocate an index for user32 thread local data */
283 User32TlsIndex = TlsAlloc();
284 if (User32TlsIndex == TLS_OUT_OF_INDEXES)
285 return FALSE;
286
287 if (MessageInit())
288 {
289 if (MenuInit())
290 {
291 InitializeCriticalSection(&U32AccelCacheLock);
292 LoadAppInitDlls();
293 return TRUE;
294 }
295 MessageCleanup();
296 }
297
298 TlsFree(User32TlsIndex);
299 return FALSE;
300 }
301
302 VOID
303 Cleanup(VOID)
304 {
305 DeleteCriticalSection(&U32AccelCacheLock);
306 MenuCleanup();
307 MessageCleanup();
308 DeleteFrameBrushes();
309 UnloadAppInitDlls();
310 TlsFree(User32TlsIndex);
311 }
312
313 INT WINAPI
314 DllMain(
315 IN PVOID hInstanceDll,
316 IN ULONG dwReason,
317 IN PVOID reserved)
318 {
319 switch (dwReason)
320 {
321 case DLL_PROCESS_ATTACH:
322 {
323
324 #if 0
325
326 #define WIN_OBJ_DIR L"\\Windows"
327 #define SESSION_DIR L"\\Sessions"
328
329 NTSTATUS Status;
330 USERSRV_API_CONNECTINFO ConnectInfo; // USERCONNECT
331 ULONG ConnectInfoSize = sizeof(ConnectInfo);
332 WCHAR SessionDir[256];
333
334 /* Cache the PEB and Session ID */
335 PPEB Peb = NtCurrentPeb();
336 ULONG SessionId = Peb->SessionId; // gSessionId
337
338 /* Don't bother us for each thread */
339 DisableThreadLibraryCalls(hInstanceDll);
340
341 /* Minimal setup of the connect info structure */
342 ConnectInfo.ulVersion = USER_VERSION;
343
344 /* Setup the Object Directory path */
345 if (!SessionId)
346 {
347 /* Use the raw path */
348 wcscpy(SessionDir, WIN_OBJ_DIR);
349 }
350 else
351 {
352 /* Use the session path */
353 swprintf(SessionDir,
354 L"%ws\\%ld%ws",
355 SESSION_DIR,
356 SessionId,
357 WIN_OBJ_DIR);
358 }
359
360 /* Connect to the USER Server */
361 Status = CsrClientConnectToServer(SessionDir,
362 USERSRV_SERVERDLL_INDEX,
363 &ConnectInfo,
364 &ConnectInfoSize,
365 &gfServerProcess);
366 if (!NT_SUCCESS(Status))
367 {
368 ERR("Failed to connect to CSR (Status %lx)\n", Status);
369 return FALSE;
370 }
371
372 #else
373 gfServerProcess = FALSE;
374 #endif
375
376 User32Instance = hInstanceDll;
377
378 if (!RegisterClientPFN())
379 return FALSE;
380
381 if (!Init())
382 return FALSE;
383
384 break;
385 }
386
387 case DLL_PROCESS_DETACH:
388 {
389 if (hImmInstance)
390 FreeLibrary(hImmInstance);
391
392 Cleanup();
393 break;
394 }
395 }
396
397 /* Finally, initialize GDI */
398 return GdiDllInitialize(hInstanceDll, dwReason, reserved);
399 }
400
401 // FIXME: This function IS A BIIG HACK!!
402 VOID
403 FASTCALL
404 GetConnected(VOID)
405 {
406 NTSTATUS Status;
407 USERCONNECT UserCon;
408
409 TRACE("user32::GetConnected()\n");
410
411 if ((PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo == NULL)
412 NtUserGetThreadState(THREADSTATE_GETTHREADINFO);
413
414 if (gpsi && g_ppi) return;
415
416 /* Minimal setup of the connect info structure */
417 UserCon.ulVersion = USER_VERSION;
418
419 /* Connect to win32k */
420 Status = NtUserProcessConnect(NtCurrentProcess(),
421 &UserCon,
422 sizeof(UserCon));
423 if (!NT_SUCCESS(Status)) return;
424
425 /* Retrieve data */
426 g_ppi = GetWin32ClientInfo()->ppi; // Snapshot PI, used as pointer only!
427 g_ulSharedDelta = UserCon.siClient.ulSharedDelta;
428 gpsi = SharedPtrToUser(UserCon.siClient.psi);
429 gHandleTable = SharedPtrToUser(UserCon.siClient.aheList);
430 gHandleEntries = SharedPtrToUser(gHandleTable->handles);
431 }
432
433 NTSTATUS
434 WINAPI
435 User32CallClientThreadSetupFromKernel(PVOID Arguments, ULONG ArgumentLength)
436 {
437 TRACE("ClientThreadSetup\n");
438 ClientThreadSetup();
439 return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
440 }
441
442 NTSTATUS
443 WINAPI
444 User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength)
445 {
446 BOOL Ret;
447 PGET_CHARSET_INFO pgci = (PGET_CHARSET_INFO)Arguments;
448
449 TRACE("GetCharsetInfo\n");
450
451 Ret = TranslateCharsetInfo((DWORD *)pgci->Locale, &pgci->Cs, TCI_SRCLOCALE);
452
453 return ZwCallbackReturn(Arguments, ArgumentLength, Ret ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
454 }
455
456 NTSTATUS
457 WINAPI
458 User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength)
459 {
460 PSETWNDICONS_CALLBACK_ARGUMENTS Common = Arguments;
461
462 if (!hIconSmWindows)
463 {
464 hIconSmWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
465 hIconWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
466 }
467 Common->hIconSmWindows = hIconSmWindows;
468 Common->hIconWindows = hIconWindows;
469 ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows);
470 return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS);
471 }
472
473 NTSTATUS
474 WINAPI
475 User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength)
476 {
477 return ZwCallbackReturn(0, 0, STATUS_SUCCESS);
478 }