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