Sync with trunk head.
[reactos.git] / 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 <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 BOOL ConsoleInitialized = FALSE;
30
31 static BOOL DllInitialized = FALSE;
32
33 BOOL WINAPI
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 extern PHANDLER_ROUTINE InitialHandler[1];
45 extern PHANDLER_ROUTINE* CtrlHandlers;
46 extern ULONG NrCtrlHandlers;
47 extern ULONG NrAllocatedHandlers;
48 extern BOOL FASTCALL NlsInit(VOID);
49 extern VOID FASTCALL NlsUninit(VOID);
50 BOOLEAN InWindows = FALSE;
51
52 HANDLE
53 WINAPI
54 DuplicateConsoleHandle(HANDLE hConsole,
55 DWORD dwDesiredAccess,
56 BOOL bInheritHandle,
57 DWORD dwOptions);
58
59 #define WIN_OBJ_DIR L"\\Windows"
60 #define SESSION_DIR L"\\Sessions"
61
62 SYSTEM_BASIC_INFORMATION BaseCachedSysInfo;
63
64 /* FUNCTIONS *****************************************************************/
65
66 NTSTATUS
67 WINAPI
68 OpenBaseDirectory(PHANDLE DirHandle)
69 {
70 OBJECT_ATTRIBUTES ObjectAttributes;
71 UNICODE_STRING Name = RTL_CONSTANT_STRING(L"\\BaseNamedObjects");
72 NTSTATUS Status;
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 return Status;
87 }
88
89 DPRINT("Opened BNO: %lx\n", *DirHandle);
90 return Status;
91 }
92
93 /*
94 * @unimplemented
95 */
96 BOOL
97 WINAPI
98 BaseQueryModuleData(IN LPSTR ModuleName,
99 IN LPSTR Unknown,
100 IN PVOID Unknown2,
101 IN PVOID Unknown3,
102 IN PVOID Unknown4)
103 {
104 DPRINT1("BaseQueryModuleData called: %s %s %x %x %x\n",
105 ModuleName,
106 Unknown,
107 Unknown2,
108 Unknown3,
109 Unknown4);
110 return FALSE;
111 }
112
113 /*
114 * @unimplemented
115 */
116 NTSTATUS
117 WINAPI
118 BaseProcessInitPostImport(VOID)
119 {
120 /* FIXME: Initialize TS pointers */
121 return STATUS_SUCCESS;
122 }
123
124 BOOL
125 WINAPI
126 BasepInitConsole(VOID)
127 {
128 CSR_API_MESSAGE Request;
129 ULONG CsrRequest;
130 NTSTATUS Status;
131 BOOLEAN NotConsole = FALSE;
132 PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
133
134 WCHAR lpTest[MAX_PATH];
135 GetModuleFileNameW(NULL, lpTest, MAX_PATH);
136 DPRINT("BasepInitConsole for : %S\n", lpTest);
137 DPRINT("Our current console handles are: %lx, %lx, %lx %lx\n",
138 Parameters->ConsoleHandle, Parameters->StandardInput,
139 Parameters->StandardOutput, Parameters->StandardError);
140
141 /* We have nothing to do if this isn't a console app... */
142 if (RtlImageNtHeader(GetModuleHandle(NULL))->OptionalHeader.Subsystem !=
143 IMAGE_SUBSYSTEM_WINDOWS_CUI)
144 {
145 DPRINT("Image is not a console application\n");
146 Parameters->ConsoleHandle = NULL;
147 Request.Data.AllocConsoleRequest.ConsoleNeeded = FALSE;
148 }
149 else
150 {
151 /* Assume one is needed */
152 Request.Data.AllocConsoleRequest.ConsoleNeeded = TRUE;
153
154 /* Handle the special flags given to us by BasepInitializeEnvironment */
155 if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS)
156 {
157 /* No console to create */
158 DPRINT("No console to create\n");
159 Parameters->ConsoleHandle = NULL;
160 Request.Data.AllocConsoleRequest.ConsoleNeeded = FALSE;
161 }
162 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE)
163 {
164 /* We'll get the real one soon */
165 DPRINT("Creating new console\n");
166 Parameters->ConsoleHandle = NULL;
167 }
168 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW)
169 {
170 /* We'll get the real one soon */
171 DPRINT1("NOT SUPPORTED: HANDLE_CREATE_NO_WINDOW\n");
172 Parameters->ConsoleHandle = NULL;
173 }
174 else
175 {
176 if (Parameters->ConsoleHandle == INVALID_HANDLE_VALUE)
177 {
178 Parameters->ConsoleHandle = 0;
179 }
180 DPRINT("Using existing console: %x\n", Parameters->ConsoleHandle);
181 }
182 }
183
184 /* Initialize Console Ctrl Handler */
185 ConsoleInitialized = TRUE;
186 RtlInitializeCriticalSection(&ConsoleLock);
187 NrAllocatedHandlers = 1;
188 NrCtrlHandlers = 1;
189 CtrlHandlers = InitialHandler;
190 CtrlHandlers[0] = DefaultConsoleCtrlHandler;
191
192 /* Now use the proper console handle */
193 Request.Data.AllocConsoleRequest.Console = Parameters->ConsoleHandle;
194
195 /*
196 * Normally, we should be connecting to the Console CSR Server...
197 * but we don't have one yet, so we will instead simply send a create
198 * console message to the Base Server. When we finally have a Console
199 * Server, this code should be changed to send connection data instead.
200 */
201 CsrRequest = MAKE_CSR_API(ALLOC_CONSOLE, CSR_CONSOLE);
202 Request.Data.AllocConsoleRequest.CtrlDispatcher = ConsoleControlDispatcher;
203 Status = CsrClientCallServer(&Request,
204 NULL,
205 CsrRequest,
206 sizeof(CSR_API_MESSAGE));
207 if(!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
208 {
209 DPRINT1("CSR Failed to give us a console\n");
210 /* We're lying here, so at least the process can load... */
211 return TRUE;
212 }
213
214 if (NotConsole) return TRUE;
215
216 /* We got the handles, let's set them */
217 if ((Parameters->ConsoleHandle = Request.Data.AllocConsoleRequest.Console))
218 {
219 /* If we already had some, don't use the new ones */
220 if (!Parameters->StandardInput)
221 {
222 Parameters->StandardInput = Request.Data.AllocConsoleRequest.InputHandle;
223 }
224 if (!Parameters->StandardOutput)
225 {
226 Parameters->StandardOutput = Request.Data.AllocConsoleRequest.OutputHandle;
227 }
228 if (!Parameters->StandardError)
229 {
230 Parameters->StandardError = Request.Data.AllocConsoleRequest.OutputHandle;
231 }
232 }
233
234 DPRINT("Console setup: %lx, %lx, %lx, %lx\n",
235 Parameters->ConsoleHandle,
236 Parameters->StandardInput,
237 Parameters->StandardOutput,
238 Parameters->StandardError);
239 return TRUE;
240 }
241
242
243 BOOL
244 WINAPI
245 DllMain(HANDLE hDll,
246 DWORD dwReason,
247 LPVOID lpReserved)
248 {
249 NTSTATUS Status;
250 BOOLEAN IsServer;
251 ULONG Dummy;
252 ULONG DummySize = sizeof(Dummy);
253 WCHAR SessionDir[256];
254
255 DPRINT("DllMain(hInst %lx, dwReason %lu)\n",
256 hDll, dwReason);
257
258 Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
259
260 /* Cache the PEB and Session ID */
261 Peb = NtCurrentPeb();
262 SessionId = Peb->SessionId;
263
264 switch (dwReason)
265 {
266 case DLL_PROCESS_ATTACH:
267
268 /* Don't bother us for each thread */
269 LdrDisableThreadCalloutsForDll((PVOID)hDll);
270
271 /* Setup the right Object Directory path */
272 if (!SessionId)
273 {
274 /* Use the raw path */
275 wcscpy(SessionDir, WIN_OBJ_DIR);
276 }
277 else
278 {
279 /* Use the session path */
280 swprintf(SessionDir,
281 L"%ws\\%ld%ws",
282 SESSION_DIR,
283 SessionId,
284 WIN_OBJ_DIR);
285 }
286
287 /* Connect to the base server */
288 DPRINT("Connecting to CSR...\n");
289 Status = CsrClientConnectToServer(SessionDir,
290 InWindows ? 1 : 0,
291 &Dummy,
292 &DummySize,
293 &IsServer);
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT1("Failed to connect to CSR (Status %lx)\n", Status);
297 ZwTerminateProcess(NtCurrentProcess(), Status);
298 return FALSE;
299 }
300
301 /* Check if we are running a CSR Server */
302 if (!IsServer)
303 {
304 /* Set the termination port for the thread */
305 DPRINT("Creating new thread for CSR\n");
306 CsrNewThread();
307 }
308
309 hProcessHeap = RtlGetProcessHeap();
310 RtlInitializeHandleTable(0xFFFF,
311 sizeof(BASE_HEAP_HANDLE_ENTRY),
312 &BaseHeapHandleTable);
313 hCurrentModule = hDll;
314 DPRINT("Heap: %p\n", hProcessHeap);
315
316 /*
317 * Initialize WindowsDirectory and SystemDirectory
318 */
319 DPRINT("NtSystemRoot: %S\n", SharedUserData->NtSystemRoot);
320 RtlCreateUnicodeString (&WindowsDirectory, SharedUserData->NtSystemRoot);
321 SystemDirectory.MaximumLength = WindowsDirectory.MaximumLength + 18;
322 SystemDirectory.Length = WindowsDirectory.Length + 18;
323 SystemDirectory.Buffer = RtlAllocateHeap(hProcessHeap,
324 0,
325 SystemDirectory.MaximumLength);
326 if(SystemDirectory.Buffer == NULL)
327 {
328 return FALSE;
329 }
330 wcscpy(SystemDirectory.Buffer, WindowsDirectory.Buffer);
331 wcscat(SystemDirectory.Buffer, L"\\System32");
332
333 /* Open object base directory */
334 Status = OpenBaseDirectory(&hBaseDir);
335 if (!NT_SUCCESS(Status))
336 {
337 DPRINT1("Failed to open object base directory (Status %lx)\n", Status);
338 return FALSE;
339 }
340
341 /* Initialize the DLL critical section */
342 RtlInitializeCriticalSection(&DllLock);
343
344 /* Initialize the National Language Support routines */
345 if (!NlsInit())
346 {
347 DPRINT1("NLS Init failed\n");
348 return FALSE;
349 }
350
351 /* Initialize Console Support */
352 if (!BasepInitConsole())
353 {
354 DPRINT1("Failure to set up console\n");
355 return FALSE;
356 }
357
358 /* Cache static system information */
359 Status = ZwQuerySystemInformation(SystemBasicInformation,
360 &BaseCachedSysInfo,
361 sizeof(BaseCachedSysInfo),
362 NULL);
363 if (!NT_SUCCESS(Status))
364 {
365 DPRINT1("Failure to get system information\n");
366 return FALSE;
367 }
368
369 /* Insert more dll attach stuff here! */
370 DllInitialized = TRUE;
371 DPRINT("Initialization complete\n");
372 break;
373
374 case DLL_PROCESS_DETACH:
375
376 DPRINT("DLL_PROCESS_DETACH\n");
377 if (DllInitialized == TRUE)
378 {
379 /* Insert more dll detach stuff here! */
380 NlsUninit();
381
382 /* Delete DLL critical section */
383 if (ConsoleInitialized == TRUE)
384 {
385 ConsoleInitialized = FALSE;
386 RtlDeleteCriticalSection (&ConsoleLock);
387 }
388 RtlDeleteCriticalSection (&DllLock);
389
390 /* Close object base directory */
391 NtClose(hBaseDir);
392
393 RtlFreeUnicodeString (&SystemDirectory);
394 RtlFreeUnicodeString (&WindowsDirectory);
395 }
396 break;
397
398 default:
399 break;
400 }
401
402 return TRUE;
403 }
404
405 #undef InterlockedIncrement
406 #undef InterlockedDecrement
407 #undef InterlockedExchange
408 #undef InterlockedExchangeAdd
409 #undef InterlockedCompareExchange
410
411 LONG
412 WINAPI
413 InterlockedIncrement(IN OUT LONG volatile *lpAddend)
414 {
415 return _InterlockedIncrement(lpAddend);
416 }
417
418 LONG
419 WINAPI
420 InterlockedDecrement(IN OUT LONG volatile *lpAddend)
421 {
422 return _InterlockedDecrement(lpAddend);
423 }
424
425 LONG
426 WINAPI
427 InterlockedExchange(IN OUT LONG volatile *Target,
428 IN LONG Value)
429 {
430 return _InterlockedExchange(Target, Value);
431 }
432
433 LONG
434 WINAPI
435 InterlockedExchangeAdd(IN OUT LONG volatile *Addend,
436 IN LONG Value)
437 {
438 return _InterlockedExchangeAdd(Addend, Value);
439 }
440
441 LONG
442 WINAPI
443 InterlockedCompareExchange(IN OUT LONG volatile *Destination,
444 IN LONG Exchange,
445 IN LONG Comperand)
446 {
447 return _InterlockedCompareExchange(Destination, Exchange, Comperand);
448 }
449
450 /* EOF */