[NTDLL/KERNEL32/CSRSRV/WIN32K/USER32/WIN32CSR]
[reactos.git] / dll / win32 / kernel32 / client / dllmain.c
1 /* $Id: dllmain.c 56414 2012-04-25 10:17:29Z tfaber $
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 PBASE_STATIC_SERVER_DATA BaseStaticServerData;
23
24 BOOLEAN BaseRunningInServerProcess;
25
26 WCHAR BaseDefaultPathBuffer[6140];
27
28 HANDLE BaseNamedObjectDirectory;
29 HMODULE hCurrentModule = NULL;
30 HMODULE kernel32_handle = NULL;
31 PPEB Peb;
32 ULONG SessionId;
33 BOOL ConsoleInitialized = FALSE;
34 static BOOL DllInitialized = FALSE;
35
36 BOOL WINAPI
37 DllMain(HANDLE hInst,
38 DWORD dwReason,
39 LPVOID lpReserved);
40
41 /* Critical section for various kernel32 data structures */
42 RTL_CRITICAL_SECTION BaseDllDirectoryLock;
43 RTL_CRITICAL_SECTION ConsoleLock;
44
45 extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
46 extern __declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
47 extern PHANDLER_ROUTINE InitialHandler[1];
48 extern PHANDLER_ROUTINE* CtrlHandlers;
49 extern ULONG NrCtrlHandlers;
50 extern ULONG NrAllocatedHandlers;
51 extern BOOL FASTCALL NlsInit(VOID);
52 extern VOID FASTCALL NlsUninit(VOID);
53 BOOLEAN InWindows = FALSE;
54
55 #define WIN_OBJ_DIR L"\\Windows"
56 #define SESSION_DIR L"\\Sessions"
57
58 /* FUNCTIONS *****************************************************************/
59
60 BOOL
61 WINAPI
62 BasepInitConsole(VOID)
63 {
64 CSR_API_MESSAGE Request;
65 NTSTATUS Status;
66 BOOLEAN NotConsole = FALSE;
67 PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
68 LPCWSTR ExeName;
69 STARTUPINFO si;
70 WCHAR SessionDir[256];
71 ULONG SessionId = NtCurrentPeb()->SessionId;
72 BOOLEAN InServer;
73
74 WCHAR lpTest[MAX_PATH];
75 GetModuleFileNameW(NULL, lpTest, MAX_PATH);
76 DPRINT("BasepInitConsole for : %S\n", lpTest);
77 DPRINT("Our current console handles are: %lx, %lx, %lx %lx\n",
78 Parameters->ConsoleHandle, Parameters->StandardInput,
79 Parameters->StandardOutput, Parameters->StandardError);
80
81 /* We have nothing to do if this isn't a console app... */
82 if (RtlImageNtHeader(GetModuleHandle(NULL))->OptionalHeader.Subsystem !=
83 IMAGE_SUBSYSTEM_WINDOWS_CUI)
84 {
85 DPRINT("Image is not a console application\n");
86 Parameters->ConsoleHandle = NULL;
87 Request.Data.AllocConsoleRequest.ConsoleNeeded = FALSE;
88 }
89 else
90 {
91 /* Assume one is needed */
92 GetStartupInfo(&si);
93 Request.Data.AllocConsoleRequest.ConsoleNeeded = TRUE;
94 Request.Data.AllocConsoleRequest.ShowCmd = si.wShowWindow;
95
96 /* Handle the special flags given to us by BasepInitializeEnvironment */
97 if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS)
98 {
99 /* No console to create */
100 DPRINT("No console to create\n");
101 Parameters->ConsoleHandle = NULL;
102 Request.Data.AllocConsoleRequest.ConsoleNeeded = FALSE;
103 }
104 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE)
105 {
106 /* We'll get the real one soon */
107 DPRINT("Creating new console\n");
108 Parameters->ConsoleHandle = NULL;
109 }
110 else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW)
111 {
112 /* We'll get the real one soon */
113 DPRINT("Creating new invisible console\n");
114 Parameters->ConsoleHandle = NULL;
115 Request.Data.AllocConsoleRequest.ShowCmd = SW_HIDE;
116 }
117 else
118 {
119 if (Parameters->ConsoleHandle == INVALID_HANDLE_VALUE)
120 {
121 Parameters->ConsoleHandle = 0;
122 }
123 DPRINT("Using existing console: %x\n", Parameters->ConsoleHandle);
124 }
125 }
126
127 /* Initialize Console Ctrl Handler and input EXE name */
128 ConsoleInitialized = TRUE;
129 RtlInitializeCriticalSection(&ConsoleLock);
130 NrAllocatedHandlers = 1;
131 NrCtrlHandlers = 1;
132 CtrlHandlers = InitialHandler;
133 CtrlHandlers[0] = DefaultConsoleCtrlHandler;
134
135 ExeName = wcsrchr(Parameters->ImagePathName.Buffer, L'\\');
136 if (ExeName)
137 SetConsoleInputExeNameW(ExeName + 1);
138
139 /* Now use the proper console handle */
140 Request.Data.AllocConsoleRequest.Console = Parameters->ConsoleHandle;
141
142 /* Setup the right Object Directory path */
143 if (!SessionId)
144 {
145 /* Use the raw path */
146 wcscpy(SessionDir, WIN_OBJ_DIR);
147 }
148 else
149 {
150 /* Use the session path */
151 swprintf(SessionDir,
152 L"%ws\\%ld%ws",
153 SESSION_DIR,
154 SessionId,
155 WIN_OBJ_DIR);
156 }
157
158 /* Connect to the base server */
159 DPRINT("Connecting to CSR...\n");
160 Status = CsrClientConnectToServer(SessionDir,
161 2,
162 NULL,
163 NULL,
164 &InServer);
165 if (!NT_SUCCESS(Status))
166 {
167 DPRINT1("Failed to connect to CSR (Status %lx)\n", Status);
168 return FALSE;
169 }
170
171 /* Nothing to do for server-to-server */
172 if (InServer) return TRUE;
173
174 /*
175 * Normally, we should be connecting to the Console CSR Server...
176 * but we don't have one yet, so we will instead simply send a create
177 * console message to the Base Server. When we finally have a Console
178 * Server, this code should be changed to send connection data instead.
179 */
180 Request.Data.AllocConsoleRequest.CtrlDispatcher = ConsoleControlDispatcher;
181 Status = CsrClientCallServer(&Request,
182 NULL,
183 CSR_CREATE_API_NUMBER(CSR_CONSOLE, ALLOC_CONSOLE),
184 sizeof(CSR_API_MESSAGE));
185 if(!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
186 {
187 DPRINT1("CSR Failed to give us a console\n");
188 /* We're lying here, so at least the process can load... */
189 return TRUE;
190 }
191
192 /* Nothing to do if not a console app */
193 if (NotConsole) return TRUE;
194
195 /* We got the handles, let's set them */
196 if ((Parameters->ConsoleHandle = Request.Data.AllocConsoleRequest.Console))
197 {
198 /* If we already had some, don't use the new ones */
199 if (!Parameters->StandardInput)
200 {
201 Parameters->StandardInput = Request.Data.AllocConsoleRequest.InputHandle;
202 }
203 if (!Parameters->StandardOutput)
204 {
205 Parameters->StandardOutput = Request.Data.AllocConsoleRequest.OutputHandle;
206 }
207 if (!Parameters->StandardError)
208 {
209 Parameters->StandardError = Request.Data.AllocConsoleRequest.OutputHandle;
210 }
211 }
212
213 DPRINT("Console setup: %lx, %lx, %lx, %lx\n",
214 Parameters->ConsoleHandle,
215 Parameters->StandardInput,
216 Parameters->StandardOutput,
217 Parameters->StandardError);
218 return TRUE;
219 }
220
221 NTSTATUS
222 NTAPI
223 BaseCreateThreadPoolThread(IN PTHREAD_START_ROUTINE Function,
224 IN PVOID Parameter,
225 OUT PHANDLE ThreadHandle)
226 {
227 NTSTATUS Status;
228
229 /* Create a Win32 thread */
230 *ThreadHandle = CreateRemoteThread(NtCurrentProcess(),
231 NULL,
232 0,
233 Function,
234 Parameter,
235 CREATE_SUSPENDED,
236 NULL);
237 if (!(*ThreadHandle))
238 {
239 /* Get the status value if we couldn't get a handle */
240 Status = NtCurrentTeb()->LastStatusValue;
241 if (NT_SUCCESS(Status)) Status = STATUS_UNSUCCESSFUL;
242 }
243 else
244 {
245 /* Set success code */
246 Status = STATUS_SUCCESS;
247 }
248
249 /* All done */
250 return Status;
251 }
252
253 NTSTATUS
254 NTAPI
255 BaseExitThreadPoolThread(IN NTSTATUS ExitStatus)
256 {
257 /* Exit the thread */
258 ExitThread(ExitStatus);
259 }
260
261 BOOL
262 WINAPI
263 DllMain(HANDLE hDll,
264 DWORD dwReason,
265 LPVOID lpReserved)
266 {
267 NTSTATUS Status;
268 ULONG Dummy;
269 ULONG DummySize = sizeof(Dummy);
270 WCHAR SessionDir[256];
271
272 DPRINT("DllMain(hInst %lx, dwReason %lu)\n",
273 hDll, dwReason);
274
275 Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString;
276
277 /* Cache the PEB and Session ID */
278 Peb = NtCurrentPeb();
279 SessionId = Peb->SessionId;
280
281 switch (dwReason)
282 {
283 case DLL_PROCESS_ATTACH:
284
285 /* Set no filter intially */
286 GlobalTopLevelExceptionFilter = RtlEncodePointer(NULL);
287
288 /* Enable the Rtl thread pool and timer queue to use proper Win32 thread */
289 RtlSetThreadPoolStartFunc(BaseCreateThreadPoolThread, BaseExitThreadPoolThread);
290
291 /* Don't bother us for each thread */
292 LdrDisableThreadCalloutsForDll((PVOID)hDll);
293
294 /* Initialize default path to NULL */
295 RtlInitUnicodeString(&BaseDefaultPath, NULL);
296
297 /* Setup the right Object Directory path */
298 if (!SessionId)
299 {
300 /* Use the raw path */
301 wcscpy(SessionDir, WIN_OBJ_DIR);
302 }
303 else
304 {
305 /* Use the session path */
306 swprintf(SessionDir,
307 L"%ws\\%ld%ws",
308 SESSION_DIR,
309 SessionId,
310 WIN_OBJ_DIR);
311 }
312
313 /* Connect to the base server */
314 DPRINT("Connecting to CSR...\n");
315 Status = CsrClientConnectToServer(SessionDir,
316 InWindows ? 1 : 0,
317 &Dummy,
318 &DummySize,
319 &BaseRunningInServerProcess);
320 if (!NT_SUCCESS(Status))
321 {
322 DPRINT1("Failed to connect to CSR (Status %lx)\n", Status);
323 NtTerminateProcess(NtCurrentProcess(), Status);
324 return FALSE;
325 }
326
327 /* Get the server data */
328 ASSERT(Peb->ReadOnlyStaticServerData);
329 BaseStaticServerData = Peb->ReadOnlyStaticServerData[CSR_CONSOLE];
330 ASSERT(BaseStaticServerData);
331
332 /* Check if we are running a CSR Server */
333 if (!BaseRunningInServerProcess)
334 {
335 /* Set the termination port for the thread */
336 DPRINT("Creating new thread for CSR\n");
337 CsrNewThread();
338 }
339
340 /* Initialize heap handle table */
341 BaseDllInitializeMemoryManager();
342
343 /* Set HMODULE for our DLL */
344 kernel32_handle = hCurrentModule = hDll;
345
346 /* Set the directories */
347 BaseWindowsDirectory = BaseStaticServerData->WindowsDirectory;
348 BaseWindowsSystemDirectory = BaseStaticServerData->WindowsSystemDirectory;
349
350 /* Construct the default path (using the static buffer) */
351 _snwprintf(BaseDefaultPathBuffer, sizeof(BaseDefaultPathBuffer) / sizeof(WCHAR),
352 L".;%wZ;%wZ\\system;%wZ;", &BaseWindowsSystemDirectory, &BaseWindowsDirectory, &BaseWindowsDirectory);
353
354 BaseDefaultPath.Buffer = BaseDefaultPathBuffer;
355 BaseDefaultPath.Length = wcslen(BaseDefaultPathBuffer) * sizeof(WCHAR);
356 BaseDefaultPath.MaximumLength = sizeof(BaseDefaultPathBuffer);
357
358 /* Use remaining part of the default path buffer for the append path */
359 BaseDefaultPathAppend.Buffer = (PWSTR)((ULONG_PTR)BaseDefaultPathBuffer + BaseDefaultPath.Length);
360 BaseDefaultPathAppend.Length = 0;
361 BaseDefaultPathAppend.MaximumLength = BaseDefaultPath.MaximumLength - BaseDefaultPath.Length;
362
363 /* Initialize command line */
364 InitCommandLines();
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 /* Initialize application certification globals */
384 InitializeListHead(&BasepAppCertDllsList);
385 RtlInitializeCriticalSection(&gcsAppCert);
386
387 /* Insert more dll attach stuff here! */
388 DllInitialized = TRUE;
389 DPRINT("Initialization complete\n");
390 break;
391
392 case DLL_PROCESS_DETACH:
393
394 DPRINT("DLL_PROCESS_DETACH\n");
395 if (DllInitialized == TRUE)
396 {
397 /* Insert more dll detach stuff here! */
398 NlsUninit();
399
400 /* Delete DLL critical section */
401 if (ConsoleInitialized == TRUE)
402 {
403 ConsoleInitialized = FALSE;
404 RtlDeleteCriticalSection (&ConsoleLock);
405 }
406 RtlDeleteCriticalSection (&BaseDllDirectoryLock);
407 }
408 break;
409
410 default:
411 break;
412 }
413
414 return TRUE;
415 }
416
417 /* EOF */