b344aefb05245d1e9681035e24c61890c9613598
[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 BOOL
190 InitThread(VOID)
191 {
192 return TRUE;
193 }
194
195 VOID
196 CleanupThread(VOID)
197 {
198 }
199
200 PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
201 {
202 User32CallWindowProcFromKernel,
203 User32CallSendAsyncProcForKernel,
204 User32LoadSysMenuTemplateForKernel,
205 User32SetupDefaultCursors,
206 User32CallHookProcFromKernel,
207 User32CallEventProcFromKernel,
208 User32CallLoadMenuFromKernel,
209 User32CallClientThreadSetupFromKernel,
210 User32CallClientLoadLibraryFromKernel,
211 User32CallGetCharsetInfo,
212 User32CallCopyImageFromKernel,
213 User32CallSetWndIconsFromKernel,
214 };
215
216 /*
217 * @unimplemented
218 */
219 BOOL
220 WINAPI
221 ClientThreadSetup(VOID)
222 {
223 //
224 // This routine, in Windows, does a lot of what Init does, but in a radically
225 // different way.
226 //
227 // In Windows, because CSRSS's threads have TIF_CSRSSTHREAD set (we have this
228 // flag in ROS but not sure if we use it), the xxxClientThreadSetup callback
229 // isn't made when CSRSS first loads WINSRV.DLL (which loads USER32.DLL).
230 //
231 // However, all the other calls are made as normal, and WINSRV.DLL loads
232 // USER32.dll, the DllMain runs, and eventually the first NtUser system call is
233 // made which initializes Win32k (and initializes the thread, but as mentioned
234 // above, the thread is marked as TIF_CSRSSTHREAD.
235 //
236 // In the DllMain of User32, there is also a CsrClientConnectToServer call to
237 // server 2 (winsrv). When this is done from CSRSS, the "InServer" flag is set,
238 // so user32 will remember that it's running inside of CSRSS. Also, another
239 // flag, called "FirstThread" is manually set by DllMain.
240 //
241 // Then, WINSRV finishes loading, and CSRSRV starts the API thread/loop. This
242 // code then calls CsrConnectToUser, which calls... ClientThreadStartup. Now
243 // this routine detects that it's in the server process, which means it's CSRSS
244 // and that the callback never happened. It does some first-time-Win32k connection
245 // initialization and caches a bunch of things -- if it's the first thread. It also
246 // acquires a critical section to initialize GDI -- and then resets the first thread
247 // flag.
248 //
249 // For now, we'll do none of this, but to support Windows' CSRSRV.DLL which calls
250 // CsrConnectToUser, we'll pretend we "did something" here. Then the rest will
251 // continue as normal.
252 //
253 UNIMPLEMENTED;
254 return TRUE;
255 }
256
257 BOOL
258 Init(VOID)
259 {
260 USERCONNECT UserCon;
261
262 /* Set PEB data */
263 NtCurrentPeb()->KernelCallbackTable = apfnDispatch;
264 NtCurrentPeb()->PostProcessInitRoutine = NULL;
265
266 NtUserProcessConnect( NtCurrentProcess(),
267 &UserCon,
268 sizeof(USERCONNECT));
269
270 g_ppi = GetWin32ClientInfo()->ppi; // Snapshot PI, used as pointer only!
271 g_ulSharedDelta = UserCon.siClient.ulSharedDelta;
272 gpsi = SharedPtrToUser(UserCon.siClient.psi);
273 gHandleTable = SharedPtrToUser(UserCon.siClient.aheList);
274 gHandleEntries = SharedPtrToUser(gHandleTable->handles);
275
276 RtlInitializeCriticalSection(&gcsUserApiHook);
277 gfServerProcess = FALSE; // FIXME HAX! Used in CsrClientConnectToServer(,,,,&gfServerProcess);
278
279 //CsrClientConnectToServer(L"\\Windows", 0, NULL, 0, &gfServerProcess);
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 {
286 if (MessageInit())
287 {
288 if (MenuInit())
289 {
290 InitializeCriticalSection(&U32AccelCacheLock);
291 GdiDllInitialize(NULL, DLL_PROCESS_ATTACH, NULL);
292 LoadAppInitDlls();
293
294 return TRUE;
295 }
296 MessageCleanup();
297 }
298 TlsFree(User32TlsIndex);
299 }
300
301 return FALSE;
302 }
303
304 VOID
305 Cleanup(VOID)
306 {
307 DeleteCriticalSection(&U32AccelCacheLock);
308 MenuCleanup();
309 MessageCleanup();
310 DeleteFrameBrushes();
311 UnloadAppInitDlls();
312 GdiDllInitialize(NULL, DLL_PROCESS_DETACH, NULL);
313 TlsFree(User32TlsIndex);
314 }
315
316 INT WINAPI
317 DllMain(
318 IN PVOID hInstanceDll,
319 IN ULONG dwReason,
320 IN PVOID reserved)
321 {
322 switch (dwReason)
323 {
324 case DLL_PROCESS_ATTACH:
325 User32Instance = hInstanceDll;
326 if (!RegisterClientPFN())
327 {
328 return FALSE;
329 }
330
331 if (!Init())
332 return FALSE;
333 if (!InitThread())
334 {
335 Cleanup();
336 return FALSE;
337 }
338 break;
339
340 case DLL_THREAD_ATTACH:
341 if (!InitThread())
342 return FALSE;
343 break;
344
345 case DLL_THREAD_DETACH:
346 CleanupThread();
347 break;
348
349 case DLL_PROCESS_DETACH:
350 if (hImmInstance) FreeLibrary(hImmInstance);
351 CleanupThread();
352 Cleanup();
353 break;
354 }
355
356 return TRUE;
357 }
358
359
360 VOID
361 FASTCALL
362 GetConnected(VOID)
363 {
364 USERCONNECT UserCon;
365 // ERR("GetConnected\n");
366
367 if ((PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo == NULL)
368 NtUserGetThreadState(THREADSTATE_GETTHREADINFO);
369
370 if (gpsi && g_ppi) return;
371 // FIXME HAX: Due to the "Dll Initialization Bug" we have to call this too.
372 GdiDllInitialize(NULL, DLL_PROCESS_ATTACH, NULL);
373
374 NtUserProcessConnect( NtCurrentProcess(),
375 &UserCon,
376 sizeof(USERCONNECT));
377
378 g_ppi = GetWin32ClientInfo()->ppi;
379 g_ulSharedDelta = UserCon.siClient.ulSharedDelta;
380 gpsi = SharedPtrToUser(UserCon.siClient.psi);
381 gHandleTable = SharedPtrToUser(UserCon.siClient.aheList);
382 gHandleEntries = SharedPtrToUser(gHandleTable->handles);
383
384 }
385
386 NTSTATUS
387 WINAPI
388 User32CallClientThreadSetupFromKernel(PVOID Arguments, ULONG ArgumentLength)
389 {
390 ERR("ClientThreadSetup\n");
391 ClientThreadSetup();
392 return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
393 }
394
395 NTSTATUS
396 WINAPI
397 User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength)
398 {
399 BOOL Ret;
400 PGET_CHARSET_INFO pgci = (PGET_CHARSET_INFO)Arguments;
401
402 TRACE("GetCharsetInfo\n");
403
404 Ret = TranslateCharsetInfo((DWORD *)pgci->Locale, &pgci->Cs, TCI_SRCLOCALE);
405
406 return ZwCallbackReturn(Arguments, ArgumentLength, Ret ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
407 }
408
409 NTSTATUS
410 WINAPI
411 User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength)
412 {
413 PSETWNDICONS_CALLBACK_ARGUMENTS Common = Arguments;
414
415 if (!hIconSmWindows)
416 {
417 hIconSmWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
418 hIconWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
419 }
420 Common->hIconSmWindows = hIconSmWindows;
421 Common->hIconWindows = hIconWindows;
422 ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows);
423 return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS);
424 }