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