3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT : ReactOS user mode libraries
5 * MODULE : kernel32.dll
6 * FILE : reactos/lib/kernel32/misc/ldr.c
15 typedef struct tagLOADPARMS32
{
22 extern BOOLEAN InWindows
;
23 extern WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle
;
25 /* FUNCTIONS ****************************************************************/
28 * @name GetDllLoadPath
30 * Internal function to compute the load path to use for a given dll.
32 * @remarks Returned pointer must be freed by caller.
36 GetDllLoadPath(LPCWSTR lpModule
)
38 ULONG Pos
= 0, Length
= 0;
39 PWCHAR EnvironmentBufferW
= NULL
;
40 LPCWSTR lpModuleEnd
= NULL
;
41 UNICODE_STRING ModuleName
;
42 DWORD LastError
= GetLastError(); /* GetEnvironmentVariable changes LastError */
44 if ((lpModule
!= NULL
) && (wcslen(lpModule
) > 2) && (lpModule
[1] == ':'))
46 lpModuleEnd
= lpModule
+ wcslen(lpModule
);
50 ModuleName
= NtCurrentPeb()->ProcessParameters
->ImagePathName
;
51 lpModule
= ModuleName
.Buffer
;
52 lpModuleEnd
= lpModule
+ (ModuleName
.Length
/ sizeof(WCHAR
));
57 while (lpModuleEnd
> lpModule
&& *lpModuleEnd
!= L
'/' &&
58 *lpModuleEnd
!= L
'\\' && *lpModuleEnd
!= L
':')
62 Length
= (lpModuleEnd
- lpModule
) + 1;
65 Length
+= GetCurrentDirectoryW(0, NULL
);
66 Length
+= GetDllDirectoryW(0, NULL
);
67 Length
+= GetSystemDirectoryW(NULL
, 0);
68 Length
+= GetWindowsDirectoryW(NULL
, 0);
69 Length
+= GetEnvironmentVariableW(L
"PATH", NULL
, 0);
71 EnvironmentBufferW
= RtlAllocateHeap(RtlGetProcessHeap(), 0,
72 Length
* sizeof(WCHAR
));
73 if (EnvironmentBufferW
== NULL
)
80 RtlCopyMemory(EnvironmentBufferW
, lpModule
,
81 (lpModuleEnd
- lpModule
) * sizeof(WCHAR
));
82 Pos
+= lpModuleEnd
- lpModule
;
83 EnvironmentBufferW
[Pos
++] = L
';';
86 Pos
+= GetCurrentDirectoryW(Length
, EnvironmentBufferW
+ Pos
);
87 EnvironmentBufferW
[Pos
++] = L
';';
88 Pos
+= GetDllDirectoryW(Length
- Pos
, EnvironmentBufferW
+ Pos
);
89 EnvironmentBufferW
[Pos
++] = L
';';
90 Pos
+= GetSystemDirectoryW(EnvironmentBufferW
+ Pos
, Length
- Pos
);
91 EnvironmentBufferW
[Pos
++] = L
';';
92 Pos
+= GetWindowsDirectoryW(EnvironmentBufferW
+ Pos
, Length
- Pos
);
93 EnvironmentBufferW
[Pos
++] = L
';';
94 Pos
+= GetEnvironmentVariableW(L
"PATH", EnvironmentBufferW
+ Pos
, Length
- Pos
);
95 EnvironmentBufferW
[Pos
] = 0;
97 SetLastError(LastError
);
98 return EnvironmentBufferW
;
106 DisableThreadLibraryCalls (
112 Status
= LdrDisableThreadCalloutsForDll ((PVOID
)hLibModule
);
113 if (!NT_SUCCESS (Status
))
115 SetLastErrorByStatus (Status
);
131 return LoadLibraryExA (lpLibFileName
, 0, 0);
141 LPCSTR lpLibFileName
,
148 if (!(FileNameW
= FilenameA2W(lpLibFileName
, FALSE
)))
151 return LoadLibraryExW(FileNameW
, hFile
, dwFlags
);
161 LPCWSTR lpLibFileName
164 return LoadLibraryExW (lpLibFileName
, 0, 0);
170 LoadLibraryAsDatafile(PWSTR path
, LPCWSTR name
, HMODULE
* hmod
)
172 static const WCHAR dotDLL
[] = {'.','d','l','l',0};
174 WCHAR filenameW
[MAX_PATH
];
175 HANDLE hFile
= INVALID_HANDLE_VALUE
;
181 if (!SearchPathW( path
, name
, dotDLL
, sizeof(filenameW
) / sizeof(filenameW
[0]),
184 return NtCurrentTeb()->LastStatusValue
;
187 hFile
= CreateFileW( filenameW
, GENERIC_READ
, FILE_SHARE_READ
,
188 NULL
, OPEN_EXISTING
, 0, 0 );
190 if (hFile
== INVALID_HANDLE_VALUE
) return NtCurrentTeb()->LastStatusValue
;
192 mapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
193 CloseHandle( hFile
);
194 if (!mapping
) return NtCurrentTeb()->LastStatusValue
;
196 module
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
197 CloseHandle( mapping
);
198 if (!module
) return NtCurrentTeb()->LastStatusValue
;
200 /* make sure it's a valid PE file */
201 if (!RtlImageNtHeader(module
))
203 UnmapViewOfFile( module
);
204 return STATUS_INVALID_IMAGE_FORMAT
;
206 *hmod
= (HMODULE
)((char *)module
+ 1); /* set low bit of handle to indicate datafile module */
207 return STATUS_SUCCESS
;
217 LPCWSTR lpLibFileName
,
222 UNICODE_STRING DllName
;
226 ULONG DllCharacteristics
;
227 BOOL FreeString
= FALSE
;
231 if ( lpLibFileName
== NULL
)
234 /* Check for any flags LdrLoadDll might be interested in */
235 if (dwFlags
& DONT_RESOLVE_DLL_REFERENCES
)
237 /* Tell LDR to treat it as an EXE */
238 DllCharacteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
242 DONT_RESOLVE_DLL_REFERENCES
|
243 LOAD_LIBRARY_AS_DATAFILE
|
244 LOAD_WITH_ALTERED_SEARCH_PATH
;
246 SearchPath
= GetDllLoadPath(
247 dwFlags
& LOAD_WITH_ALTERED_SEARCH_PATH
? lpLibFileName
: NULL
);
249 RtlInitUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
251 if (DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
253 RtlCreateUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
254 while (DllName
.Length
> sizeof(WCHAR
) &&
255 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
257 DllName
.Length
-= sizeof(WCHAR
);
259 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
263 if (dwFlags
& LOAD_LIBRARY_AS_DATAFILE
)
265 Status
= LdrGetDllHandle(SearchPath
, NULL
, &DllName
, (PVOID
*)&hInst
);
266 if (!NT_SUCCESS(Status
))
268 /* The method in load_library_as_datafile allows searching for the
269 * 'native' libraries only
271 Status
= LoadLibraryAsDatafile(SearchPath
, DllName
.Buffer
, &hInst
);
279 /* Call the API Properly */
280 Status
= LdrLoadDll(SearchPath
,
287 /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */
288 Status
= LdrLoadDll(SearchPath
, &dwFlags
, &DllName
, (PVOID
*)&hInst
);
292 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
294 RtlFreeUnicodeString(&DllName
);
295 if ( !NT_SUCCESS(Status
))
297 SetLastErrorByStatus (Status
);
310 GetProcAddress( HMODULE hModule
, LPCSTR lpProcName
)
312 ANSI_STRING ProcedureName
;
313 FARPROC fnExp
= NULL
;
316 if (HIWORD(lpProcName
) != 0)
318 RtlInitAnsiString (&ProcedureName
,
320 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
327 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
333 if (!NT_SUCCESS(Status
))
335 SetLastErrorByStatus(Status
);
346 BOOL WINAPI
FreeLibrary(HINSTANCE hLibModule
)
352 SetLastError(ERROR_INVALID_HANDLE
);
356 if ((ULONG_PTR
)hLibModule
& 1)
358 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
359 char *ptr
= (char *)hLibModule
- 1;
360 UnmapViewOfFile(ptr
);
364 Status
= LdrUnloadDll(hLibModule
);
365 if (!NT_SUCCESS(Status
))
367 SetLastErrorByStatus(Status
);
380 FreeLibraryAndExitThread (
385 FreeLibrary(hLibModule
);
386 ExitThread(dwExitCode
);
401 ANSI_STRING FileName
;
402 PLIST_ENTRY ModuleListHead
;
404 PLDR_DATA_TABLE_ENTRY Module
;
408 Peb
= NtCurrentPeb ();
409 RtlEnterCriticalSection (Peb
->LoaderLock
);
412 hModule
= Peb
->ImageBaseAddress
;
414 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
415 Entry
= ModuleListHead
->Flink
;
417 while (Entry
!= ModuleListHead
)
419 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
420 if (Module
->DllBase
== (PVOID
)hModule
)
422 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
424 FileName
.MaximumLength
= (USHORT
)Length
* sizeof(WCHAR
);
425 FileName
.Buffer
= lpFilename
;
427 /* convert unicode string to ansi (or oem) */
429 RtlUnicodeStringToAnsiString (&FileName
,
430 &Module
->FullDllName
,
433 RtlUnicodeStringToOemString (&FileName
,
434 &Module
->FullDllName
,
438 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
440 lpFilename
[Length
] = '\0';
442 RtlLeaveCriticalSection (Peb
->LoaderLock
);
446 Entry
= Entry
->Flink
;
449 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
450 RtlLeaveCriticalSection (Peb
->LoaderLock
);
467 UNICODE_STRING FileName
;
468 PLIST_ENTRY ModuleListHead
;
470 PLDR_DATA_TABLE_ENTRY Module
;
474 Peb
= NtCurrentPeb ();
475 RtlEnterCriticalSection (Peb
->LoaderLock
);
478 hModule
= Peb
->ImageBaseAddress
;
480 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
481 Entry
= ModuleListHead
->Flink
;
482 while (Entry
!= ModuleListHead
)
484 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
486 if (Module
->DllBase
== (PVOID
)hModule
)
488 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
490 FileName
.MaximumLength
= (USHORT
) Length
* sizeof(WCHAR
);
491 FileName
.Buffer
= lpFilename
;
493 RtlCopyUnicodeString (&FileName
,
494 &Module
->FullDllName
);
496 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
498 lpFilename
[Length
] = L
'\0';
500 RtlLeaveCriticalSection (Peb
->LoaderLock
);
505 Entry
= Entry
->Flink
;
508 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
509 RtlLeaveCriticalSection (Peb
->LoaderLock
);
520 GetModuleHandleA ( LPCSTR lpModuleName
)
522 ANSI_STRING ModuleName
;
524 PTEB pTeb
= NtCurrentTeb();
526 if (lpModuleName
== NULL
)
528 return ((HMODULE
)pTeb
->ProcessEnvironmentBlock
->ImageBaseAddress
);
531 RtlInitAnsiString(&ModuleName
, lpModuleName
);
533 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
537 if (NT_SUCCESS(Status
))
539 return GetModuleHandleW(pTeb
->StaticUnicodeString
.Buffer
);
542 SetLastErrorByStatus(Status
);
552 GetModuleHandleW (LPCWSTR lpModuleName
)
554 UNICODE_STRING ModuleName
;
558 if (lpModuleName
== NULL
)
559 return ((HMODULE
)NtCurrentPeb()->ImageBaseAddress
);
561 RtlInitUnicodeString (&ModuleName
,
562 (LPWSTR
)lpModuleName
);
564 Status
= LdrGetDllHandle (0,
568 if (!NT_SUCCESS(Status
))
570 SetLastErrorByStatus (Status
);
574 return ((HMODULE
)BaseAddress
);
583 GetModuleHandleExW(IN DWORD dwFlags
,
584 IN LPCWSTR lpModuleName OPTIONAL
,
585 OUT HMODULE
* phModule
)
591 if (phModule
== NULL
||
592 ((dwFlags
& (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)) ==
593 (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)))
595 SetLastError(ERROR_INVALID_PARAMETER
);
599 if (lpModuleName
== NULL
)
601 hModule
= NtCurrentPeb()->ImageBaseAddress
;
605 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
607 hModule
= (HMODULE
)RtlPcToFileHeader((PVOID
)lpModuleName
,
611 SetLastErrorByStatus(STATUS_DLL_NOT_FOUND
);
616 hModule
= GetModuleHandleW(lpModuleName
);
622 if (!(dwFlags
& GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
))
624 Status
= LdrAddRefDll((dwFlags
& GET_MODULE_HANDLE_EX_FLAG_PIN
) ? LDR_PIN_MODULE
: 0,
627 if (NT_SUCCESS(Status
))
633 SetLastErrorByStatus(Status
);
650 GetModuleHandleExA(IN DWORD dwFlags
,
651 IN LPCSTR lpModuleName OPTIONAL
,
652 OUT HMODULE
* phModule
)
654 ANSI_STRING ModuleName
;
655 LPCWSTR lpModuleNameW
;
659 PTEB pTeb
= NtCurrentTeb();
661 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
663 lpModuleNameW
= (LPCWSTR
)lpModuleName
;
667 RtlInitAnsiString(&ModuleName
, lpModuleName
);
669 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
673 if (!NT_SUCCESS(Status
))
675 SetLastErrorByStatus(Status
);
679 lpModuleNameW
= pTeb
->StaticUnicodeString
.Buffer
;
682 Ret
= GetModuleHandleExW(dwFlags
,
697 LPVOID lpParameterBlock
700 STARTUPINFOA StartupInfo
;
701 PROCESS_INFORMATION ProcessInformation
;
702 LOADPARMS32
*LoadParams
;
703 char FileName
[MAX_PATH
];
704 char *CommandLine
, *t
;
707 LoadParams
= (LOADPARMS32
*)lpParameterBlock
;
708 if(!lpModuleName
|| !LoadParams
|| (((WORD
*)LoadParams
->lpCmdShow
)[0] != 2))
710 /* windows doesn't check parameters, we do */
711 SetLastError(ERROR_INVALID_PARAMETER
);
715 if(!SearchPathA(NULL
, lpModuleName
, ".exe", MAX_PATH
, FileName
, NULL
) &&
716 !SearchPathA(NULL
, lpModuleName
, NULL
, MAX_PATH
, FileName
, NULL
))
718 return ERROR_FILE_NOT_FOUND
;
721 Length
= (BYTE
)LoadParams
->lpCmdLine
[0];
722 if(!(CommandLine
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
723 strlen(lpModuleName
) + Length
+ 2)))
725 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
729 /* Create command line string */
730 strcpy(CommandLine
, lpModuleName
);
731 t
= CommandLine
+ strlen(CommandLine
);
733 memcpy(t
, LoadParams
->lpCmdLine
+ 1, Length
);
735 /* Build StartupInfo */
736 RtlZeroMemory(&StartupInfo
, sizeof(STARTUPINFOA
));
737 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
738 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
739 StartupInfo
.wShowWindow
= ((WORD
*)LoadParams
->lpCmdShow
)[1];
741 if(!CreateProcessA(FileName
, CommandLine
, NULL
, NULL
, FALSE
, 0, LoadParams
->lpEnvAddress
,
742 NULL
, &StartupInfo
, &ProcessInformation
))
746 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
747 /* return the right value */
748 Error
= GetLastError();
751 case ERROR_BAD_EXE_FORMAT
:
753 return ERROR_BAD_FORMAT
;
755 case ERROR_FILE_NOT_FOUND
:
756 case ERROR_PATH_NOT_FOUND
:
764 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
766 /* Wait up to 15 seconds for the process to become idle */
767 if (NULL
!= lpfnGlobalRegisterWaitForInputIdle
)
769 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
, 15000);
772 NtClose(ProcessInformation
.hThread
);
773 NtClose(ProcessInformation
.hProcess
);