2f5e0ac93562dfe01b93a5f86499b0a7cc0e8354
[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 = 0;
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 /* Call the API Properly */
447 Status = LdrLoadDll(SearchPath,
448 &DllCharacteristics,
449 &DllName,
450 (PVOID*)&hInst);
451 }
452 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
453 {
454 Status = _SEH2_GetExceptionCode();
455 } _SEH2_END
456
457
458 done:
459 /* Free SearchPath buffer */
460 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
461
462 /* Free DllName string if it was dynamically allocated */
463 if (FreeString) RtlFreeUnicodeString(&DllName);
464
465 /* Set last error in failure case */
466 if (!NT_SUCCESS(Status))
467 {
468 BaseSetLastNTError(Status);
469 return NULL;
470 }
471
472 /* Return loaded module handle */
473 return hInst;
474 }
475
476
477 /*
478 * @implemented
479 */
480 FARPROC
481 WINAPI
482 GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
483 {
484 ANSI_STRING ProcedureName, *ProcNamePtr = NULL;
485 FARPROC fnExp = NULL;
486 NTSTATUS Status;
487 PVOID hMapped;
488 ULONG Ordinal = 0;
489
490 if (HIWORD(lpProcName) != 0)
491 {
492 /* Look up by name */
493 RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
494 ProcNamePtr = &ProcedureName;
495 }
496 else
497 {
498 /* Look up by ordinal */
499 Ordinal = (ULONG)lpProcName;
500 }
501
502 /* Map provided handle */
503 hMapped = BasepMapModuleHandle(hModule, FALSE);
504
505 /* Get the proc address */
506 Status = LdrGetProcedureAddress(hMapped,
507 ProcNamePtr,
508 Ordinal,
509 (PVOID*)&fnExp);
510
511 if (!NT_SUCCESS(Status))
512 {
513 BaseSetLastNTError(Status);
514 return NULL;
515 }
516
517 /* Check for a special case when returned pointer is
518 the same as iamge's base address */
519 if (fnExp == hMapped)
520 {
521 /* Set correct error code */
522 if (HIWORD(lpProcName) != 0)
523 BaseSetLastNTError(STATUS_ENTRYPOINT_NOT_FOUND);
524 else
525 BaseSetLastNTError(STATUS_ORDINAL_NOT_FOUND);
526
527 return NULL;
528 }
529
530 /* All good, return procedure pointer */
531 return fnExp;
532 }
533
534
535 /*
536 * @implemented
537 */
538 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
539 {
540 NTSTATUS Status;
541 PIMAGE_NT_HEADERS NtHeaders;
542
543 if (LDR_IS_DATAFILE(hLibModule))
544 {
545 // FIXME: This SEH should go inside RtlImageNtHeader instead
546 _SEH2_TRY
547 {
548 /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
549 NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1));
550 }
551 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
552 {
553 NtHeaders = NULL;
554 } _SEH2_END
555
556 if (NtHeaders)
557 {
558 /* Unmap view */
559 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
560
561 /* Unload alternate resource module */
562 LdrUnloadAlternateResourceModule(hLibModule);
563 }
564 else
565 Status = STATUS_INVALID_IMAGE_FORMAT;
566 }
567 else
568 {
569 /* Just unload it */
570 Status = LdrUnloadDll((PVOID)hLibModule);
571 }
572
573 /* Check what kind of status we got */
574 if (!NT_SUCCESS(Status))
575 {
576 /* Set last error */
577 BaseSetLastNTError(Status);
578
579 /* Return failure */
580 return FALSE;
581 }
582
583 /* Return success */
584 return TRUE;
585 }
586
587
588 /*
589 * @implemented
590 */
591 VOID
592 WINAPI
593 FreeLibraryAndExitThread(HMODULE hLibModule,
594 DWORD dwExitCode)
595 {
596 NTSTATUS Status;
597
598 if (LDR_IS_DATAFILE(hLibModule))
599 {
600 /* This is a LOAD_LIBRARY_AS_DATAFILE module */
601 if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)))
602 {
603 /* Unmap view */
604 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
605
606 /* Unload alternate resource module */
607 LdrUnloadAlternateResourceModule(hLibModule);
608 }
609 }
610 else
611 {
612 /* Just unload it */
613 Status = LdrUnloadDll((PVOID)hLibModule);
614 }
615
616 /* Exit thread */
617 ExitThread(dwExitCode);
618 }
619
620
621 /*
622 * @implemented
623 */
624 DWORD
625 WINAPI
626 GetModuleFileNameA(HINSTANCE hModule,
627 LPSTR lpFilename,
628 DWORD nSize)
629 {
630 UNICODE_STRING FilenameW;
631 ANSI_STRING FilenameA;
632 NTSTATUS Status;
633 DWORD Length = 0, LengthToCopy;
634
635 /* Allocate a unicode buffer */
636 FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR));
637 if (!FilenameW.Buffer)
638 {
639 BaseSetLastNTError(STATUS_NO_MEMORY);
640 return 0;
641 }
642
643 /* Call unicode API */
644 FilenameW.Length = GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR);
645 FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR);
646
647 if (FilenameW.Length)
648 {
649 /* Convert to ansi string */
650 Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE);
651 if (!NT_SUCCESS(Status))
652 {
653 /* Set last error, free string and retun failure */
654 BaseSetLastNTError(Status);
655 RtlFreeUnicodeString(&FilenameW);
656 return 0;
657 }
658
659 /* Calculate size to copy */
660 Length = min(nSize, FilenameA.Length);
661
662 /* Include terminating zero */
663 if (nSize > Length)
664 LengthToCopy = Length + 1;
665 else
666 LengthToCopy = nSize;
667
668 /* Now copy back to the caller amount he asked */
669 RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy);
670
671 /* Free ansi filename */
672 RtlFreeAnsiString(&FilenameA);
673 }
674
675 /* Free unicode filename */
676 RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer);
677
678 /* Return length copied */
679 return Length;
680 }
681
682 /*
683 * @implemented
684 */
685 DWORD
686 WINAPI
687 GetModuleFileNameW(HINSTANCE hModule,
688 LPWSTR lpFilename,
689 DWORD nSize)
690 {
691 PLIST_ENTRY ModuleListHead, Entry;
692 PLDR_DATA_TABLE_ENTRY Module;
693 ULONG Length = 0;
694 ULONG Cookie;
695 PPEB Peb;
696
697 hModule = BasepMapModuleHandle(hModule, FALSE);
698
699 /* Upscale nSize from chars to bytes */
700 nSize *= sizeof(WCHAR);
701
702 _SEH2_TRY
703 {
704 /* We don't use per-thread cur dir now */
705 //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
706
707 Peb = NtCurrentPeb ();
708
709 /* Acquire a loader lock */
710 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
711
712 /* Traverse the module list */
713 ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
714 Entry = ModuleListHead->Flink;
715 while (Entry != ModuleListHead)
716 {
717 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
718
719 /* Check if this is the requested module */
720 if (Module->DllBase == (PVOID)hModule)
721 {
722 /* Calculate size to copy */
723 Length = min(nSize, Module->FullDllName.MaximumLength);
724
725 /* Copy contents */
726 RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length);
727
728 /* Subtract a terminating zero */
729 if (Length == Module->FullDllName.MaximumLength)
730 Length -= sizeof(WCHAR);
731
732 /* Break out of the loop */
733 break;
734 }
735
736 /* Advance to the next entry */
737 Entry = Entry->Flink;
738 }
739 }
740 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
741 {
742 BaseSetLastNTError(_SEH2_GetExceptionCode());
743 Length = 0;
744 } _SEH2_END
745
746 /* Release the loader lock */
747 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
748
749 return Length / sizeof(WCHAR);
750 }
751
752 HMODULE
753 WINAPI
754 GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)
755 {
756 NTSTATUS Status;
757 PVOID Module;
758 LPWSTR DllPath;
759
760 /* Try to get a handle with a magic value of 1 for DllPath */
761 Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module);
762
763 /* If that succeeded - we're done */
764 if (NT_SUCCESS(Status)) return Module;
765
766 /* If not, then the path should be computed */
767 DllPath = BasepGetDllPath(NULL, 0);
768
769 /* Call LdrGetHandle() again providing the computed DllPath
770 and wrapped into SEH */
771 _SEH2_TRY
772 {
773 Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module);
774 }
775 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
776 {
777 /* Fail with the SEH error */
778 Status = _SEH2_GetExceptionCode();
779 }
780 _SEH2_END;
781
782 /* Free the DllPath */
783 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
784
785 /* In case of error set last win32 error and return NULL */
786 if (!NT_SUCCESS(Status))
787 {
788 DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status);
789 SetLastErrorByStatus(Status);
790 Module = 0;
791 }
792
793 /* Return module */
794 return (HMODULE)Module;
795 }
796
797 BOOLEAN
798 WINAPI
799 BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule)
800 {
801 DWORD Cookie;
802 NTSTATUS Status = STATUS_SUCCESS, Status2;
803 HANDLE hModule = 0;
804 UNICODE_STRING ModuleNameU;
805 DWORD dwValid;
806 BOOLEAN Redirected = FALSE; // FIXME
807
808 /* Validate parameters */
809 dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule);
810 ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE);
811
812 /* Acquire lock if necessary */
813 if (!NoLock)
814 {
815 Status = LdrLockLoaderLock(0, NULL, &Cookie);
816 if (!NT_SUCCESS(Status))
817 {
818 /* Fail */
819 SetLastErrorByStatus(Status);
820 if (phModule) *phModule = 0;
821 return Status;
822 }
823 }
824
825 if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
826 {
827 /* Create a unicode string out of module name */
828 RtlInitUnicodeString(&ModuleNameU, lpwModuleName);
829
830 // FIXME: Do some redirected DLL stuff?
831 if (Redirected)
832 {
833 UNIMPLEMENTED;
834 }
835
836 if (!hModule)
837 {
838 hModule = GetModuleHandleForUnicodeString(&ModuleNameU);
839 if (!hModule)
840 {
841 /* Last error is already set, so just return failure by setting status */
842 Status = STATUS_DLL_NOT_FOUND;
843 goto quickie;
844 }
845 }
846 }
847 else
848 {
849 /* Perform Pc to file header to get module instance */
850 hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName,
851 (PVOID*)&hModule);
852
853 /* Check if it succeeded */
854 if (!hModule)
855 {
856 /* Set "dll not found" status and quit */
857 Status = STATUS_DLL_NOT_FOUND;
858 goto quickie;
859 }
860 }
861
862 /* Check if changing reference is not forbidden */
863 if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
864 {
865 /* Add reference to this DLL */
866 Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_ADDREF_DLL_PIN : 0,
867 hModule);
868 }
869
870 /* Set last error in case of failure */
871 if (!NT_SUCCESS(Status))
872 SetLastErrorByStatus(Status);
873
874 quickie:
875 /* Unlock loader lock if it was acquired */
876 if (!NoLock)
877 {
878 Status2 = LdrUnlockLoaderLock(0, Cookie);
879 ASSERT(NT_SUCCESS(Status2));
880 }
881
882 /* Set the module handle to the caller */
883 if (phModule) *phModule = hModule;
884
885 /* Return TRUE on success and FALSE otherwise */
886 return NT_SUCCESS(Status);
887 }
888
889 /*
890 * @implemented
891 */
892 HMODULE
893 WINAPI
894 GetModuleHandleA(LPCSTR lpModuleName)
895 {
896 PUNICODE_STRING ModuleNameW;
897 PTEB pTeb = NtCurrentTeb();
898
899 /* Check if we have no name to convert */
900 if (!lpModuleName)
901 return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
902
903 /* Convert module name to unicode */
904 ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
905
906 /* Call W version if conversion was successful */
907 if (ModuleNameW)
908 return GetModuleHandleW(ModuleNameW->Buffer);
909
910 /* Return failure */
911 return 0;
912 }
913
914
915 /*
916 * @implemented
917 */
918 HMODULE
919 WINAPI
920 GetModuleHandleW(LPCWSTR lpModuleName)
921 {
922 HMODULE hModule;
923 NTSTATUS Status;
924
925 /* If current module is requested - return it right away */
926 if (!lpModuleName)
927 return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
928
929 /* Use common helper routine */
930 Status = BasepGetModuleHandleExW(TRUE,
931 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
932 lpModuleName,
933 &hModule);
934
935 /* If it wasn't successful - return 0 */
936 if (!NT_SUCCESS(Status)) hModule = 0;
937
938 /* Return the handle */
939 return hModule;
940 }
941
942
943 /*
944 * @implemented
945 */
946 BOOL
947 WINAPI
948 GetModuleHandleExW(IN DWORD dwFlags,
949 IN LPCWSTR lpwModuleName OPTIONAL,
950 OUT HMODULE* phModule)
951 {
952 NTSTATUS Status;
953 DWORD dwValid;
954 BOOL Ret = FALSE;
955
956 /* Validate parameters */
957 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule);
958
959 /* If result is invalid parameter - return failure */
960 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
961
962 /* If result is 2, there is no need to do anything - return success. */
963 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
964
965 /* Use common helper routine */
966 Status = BasepGetModuleHandleExW(FALSE,
967 dwFlags,
968 lpwModuleName,
969 phModule);
970
971 /* Return TRUE in case of success */
972 if (NT_SUCCESS(Status)) Ret = TRUE;
973
974 return Ret;
975 }
976
977 /*
978 * @implemented
979 */
980 BOOL
981 WINAPI
982 GetModuleHandleExA(IN DWORD dwFlags,
983 IN LPCSTR lpModuleName OPTIONAL,
984 OUT HMODULE* phModule)
985 {
986 PUNICODE_STRING lpModuleNameW;
987 DWORD dwValid;
988 BOOL Ret = FALSE;
989 NTSTATUS Status;
990
991 /* Validate parameters */
992 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
993
994 /* If result is invalid parameter - return failure */
995 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
996
997 /* If result is 2, there is no need to do anything - return success. */
998 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
999
1000 /* Check if we don't need to convert the name */
1001 if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
1002 {
1003 /* Call the extended version of the API without conversion */
1004 Status = BasepGetModuleHandleExW(FALSE,
1005 dwFlags,
1006 (LPCWSTR)lpModuleName,
1007 phModule);
1008 }
1009 else
1010 {
1011 /* Convert module name to unicode */
1012 lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
1013
1014 /* Return FALSE if conversion failed */
1015 if (!lpModuleNameW) return FALSE;
1016
1017 /* Call the extended version of the API */
1018 Status = BasepGetModuleHandleExW(FALSE,
1019 dwFlags,
1020 lpModuleNameW->Buffer,
1021 phModule);
1022 }
1023
1024 /* If result was successful - return true */
1025 if (NT_SUCCESS(Status))
1026 Ret = TRUE;
1027
1028 /* Return result */
1029 return Ret;
1030 }
1031
1032
1033 /*
1034 * @implemented
1035 */
1036 DWORD
1037 WINAPI
1038 LoadModule(LPCSTR lpModuleName,
1039 LPVOID lpParameterBlock)
1040 {
1041 STARTUPINFOA StartupInfo;
1042 PROCESS_INFORMATION ProcessInformation;
1043 LOADPARMS32 *LoadParams;
1044 char FileName[MAX_PATH];
1045 LPSTR CommandLine;
1046 DWORD Length, Error;
1047 BOOL ProcessStatus;
1048 ANSI_STRING AnsiStr;
1049 UNICODE_STRING UnicStr;
1050 RTL_PATH_TYPE PathType;
1051 HANDLE Handle;
1052
1053 LoadParams = (LOADPARMS32*)lpParameterBlock;
1054
1055 /* Check load parameters */
1056 if (LoadParams->dwReserved || LoadParams->wMagicValue != 2)
1057 {
1058 /* Fail with invalid param error */
1059 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1060 return 0;
1061 }
1062
1063 /* Search path */
1064 Length = SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL);
1065
1066 /* Check if path was found */
1067 if (Length && Length < MAX_PATH)
1068 {
1069 /* Build StartupInfo */
1070 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
1071
1072 StartupInfo.cb = sizeof(STARTUPINFOA);
1073 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
1074 StartupInfo.wShowWindow = LoadParams->wCmdShow;
1075
1076 /* Allocate command line buffer */
1077 CommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
1078 HEAP_ZERO_MEMORY,
1079 (ULONG)LoadParams->lpCmdLine[0] + Length + 2);
1080
1081 /* Put module name there, then a space, and then copy provided command line,
1082 and null-terminate it */
1083 RtlCopyMemory(CommandLine, FileName, Length);
1084 CommandLine[Length] = ' ';
1085 RtlCopyMemory(&CommandLine[Length + 1], &LoadParams->lpCmdLine[1], (ULONG)LoadParams->lpCmdLine[0]);
1086 CommandLine[Length + 1 + (ULONG)LoadParams->lpCmdLine[0]] = 0;
1087
1088 /* Create the process */
1089 ProcessStatus = CreateProcessA(FileName,
1090 CommandLine,
1091 NULL,
1092 NULL,
1093 FALSE,
1094 0,
1095 LoadParams->lpEnvAddress,
1096 NULL,
1097 &StartupInfo,
1098 &ProcessInformation);
1099
1100 /* Free the command line buffer */
1101 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
1102
1103 if (!ProcessStatus)
1104 {
1105 /* Creating process failed, return right error code */
1106 Error = GetLastError();
1107 switch(Error)
1108 {
1109 case ERROR_BAD_EXE_FORMAT:
1110 return ERROR_BAD_FORMAT;
1111
1112 case ERROR_FILE_NOT_FOUND:
1113 case ERROR_PATH_NOT_FOUND:
1114 return Error;
1115 }
1116
1117 /* Return 0 otherwise */
1118 return 0;
1119 }
1120
1121 /* Wait up to 30 seconds for the process to become idle */
1122 if (lpfnGlobalRegisterWaitForInputIdle)
1123 {
1124 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess, 30000);
1125 }
1126
1127 /* Close handles */
1128 NtClose(ProcessInformation.hThread);
1129 NtClose(ProcessInformation.hProcess);
1130
1131 /* Return magic success value (33) */
1132 return 33;
1133 }
1134
1135 /* The path was not found, create an ansi string from
1136 the module name and convert it to unicode */
1137 RtlInitAnsiString(&AnsiStr, lpModuleName);
1138 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicStr,&AnsiStr,TRUE)))
1139 return ERROR_FILE_NOT_FOUND;
1140
1141 /* Determine path type */
1142 PathType = RtlDetermineDosPathNameType_U(UnicStr.Buffer);
1143
1144 /* Free the unicode module name */
1145 RtlFreeUnicodeString(&UnicStr);
1146
1147 /* If it's a relative path, return file not found */
1148 if (PathType == RtlPathTypeRelative)
1149 return ERROR_FILE_NOT_FOUND;
1150
1151 /* If not, try to open it */
1152 Handle = CreateFile(lpModuleName,
1153 GENERIC_READ,
1154 FILE_SHARE_READ | FILE_SHARE_WRITE,
1155 NULL,
1156 OPEN_EXISTING,
1157 FILE_ATTRIBUTE_NORMAL,
1158 NULL);
1159
1160 if (Handle != INVALID_HANDLE_VALUE)
1161 {
1162 /* Opening file succeeded for some reason, close the handle and return file not found anyway */
1163 CloseHandle(Handle);
1164 return ERROR_FILE_NOT_FOUND;
1165 }
1166
1167 /* Return last error which CreateFile set during an attempt to open it */
1168 return GetLastError();
1169 }
1170
1171 /* EOF */