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