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
);
96 SetLastError(LastError
);
97 return EnvironmentBufferW
;
105 DisableThreadLibraryCalls(
106 IN HMODULE hLibModule
)
110 Status
= LdrDisableThreadCalloutsForDll((PVOID
)hLibModule
);
111 if (!NT_SUCCESS(Status
))
113 BaseSetLastNTError(Status
);
129 return LoadLibraryExA (lpLibFileName
, 0, 0);
139 LPCSTR lpLibFileName
,
143 PUNICODE_STRING FileNameW
;
145 if (!(FileNameW
= Basep8BitStringToStaticUnicodeString(lpLibFileName
)))
148 return LoadLibraryExW(FileNameW
->Buffer
, hFile
, dwFlags
);
158 LPCWSTR lpLibFileName
161 return LoadLibraryExW (lpLibFileName
, 0, 0);
167 LoadLibraryAsDatafile(PWSTR path
, LPCWSTR name
, HMODULE
* hmod
)
169 static const WCHAR dotDLL
[] = {'.','d','l','l',0};
171 WCHAR filenameW
[MAX_PATH
];
172 HANDLE hFile
= INVALID_HANDLE_VALUE
;
178 if (!SearchPathW( path
, name
, dotDLL
, sizeof(filenameW
) / sizeof(filenameW
[0]),
181 return NtCurrentTeb()->LastStatusValue
;
184 hFile
= CreateFileW( filenameW
, GENERIC_READ
, FILE_SHARE_READ
,
185 NULL
, OPEN_EXISTING
, 0, 0 );
187 if (hFile
== INVALID_HANDLE_VALUE
) return NtCurrentTeb()->LastStatusValue
;
189 mapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
190 CloseHandle( hFile
);
191 if (!mapping
) return NtCurrentTeb()->LastStatusValue
;
193 module
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
194 CloseHandle( mapping
);
195 if (!module
) return NtCurrentTeb()->LastStatusValue
;
197 /* make sure it's a valid PE file */
198 if (!RtlImageNtHeader(module
))
200 UnmapViewOfFile( module
);
201 return STATUS_INVALID_IMAGE_FORMAT
;
203 *hmod
= (HMODULE
)((char *)module
+ 1); /* set low bit of handle to indicate datafile module */
204 return STATUS_SUCCESS
;
214 LPCWSTR lpLibFileName
,
219 UNICODE_STRING DllName
;
223 ULONG DllCharacteristics
;
224 BOOL FreeString
= FALSE
;
228 if ( lpLibFileName
== NULL
)
231 /* Check for any flags LdrLoadDll might be interested in */
232 if (dwFlags
& DONT_RESOLVE_DLL_REFERENCES
)
234 /* Tell LDR to treat it as an EXE */
235 DllCharacteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
239 DONT_RESOLVE_DLL_REFERENCES
|
240 LOAD_LIBRARY_AS_DATAFILE
|
241 LOAD_WITH_ALTERED_SEARCH_PATH
;
243 SearchPath
= GetDllLoadPath(
244 dwFlags
& LOAD_WITH_ALTERED_SEARCH_PATH
? lpLibFileName
: NULL
);
246 RtlInitUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
248 if (DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
250 RtlCreateUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
251 while (DllName
.Length
> sizeof(WCHAR
) &&
252 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
254 DllName
.Length
-= sizeof(WCHAR
);
256 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
260 if (dwFlags
& LOAD_LIBRARY_AS_DATAFILE
)
262 Status
= LdrGetDllHandle(SearchPath
, NULL
, &DllName
, (PVOID
*)&hInst
);
263 if (!NT_SUCCESS(Status
))
265 /* The method in load_library_as_datafile allows searching for the
266 * 'native' libraries only
268 Status
= LoadLibraryAsDatafile(SearchPath
, DllName
.Buffer
, &hInst
);
276 /* Call the API Properly */
277 Status
= LdrLoadDll(SearchPath
,
284 /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */
285 Status
= LdrLoadDll(SearchPath
, &dwFlags
, &DllName
, (PVOID
*)&hInst
);
289 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
291 RtlFreeUnicodeString(&DllName
);
292 if ( !NT_SUCCESS(Status
))
294 SetLastErrorByStatus (Status
);
307 GetProcAddress( HMODULE hModule
, LPCSTR lpProcName
)
309 ANSI_STRING ProcedureName
;
310 FARPROC fnExp
= NULL
;
315 SetLastError(ERROR_PROC_NOT_FOUND
);
319 if (HIWORD(lpProcName
) != 0)
321 RtlInitAnsiString (&ProcedureName
,
323 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
330 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
336 if (!NT_SUCCESS(Status
))
338 SetLastErrorByStatus(Status
);
349 BOOL WINAPI
FreeLibrary(HINSTANCE hLibModule
)
355 SetLastError(ERROR_INVALID_HANDLE
);
359 if ((ULONG_PTR
)hLibModule
& 1)
361 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
362 char *ptr
= (char *)hLibModule
- 1;
363 return UnmapViewOfFile(ptr
);
366 Status
= LdrUnloadDll(hLibModule
);
367 if (!NT_SUCCESS(Status
))
369 SetLastErrorByStatus(Status
);
382 FreeLibraryAndExitThread (
387 FreeLibrary(hLibModule
);
388 ExitThread(dwExitCode
);
403 ANSI_STRING FileName
;
404 PLIST_ENTRY ModuleListHead
;
406 PLDR_DATA_TABLE_ENTRY Module
;
410 Peb
= NtCurrentPeb ();
411 RtlEnterCriticalSection (Peb
->LoaderLock
);
414 hModule
= Peb
->ImageBaseAddress
;
416 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
417 Entry
= ModuleListHead
->Flink
;
419 while (Entry
!= ModuleListHead
)
421 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
422 if (Module
->DllBase
== (PVOID
)hModule
)
424 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
426 FileName
.MaximumLength
= (USHORT
)Length
* sizeof(WCHAR
);
427 FileName
.Buffer
= lpFilename
;
429 /* convert unicode string to ansi (or oem) */
431 RtlUnicodeStringToAnsiString (&FileName
,
432 &Module
->FullDllName
,
435 RtlUnicodeStringToOemString (&FileName
,
436 &Module
->FullDllName
,
440 lpFilename
[Length
] = '\0';
442 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
444 RtlLeaveCriticalSection (Peb
->LoaderLock
);
448 Entry
= Entry
->Flink
;
451 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
452 RtlLeaveCriticalSection (Peb
->LoaderLock
);
469 UNICODE_STRING FileName
;
470 PLIST_ENTRY ModuleListHead
;
472 PLDR_DATA_TABLE_ENTRY Module
;
476 Peb
= NtCurrentPeb ();
477 RtlEnterCriticalSection (Peb
->LoaderLock
);
480 hModule
= Peb
->ImageBaseAddress
;
482 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
483 Entry
= ModuleListHead
->Flink
;
484 while (Entry
!= ModuleListHead
)
486 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
488 if (Module
->DllBase
== (PVOID
)hModule
)
490 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
492 FileName
.MaximumLength
= (USHORT
) Length
* sizeof(WCHAR
);
493 FileName
.Buffer
= lpFilename
;
495 RtlCopyUnicodeString (&FileName
,
496 &Module
->FullDllName
);
498 lpFilename
[Length
] = L
'\0';
500 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
502 RtlLeaveCriticalSection (Peb
->LoaderLock
);
507 Entry
= Entry
->Flink
;
510 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
511 RtlLeaveCriticalSection (Peb
->LoaderLock
);
522 GetModuleHandleA ( LPCSTR lpModuleName
)
524 ANSI_STRING ModuleName
;
526 PTEB pTeb
= NtCurrentTeb();
528 if (lpModuleName
== NULL
)
530 return ((HMODULE
)pTeb
->ProcessEnvironmentBlock
->ImageBaseAddress
);
533 RtlInitAnsiString(&ModuleName
, lpModuleName
);
535 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
539 if (NT_SUCCESS(Status
))
541 return GetModuleHandleW(pTeb
->StaticUnicodeString
.Buffer
);
544 SetLastErrorByStatus(Status
);
554 GetModuleHandleW (LPCWSTR lpModuleName
)
556 UNICODE_STRING ModuleName
;
560 if (lpModuleName
== NULL
)
561 return ((HMODULE
)NtCurrentPeb()->ImageBaseAddress
);
563 RtlInitUnicodeString (&ModuleName
,
564 (LPWSTR
)lpModuleName
);
566 Status
= LdrGetDllHandle (0,
570 if (!NT_SUCCESS(Status
))
572 SetLastErrorByStatus (Status
);
576 return ((HMODULE
)BaseAddress
);
585 GetModuleHandleExW(IN DWORD dwFlags
,
586 IN LPCWSTR lpModuleName OPTIONAL
,
587 OUT HMODULE
* phModule
)
593 if (phModule
== NULL
||
594 ((dwFlags
& (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)) ==
595 (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)))
597 SetLastError(ERROR_INVALID_PARAMETER
);
601 if (lpModuleName
== NULL
)
603 hModule
= NtCurrentPeb()->ImageBaseAddress
;
607 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
609 hModule
= (HMODULE
)RtlPcToFileHeader((PVOID
)lpModuleName
,
613 SetLastErrorByStatus(STATUS_DLL_NOT_FOUND
);
618 hModule
= GetModuleHandleW(lpModuleName
);
624 if (!(dwFlags
& GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
))
626 Status
= LdrAddRefDll((dwFlags
& GET_MODULE_HANDLE_EX_FLAG_PIN
) ? LDR_PIN_MODULE
: 0,
629 if (NT_SUCCESS(Status
))
635 SetLastErrorByStatus(Status
);
652 GetModuleHandleExA(IN DWORD dwFlags
,
653 IN LPCSTR lpModuleName OPTIONAL
,
654 OUT HMODULE
* phModule
)
656 ANSI_STRING ModuleName
;
657 LPCWSTR lpModuleNameW
;
661 PTEB pTeb
= NtCurrentTeb();
663 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
665 lpModuleNameW
= (LPCWSTR
)lpModuleName
;
669 RtlInitAnsiString(&ModuleName
, lpModuleName
);
671 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
675 if (!NT_SUCCESS(Status
))
677 SetLastErrorByStatus(Status
);
681 lpModuleNameW
= pTeb
->StaticUnicodeString
.Buffer
;
684 Ret
= GetModuleHandleExW(dwFlags
,
699 LPVOID lpParameterBlock
702 STARTUPINFOA StartupInfo
;
703 PROCESS_INFORMATION ProcessInformation
;
704 LOADPARMS32
*LoadParams
;
705 char FileName
[MAX_PATH
];
706 char *CommandLine
, *t
;
709 LoadParams
= (LOADPARMS32
*)lpParameterBlock
;
710 if(!lpModuleName
|| !LoadParams
|| (((WORD
*)LoadParams
->lpCmdShow
)[0] != 2))
712 /* windows doesn't check parameters, we do */
713 SetLastError(ERROR_INVALID_PARAMETER
);
717 if(!SearchPathA(NULL
, lpModuleName
, ".exe", MAX_PATH
, FileName
, NULL
) &&
718 !SearchPathA(NULL
, lpModuleName
, NULL
, MAX_PATH
, FileName
, NULL
))
720 return ERROR_FILE_NOT_FOUND
;
723 Length
= (BYTE
)LoadParams
->lpCmdLine
[0];
724 if(!(CommandLine
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
725 strlen(lpModuleName
) + Length
+ 2)))
727 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
731 /* Create command line string */
732 strcpy(CommandLine
, lpModuleName
);
733 t
= CommandLine
+ strlen(CommandLine
);
735 memcpy(t
, LoadParams
->lpCmdLine
+ 1, Length
);
737 /* Build StartupInfo */
738 RtlZeroMemory(&StartupInfo
, sizeof(STARTUPINFOA
));
739 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
740 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
741 StartupInfo
.wShowWindow
= ((WORD
*)LoadParams
->lpCmdShow
)[1];
743 if(!CreateProcessA(FileName
, CommandLine
, NULL
, NULL
, FALSE
, 0, LoadParams
->lpEnvAddress
,
744 NULL
, &StartupInfo
, &ProcessInformation
))
748 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
749 /* return the right value */
750 Error
= GetLastError();
753 case ERROR_BAD_EXE_FORMAT
:
755 return ERROR_BAD_FORMAT
;
757 case ERROR_FILE_NOT_FOUND
:
758 case ERROR_PATH_NOT_FOUND
:
766 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
768 /* Wait up to 15 seconds for the process to become idle */
769 if (NULL
!= lpfnGlobalRegisterWaitForInputIdle
)
771 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
, 15000);
774 NtClose(ProcessInformation
.hThread
);
775 NtClose(ProcessInformation
.hProcess
);