move from branch
[reactos.git] / reactos / dll / win32 / kernel32 / misc / dllmain.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/misc/dllmain.c
6 * PURPOSE: Initialization
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <k32.h>
15
16 #define NDEBUG
17 #include "../include/debug.h"
18
19 /* GLOBALS *******************************************************************/
20
21 extern UNICODE_STRING SystemDirectory;
22 extern UNICODE_STRING WindowsDirectory;
23
24 HANDLE hProcessHeap = NULL;
25 HMODULE hCurrentModule = NULL;
26 HANDLE hBaseDir = NULL;
27 PPEB Peb;
28 ULONG SessionId;
29
30 static BOOL DllInitialized = FALSE;
31 static BOOL ConsoleInitialized = FALSE;
32
33 BOOL STDCALL
34 DllMain(HANDLE hInst,
35 DWORD dwReason,
36 LPVOID lpReserved);
37
38 /* Critical section for various kernel32 data structures */
39 RTL_CRITICAL_SECTION DllLock;
40 RTL_CRITICAL_SECTION ConsoleLock;
41
42 extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
43 extern __declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
44
45 extern BOOL FASTCALL NlsInit();
46 extern VOID FASTCALL NlsUninit();
47 BOOLEAN InWindows = FALSE;
48
49 HANDLE
50 STDCALL
51 DuplicateConsoleHandle(HANDLE hConsole,
52 DWORD dwDesiredAccess,
53 BOOL bInheritHandle,
54 DWORD dwOptions);
55
56 #define WIN_OBJ_DIR L"\\Windows"
57 #define SESSION_DIR L"\\Sessions"
58
59 SYSTEM_BASIC_INFORMATION BaseCachedSysInfo;
60
61 /* FUNCTIONS *****************************************************************/
62
63 NTSTATUS
64 WINAPI
65 OpenBaseDirectory(PHANDLE DirHandle)
66 {
67 OBJECT_ATTRIBUTES ObjectAttributes;
68 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\BaseNamedObjects");
69 UNICODE_STRING SymName = RTL_CONSTANT_STRING(L"Local");
70 UNICODE_STRING SymName2 = RTL_CONSTANT_STRING(L"Global");
71 NTSTATUS Status;
72 HANDLE SymHandle;
73
74 InitializeObjectAttributes(&ObjectAttributes,
75 &Name,
76 OBJ_CASE_INSENSITIVE,
77 NULL,
78 NULL);
79
80 Status = NtOpenDirectoryObject(DirHandle,
81 DIRECTORY_ALL_ACCESS &
82 ~(DELETE | WRITE_DAC | WRITE_OWNER),
83 &ObjectAttributes);
84 if (!NT_SUCCESS(Status))
85 {
86 /* FIXME: It's not our job to create the BNO directory, csr does it */
87 Status = NtCreateDirectoryObject(DirHandle,
88 DIRECTORY_ALL_ACCESS,
89 &ObjectAttributes);
90 if (!NT_SUCCESS(Status))
91 {
92 DPRINT1("NtCreateDirectoryObject() failed\n");
93 }
94
95 /* Create the "local" Symbolic Link. FIXME: CSR should do this */
96 InitializeObjectAttributes(&ObjectAttributes,
97 &SymName,
98 OBJ_CASE_INSENSITIVE,
99 *DirHandle,
100 NULL);
101 Status = NtCreateSymbolicLinkObject(&SymHandle,
102 SYMBOLIC_LINK_ALL_ACCESS,
103 &ObjectAttributes,
104 &Name);
105 if (!NT_SUCCESS(Status))
106 {
107 DPRINT1("NtCreateSymbolicLinkObject() failed\n");
108 }
109
110 /* Create the "global" Symbolic Link. FIXME: CSR should do this */
111 InitializeObjectAttributes(&ObjectAttributes,
112 &SymName2,
113 OBJ_CASE_INSENSITIVE,
114 *DirHandle,
115 NULL);
116 Status = NtCreateSymbolicLinkObject(&SymHandle,
117 SYMBOLIC_LINK_ALL_ACCESS,
118 &ObjectAttributes,
119 &Name);
120 if (!NT_SUCCESS(Status))
121 {
122 DPRINT1("NtCreateSymbolicLinkObject() failed\n");
123 }
124 }
125
126 DPRINT("Opened BNO: %lx\n", *DirHandle);
127 return Status;
128 }
129
130 /*
131 * @unimplemented
132 */
133 BOOL
134 WINAPI
135 BaseQueryModuleData(IN LPSTR ModuleName,
136 IN LPSTR Unknown,
137 IN PVOID Unknown2,
138 IN PVOID Unknown3,
139 IN PVOID Unknown4)
140 {
141 DPRINT1("BaseQueryModuleData called: %s %s %x %x %x\n",
142 ModuleName,
143 Unknown,
144 Unknown2,
145 Unknown3,
146 Unknown4);
147 return FALSE;
148 }
149
150 /*
151 * @unimplemented
152 */
153 NTSTATUS
154 WINAPI
155 BaseProcessInitPostImport(VOID)
156 {
157 /* FIXME: Initialize TS pointers */
158 return STATUS_SUCCESS;
159 }
160
161 BOOL
162 STDCALL
163 BasepInitConsole(VOID)
164 {
165 CSR_API_MESSAGE Request;
166 ULONG CsrRequest;
167 NTSTATUS Status;
168 PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
169
170 WCHAR lpTest[MAX_PATH];
171 GetModuleFileNameW(NULL, lpTest, MAX_PATH);
172 DPRINT("BasepInitConsole for : %S\n", lpTest);
173 DPRINT("Our current console handles are: %lx, %lx, %lx %lx\n",
174 Parameters->ConsoleHandle, Parameters->StandardInput,
175 Parameters->StandardOutput, Parameters->StandardError);
176
177 /* We have nothing to do if this isn't a console app... */
178 if (RtlImageNtHeader(GetModuleHandle(NULL))->OptionalHeader.Subsystem !=
179 IMAGE_SUBSYSTEM_WINDOWS_CUI)
180 {
181 DPRINT("Image is not a console application\n");
182 Parameters->ConsoleHandle = NULL;
183 return TRUE;
184 }
185
186 /* Assume one is needed */
187 Request.Data.AllocConsoleRequest.ConsoleNeeded = TRUE;
188
189 /* Handle the special flags given to us by BasepInitializeEnvironment */
190 if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS)
191 {
192 /* No console to create */
193 DPRINT("No console to create\n");
194 Parameters->ConsoleHandle = NULL;
195 Request.Data.AllocConsoleRequest.ConsoleNeeded = FALSE;
196 }
197 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE)
198 {
199 /* We'll get the real one soon */
200 DPRINT("Creating new console\n");
201 Parameters->ConsoleHandle = NULL;
202 }
203 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW)
204 {
205 /* We'll get the real one soon */
206 DPRINT1("NOT SUPPORTED: HANDLE_CREATE_NO_WINDOW\n");
207 Parameters->ConsoleHandle = NULL;
208 }
209 else
210 {
211 if (Parameters->ConsoleHandle == INVALID_HANDLE_VALUE)
212 {
213 Parameters->ConsoleHandle = 0;
214 }
215 DPRINT("Using existing console: %x\n", Parameters->ConsoleHandle);
216 }
217
218 /* Initialize Console Ctrl Handler */
219 ConsoleInitialized = TRUE;
220 RtlInitializeCriticalSection(&ConsoleLock);
221 SetConsoleCtrlHandler(DefaultConsoleCtrlHandler, TRUE);
222
223 /* Now use the proper console handle */
224 Request.Data.AllocConsoleRequest.Console = Parameters->ConsoleHandle;
225
226 /*
227 * Normally, we should be connecting to the Console CSR Server...
228 * but we don't have one yet, so we will instead simply send a create
229 * console message to the Base Server. When we finally have a Console
230 * Server, this code should be changed to send connection data instead.
231 *
232 * Also note that this connection should be made for any console app, even
233 * in the case above where -we- return.
234 */
235 CsrRequest = MAKE_CSR_API(ALLOC_CONSOLE, CSR_CONSOLE);
236 Request.Data.AllocConsoleRequest.CtrlDispatcher = ConsoleControlDispatcher;
237 Status = CsrClientCallServer(&Request,
238 NULL,
239 CsrRequest,
240 sizeof(CSR_API_MESSAGE));
241 if(!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
242 {
243 DPRINT1("CSR Failed to give us a console\n");
244 /* We're lying here, so at least the process can load... */
245 return TRUE;
246 }
247
248 /* We got the handles, let's set them */
249 if ((Parameters->ConsoleHandle = Request.Data.AllocConsoleRequest.Console))
250 {
251 /* If we already had some, don't use the new ones */
252 if (!Parameters->StandardInput)
253 {
254 Parameters->StandardInput = Request.Data.AllocConsoleRequest.InputHandle;
255 }
256 if (!Parameters->StandardOutput)
257 {
258 Parameters->StandardOutput = Request.Data.AllocConsoleRequest.OutputHandle;
259 }
260 if (!Parameters->StandardError)
261 {
262 Parameters->StandardError = Request.Data.AllocConsoleRequest.OutputHandle;
263 }
264 }
265
266 DPRINT("Console setup: %lx, %lx, %lx, %lx\n",
267 Parameters->ConsoleHandle,
268 Parameters->StandardInput,
269 Parameters->StandardOutput,
270 Parameters->StandardError);
271 return TRUE;
272 }
273
274
275 BOOL
276 STDCALL
277 DllMain(HANDLE hDll,
278 DWORD dwReason,
279 LPVOID lpReserved)
280 {
281 NTSTATUS Status;
282 BOOLEAN IsServer;
283 ULONG Dummy;
284 ULONG DummySize = sizeof(Dummy);
285 WCHAR SessionDir[256];
286
287 DPRINT("DllMain(hInst %lx, dwReason %lu)\n",
288 hDll, dwReason);
289
290 Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
291
292 /* Cache the PEB and Session ID */
293 Peb = NtCurrentPeb();
294 SessionId = Peb->SessionId;
295
296 switch (dwReason)
297 {
298 case DLL_PROCESS_ATTACH:
299
300 /* OK, yes, this is really retarded but it works for now */
301 InWindows = NtCurrentPeb()->BeingDebugged;
302
303 /*
304 * CreateProcess will run in the real kernel32 and it will write
305 * its own BaseProcessStartThunk EIP in the CONTEXT that ZwContinue
306 * will get. We'll be first called by Ldr while initializing, and we'll
307 * be wrapped in 3 layers of SEH, followed by two frames, finally
308 * followed by our CONTEXT on the stack. We'll modify the EIP in it
309 * to match the correct one (our own) and then everything works.
310 * Tested on XP and 2K3, probably doesn't work in 2K.
311 */
312 if (InWindows)
313 {
314 /*
315 * Due to yet another bug in how Windows handles .local, LDR will
316 * actually end up loading us twice. The second time will be the
317 * "official" load, at a totally different address. It will be,
318 * it will be at -that- address that all the APIs will be called.
319 * However, that address is dynamic while this one will be static,
320 * so we'll do initilization with this one. Plus, at this one,
321 * we know exactly that we're within 3 SEH layers.
322 */
323 if (hDll == (HANDLE)0x7c800000)
324 {
325 PULONG Eip;
326 __debugbreak();
327 Eip = (PULONG)*(PULONG)*(PULONG)NtCurrentTeb()->Tib.ExceptionList +
328 0x9 +
329 FIELD_OFFSET(CONTEXT, Eip) / sizeof(ULONG);
330 *Eip = (ULONG)BaseProcessStartThunk;
331 }
332 }
333
334 /* Don't bother us for each thread */
335 LdrDisableThreadCalloutsForDll((PVOID)hDll);
336
337 /* Setup the right Object Directory path */
338 if (!SessionId)
339 {
340 /* Use the raw path */
341 wcscpy(SessionDir, WIN_OBJ_DIR);
342 }
343 else
344 {
345 /* Use the session path */
346 swprintf(SessionDir,
347 L"%ws\\%ld%ws",
348 SESSION_DIR,
349 SessionId,
350 WIN_OBJ_DIR);
351 }
352
353 /* Connect to the base server */
354 DPRINT("Connecting to CSR...\n");
355 Status = CsrClientConnectToServer(SessionDir,
356 InWindows ? 1 : 0,
357 &Dummy,
358 &DummySize,
359 &IsServer);
360 if (!NT_SUCCESS(Status))
361 {
362 DPRINT1("Failed to connect to CSR (Status %lx)\n", Status);
363 ZwTerminateProcess(NtCurrentProcess(), Status);
364 return FALSE;
365 }
366
367 /* Check if we are running a CSR Server */
368 if (!IsServer)
369 {
370 /* Set the termination port for the thread */
371 DPRINT("Creating new thread for CSR\n");
372 CsrNewThread();
373 }
374
375 hProcessHeap = RtlGetProcessHeap();
376 RtlInitializeHandleTable(0xFFFF,
377 sizeof(BASE_HEAP_HANDLE_ENTRY),
378 &BaseHeapHandleTable);
379 hCurrentModule = hDll;
380 DPRINT("Heap: %p\n", hProcessHeap);
381
382 /*
383 * Initialize WindowsDirectory and SystemDirectory
384 */
385 DPRINT("NtSystemRoot: %S\n", SharedUserData->NtSystemRoot);
386 RtlCreateUnicodeString (&WindowsDirectory, SharedUserData->NtSystemRoot);
387 SystemDirectory.MaximumLength = WindowsDirectory.MaximumLength + 18;
388 SystemDirectory.Length = WindowsDirectory.Length + 18;
389 SystemDirectory.Buffer = RtlAllocateHeap(hProcessHeap,
390 0,
391 SystemDirectory.MaximumLength);
392 if(SystemDirectory.Buffer == NULL)
393 {
394 return FALSE;
395 }
396 wcscpy(SystemDirectory.Buffer, WindowsDirectory.Buffer);
397 wcscat(SystemDirectory.Buffer, L"\\System32");
398
399 /* Open object base directory */
400 Status = OpenBaseDirectory(&hBaseDir);
401 if (!NT_SUCCESS(Status))
402 {
403 DPRINT1("Failed to open object base directory (Status %lx)\n", Status);
404 return FALSE;
405 }
406
407 /* Initialize the DLL critical section */
408 RtlInitializeCriticalSection(&DllLock);
409
410 /* Initialize the National Language Support routines */
411 if (!NlsInit())
412 {
413 DPRINT1("NLS Init failed\n");
414 return FALSE;
415 }
416
417 /* Initialize Console Support */
418 if (!BasepInitConsole())
419 {
420 DPRINT1("Failure to set up console\n");
421 return FALSE;
422 }
423
424 /* Cache static system information */
425 Status = ZwQuerySystemInformation(SystemBasicInformation,
426 &BaseCachedSysInfo,
427 sizeof(BaseCachedSysInfo),
428 NULL);
429 if (!NT_SUCCESS(Status))
430 {
431 DPRINT1("Failure to get system information\n");
432 return FALSE;
433 }
434
435 /* Insert more dll attach stuff here! */
436 DllInitialized = TRUE;
437 DPRINT("Initialization complete\n");
438 break;
439
440 case DLL_PROCESS_DETACH:
441
442 DPRINT("DLL_PROCESS_DETACH\n");
443 if (DllInitialized == TRUE)
444 {
445 /* Insert more dll detach stuff here! */
446 NlsUninit();
447
448 /* Delete DLL critical section */
449 if (ConsoleInitialized == TRUE)
450 {
451 RtlDeleteCriticalSection (&ConsoleLock);
452 }
453 RtlDeleteCriticalSection (&DllLock);
454
455 /* Close object base directory */
456 NtClose(hBaseDir);
457
458 RtlFreeUnicodeString (&SystemDirectory);
459 RtlFreeUnicodeString (&WindowsDirectory);
460 }
461 break;
462
463 default:
464 break;
465 }
466
467 return TRUE;
468 }
469
470 LONG
471 WINAPI
472 InterlockedIncrement(IN OUT LONG volatile *lpAddend)
473 {
474 return _InterlockedIncrement(lpAddend);
475 }
476
477 LONG
478 WINAPI
479 InterlockedDecrement(IN OUT LONG volatile *lpAddend)
480 {
481 return _InterlockedDecrement(lpAddend);
482 }
483
484 LONG
485 WINAPI
486 InterlockedExchange(IN OUT LONG volatile *Target,
487 IN LONG Value)
488 {
489 return _InterlockedExchange(Target, Value);
490 }
491
492 LONG
493 WINAPI
494 InterlockedExchangeAdd(IN OUT LONG volatile *Addend,
495 IN LONG Value)
496 {
497 return _InterlockedExchangeAdd(Addend, Value);
498 }
499
500 LONG
501 WINAPI
502 InterlockedCompareExchange(IN OUT LONG volatile *Destination,
503 IN LONG Exchange,
504 IN LONG Comperand)
505 {
506 return _InterlockedCompareExchange(Destination, Exchange, Comperand);
507 }
508
509 /* EOF */