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