b95ea29efac407a58fdf55acee156422cde0dc9b
[reactos.git] / reactos / lib / kernel32 / misc / ldr.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT : ReactOS user mode libraries
5 * MODULE : kernel32.dll
6 * FILE : reactos/lib/kernel32/misc/ldr.c
7 * AUTHOR : Boudewijn Dekker
8 */
9
10 #include <k32.h>
11
12 #define NDEBUG
13 #include "../include/debug.h"
14
15 typedef struct tagLOADPARMS32 {
16 LPSTR lpEnvAddress;
17 LPSTR lpCmdLine;
18 LPSTR lpCmdShow;
19 DWORD dwReserved;
20 } LOADPARMS32;
21
22 /* FUNCTIONS ****************************************************************/
23
24 /**
25 * @name GetDllLoadPath
26 *
27 * Internal function to compute the load path to use for a given dll.
28 *
29 * @remarks Returned pointer must be freed by caller.
30 */
31
32 LPWSTR STDCALL
33 GetDllLoadPath(LPCWSTR lpModule)
34 {
35 ULONG Pos = 0, Length = 0;
36 PWCHAR EnvironmentBufferW = NULL;
37 LPCWSTR lpModuleEnd = NULL;
38 UNICODE_STRING ModuleName;
39
40 if (lpModule != NULL)
41 {
42 lpModuleEnd = lpModule + wcslen(lpModule);
43 }
44 else
45 {
46 ModuleName = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName;
47 lpModule = ModuleName.Buffer;
48 lpModuleEnd = lpModule + (ModuleName.Length / sizeof(WCHAR));
49 }
50
51 if (lpModule != NULL)
52 {
53 while (lpModuleEnd > lpModule && *lpModuleEnd != L'/' &&
54 *lpModuleEnd != L'\\' && *lpModuleEnd != L':')
55 --lpModuleEnd;
56 Length = (lpModuleEnd - lpModule) + 1;
57 }
58
59 Length += GetCurrentDirectoryW(0, NULL);
60 Length += GetSystemDirectoryW(NULL, 0);
61 Length += GetWindowsDirectoryW(NULL, 0);
62 Length += GetEnvironmentVariableW(L"PATH", NULL, 0);
63
64 EnvironmentBufferW = RtlAllocateHeap(RtlGetProcessHeap(), 0,
65 Length * sizeof(WCHAR));
66 if (EnvironmentBufferW == NULL)
67 return NULL;
68
69 if (lpModule)
70 {
71 RtlCopyMemory(EnvironmentBufferW, lpModule,
72 (lpModuleEnd - lpModule) * sizeof(WCHAR));
73 Pos += lpModuleEnd - lpModule;
74 EnvironmentBufferW[Pos++] = L';';
75 }
76 Pos += GetCurrentDirectoryW(Length, EnvironmentBufferW + Pos);
77 EnvironmentBufferW[Pos++] = L';';
78 Pos += GetSystemDirectoryW(EnvironmentBufferW + Pos, Length - Pos);
79 EnvironmentBufferW[Pos++] = L';';
80 Pos += GetWindowsDirectoryW(EnvironmentBufferW + Pos, Length - Pos);
81 EnvironmentBufferW[Pos++] = L';';
82 Pos += GetEnvironmentVariableW(L"PATH", EnvironmentBufferW + Pos, Length - Pos);
83 EnvironmentBufferW[Pos] = 0;
84
85 return EnvironmentBufferW;
86 }
87
88 /*
89 * @implemented
90 */
91 BOOL
92 STDCALL
93 DisableThreadLibraryCalls (
94 HMODULE hLibModule
95 )
96 {
97 NTSTATUS Status;
98
99 Status = LdrDisableThreadCalloutsForDll ((PVOID)hLibModule);
100 if (!NT_SUCCESS (Status))
101 {
102 SetLastErrorByStatus (Status);
103 return FALSE;
104 }
105 return TRUE;
106 }
107
108
109 /*
110 * @implemented
111 */
112 HINSTANCE
113 STDCALL
114 LoadLibraryA (
115 LPCSTR lpLibFileName
116 )
117 {
118 return LoadLibraryExA (lpLibFileName, 0, 0);
119 }
120
121
122 /*
123 * @implemented
124 */
125 HINSTANCE
126 STDCALL
127 LoadLibraryExA (
128 LPCSTR lpLibFileName,
129 HANDLE hFile,
130 DWORD dwFlags
131 )
132 {
133 PWCHAR FileNameW;
134
135 if (!(FileNameW = FilenameA2W(lpLibFileName, FALSE)))
136 return FALSE;
137
138 return LoadLibraryExW(FileNameW, hFile, dwFlags);
139 }
140
141
142 /*
143 * @implemented
144 */
145 HINSTANCE
146 STDCALL
147 LoadLibraryW (
148 LPCWSTR lpLibFileName
149 )
150 {
151 return LoadLibraryExW (lpLibFileName, 0, 0);
152 }
153
154
155 /*
156 * @implemented
157 */
158 HINSTANCE
159 STDCALL
160 LoadLibraryExW (
161 LPCWSTR lpLibFileName,
162 HANDLE hFile,
163 DWORD dwFlags
164 )
165 {
166 UNICODE_STRING DllName;
167 HINSTANCE hInst;
168 NTSTATUS Status;
169 PWSTR SearchPath;
170
171 (void)hFile;
172
173 if ( lpLibFileName == NULL )
174 return NULL;
175
176 dwFlags &=
177 DONT_RESOLVE_DLL_REFERENCES |
178 LOAD_LIBRARY_AS_DATAFILE |
179 LOAD_WITH_ALTERED_SEARCH_PATH;
180
181 SearchPath = GetDllLoadPath(
182 dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH ? lpLibFileName : NULL);
183
184 RtlInitUnicodeString(&DllName, (LPWSTR)lpLibFileName);
185 Status = LdrLoadDll(SearchPath, dwFlags, &DllName, (PVOID*)&hInst);
186 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
187 if ( !NT_SUCCESS(Status))
188 {
189 SetLastErrorByStatus (Status);
190 return NULL;
191 }
192
193 return hInst;
194 }
195
196
197 /*
198 * @implemented
199 */
200 FARPROC
201 STDCALL
202 GetProcAddress( HMODULE hModule, LPCSTR lpProcName )
203 {
204 ANSI_STRING ProcedureName;
205 FARPROC fnExp = NULL;
206
207 if (HIWORD(lpProcName) != 0)
208 {
209 RtlInitAnsiString (&ProcedureName,
210 (LPSTR)lpProcName);
211 LdrGetProcedureAddress ((PVOID)hModule,
212 &ProcedureName,
213 0,
214 (PVOID*)&fnExp);
215 }
216 else
217 {
218 LdrGetProcedureAddress ((PVOID)hModule,
219 NULL,
220 (ULONG)lpProcName,
221 (PVOID*)&fnExp);
222 }
223
224 return fnExp;
225 }
226
227
228 /*
229 * @implemented
230 */
231 BOOL
232 STDCALL
233 FreeLibrary( HMODULE hLibModule )
234 {
235 LdrUnloadDll(hLibModule);
236 return TRUE;
237 }
238
239
240 /*
241 * @implemented
242 */
243 VOID
244 STDCALL
245 FreeLibraryAndExitThread (
246 HMODULE hLibModule,
247 DWORD dwExitCode
248 )
249 {
250 if ( FreeLibrary(hLibModule) )
251 ExitThread(dwExitCode);
252 for (;;)
253 ;
254 }
255
256
257 /*
258 * @implemented
259 */
260 DWORD
261 STDCALL
262 GetModuleFileNameA (
263 HINSTANCE hModule,
264 LPSTR lpFilename,
265 DWORD nSize
266 )
267 {
268 ANSI_STRING FileName;
269 PLIST_ENTRY ModuleListHead;
270 PLIST_ENTRY Entry;
271 PLDR_DATA_TABLE_ENTRY Module;
272 PPEB Peb;
273 ULONG Length = 0;
274
275 Peb = NtCurrentPeb ();
276 RtlEnterCriticalSection (Peb->LoaderLock);
277
278 if (hModule == NULL)
279 hModule = Peb->ImageBaseAddress;
280
281 ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
282 Entry = ModuleListHead->Flink;
283
284 while (Entry != ModuleListHead)
285 {
286 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
287 if (Module->DllBase == (PVOID)hModule)
288 {
289 if (nSize * sizeof(WCHAR) < Module->FullDllName.Length)
290 {
291 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL);
292 }
293 else
294 {
295 FileName.Length = 0;
296 FileName.MaximumLength = nSize * sizeof(WCHAR);
297 FileName.Buffer = lpFilename;
298
299 /* convert unicode string to ansi (or oem) */
300 if (bIsFileApiAnsi)
301 RtlUnicodeStringToAnsiString (&FileName,
302 &Module->FullDllName,
303 FALSE);
304 else
305 RtlUnicodeStringToOemString (&FileName,
306 &Module->FullDllName,
307 FALSE);
308 Length = Module->FullDllName.Length / sizeof(WCHAR);
309 }
310
311 RtlLeaveCriticalSection (Peb->LoaderLock);
312 return Length;
313 }
314
315 Entry = Entry->Flink;
316 }
317
318 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND);
319 RtlLeaveCriticalSection (Peb->LoaderLock);
320
321 return 0;
322 }
323
324
325 /*
326 * @implemented
327 */
328 DWORD
329 STDCALL
330 GetModuleFileNameW (
331 HINSTANCE hModule,
332 LPWSTR lpFilename,
333 DWORD nSize
334 )
335 {
336 UNICODE_STRING FileName;
337 PLIST_ENTRY ModuleListHead;
338 PLIST_ENTRY Entry;
339 PLDR_DATA_TABLE_ENTRY Module;
340 PPEB Peb;
341 ULONG Length = 0;
342
343 Peb = NtCurrentPeb ();
344 RtlEnterCriticalSection (Peb->LoaderLock);
345
346 if (hModule == NULL)
347 hModule = Peb->ImageBaseAddress;
348
349 ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
350 Entry = ModuleListHead->Flink;
351 while (Entry != ModuleListHead)
352 {
353 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
354
355 if (Module->DllBase == (PVOID)hModule)
356 {
357 if (nSize * sizeof(WCHAR) < Module->FullDllName.Length)
358 {
359 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL);
360 }
361 else
362 {
363 FileName.Length = 0;
364 FileName.MaximumLength = nSize * sizeof(WCHAR);
365 FileName.Buffer = lpFilename;
366
367 RtlCopyUnicodeString (&FileName,
368 &Module->FullDllName);
369 Length = Module->FullDllName.Length / sizeof(WCHAR);
370 }
371
372 RtlLeaveCriticalSection (Peb->LoaderLock);
373 return Length;
374 }
375
376 Entry = Entry->Flink;
377 }
378
379 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND);
380 RtlLeaveCriticalSection (Peb->LoaderLock);
381
382 return 0;
383 }
384
385
386 /*
387 * @implemented
388 */
389 HMODULE
390 STDCALL
391 GetModuleHandleA ( LPCSTR lpModuleName )
392 {
393 UNICODE_STRING UnicodeName;
394 ANSI_STRING ModuleName;
395 PVOID BaseAddress;
396 NTSTATUS Status;
397
398 if (lpModuleName == NULL)
399 return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
400 RtlInitAnsiString (&ModuleName,
401 (LPSTR)lpModuleName);
402
403 /* convert ansi (or oem) string to unicode */
404 if (bIsFileApiAnsi)
405 RtlAnsiStringToUnicodeString (&UnicodeName,
406 &ModuleName,
407 TRUE);
408 else
409 RtlOemStringToUnicodeString (&UnicodeName,
410 &ModuleName,
411 TRUE);
412
413 Status = LdrGetDllHandle (0,
414 0,
415 &UnicodeName,
416 &BaseAddress);
417
418 RtlFreeUnicodeString (&UnicodeName);
419
420 if (!NT_SUCCESS(Status))
421 {
422 SetLastErrorByStatus (Status);
423 return NULL;
424 }
425
426 return ((HMODULE)BaseAddress);
427 }
428
429
430 /*
431 * @implemented
432 */
433 HMODULE
434 STDCALL
435 GetModuleHandleW (LPCWSTR lpModuleName)
436 {
437 UNICODE_STRING ModuleName;
438 PVOID BaseAddress;
439 NTSTATUS Status;
440
441 if (lpModuleName == NULL)
442 return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
443
444 RtlInitUnicodeString (&ModuleName,
445 (LPWSTR)lpModuleName);
446
447 Status = LdrGetDllHandle (0,
448 0,
449 &ModuleName,
450 &BaseAddress);
451 if (!NT_SUCCESS(Status))
452 {
453 SetLastErrorByStatus (Status);
454 return NULL;
455 }
456
457 return ((HMODULE)BaseAddress);
458 }
459
460
461 /*
462 * @implemented
463 */
464 DWORD
465 STDCALL
466 LoadModule (
467 LPCSTR lpModuleName,
468 LPVOID lpParameterBlock
469 )
470 {
471 STARTUPINFOA StartupInfo;
472 PROCESS_INFORMATION ProcessInformation;
473 LOADPARMS32 *LoadParams;
474 char FileName[MAX_PATH];
475 char *CommandLine, *t;
476 BYTE Length;
477
478 LoadParams = (LOADPARMS32*)lpParameterBlock;
479 if(!lpModuleName || !LoadParams || (((WORD*)LoadParams->lpCmdShow)[0] != 2))
480 {
481 /* windows doesn't check parameters, we do */
482 SetLastError(ERROR_INVALID_PARAMETER);
483 return 0;
484 }
485
486 if(!SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL) &&
487 !SearchPathA(NULL, lpModuleName, NULL, MAX_PATH, FileName, NULL))
488 {
489 return ERROR_FILE_NOT_FOUND;
490 }
491
492 Length = (BYTE)LoadParams->lpCmdLine[0];
493 if(!(CommandLine = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
494 strlen(lpModuleName) + Length + 2)))
495 {
496 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
497 return 0;
498 }
499
500 /* Create command line string */
501 strcpy(CommandLine, lpModuleName);
502 t = CommandLine + strlen(CommandLine);
503 *(t++) = ' ';
504 memcpy(t, LoadParams->lpCmdLine + 1, Length);
505
506 /* Build StartupInfo */
507 RtlZeroMemory(&StartupInfo, sizeof(STARTUPINFOA));
508 StartupInfo.cb = sizeof(STARTUPINFOA);
509 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
510 StartupInfo.wShowWindow = ((WORD*)LoadParams->lpCmdShow)[1];
511
512 if(!CreateProcessA(FileName, CommandLine, NULL, NULL, FALSE, 0, LoadParams->lpEnvAddress,
513 NULL, &StartupInfo, &ProcessInformation))
514 {
515 DWORD Error;
516
517 HeapFree(GetProcessHeap(), 0, CommandLine);
518 /* return the right value */
519 Error = GetLastError();
520 switch(Error)
521 {
522 case ERROR_BAD_EXE_FORMAT:
523 {
524 return ERROR_BAD_FORMAT;
525 }
526 case ERROR_FILE_NOT_FOUND:
527 case ERROR_PATH_NOT_FOUND:
528 {
529 return Error;
530 }
531 }
532 return 0;
533 }
534
535 HeapFree(GetProcessHeap(), 0, CommandLine);
536
537 /* Wait up to 15 seconds for the process to become idle */
538 WaitForInputIdle(ProcessInformation.hProcess, 15000);
539
540 CloseHandle(ProcessInformation.hThread);
541 CloseHandle(ProcessInformation.hProcess);
542
543 return 33;
544 }
545
546 /* EOF */