[CMAKE]
[reactos.git] / dll / win32 / kernel32 / misc / ldr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT : ReactOS system libraries
4 * MODULE : kernel32.dll
5 * FILE : reactos/dll/win32/kernel32/misc/ldr.c
6 * AUTHOR : Aleksey Bragin <aleksey@reactos.org>
7 */
8
9 #include <k32.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 typedef struct tagLOADPARMS32 {
15 LPSTR lpEnvAddress;
16 LPSTR lpCmdLine;
17 WORD wMagicValue;
18 WORD wCmdShow;
19 DWORD dwReserved;
20 } LOADPARMS32;
21
22 extern BOOLEAN InWindows;
23 extern WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle;
24
25 #define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR 1
26 #define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS 2
27 #define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE 3
28
29 VOID
30 NTAPI
31 BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry,
32 IN PVOID Context,
33 OUT BOOLEAN *StopEnumeration);
34
35 /* FUNCTIONS ****************************************************************/
36
37 DWORD
38 WINAPI
39 BasepGetModuleHandleExParameterValidation(DWORD dwFlags,
40 LPCWSTR lpwModuleName,
41 HMODULE *phModule)
42 {
43 /* Set phModule to 0 if it's not a NULL pointer */
44 if (phModule) *phModule = 0;
45
46 /* Check for invalid flags combination */
47 if (dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN |
48 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
49 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) ||
50 ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) &&
51 (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) ||
52 (!lpwModuleName && (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
53 )
54 {
55 BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
56 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR;
57 }
58
59 /* Check 2nd parameter */
60 if (!phModule)
61 {
62 BaseSetLastNTError(STATUS_INVALID_PARAMETER_2);
63 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR;
64 }
65
66 /* Return what we have according to the module name */
67 if (lpwModuleName)
68 {
69 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE;
70 }
71
72 /* No name given, so put ImageBaseAddress there */
73 *phModule = (HMODULE)NtCurrentPeb()->ImageBaseAddress;
74
75 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS;
76 }
77
78 PVOID
79 WINAPI
80 BasepMapModuleHandle(HMODULE hModule, BOOLEAN AsDataFile)
81 {
82 /* If no handle is provided - use current image base address */
83 if (!hModule) return NtCurrentPeb()->ImageBaseAddress;
84
85 /* Check if it's a normal or a datafile one */
86 if (LDR_IS_DATAFILE(hModule) && !AsDataFile)
87 return NULL;
88
89 /* It'a a normal DLL, just return its handle */
90 return hModule;
91 }
92
93 /**
94 * @name GetDllLoadPath
95 *
96 * Internal function to compute the load path to use for a given dll.
97 *
98 * @remarks Returned pointer must be freed by caller.
99 */
100
101 LPWSTR
102 GetDllLoadPath(LPCWSTR lpModule)
103 {
104 ULONG Pos = 0, Length = 0;
105 PWCHAR EnvironmentBufferW = NULL;
106 LPCWSTR lpModuleEnd = NULL;
107 UNICODE_STRING ModuleName;
108 DWORD LastError = GetLastError(); /* GetEnvironmentVariable changes LastError */
109
110 // FIXME: This function is used only by SearchPathW, and is deprecated and will be deleted ASAP.
111
112 if ((lpModule != NULL) && (wcslen(lpModule) > 2) && (lpModule[1] == ':'))
113 {
114 lpModuleEnd = lpModule + wcslen(lpModule);
115 }
116 else
117 {
118 ModuleName = NtCurrentPeb()->ProcessParameters->ImagePathName;
119 lpModule = ModuleName.Buffer;
120 lpModuleEnd = lpModule + (ModuleName.Length / sizeof(WCHAR));
121 }
122
123 if (lpModule != NULL)
124 {
125 while (lpModuleEnd > lpModule && *lpModuleEnd != L'/' &&
126 *lpModuleEnd != L'\\' && *lpModuleEnd != L':')
127 {
128 --lpModuleEnd;
129 }
130 Length = (lpModuleEnd - lpModule) + 1;
131 }
132
133 Length += GetCurrentDirectoryW(0, NULL);
134 Length += GetDllDirectoryW(0, NULL);
135 Length += GetSystemDirectoryW(NULL, 0);
136 Length += GetWindowsDirectoryW(NULL, 0);
137 Length += GetEnvironmentVariableW(L"PATH", NULL, 0);
138
139 EnvironmentBufferW = RtlAllocateHeap(RtlGetProcessHeap(), 0,
140 Length * sizeof(WCHAR));
141 if (EnvironmentBufferW == NULL)
142 {
143 return NULL;
144 }
145
146 if (lpModule)
147 {
148 RtlCopyMemory(EnvironmentBufferW, lpModule,
149 (lpModuleEnd - lpModule) * sizeof(WCHAR));
150 Pos += lpModuleEnd - lpModule;
151 EnvironmentBufferW[Pos++] = L';';
152 }
153
154 Pos += GetCurrentDirectoryW(Length, EnvironmentBufferW + Pos);
155 EnvironmentBufferW[Pos++] = L';';
156 Pos += GetDllDirectoryW(Length - Pos, EnvironmentBufferW + Pos);
157 EnvironmentBufferW[Pos++] = L';';
158 Pos += GetSystemDirectoryW(EnvironmentBufferW + Pos, Length - Pos);
159 EnvironmentBufferW[Pos++] = L';';
160 Pos += GetWindowsDirectoryW(EnvironmentBufferW + Pos, Length - Pos);
161 EnvironmentBufferW[Pos++] = L';';
162 Pos += GetEnvironmentVariableW(L"PATH", EnvironmentBufferW + Pos, Length - Pos);
163
164 SetLastError(LastError);
165 return EnvironmentBufferW;
166 }
167
168 /*
169 * @implemented
170 */
171 BOOL
172 WINAPI
173 DisableThreadLibraryCalls(
174 IN HMODULE hLibModule)
175 {
176 NTSTATUS Status;
177
178 /* Disable thread library calls */
179 Status = LdrDisableThreadCalloutsForDll((PVOID)hLibModule);
180
181 /* If it wasn't success - set last error and return failure */
182 if (!NT_SUCCESS(Status))
183 {
184 BaseSetLastNTError(Status);
185 return FALSE;
186 }
187
188 /* Return success */
189 return TRUE;
190 }
191
192
193 /*
194 * @implemented
195 */
196 HINSTANCE
197 WINAPI
198 LoadLibraryA(LPCSTR lpLibFileName)
199 {
200 LPSTR PathBuffer;
201 UINT Len;
202 HINSTANCE Result;
203
204 /* Treat twain_32.dll in a special way (what a surprise...) */
205 if (lpLibFileName && !_strcmpi(lpLibFileName, "twain_32.dll"))
206 {
207 /* Allocate space for the buffer */
208 PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH);
209 if (PathBuffer)
210 {
211 /* Get windows dir in this buffer */
212 Len = GetWindowsDirectoryA(PathBuffer, MAX_PATH - 13); /* 13 is sizeof of '\\twain_32.dll' */
213 if (Len && Len < (MAX_PATH - 13))
214 {
215 /* We successfully got windows directory. Concatenate twain_32.dll to it */
216 strncat(PathBuffer, "\\twain_32.dll", 13);
217
218 /* And recursively call ourselves with a new string */
219 Result = LoadLibraryA(PathBuffer);
220
221 /* If it was successful - free memory and return result */
222 if (Result)
223 {
224 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
225 return Result;
226 }
227 }
228
229 /* Free allocated buffer */
230 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
231 }
232 }
233
234 /* Call the Ex version of the API */
235 return LoadLibraryExA(lpLibFileName, 0, 0);
236 }
237
238 /*
239 * @implemented
240 */
241 HINSTANCE
242 WINAPI
243 LoadLibraryExA(LPCSTR lpLibFileName,
244 HANDLE hFile,
245 DWORD dwFlags)
246 {
247 PUNICODE_STRING FileNameW;
248
249 /* Convert file name to unicode */
250 if (!(FileNameW = Basep8BitStringToStaticUnicodeString(lpLibFileName)))
251 return NULL;
252
253 /* And call W version of the API */
254 return LoadLibraryExW(FileNameW->Buffer, hFile, dwFlags);
255 }
256
257 /*
258 * @implemented
259 */
260 HINSTANCE
261 WINAPI
262 LoadLibraryW(LPCWSTR lpLibFileName)
263 {
264 /* Call Ex version of the API */
265 return LoadLibraryExW (lpLibFileName, 0, 0);
266 }
267
268
269 static
270 NTSTATUS
271 BasepLoadLibraryAsDatafile(PWSTR Path, LPCWSTR Name, HMODULE *hModule)
272 {
273 WCHAR FilenameW[MAX_PATH];
274 HANDLE hFile = INVALID_HANDLE_VALUE;
275 HANDLE hMapping;
276 NTSTATUS Status;
277 PVOID lpBaseAddress = NULL;
278 SIZE_T ViewSize;
279 //PUNICODE_STRING OriginalName;
280 //UNICODE_STRING dotDLL = RTL_CONSTANT_STRING(L".DLL");
281
282 /* Zero out handle value */
283 *hModule = 0;
284
285 DPRINT("BasepLoadLibraryAsDatafile(%S %S %p)\n", Path, Name, hModule);
286
287 /*Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
288 Name,
289 &dotDLL,
290 RedirName,
291 RedirName2,
292 &OriginalName2,
293 NULL,
294 NULL,
295 NULL);*/
296
297 /* Try to search for it */
298 if (!SearchPathW(Path,
299 Name,
300 L".DLL",
301 sizeof(FilenameW) / sizeof(FilenameW[0]),
302 FilenameW,
303 NULL))
304 {
305 /* Return last status value directly */
306 return NtCurrentTeb()->LastStatusValue;
307 }
308
309 /* Open this file we found */
310 hFile = CreateFileW(FilenameW,
311 GENERIC_READ,
312 FILE_SHARE_READ | FILE_SHARE_DELETE,
313 NULL,
314 OPEN_EXISTING,
315 0,
316 0);
317
318 /* If opening failed - return last status value */
319 if (hFile == INVALID_HANDLE_VALUE) return NtCurrentTeb()->LastStatusValue;
320
321 /* Create file mapping */
322 hMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
323
324 /* Close the file handle */
325 CloseHandle(hFile);
326
327 /* If creating file mapping failed - return last status value */
328 if (!hMapping) return NtCurrentTeb()->LastStatusValue;
329
330 /* Map view of section */
331 Status = NtMapViewOfSection(hMapping,
332 NtCurrentProcess(),
333 &lpBaseAddress,
334 0,
335 0,
336 0,
337 &ViewSize,
338 ViewShare,
339 0,
340 PAGE_READONLY);
341
342 /* Close handle to the section */
343 CloseHandle(hMapping);
344
345 /* If mapping view of section failed - return last status value */
346 if (!NT_SUCCESS(Status)) return NtCurrentTeb()->LastStatusValue;
347
348 /* Make sure it's a valid PE file */
349 if (!RtlImageNtHeader(lpBaseAddress))
350 {
351 /* Unmap the view and return failure status */
352 UnmapViewOfFile(lpBaseAddress);
353 return STATUS_INVALID_IMAGE_FORMAT;
354 }
355
356 /* Set low bit of handle to indicate datafile module */
357 *hModule = (HMODULE)((ULONG_PTR)lpBaseAddress | 1);
358
359 /* Load alternate resource module */
360 //LdrLoadAlternateResourceModule(*hModule, FilenameW);
361
362 return STATUS_SUCCESS;
363 }
364
365 /*
366 * @implemented
367 */
368 HINSTANCE
369 WINAPI
370 LoadLibraryExW(LPCWSTR lpLibFileName,
371 HANDLE hFile,
372 DWORD dwFlags)
373 {
374 UNICODE_STRING DllName;
375 HINSTANCE hInst;
376 NTSTATUS Status;
377 PWSTR SearchPath;
378 ULONG DllCharacteristics = 0;
379 BOOL FreeString = FALSE;
380
381 /* Check for any flags LdrLoadDll might be interested in */
382 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
383 {
384 /* Tell LDR to treat it as an EXE */
385 DllCharacteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
386 }
387
388 /* Build up a unicode dll name from null-terminated string */
389 RtlInitUnicodeString(&DllName, (LPWSTR)lpLibFileName);
390
391 /* Lazy-initialize BasepExeLdrEntry */
392 if (!BasepExeLdrEntry)
393 LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry, NtCurrentPeb()->ImageBaseAddress);
394
395 /* Check if that module is our exe*/
396 if (BasepExeLdrEntry && !(dwFlags & LOAD_LIBRARY_AS_DATAFILE) &&
397 DllName.Length == BasepExeLdrEntry->FullDllName.Length)
398 {
399 /* Lengths match and it's not a datafile, so perform name comparison */
400 if (RtlEqualUnicodeString(&DllName, &BasepExeLdrEntry->FullDllName, TRUE))
401 {
402 /* That's us! */
403 return BasepExeLdrEntry->DllBase;
404 }
405 }
406
407 /* Check for trailing spaces and remove them if necessary */
408 if (DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
409 {
410 RtlCreateUnicodeString(&DllName, (LPWSTR)lpLibFileName);
411 while (DllName.Length > sizeof(WCHAR) &&
412 DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
413 {
414 DllName.Length -= sizeof(WCHAR);
415 }
416 DllName.Buffer[DllName.Length/sizeof(WCHAR)] = UNICODE_NULL;
417 FreeString = TRUE;
418 }
419
420 /* Compute the load path */
421 SearchPath = BasepGetDllPath((dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) ? (LPWSTR)lpLibFileName : NULL,
422 NULL);
423
424 if (!SearchPath)
425 {
426 /* Getting DLL path failed, so set last error, free mem and return */
427 BaseSetLastNTError(STATUS_NO_MEMORY);
428 if (FreeString) RtlFreeUnicodeString(&DllName);
429 return NULL;
430 }
431
432 _SEH2_TRY
433 {
434 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
435 {
436 /* If the image is loaded as a datafile, try to get its handle */
437 Status = LdrGetDllHandle(SearchPath, NULL, &DllName, (PVOID*)&hInst);
438 if (!NT_SUCCESS(Status))
439 {
440 /* It's not loaded yet - so load it up */
441 Status = BasepLoadLibraryAsDatafile(SearchPath, DllName.Buffer, &hInst);
442 _SEH2_YIELD(goto done;)
443 }
444 }
445
446 /* HACK!!! FIXME */
447 if (InWindows)
448 {
449 /* Call the API Properly */
450 Status = LdrLoadDll(SearchPath,
451 &DllCharacteristics,
452 &DllName,
453 (PVOID*)&hInst);
454 }
455 else
456 {
457 /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */
458 Status = LdrLoadDll(SearchPath, &dwFlags, &DllName, (PVOID*)&hInst);
459 }
460 }
461 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
462 {
463 Status = _SEH2_GetExceptionCode();
464 } _SEH2_END
465
466
467 done:
468 /* Free SearchPath buffer */
469 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
470
471 /* Free DllName string if it was dynamically allocated */
472 if (FreeString) RtlFreeUnicodeString(&DllName);
473
474 /* Set last error in failure case */
475 if (!NT_SUCCESS(Status))
476 {
477 BaseSetLastNTError(Status);
478 return NULL;
479 }
480
481 /* Return loaded module handle */
482 return hInst;
483 }
484
485
486 /*
487 * @implemented
488 */
489 FARPROC
490 WINAPI
491 GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
492 {
493 ANSI_STRING ProcedureName, *ProcNamePtr = NULL;
494 FARPROC fnExp = NULL;
495 NTSTATUS Status;
496 PVOID hMapped;
497 ULONG Ordinal = 0;
498
499 if (HIWORD(lpProcName) != 0)
500 {
501 /* Look up by name */
502 RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
503 ProcNamePtr = &ProcedureName;
504 }
505 else
506 {
507 /* Look up by ordinal */
508 Ordinal = (ULONG)lpProcName;
509 }
510
511 /* Map provided handle */
512 hMapped = BasepMapModuleHandle(hModule, FALSE);
513
514 /* Get the proc address */
515 Status = LdrGetProcedureAddress(hMapped,
516 ProcNamePtr,
517 Ordinal,
518 (PVOID*)&fnExp);
519
520 if (!NT_SUCCESS(Status))
521 {
522 BaseSetLastNTError(Status);
523 return NULL;
524 }
525
526 /* Check for a special case when returned pointer is
527 the same as iamge's base address */
528 if (fnExp == hMapped)
529 {
530 /* Set correct error code */
531 if (HIWORD(lpProcName) != 0)
532 BaseSetLastNTError(STATUS_ENTRYPOINT_NOT_FOUND);
533 else
534 BaseSetLastNTError(STATUS_ORDINAL_NOT_FOUND);
535
536 return NULL;
537 }
538
539 /* All good, return procedure pointer */
540 return fnExp;
541 }
542
543
544 /*
545 * @implemented
546 */
547 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
548 {
549 NTSTATUS Status;
550 PIMAGE_NT_HEADERS NtHeaders;
551
552 if (LDR_IS_DATAFILE(hLibModule))
553 {
554 // FIXME: This SEH should go inside RtlImageNtHeader instead
555 _SEH2_TRY
556 {
557 /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
558 NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1));
559 }
560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
561 {
562 NtHeaders = NULL;
563 } _SEH2_END
564
565 if (NtHeaders)
566 {
567 /* Unmap view */
568 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
569
570 /* Unload alternate resource module */
571 LdrUnloadAlternateResourceModule(hLibModule);
572 }
573 else
574 Status = STATUS_INVALID_IMAGE_FORMAT;
575 }
576 else
577 {
578 /* Just unload it */
579 Status = LdrUnloadDll((PVOID)hLibModule);
580 }
581
582 /* Check what kind of status we got */
583 if (!NT_SUCCESS(Status))
584 {
585 /* Set last error */
586 BaseSetLastNTError(Status);
587
588 /* Return failure */
589 return FALSE;
590 }
591
592 /* Return success */
593 return TRUE;
594 }
595
596
597 /*
598 * @implemented
599 */
600 VOID
601 WINAPI
602 FreeLibraryAndExitThread(HMODULE hLibModule,
603 DWORD dwExitCode)
604 {
605 NTSTATUS Status;
606
607 if (LDR_IS_DATAFILE(hLibModule))
608 {
609 /* This is a LOAD_LIBRARY_AS_DATAFILE module */
610 if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)))
611 {
612 /* Unmap view */
613 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
614
615 /* Unload alternate resource module */
616 LdrUnloadAlternateResourceModule(hLibModule);
617 }
618 }
619 else
620 {
621 /* Just unload it */
622 Status = LdrUnloadDll((PVOID)hLibModule);
623 }
624
625 /* Exit thread */
626 ExitThread(dwExitCode);
627 }
628
629
630 /*
631 * @implemented
632 */
633 DWORD
634 WINAPI
635 GetModuleFileNameA(HINSTANCE hModule,
636 LPSTR lpFilename,
637 DWORD nSize)
638 {
639 UNICODE_STRING FilenameW;
640 ANSI_STRING FilenameA;
641 NTSTATUS Status;
642 DWORD Length = 0, LengthToCopy;
643
644 /* Allocate a unicode buffer */
645 FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR));
646 if (!FilenameW.Buffer)
647 {
648 BaseSetLastNTError(STATUS_NO_MEMORY);
649 return 0;
650 }
651
652 /* Call unicode API */
653 FilenameW.Length = GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR);
654 FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR);
655
656 if (FilenameW.Length)
657 {
658 /* Convert to ansi string */
659 Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE);
660 if (!NT_SUCCESS(Status))
661 {
662 /* Set last error, free string and retun failure */
663 BaseSetLastNTError(Status);
664 RtlFreeUnicodeString(&FilenameW);
665 return 0;
666 }
667
668 /* Calculate size to copy */
669 Length = min(nSize, FilenameA.Length);
670
671 /* Include terminating zero */
672 if (nSize > Length)
673 LengthToCopy = Length + 1;
674 else
675 LengthToCopy = nSize;
676
677 /* Now copy back to the caller amount he asked */
678 RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy);
679
680 /* Free ansi filename */
681 RtlFreeAnsiString(&FilenameA);
682 }
683
684 /* Free unicode filename */
685 RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer);
686
687 /* Return length copied */
688 return Length;
689 }
690
691 /*
692 * @implemented
693 */
694 DWORD
695 WINAPI
696 GetModuleFileNameW(HINSTANCE hModule,
697 LPWSTR lpFilename,
698 DWORD nSize)
699 {
700 PLIST_ENTRY ModuleListHead, Entry;
701 PLDR_DATA_TABLE_ENTRY Module;
702 ULONG Length = 0;
703 ULONG Cookie;
704 PPEB Peb;
705
706 hModule = BasepMapModuleHandle(hModule, FALSE);
707
708 /* Upscale nSize from chars to bytes */
709 nSize *= sizeof(WCHAR);
710
711 _SEH2_TRY
712 {
713 /* We don't use per-thread cur dir now */
714 //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
715
716 Peb = NtCurrentPeb ();
717
718 /* Acquire a loader lock */
719 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
720
721 /* Traverse the module list */
722 ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
723 Entry = ModuleListHead->Flink;
724 while (Entry != ModuleListHead)
725 {
726 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
727
728 /* Check if this is the requested module */
729 if (Module->DllBase == (PVOID)hModule)
730 {
731 /* Calculate size to copy */
732 Length = min(nSize, Module->FullDllName.MaximumLength);
733
734 /* Copy contents */
735 RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length);
736
737 /* Subtract a terminating zero */
738 if (Length == Module->FullDllName.MaximumLength)
739 Length -= sizeof(WCHAR);
740
741 /* Break out of the loop */
742 break;
743 }
744
745 /* Advance to the next entry */
746 Entry = Entry->Flink;
747 }
748 }
749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
750 {
751 BaseSetLastNTError(_SEH2_GetExceptionCode());
752 Length = 0;
753 } _SEH2_END
754
755 /* Release the loader lock */
756 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
757
758 return Length / sizeof(WCHAR);
759 }
760
761 HMODULE
762 WINAPI
763 GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)
764 {
765 NTSTATUS Status;
766 PVOID Module;
767 LPWSTR DllPath;
768
769 /* Try to get a handle with a magic value of 1 for DllPath */
770 Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module);
771
772 /* If that succeeded - we're done */
773 if (NT_SUCCESS(Status)) return Module;
774
775 /* If not, then the path should be computed */
776 DllPath = BasepGetDllPath(NULL, 0);
777
778 /* Call LdrGetHandle() again providing the computed DllPath
779 and wrapped into SEH */
780 _SEH2_TRY
781 {
782 Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module);
783 }
784 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
785 {
786 /* Fail with the SEH error */
787 Status = _SEH2_GetExceptionCode();
788 }
789 _SEH2_END;
790
791 /* Free the DllPath */
792 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
793
794 /* In case of error set last win32 error and return NULL */
795 if (!NT_SUCCESS(Status))
796 {
797 DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status);
798 SetLastErrorByStatus(Status);
799 Module = 0;
800 }
801
802 /* Return module */
803 return (HMODULE)Module;
804 }
805
806 BOOLEAN
807 WINAPI
808 BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule)
809 {
810 DWORD Cookie;
811 NTSTATUS Status = STATUS_SUCCESS, Status2;
812 HANDLE hModule = 0;
813 UNICODE_STRING ModuleNameU;
814 DWORD dwValid;
815 BOOLEAN Redirected = FALSE; // FIXME
816
817 /* Validate parameters */
818 dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule);
819 ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE);
820
821 /* Acquire lock if necessary */
822 if (!NoLock)
823 {
824 Status = LdrLockLoaderLock(0, NULL, &Cookie);
825 if (!NT_SUCCESS(Status))
826 {
827 /* Fail */
828 SetLastErrorByStatus(Status);
829 if (phModule) *phModule = 0;
830 return Status;
831 }
832 }
833
834 if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
835 {
836 /* Create a unicode string out of module name */
837 RtlInitUnicodeString(&ModuleNameU, lpwModuleName);
838
839 // FIXME: Do some redirected DLL stuff?
840 if (Redirected)
841 {
842 UNIMPLEMENTED;
843 }
844
845 if (!hModule)
846 {
847 hModule = GetModuleHandleForUnicodeString(&ModuleNameU);
848 if (!hModule)
849 {
850 /* Last error is already set, so just return failure by setting status */
851 Status = STATUS_DLL_NOT_FOUND;
852 goto quickie;
853 }
854 }
855 }
856 else
857 {
858 /* Perform Pc to file header to get module instance */
859 hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName,
860 (PVOID*)&hModule);
861
862 /* Check if it succeeded */
863 if (!hModule)
864 {
865 /* Set "dll not found" status and quit */
866 Status = STATUS_DLL_NOT_FOUND;
867 goto quickie;
868 }
869 }
870
871 /* Check if changing reference is not forbidden */
872 if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
873 {
874 /* Add reference to this DLL */
875 Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_PIN_MODULE : 0,
876 hModule);
877 }
878
879 /* Set last error in case of failure */
880 if (!NT_SUCCESS(Status))
881 SetLastErrorByStatus(Status);
882
883 quickie:
884 /* Unlock loader lock if it was acquired */
885 if (!NoLock)
886 {
887 Status2 = LdrUnlockLoaderLock(0, Cookie);
888 ASSERT(NT_SUCCESS(Status2));
889 }
890
891 /* Set the module handle to the caller */
892 if (phModule) *phModule = hModule;
893
894 /* Return TRUE on success and FALSE otherwise */
895 return NT_SUCCESS(Status);
896 }
897
898 /*
899 * @implemented
900 */
901 HMODULE
902 WINAPI
903 GetModuleHandleA(LPCSTR lpModuleName)
904 {
905 PUNICODE_STRING ModuleNameW;
906 PTEB pTeb = NtCurrentTeb();
907
908 /* Check if we have no name to convert */
909 if (!lpModuleName)
910 return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
911
912 /* Convert module name to unicode */
913 ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
914
915 /* Call W version if conversion was successful */
916 if (ModuleNameW)
917 return GetModuleHandleW(ModuleNameW->Buffer);
918
919 /* Return failure */
920 return 0;
921 }
922
923
924 /*
925 * @implemented
926 */
927 HMODULE
928 WINAPI
929 GetModuleHandleW(LPCWSTR lpModuleName)
930 {
931 HMODULE hModule;
932 NTSTATUS Status;
933
934 /* If current module is requested - return it right away */
935 if (!lpModuleName)
936 return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
937
938 /* Use common helper routine */
939 Status = BasepGetModuleHandleExW(TRUE,
940 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
941 lpModuleName,
942 &hModule);
943
944 /* If it wasn't successful - return 0 */
945 if (!NT_SUCCESS(Status)) hModule = 0;
946
947 /* Return the handle */
948 return hModule;
949 }
950
951
952 /*
953 * @implemented
954 */
955 BOOL
956 WINAPI
957 GetModuleHandleExW(IN DWORD dwFlags,
958 IN LPCWSTR lpwModuleName OPTIONAL,
959 OUT HMODULE* phModule)
960 {
961 NTSTATUS Status;
962 DWORD dwValid;
963 BOOL Ret = FALSE;
964
965 /* Validate parameters */
966 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule);
967
968 /* If result is invalid parameter - return failure */
969 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
970
971 /* If result is 2, there is no need to do anything - return success. */
972 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
973
974 /* Use common helper routine */
975 Status = BasepGetModuleHandleExW(FALSE,
976 dwFlags,
977 lpwModuleName,
978 phModule);
979
980 /* Return TRUE in case of success */
981 if (NT_SUCCESS(Status)) Ret = TRUE;
982
983 return Ret;
984 }
985
986 /*
987 * @implemented
988 */
989 BOOL
990 WINAPI
991 GetModuleHandleExA(IN DWORD dwFlags,
992 IN LPCSTR lpModuleName OPTIONAL,
993 OUT HMODULE* phModule)
994 {
995 PUNICODE_STRING lpModuleNameW;
996 DWORD dwValid;
997 BOOL Ret = FALSE;
998 NTSTATUS Status;
999
1000 /* Validate parameters */
1001 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
1002
1003 /* If result is invalid parameter - return failure */
1004 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
1005
1006 /* If result is 2, there is no need to do anything - return success. */
1007 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
1008
1009 /* Check if we don't need to convert the name */
1010 if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
1011 {
1012 /* Call the extended version of the API without conversion */
1013 Status = BasepGetModuleHandleExW(FALSE,
1014 dwFlags,
1015 (LPCWSTR)lpModuleName,
1016 phModule);
1017 }
1018 else
1019 {
1020 /* Convert module name to unicode */
1021 lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
1022
1023 /* Return FALSE if conversion failed */
1024 if (!lpModuleNameW) return FALSE;
1025
1026 /* Call the extended version of the API */
1027 Status = BasepGetModuleHandleExW(FALSE,
1028 dwFlags,
1029 lpModuleNameW->Buffer,
1030 phModule);
1031 }
1032
1033 /* If result was successful - return true */
1034 if (NT_SUCCESS(Status))
1035 Ret = TRUE;
1036
1037 /* Return result */
1038 return Ret;
1039 }
1040
1041
1042 /*
1043 * @implemented
1044 */
1045 DWORD
1046 WINAPI
1047 LoadModule(LPCSTR lpModuleName,
1048 LPVOID lpParameterBlock)
1049 {
1050 STARTUPINFOA StartupInfo;
1051 PROCESS_INFORMATION ProcessInformation;
1052 LOADPARMS32 *LoadParams;
1053 char FileName[MAX_PATH];
1054 LPSTR CommandLine;
1055 DWORD Length, Error;
1056 BOOL ProcessStatus;
1057 ANSI_STRING AnsiStr;
1058 UNICODE_STRING UnicStr;
1059 RTL_PATH_TYPE PathType;
1060 HANDLE Handle;
1061
1062 LoadParams = (LOADPARMS32*)lpParameterBlock;
1063
1064 /* Check load parameters */
1065 if (LoadParams->dwReserved || LoadParams->wMagicValue != 2)
1066 {
1067 /* Fail with invalid param error */
1068 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1069 return 0;
1070 }
1071
1072 /* Search path */
1073 Length = SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL);
1074
1075 /* Check if path was found */
1076 if (Length && Length < MAX_PATH)
1077 {
1078 /* Build StartupInfo */
1079 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
1080
1081 StartupInfo.cb = sizeof(STARTUPINFOA);
1082 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
1083 StartupInfo.wShowWindow = LoadParams->wCmdShow;
1084
1085 /* Allocate command line buffer */
1086 CommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
1087 HEAP_ZERO_MEMORY,
1088 (ULONG)LoadParams->lpCmdLine[0] + Length + 2);
1089
1090 /* Put module name there, then a space, and then copy provided command line,
1091 and null-terminate it */
1092 RtlCopyMemory(CommandLine, FileName, Length);
1093 CommandLine[Length] = ' ';
1094 RtlCopyMemory(&CommandLine[Length + 1], &LoadParams->lpCmdLine[1], (ULONG)LoadParams->lpCmdLine[0]);
1095 CommandLine[Length + 1 + (ULONG)LoadParams->lpCmdLine[0]] = 0;
1096
1097 /* Create the process */
1098 ProcessStatus = CreateProcessA(FileName,
1099 CommandLine,
1100 NULL,
1101 NULL,
1102 FALSE,
1103 0,
1104 LoadParams->lpEnvAddress,
1105 NULL,
1106 &StartupInfo,
1107 &ProcessInformation);
1108
1109 /* Free the command line buffer */
1110 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
1111
1112 if (!ProcessStatus)
1113 {
1114 /* Creating process failed, return right error code */
1115 Error = GetLastError();
1116 switch(Error)
1117 {
1118 case ERROR_BAD_EXE_FORMAT:
1119 return ERROR_BAD_FORMAT;
1120
1121 case ERROR_FILE_NOT_FOUND:
1122 case ERROR_PATH_NOT_FOUND:
1123 return Error;
1124 }
1125
1126 /* Return 0 otherwise */
1127 return 0;
1128 }
1129
1130 /* Wait up to 30 seconds for the process to become idle */
1131 if (lpfnGlobalRegisterWaitForInputIdle)
1132 {
1133 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess, 30000);
1134 }
1135
1136 /* Close handles */
1137 NtClose(ProcessInformation.hThread);
1138 NtClose(ProcessInformation.hProcess);
1139
1140 /* Return magic success value (33) */
1141 return 33;
1142 }
1143
1144 /* The path was not found, create an ansi string from
1145 the module name and convert it to unicode */
1146 RtlInitAnsiString(&AnsiStr, lpModuleName);
1147 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicStr,&AnsiStr,TRUE)))
1148 return ERROR_FILE_NOT_FOUND;
1149
1150 /* Determine path type */
1151 PathType = RtlDetermineDosPathNameType_U(UnicStr.Buffer);
1152
1153 /* Free the unicode module name */
1154 RtlFreeUnicodeString(&UnicStr);
1155
1156 /* If it's a relative path, return file not found */
1157 if (PathType == RtlPathTypeRelative)
1158 return ERROR_FILE_NOT_FOUND;
1159
1160 /* If not, try to open it */
1161 Handle = CreateFile(lpModuleName,
1162 GENERIC_READ,
1163 FILE_SHARE_READ | FILE_SHARE_WRITE,
1164 NULL,
1165 OPEN_EXISTING,
1166 FILE_ATTRIBUTE_NORMAL,
1167 NULL);
1168
1169 if (Handle != INVALID_HANDLE_VALUE)
1170 {
1171 /* Opening file succeeded for some reason, close the handle and return file not found anyway */
1172 CloseHandle(Handle);
1173 return ERROR_FILE_NOT_FOUND;
1174 }
1175
1176 /* Return last error which CreateFile set during an attempt to open it */
1177 return GetLastError();
1178 }
1179
1180 /* EOF */