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)
12 /* INCLUDES ******************************************************************/
17 #include "../include/debug.h"
19 /* GLOBALS *******************************************************************/
21 extern UNICODE_STRING SystemDirectory
;
22 extern UNICODE_STRING WindowsDirectory
;
24 HANDLE hProcessHeap
= NULL
;
25 HMODULE hCurrentModule
= NULL
;
26 HANDLE hBaseDir
= NULL
;
30 static BOOL DllInitialized
= FALSE
;
31 static BOOL ConsoleInitialized
= FALSE
;
38 /* Critical section for various kernel32 data structures */
39 RTL_CRITICAL_SECTION DllLock
;
40 RTL_CRITICAL_SECTION ConsoleLock
;
42 extern BOOL WINAPI
DefaultConsoleCtrlHandler(DWORD Event
);
43 extern __declspec(noreturn
) VOID CALLBACK
ConsoleControlDispatcher(DWORD CodeAndFlag
);
45 extern BOOL FASTCALL
NlsInit();
46 extern VOID FASTCALL
NlsUninit();
47 BOOLEAN InWindows
= FALSE
;
51 DuplicateConsoleHandle(HANDLE hConsole
,
52 DWORD dwDesiredAccess
,
56 #define WIN_OBJ_DIR L"\\Windows"
57 #define SESSION_DIR L"\\Sessions"
59 SYSTEM_BASIC_INFORMATION BaseCachedSysInfo
;
61 /* FUNCTIONS *****************************************************************/
65 OpenBaseDirectory(PHANDLE DirHandle
)
67 OBJECT_ATTRIBUTES ObjectAttributes
;
68 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\BaseNamedObjects");
69 UNICODE_STRING SymName
= RTL_CONSTANT_STRING(L
"Local");
70 UNICODE_STRING SymName2
= RTL_CONSTANT_STRING(L
"Global");
74 InitializeObjectAttributes(&ObjectAttributes
,
80 Status
= NtOpenDirectoryObject(DirHandle
,
81 DIRECTORY_ALL_ACCESS
&
82 ~(DELETE
| WRITE_DAC
| WRITE_OWNER
),
84 if (!NT_SUCCESS(Status
))
86 /* FIXME: It's not our job to create the BNO directory, csr does it */
87 Status
= NtCreateDirectoryObject(DirHandle
,
90 if (!NT_SUCCESS(Status
))
92 DPRINT1("NtCreateDirectoryObject() failed\n");
95 /* Create the "local" Symbolic Link. FIXME: CSR should do this */
96 InitializeObjectAttributes(&ObjectAttributes
,
101 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
102 SYMBOLIC_LINK_ALL_ACCESS
,
105 if (!NT_SUCCESS(Status
))
107 DPRINT1("NtCreateSymbolicLinkObject() failed\n");
110 /* Create the "global" Symbolic Link. FIXME: CSR should do this */
111 InitializeObjectAttributes(&ObjectAttributes
,
113 OBJ_CASE_INSENSITIVE
,
116 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
117 SYMBOLIC_LINK_ALL_ACCESS
,
120 if (!NT_SUCCESS(Status
))
122 DPRINT1("NtCreateSymbolicLinkObject() failed\n");
126 DPRINT("Opened BNO: %lx\n", *DirHandle
);
135 BaseQueryModuleData(IN LPSTR ModuleName
,
141 DPRINT1("BaseQueryModuleData called: %s %s %x %x %x\n",
155 BaseProcessInitPostImport(VOID
)
157 /* FIXME: Initialize TS pointers */
158 return STATUS_SUCCESS
;
163 BasepInitConsole(VOID
)
165 CSR_API_MESSAGE Request
;
168 PRTL_USER_PROCESS_PARAMETERS Parameters
= NtCurrentPeb()->ProcessParameters
;
170 WCHAR lpTest
[MAX_PATH
];
171 GetModuleFileNameW(NULL
, lpTest
, MAX_PATH
);
172 DPRINT("BasepInitConsole for : %S\n", lpTest
);
173 DPRINT("Our current console handles are: %lx, %lx, %lx %lx\n",
174 Parameters
->ConsoleHandle
, Parameters
->StandardInput
,
175 Parameters
->StandardOutput
, Parameters
->StandardError
);
177 /* We have nothing to do if this isn't a console app... */
178 if (RtlImageNtHeader(GetModuleHandle(NULL
))->OptionalHeader
.Subsystem
!=
179 IMAGE_SUBSYSTEM_WINDOWS_CUI
)
181 DPRINT("Image is not a console application\n");
182 Parameters
->ConsoleHandle
= NULL
;
186 /* Assume one is needed */
187 Request
.Data
.AllocConsoleRequest
.ConsoleNeeded
= TRUE
;
189 /* Handle the special flags given to us by BasepInitializeEnvironment */
190 if (Parameters
->ConsoleHandle
== HANDLE_DETACHED_PROCESS
)
192 /* No console to create */
193 DPRINT("No console to create\n");
194 Parameters
->ConsoleHandle
= NULL
;
195 Request
.Data
.AllocConsoleRequest
.ConsoleNeeded
= FALSE
;
197 else if (Parameters
->ConsoleHandle
== HANDLE_CREATE_NEW_CONSOLE
)
199 /* We'll get the real one soon */
200 DPRINT("Creating new console\n");
201 Parameters
->ConsoleHandle
= NULL
;
203 else if (Parameters
->ConsoleHandle
== HANDLE_CREATE_NO_WINDOW
)
205 /* We'll get the real one soon */
206 DPRINT1("NOT SUPPORTED: HANDLE_CREATE_NO_WINDOW\n");
207 Parameters
->ConsoleHandle
= NULL
;
211 if (Parameters
->ConsoleHandle
== INVALID_HANDLE_VALUE
)
213 Parameters
->ConsoleHandle
= 0;
215 DPRINT("Using existing console: %x\n", Parameters
->ConsoleHandle
);
218 /* Initialize Console Ctrl Handler */
219 ConsoleInitialized
= TRUE
;
220 RtlInitializeCriticalSection(&ConsoleLock
);
221 SetConsoleCtrlHandler(DefaultConsoleCtrlHandler
, TRUE
);
223 /* Now use the proper console handle */
224 Request
.Data
.AllocConsoleRequest
.Console
= Parameters
->ConsoleHandle
;
227 * Normally, we should be connecting to the Console CSR Server...
228 * but we don't have one yet, so we will instead simply send a create
229 * console message to the Base Server. When we finally have a Console
230 * Server, this code should be changed to send connection data instead.
232 * Also note that this connection should be made for any console app, even
233 * in the case above where -we- return.
235 CsrRequest
= MAKE_CSR_API(ALLOC_CONSOLE
, CSR_CONSOLE
);
236 Request
.Data
.AllocConsoleRequest
.CtrlDispatcher
= ConsoleControlDispatcher
;
237 Status
= CsrClientCallServer(&Request
,
240 sizeof(CSR_API_MESSAGE
));
241 if(!NT_SUCCESS(Status
) || !NT_SUCCESS(Status
= Request
.Status
))
243 DPRINT1("CSR Failed to give us a console\n");
244 /* We're lying here, so at least the process can load... */
248 /* We got the handles, let's set them */
249 if ((Parameters
->ConsoleHandle
= Request
.Data
.AllocConsoleRequest
.Console
))
251 /* If we already had some, don't use the new ones */
252 if (!Parameters
->StandardInput
)
254 Parameters
->StandardInput
= Request
.Data
.AllocConsoleRequest
.InputHandle
;
256 if (!Parameters
->StandardOutput
)
258 Parameters
->StandardOutput
= Request
.Data
.AllocConsoleRequest
.OutputHandle
;
260 if (!Parameters
->StandardError
)
262 Parameters
->StandardError
= Request
.Data
.AllocConsoleRequest
.OutputHandle
;
266 DPRINT("Console setup: %lx, %lx, %lx, %lx\n",
267 Parameters
->ConsoleHandle
,
268 Parameters
->StandardInput
,
269 Parameters
->StandardOutput
,
270 Parameters
->StandardError
);
284 ULONG DummySize
= sizeof(Dummy
);
285 WCHAR SessionDir
[256];
287 DPRINT("DllMain(hInst %lx, dwReason %lu)\n",
290 Basep8BitStringToUnicodeString
= RtlAnsiStringToUnicodeString
;
292 /* Cache the PEB and Session ID */
293 Peb
= NtCurrentPeb();
294 SessionId
= Peb
->SessionId
;
298 case DLL_PROCESS_ATTACH
:
300 /* OK, yes, this is really retarded but it works for now */
301 InWindows
= NtCurrentPeb()->BeingDebugged
;
304 * CreateProcess will run in the real kernel32 and it will write
305 * its own BaseProcessStartThunk EIP in the CONTEXT that ZwContinue
306 * will get. We'll be first called by Ldr while initializing, and we'll
307 * be wrapped in 3 layers of SEH, followed by two frames, finally
308 * followed by our CONTEXT on the stack. We'll modify the EIP in it
309 * to match the correct one (our own) and then everything works.
310 * Tested on XP and 2K3, probably doesn't work in 2K.
315 * Due to yet another bug in how Windows handles .local, LDR will
316 * actually end up loading us twice. The second time will be the
317 * "official" load, at a totally different address. It will be,
318 * it will be at -that- address that all the APIs will be called.
319 * However, that address is dynamic while this one will be static,
320 * so we'll do initilization with this one. Plus, at this one,
321 * we know exactly that we're within 3 SEH layers.
323 if (hDll
== (HANDLE
)0x7c800000)
327 Eip
= (PULONG
)*(PULONG
)*(PULONG
)NtCurrentTeb()->Tib
.ExceptionList
+
329 FIELD_OFFSET(CONTEXT
, Eip
) / sizeof(ULONG
);
330 *Eip
= (ULONG
)BaseProcessStartThunk
;
334 /* Don't bother us for each thread */
335 LdrDisableThreadCalloutsForDll((PVOID
)hDll
);
337 /* Setup the right Object Directory path */
340 /* Use the raw path */
341 wcscpy(SessionDir
, WIN_OBJ_DIR
);
345 /* Use the session path */
353 /* Connect to the base server */
354 DPRINT("Connecting to CSR...\n");
355 Status
= CsrClientConnectToServer(SessionDir
,
360 if (!NT_SUCCESS(Status
))
362 DPRINT1("Failed to connect to CSR (Status %lx)\n", Status
);
363 ZwTerminateProcess(NtCurrentProcess(), Status
);
367 /* Check if we are running a CSR Server */
370 /* Set the termination port for the thread */
371 DPRINT("Creating new thread for CSR\n");
375 hProcessHeap
= RtlGetProcessHeap();
376 RtlInitializeHandleTable(0xFFFF,
377 sizeof(BASE_HEAP_HANDLE_ENTRY
),
378 &BaseHeapHandleTable
);
379 hCurrentModule
= hDll
;
380 DPRINT("Heap: %p\n", hProcessHeap
);
383 * Initialize WindowsDirectory and SystemDirectory
385 DPRINT("NtSystemRoot: %S\n", SharedUserData
->NtSystemRoot
);
386 RtlCreateUnicodeString (&WindowsDirectory
, SharedUserData
->NtSystemRoot
);
387 SystemDirectory
.MaximumLength
= WindowsDirectory
.MaximumLength
+ 18;
388 SystemDirectory
.Length
= WindowsDirectory
.Length
+ 18;
389 SystemDirectory
.Buffer
= RtlAllocateHeap(hProcessHeap
,
391 SystemDirectory
.MaximumLength
);
392 if(SystemDirectory
.Buffer
== NULL
)
396 wcscpy(SystemDirectory
.Buffer
, WindowsDirectory
.Buffer
);
397 wcscat(SystemDirectory
.Buffer
, L
"\\System32");
399 /* Open object base directory */
400 Status
= OpenBaseDirectory(&hBaseDir
);
401 if (!NT_SUCCESS(Status
))
403 DPRINT1("Failed to open object base directory (Status %lx)\n", Status
);
407 /* Initialize the DLL critical section */
408 RtlInitializeCriticalSection(&DllLock
);
410 /* Initialize the National Language Support routines */
413 DPRINT1("NLS Init failed\n");
417 /* Initialize Console Support */
418 if (!BasepInitConsole())
420 DPRINT1("Failure to set up console\n");
424 /* Cache static system information */
425 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
427 sizeof(BaseCachedSysInfo
),
429 if (!NT_SUCCESS(Status
))
431 DPRINT1("Failure to get system information\n");
435 /* Insert more dll attach stuff here! */
436 DllInitialized
= TRUE
;
437 DPRINT("Initialization complete\n");
440 case DLL_PROCESS_DETACH
:
442 DPRINT("DLL_PROCESS_DETACH\n");
443 if (DllInitialized
== TRUE
)
445 /* Insert more dll detach stuff here! */
448 /* Delete DLL critical section */
449 if (ConsoleInitialized
== TRUE
)
451 RtlDeleteCriticalSection (&ConsoleLock
);
453 RtlDeleteCriticalSection (&DllLock
);
455 /* Close object base directory */
458 RtlFreeUnicodeString (&SystemDirectory
);
459 RtlFreeUnicodeString (&WindowsDirectory
);
472 InterlockedIncrement(IN OUT LONG
volatile *lpAddend
)
474 return _InterlockedIncrement(lpAddend
);
479 InterlockedDecrement(IN OUT LONG
volatile *lpAddend
)
481 return _InterlockedDecrement(lpAddend
);
486 InterlockedExchange(IN OUT LONG
volatile *Target
,
489 return _InterlockedExchange(Target
, Value
);
494 InterlockedExchangeAdd(IN OUT LONG
volatile *Addend
,
497 return _InterlockedExchangeAdd(Addend
, Value
);
502 InterlockedCompareExchange(IN OUT LONG
volatile *Destination
,
506 return _InterlockedCompareExchange(Destination
, Exchange
, Comperand
);