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>
14 typedef struct tagLOADPARMS32
{
22 extern BOOLEAN InWindows
;
23 extern WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle
;
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
31 BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry
,
33 OUT BOOLEAN
*StopEnumeration
);
35 /* FUNCTIONS ****************************************************************/
39 BasepGetModuleHandleExParameterValidation(DWORD dwFlags
,
40 LPCWSTR lpwModuleName
,
43 /* Set phModule to 0 if it's not a NULL pointer */
44 if (phModule
) *phModule
= 0;
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
))
55 BaseSetLastNTError(STATUS_INVALID_PARAMETER_1
);
56 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR
;
59 /* Check 2nd parameter */
62 BaseSetLastNTError(STATUS_INVALID_PARAMETER_2
);
63 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR
;
66 /* Return what we have according to the module name */
69 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE
;
72 /* No name given, so put ImageBaseAddress there */
73 *phModule
= (HMODULE
)NtCurrentPeb()->ImageBaseAddress
;
75 return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS
;
80 BasepMapModuleHandle(HMODULE hModule
, BOOLEAN AsDataFile
)
82 /* If no handle is provided - use current image base address */
83 if (!hModule
) return NtCurrentPeb()->ImageBaseAddress
;
85 /* Check if it's a normal or a datafile one */
86 if (LDR_IS_DATAFILE(hModule
) && !AsDataFile
)
89 /* It'a a normal DLL, just return its handle */
94 * @name GetDllLoadPath
96 * Internal function to compute the load path to use for a given dll.
98 * @remarks Returned pointer must be freed by caller.
102 GetDllLoadPath(LPCWSTR lpModule
)
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 */
110 // FIXME: This function is used only by SearchPathW, and is deprecated and will be deleted ASAP.
112 if ((lpModule
!= NULL
) && (wcslen(lpModule
) > 2) && (lpModule
[1] == ':'))
114 lpModuleEnd
= lpModule
+ wcslen(lpModule
);
118 ModuleName
= NtCurrentPeb()->ProcessParameters
->ImagePathName
;
119 lpModule
= ModuleName
.Buffer
;
120 lpModuleEnd
= lpModule
+ (ModuleName
.Length
/ sizeof(WCHAR
));
123 if (lpModule
!= NULL
)
125 while (lpModuleEnd
> lpModule
&& *lpModuleEnd
!= L
'/' &&
126 *lpModuleEnd
!= L
'\\' && *lpModuleEnd
!= L
':')
130 Length
= (lpModuleEnd
- lpModule
) + 1;
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);
139 EnvironmentBufferW
= RtlAllocateHeap(RtlGetProcessHeap(), 0,
140 Length
* sizeof(WCHAR
));
141 if (EnvironmentBufferW
== NULL
)
148 RtlCopyMemory(EnvironmentBufferW
, lpModule
,
149 (lpModuleEnd
- lpModule
) * sizeof(WCHAR
));
150 Pos
+= lpModuleEnd
- lpModule
;
151 EnvironmentBufferW
[Pos
++] = L
';';
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
);
164 SetLastError(LastError
);
165 return EnvironmentBufferW
;
173 DisableThreadLibraryCalls(
174 IN HMODULE hLibModule
)
178 /* Disable thread library calls */
179 Status
= LdrDisableThreadCalloutsForDll((PVOID
)hLibModule
);
181 /* If it wasn't success - set last error and return failure */
182 if (!NT_SUCCESS(Status
))
184 BaseSetLastNTError(Status
);
198 LoadLibraryA(LPCSTR lpLibFileName
)
204 /* Treat twain_32.dll in a special way (what a surprise...) */
205 if (lpLibFileName
&& !_strcmpi(lpLibFileName
, "twain_32.dll"))
207 /* Allocate space for the buffer */
208 PathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH
);
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))
215 /* We successfully got windows directory. Concatenate twain_32.dll to it */
216 strncat(PathBuffer
, "\\twain_32.dll", 13);
218 /* And recursively call ourselves with a new string */
219 Result
= LoadLibraryA(PathBuffer
);
221 /* If it was successful - free memory and return result */
224 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
229 /* Free allocated buffer */
230 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
234 /* Call the Ex version of the API */
235 return LoadLibraryExA(lpLibFileName
, 0, 0);
243 LoadLibraryExA(LPCSTR lpLibFileName
,
247 PUNICODE_STRING FileNameW
;
249 /* Convert file name to unicode */
250 if (!(FileNameW
= Basep8BitStringToStaticUnicodeString(lpLibFileName
)))
253 /* And call W version of the API */
254 return LoadLibraryExW(FileNameW
->Buffer
, hFile
, dwFlags
);
262 LoadLibraryW(LPCWSTR lpLibFileName
)
264 /* Call Ex version of the API */
265 return LoadLibraryExW (lpLibFileName
, 0, 0);
271 BasepLoadLibraryAsDatafile(PWSTR Path
, LPCWSTR Name
, HMODULE
*hModule
)
273 WCHAR FilenameW
[MAX_PATH
];
274 HANDLE hFile
= INVALID_HANDLE_VALUE
;
277 PVOID lpBaseAddress
= NULL
;
279 //PUNICODE_STRING OriginalName;
280 //UNICODE_STRING dotDLL = RTL_CONSTANT_STRING(L".DLL");
282 /* Zero out handle value */
285 DPRINT("BasepLoadLibraryAsDatafile(%S %S %p)\n", Path
, Name
, hModule
);
287 /*Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
297 /* Try to search for it */
298 if (!SearchPathW(Path
,
301 sizeof(FilenameW
) / sizeof(FilenameW
[0]),
305 /* Return last status value directly */
306 return NtCurrentTeb()->LastStatusValue
;
309 /* Open this file we found */
310 hFile
= CreateFileW(FilenameW
,
312 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
318 /* If opening failed - return last status value */
319 if (hFile
== INVALID_HANDLE_VALUE
) return NtCurrentTeb()->LastStatusValue
;
321 /* Create file mapping */
322 hMapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
324 /* Close the file handle */
327 /* If creating file mapping failed - return last status value */
328 if (!hMapping
) return NtCurrentTeb()->LastStatusValue
;
330 /* Map view of section */
331 Status
= NtMapViewOfSection(hMapping
,
342 /* Close handle to the section */
343 CloseHandle(hMapping
);
345 /* If mapping view of section failed - return last status value */
346 if (!NT_SUCCESS(Status
)) return NtCurrentTeb()->LastStatusValue
;
348 /* Make sure it's a valid PE file */
349 if (!RtlImageNtHeader(lpBaseAddress
))
351 /* Unmap the view and return failure status */
352 UnmapViewOfFile(lpBaseAddress
);
353 return STATUS_INVALID_IMAGE_FORMAT
;
356 /* Set low bit of handle to indicate datafile module */
357 *hModule
= (HMODULE
)((ULONG_PTR
)lpBaseAddress
| 1);
359 /* Load alternate resource module */
360 //LdrLoadAlternateResourceModule(*hModule, FilenameW);
362 return STATUS_SUCCESS
;
370 LoadLibraryExW(LPCWSTR lpLibFileName
,
374 UNICODE_STRING DllName
;
378 ULONG DllCharacteristics
= 0;
379 BOOL FreeString
= FALSE
;
381 /* Check for any flags LdrLoadDll might be interested in */
382 if (dwFlags
& DONT_RESOLVE_DLL_REFERENCES
)
384 /* Tell LDR to treat it as an EXE */
385 DllCharacteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
388 /* Build up a unicode dll name from null-terminated string */
389 RtlInitUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
391 /* Lazy-initialize BasepExeLdrEntry */
392 if (!BasepExeLdrEntry
)
393 LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry
, NtCurrentPeb()->ImageBaseAddress
);
395 /* Check if that module is our exe*/
396 if (BasepExeLdrEntry
&& !(dwFlags
& LOAD_LIBRARY_AS_DATAFILE
) &&
397 DllName
.Length
== BasepExeLdrEntry
->FullDllName
.Length
)
399 /* Lengths match and it's not a datafile, so perform name comparison */
400 if (RtlEqualUnicodeString(&DllName
, &BasepExeLdrEntry
->FullDllName
, TRUE
))
403 return BasepExeLdrEntry
->DllBase
;
407 /* Check for trailing spaces and remove them if necessary */
408 if (DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
410 RtlCreateUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
411 while (DllName
.Length
> sizeof(WCHAR
) &&
412 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
414 DllName
.Length
-= sizeof(WCHAR
);
416 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
420 /* Compute the load path */
421 SearchPath
= BasepGetDllPath((dwFlags
& LOAD_WITH_ALTERED_SEARCH_PATH
) ? (LPWSTR
)lpLibFileName
: NULL
,
426 /* Getting DLL path failed, so set last error, free mem and return */
427 BaseSetLastNTError(STATUS_NO_MEMORY
);
428 if (FreeString
) RtlFreeUnicodeString(&DllName
);
434 if (dwFlags
& LOAD_LIBRARY_AS_DATAFILE
)
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
))
440 /* It's not loaded yet - so load it up */
441 Status
= BasepLoadLibraryAsDatafile(SearchPath
, DllName
.Buffer
, &hInst
);
442 _SEH2_YIELD(goto done
;)
449 /* Call the API Properly */
450 Status
= LdrLoadDll(SearchPath
,
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
);
461 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
463 Status
= _SEH2_GetExceptionCode();
468 /* Free SearchPath buffer */
469 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
471 /* Free DllName string if it was dynamically allocated */
472 if (FreeString
) RtlFreeUnicodeString(&DllName
);
474 /* Set last error in failure case */
475 if (!NT_SUCCESS(Status
))
477 BaseSetLastNTError(Status
);
481 /* Return loaded module handle */
491 GetProcAddress(HMODULE hModule
, LPCSTR lpProcName
)
493 ANSI_STRING ProcedureName
, *ProcNamePtr
= NULL
;
494 FARPROC fnExp
= NULL
;
499 if (HIWORD(lpProcName
) != 0)
501 /* Look up by name */
502 RtlInitAnsiString(&ProcedureName
, (LPSTR
)lpProcName
);
503 ProcNamePtr
= &ProcedureName
;
507 /* Look up by ordinal */
508 Ordinal
= (ULONG
)lpProcName
;
511 /* Map provided handle */
512 hMapped
= BasepMapModuleHandle(hModule
, FALSE
);
514 /* Get the proc address */
515 Status
= LdrGetProcedureAddress(hMapped
,
520 if (!NT_SUCCESS(Status
))
522 BaseSetLastNTError(Status
);
526 /* Check for a special case when returned pointer is
527 the same as iamge's base address */
528 if (fnExp
== hMapped
)
530 /* Set correct error code */
531 if (HIWORD(lpProcName
) != 0)
532 BaseSetLastNTError(STATUS_ENTRYPOINT_NOT_FOUND
);
534 BaseSetLastNTError(STATUS_ORDINAL_NOT_FOUND
);
539 /* All good, return procedure pointer */
547 BOOL WINAPI
FreeLibrary(HINSTANCE hLibModule
)
550 PIMAGE_NT_HEADERS NtHeaders
;
552 if (LDR_IS_DATAFILE(hLibModule
))
554 // FIXME: This SEH should go inside RtlImageNtHeader instead
557 /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
558 NtHeaders
= RtlImageNtHeader((PVOID
)((ULONG_PTR
)hLibModule
& ~1));
560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
568 Status
= NtUnmapViewOfSection(NtCurrentProcess(), (PVOID
)((ULONG_PTR
)hLibModule
& ~1));
570 /* Unload alternate resource module */
571 LdrUnloadAlternateResourceModule(hLibModule
);
574 Status
= STATUS_INVALID_IMAGE_FORMAT
;
579 Status
= LdrUnloadDll((PVOID
)hLibModule
);
582 /* Check what kind of status we got */
583 if (!NT_SUCCESS(Status
))
586 BaseSetLastNTError(Status
);
602 FreeLibraryAndExitThread(HMODULE hLibModule
,
607 if (LDR_IS_DATAFILE(hLibModule
))
609 /* This is a LOAD_LIBRARY_AS_DATAFILE module */
610 if (RtlImageNtHeader((PVOID
)((ULONG_PTR
)hLibModule
& ~1)))
613 Status
= NtUnmapViewOfSection(NtCurrentProcess(), (PVOID
)((ULONG_PTR
)hLibModule
& ~1));
615 /* Unload alternate resource module */
616 LdrUnloadAlternateResourceModule(hLibModule
);
622 Status
= LdrUnloadDll((PVOID
)hLibModule
);
626 ExitThread(dwExitCode
);
635 GetModuleFileNameA(HINSTANCE hModule
,
639 UNICODE_STRING FilenameW
;
640 ANSI_STRING FilenameA
;
642 DWORD Length
= 0, LengthToCopy
;
644 /* Allocate a unicode buffer */
645 FilenameW
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize
* sizeof(WCHAR
));
646 if (!FilenameW
.Buffer
)
648 BaseSetLastNTError(STATUS_NO_MEMORY
);
652 /* Call unicode API */
653 FilenameW
.Length
= GetModuleFileNameW(hModule
, FilenameW
.Buffer
, nSize
) * sizeof(WCHAR
);
654 FilenameW
.MaximumLength
= FilenameW
.Length
+ sizeof(WCHAR
);
656 if (FilenameW
.Length
)
658 /* Convert to ansi string */
659 Status
= BasepUnicodeStringTo8BitString(&FilenameA
, &FilenameW
, TRUE
);
660 if (!NT_SUCCESS(Status
))
662 /* Set last error, free string and retun failure */
663 BaseSetLastNTError(Status
);
664 RtlFreeUnicodeString(&FilenameW
);
668 /* Calculate size to copy */
669 Length
= min(nSize
, FilenameA
.Length
);
671 /* Include terminating zero */
673 LengthToCopy
= Length
+ 1;
675 LengthToCopy
= nSize
;
677 /* Now copy back to the caller amount he asked */
678 RtlMoveMemory(lpFilename
, FilenameA
.Buffer
, LengthToCopy
);
680 /* Free ansi filename */
681 RtlFreeAnsiString(&FilenameA
);
684 /* Free unicode filename */
685 RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW
.Buffer
);
687 /* Return length copied */
696 GetModuleFileNameW(HINSTANCE hModule
,
700 PLIST_ENTRY ModuleListHead
, Entry
;
701 PLDR_DATA_TABLE_ENTRY Module
;
706 hModule
= BasepMapModuleHandle(hModule
, FALSE
);
708 /* Upscale nSize from chars to bytes */
709 nSize
*= sizeof(WCHAR
);
713 /* We don't use per-thread cur dir now */
714 //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
716 Peb
= NtCurrentPeb ();
718 /* Acquire a loader lock */
719 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
721 /* Traverse the module list */
722 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
723 Entry
= ModuleListHead
->Flink
;
724 while (Entry
!= ModuleListHead
)
726 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
728 /* Check if this is the requested module */
729 if (Module
->DllBase
== (PVOID
)hModule
)
731 /* Calculate size to copy */
732 Length
= min(nSize
, Module
->FullDllName
.MaximumLength
);
735 RtlMoveMemory(lpFilename
, Module
->FullDllName
.Buffer
, Length
);
737 /* Subtract a terminating zero */
738 if (Length
== Module
->FullDllName
.MaximumLength
)
739 Length
-= sizeof(WCHAR
);
741 /* Break out of the loop */
745 /* Advance to the next entry */
746 Entry
= Entry
->Flink
;
749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
751 BaseSetLastNTError(_SEH2_GetExceptionCode());
755 /* Release the loader lock */
756 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
758 return Length
/ sizeof(WCHAR
);
763 GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName
)
769 /* Try to get a handle with a magic value of 1 for DllPath */
770 Status
= LdrGetDllHandle((LPWSTR
)1, NULL
, ModuleName
, &Module
);
772 /* If that succeeded - we're done */
773 if (NT_SUCCESS(Status
)) return Module
;
775 /* If not, then the path should be computed */
776 DllPath
= BasepGetDllPath(NULL
, 0);
778 /* Call LdrGetHandle() again providing the computed DllPath
779 and wrapped into SEH */
782 Status
= LdrGetDllHandle(DllPath
, NULL
, ModuleName
, &Module
);
784 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
786 /* Fail with the SEH error */
787 Status
= _SEH2_GetExceptionCode();
791 /* Free the DllPath */
792 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
);
794 /* In case of error set last win32 error and return NULL */
795 if (!NT_SUCCESS(Status
))
797 DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName
, Status
);
798 SetLastErrorByStatus(Status
);
803 return (HMODULE
)Module
;
808 BasepGetModuleHandleExW(BOOLEAN NoLock
, DWORD dwPublicFlags
, LPCWSTR lpwModuleName
, HMODULE
*phModule
)
811 NTSTATUS Status
= STATUS_SUCCESS
, Status2
;
813 UNICODE_STRING ModuleNameU
;
815 BOOLEAN Redirected
= FALSE
; // FIXME
817 /* Validate parameters */
818 dwValid
= BasepGetModuleHandleExParameterValidation(dwPublicFlags
, lpwModuleName
, phModule
);
819 ASSERT(dwValid
== BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE
);
821 /* Acquire lock if necessary */
824 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
825 if (!NT_SUCCESS(Status
))
828 SetLastErrorByStatus(Status
);
829 if (phModule
) *phModule
= 0;
834 if (!(dwPublicFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
))
836 /* Create a unicode string out of module name */
837 RtlInitUnicodeString(&ModuleNameU
, lpwModuleName
);
839 // FIXME: Do some redirected DLL stuff?
847 hModule
= GetModuleHandleForUnicodeString(&ModuleNameU
);
850 /* Last error is already set, so just return failure by setting status */
851 Status
= STATUS_DLL_NOT_FOUND
;
858 /* Perform Pc to file header to get module instance */
859 hModule
= (HMODULE
)RtlPcToFileHeader((PVOID
)lpwModuleName
,
862 /* Check if it succeeded */
865 /* Set "dll not found" status and quit */
866 Status
= STATUS_DLL_NOT_FOUND
;
871 /* Check if changing reference is not forbidden */
872 if (!(dwPublicFlags
& GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
))
874 /* Add reference to this DLL */
875 Status
= LdrAddRefDll((dwPublicFlags
& GET_MODULE_HANDLE_EX_FLAG_PIN
) ? LDR_PIN_MODULE
: 0,
879 /* Set last error in case of failure */
880 if (!NT_SUCCESS(Status
))
881 SetLastErrorByStatus(Status
);
884 /* Unlock loader lock if it was acquired */
887 Status2
= LdrUnlockLoaderLock(0, Cookie
);
888 ASSERT(NT_SUCCESS(Status2
));
891 /* Set the module handle to the caller */
892 if (phModule
) *phModule
= hModule
;
894 /* Return TRUE on success and FALSE otherwise */
895 return NT_SUCCESS(Status
);
903 GetModuleHandleA(LPCSTR lpModuleName
)
905 PUNICODE_STRING ModuleNameW
;
906 PTEB pTeb
= NtCurrentTeb();
908 /* Check if we have no name to convert */
910 return ((HMODULE
)pTeb
->ProcessEnvironmentBlock
->ImageBaseAddress
);
912 /* Convert module name to unicode */
913 ModuleNameW
= Basep8BitStringToStaticUnicodeString(lpModuleName
);
915 /* Call W version if conversion was successful */
917 return GetModuleHandleW(ModuleNameW
->Buffer
);
929 GetModuleHandleW(LPCWSTR lpModuleName
)
934 /* If current module is requested - return it right away */
936 return ((HMODULE
)NtCurrentPeb()->ImageBaseAddress
);
938 /* Use common helper routine */
939 Status
= BasepGetModuleHandleExW(TRUE
,
940 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
944 /* If it wasn't successful - return 0 */
945 if (!NT_SUCCESS(Status
)) hModule
= 0;
947 /* Return the handle */
957 GetModuleHandleExW(IN DWORD dwFlags
,
958 IN LPCWSTR lpwModuleName OPTIONAL
,
959 OUT HMODULE
* phModule
)
965 /* Validate parameters */
966 dwValid
= BasepGetModuleHandleExParameterValidation(dwFlags
, lpwModuleName
, phModule
);
968 /* If result is invalid parameter - return failure */
969 if (dwValid
== BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR
) return FALSE
;
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
;
974 /* Use common helper routine */
975 Status
= BasepGetModuleHandleExW(FALSE
,
980 /* Return TRUE in case of success */
981 if (NT_SUCCESS(Status
)) Ret
= TRUE
;
991 GetModuleHandleExA(IN DWORD dwFlags
,
992 IN LPCSTR lpModuleName OPTIONAL
,
993 OUT HMODULE
* phModule
)
995 PUNICODE_STRING lpModuleNameW
;
1000 /* Validate parameters */
1001 dwValid
= BasepGetModuleHandleExParameterValidation(dwFlags
, (LPCWSTR
)lpModuleName
, phModule
);
1003 /* If result is invalid parameter - return failure */
1004 if (dwValid
== BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR
) return FALSE
;
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
;
1009 /* Check if we don't need to convert the name */
1010 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
1012 /* Call the extended version of the API without conversion */
1013 Status
= BasepGetModuleHandleExW(FALSE
,
1015 (LPCWSTR
)lpModuleName
,
1020 /* Convert module name to unicode */
1021 lpModuleNameW
= Basep8BitStringToStaticUnicodeString(lpModuleName
);
1023 /* Return FALSE if conversion failed */
1024 if (!lpModuleNameW
) return FALSE
;
1026 /* Call the extended version of the API */
1027 Status
= BasepGetModuleHandleExW(FALSE
,
1029 lpModuleNameW
->Buffer
,
1033 /* If result was successful - return true */
1034 if (NT_SUCCESS(Status
))
1047 LoadModule(LPCSTR lpModuleName
,
1048 LPVOID lpParameterBlock
)
1050 STARTUPINFOA StartupInfo
;
1051 PROCESS_INFORMATION ProcessInformation
;
1052 LOADPARMS32
*LoadParams
;
1053 char FileName
[MAX_PATH
];
1055 DWORD Length
, Error
;
1057 ANSI_STRING AnsiStr
;
1058 UNICODE_STRING UnicStr
;
1059 RTL_PATH_TYPE PathType
;
1062 LoadParams
= (LOADPARMS32
*)lpParameterBlock
;
1064 /* Check load parameters */
1065 if (LoadParams
->dwReserved
|| LoadParams
->wMagicValue
!= 2)
1067 /* Fail with invalid param error */
1068 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1073 Length
= SearchPathA(NULL
, lpModuleName
, ".exe", MAX_PATH
, FileName
, NULL
);
1075 /* Check if path was found */
1076 if (Length
&& Length
< MAX_PATH
)
1078 /* Build StartupInfo */
1079 RtlZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1081 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
1082 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
1083 StartupInfo
.wShowWindow
= LoadParams
->wCmdShow
;
1085 /* Allocate command line buffer */
1086 CommandLine
= RtlAllocateHeap(RtlGetProcessHeap(),
1088 (ULONG
)LoadParams
->lpCmdLine
[0] + Length
+ 2);
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;
1097 /* Create the process */
1098 ProcessStatus
= CreateProcessA(FileName
,
1104 LoadParams
->lpEnvAddress
,
1107 &ProcessInformation
);
1109 /* Free the command line buffer */
1110 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
1114 /* Creating process failed, return right error code */
1115 Error
= GetLastError();
1118 case ERROR_BAD_EXE_FORMAT
:
1119 return ERROR_BAD_FORMAT
;
1121 case ERROR_FILE_NOT_FOUND
:
1122 case ERROR_PATH_NOT_FOUND
:
1126 /* Return 0 otherwise */
1130 /* Wait up to 30 seconds for the process to become idle */
1131 if (lpfnGlobalRegisterWaitForInputIdle
)
1133 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
, 30000);
1137 NtClose(ProcessInformation
.hThread
);
1138 NtClose(ProcessInformation
.hProcess
);
1140 /* Return magic success value (33) */
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
;
1150 /* Determine path type */
1151 PathType
= RtlDetermineDosPathNameType_U(UnicStr
.Buffer
);
1153 /* Free the unicode module name */
1154 RtlFreeUnicodeString(&UnicStr
);
1156 /* If it's a relative path, return file not found */
1157 if (PathType
== RtlPathTypeRelative
)
1158 return ERROR_FILE_NOT_FOUND
;
1160 /* If not, try to open it */
1161 Handle
= CreateFile(lpModuleName
,
1163 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1166 FILE_ATTRIBUTE_NORMAL
,
1169 if (Handle
!= INVALID_HANDLE_VALUE
)
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
;
1176 /* Return last error which CreateFile set during an attempt to open it */
1177 return GetLastError();