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
;
313 if (HIWORD(lpProcName
) != 0)
315 RtlInitAnsiString (&ProcedureName
,
317 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
324 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
330 if (!NT_SUCCESS(Status
))
332 SetLastErrorByStatus(Status
);
343 BOOL WINAPI
FreeLibrary(HINSTANCE hLibModule
)
349 SetLastError(ERROR_INVALID_HANDLE
);
353 if ((ULONG_PTR
)hLibModule
& 1)
355 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
356 char *ptr
= (char *)hLibModule
- 1;
357 UnmapViewOfFile(ptr
);
361 Status
= LdrUnloadDll(hLibModule
);
362 if (!NT_SUCCESS(Status
))
364 SetLastErrorByStatus(Status
);
377 FreeLibraryAndExitThread (
382 FreeLibrary(hLibModule
);
383 ExitThread(dwExitCode
);
398 ANSI_STRING FileName
;
399 PLIST_ENTRY ModuleListHead
;
401 PLDR_DATA_TABLE_ENTRY Module
;
405 Peb
= NtCurrentPeb ();
406 RtlEnterCriticalSection (Peb
->LoaderLock
);
409 hModule
= Peb
->ImageBaseAddress
;
411 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
412 Entry
= ModuleListHead
->Flink
;
414 while (Entry
!= ModuleListHead
)
416 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
417 if (Module
->DllBase
== (PVOID
)hModule
)
419 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
421 FileName
.MaximumLength
= (USHORT
)Length
* sizeof(WCHAR
);
422 FileName
.Buffer
= lpFilename
;
424 /* convert unicode string to ansi (or oem) */
426 RtlUnicodeStringToAnsiString (&FileName
,
427 &Module
->FullDllName
,
430 RtlUnicodeStringToOemString (&FileName
,
431 &Module
->FullDllName
,
435 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
437 lpFilename
[Length
] = '\0';
439 RtlLeaveCriticalSection (Peb
->LoaderLock
);
443 Entry
= Entry
->Flink
;
446 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
447 RtlLeaveCriticalSection (Peb
->LoaderLock
);
464 UNICODE_STRING FileName
;
465 PLIST_ENTRY ModuleListHead
;
467 PLDR_DATA_TABLE_ENTRY Module
;
471 Peb
= NtCurrentPeb ();
472 RtlEnterCriticalSection (Peb
->LoaderLock
);
475 hModule
= Peb
->ImageBaseAddress
;
477 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
478 Entry
= ModuleListHead
->Flink
;
479 while (Entry
!= ModuleListHead
)
481 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
483 if (Module
->DllBase
== (PVOID
)hModule
)
485 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
487 FileName
.MaximumLength
= (USHORT
) Length
* sizeof(WCHAR
);
488 FileName
.Buffer
= lpFilename
;
490 RtlCopyUnicodeString (&FileName
,
491 &Module
->FullDllName
);
493 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
495 lpFilename
[Length
] = L
'\0';
497 RtlLeaveCriticalSection (Peb
->LoaderLock
);
502 Entry
= Entry
->Flink
;
505 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
506 RtlLeaveCriticalSection (Peb
->LoaderLock
);
517 GetModuleHandleA ( LPCSTR lpModuleName
)
519 ANSI_STRING ModuleName
;
521 PTEB pTeb
= NtCurrentTeb();
523 if (lpModuleName
== NULL
)
525 return ((HMODULE
)pTeb
->ProcessEnvironmentBlock
->ImageBaseAddress
);
528 RtlInitAnsiString(&ModuleName
, lpModuleName
);
530 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
534 if (NT_SUCCESS(Status
))
536 return GetModuleHandleW(pTeb
->StaticUnicodeString
.Buffer
);
539 SetLastErrorByStatus(Status
);
549 GetModuleHandleW (LPCWSTR lpModuleName
)
551 UNICODE_STRING ModuleName
;
555 if (lpModuleName
== NULL
)
556 return ((HMODULE
)NtCurrentPeb()->ImageBaseAddress
);
558 RtlInitUnicodeString (&ModuleName
,
559 (LPWSTR
)lpModuleName
);
561 Status
= LdrGetDllHandle (0,
565 if (!NT_SUCCESS(Status
))
567 SetLastErrorByStatus (Status
);
571 return ((HMODULE
)BaseAddress
);
580 GetModuleHandleExW(IN DWORD dwFlags
,
581 IN LPCWSTR lpModuleName OPTIONAL
,
582 OUT HMODULE
* phModule
)
588 if (phModule
== NULL
||
589 ((dwFlags
& (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)) ==
590 (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)))
592 SetLastError(ERROR_INVALID_PARAMETER
);
596 if (lpModuleName
== NULL
)
598 hModule
= NtCurrentPeb()->ImageBaseAddress
;
602 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
604 hModule
= (HMODULE
)RtlPcToFileHeader((PVOID
)lpModuleName
,
608 SetLastErrorByStatus(STATUS_DLL_NOT_FOUND
);
613 hModule
= GetModuleHandleW(lpModuleName
);
619 if (!(dwFlags
& GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
))
621 Status
= LdrAddRefDll((dwFlags
& GET_MODULE_HANDLE_EX_FLAG_PIN
) ? LDR_PIN_MODULE
: 0,
624 if (NT_SUCCESS(Status
))
630 SetLastErrorByStatus(Status
);
647 GetModuleHandleExA(IN DWORD dwFlags
,
648 IN LPCSTR lpModuleName OPTIONAL
,
649 OUT HMODULE
* phModule
)
651 ANSI_STRING ModuleName
;
652 LPCWSTR lpModuleNameW
;
656 PTEB pTeb
= NtCurrentTeb();
658 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
660 lpModuleNameW
= (LPCWSTR
)lpModuleName
;
664 RtlInitAnsiString(&ModuleName
, lpModuleName
);
666 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
670 if (!NT_SUCCESS(Status
))
672 SetLastErrorByStatus(Status
);
676 lpModuleNameW
= pTeb
->StaticUnicodeString
.Buffer
;
679 Ret
= GetModuleHandleExW(dwFlags
,
694 LPVOID lpParameterBlock
697 STARTUPINFOA StartupInfo
;
698 PROCESS_INFORMATION ProcessInformation
;
699 LOADPARMS32
*LoadParams
;
700 char FileName
[MAX_PATH
];
701 char *CommandLine
, *t
;
704 LoadParams
= (LOADPARMS32
*)lpParameterBlock
;
705 if(!lpModuleName
|| !LoadParams
|| (((WORD
*)LoadParams
->lpCmdShow
)[0] != 2))
707 /* windows doesn't check parameters, we do */
708 SetLastError(ERROR_INVALID_PARAMETER
);
712 if(!SearchPathA(NULL
, lpModuleName
, ".exe", MAX_PATH
, FileName
, NULL
) &&
713 !SearchPathA(NULL
, lpModuleName
, NULL
, MAX_PATH
, FileName
, NULL
))
715 return ERROR_FILE_NOT_FOUND
;
718 Length
= (BYTE
)LoadParams
->lpCmdLine
[0];
719 if(!(CommandLine
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
720 strlen(lpModuleName
) + Length
+ 2)))
722 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
726 /* Create command line string */
727 strcpy(CommandLine
, lpModuleName
);
728 t
= CommandLine
+ strlen(CommandLine
);
730 memcpy(t
, LoadParams
->lpCmdLine
+ 1, Length
);
732 /* Build StartupInfo */
733 RtlZeroMemory(&StartupInfo
, sizeof(STARTUPINFOA
));
734 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
735 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
736 StartupInfo
.wShowWindow
= ((WORD
*)LoadParams
->lpCmdShow
)[1];
738 if(!CreateProcessA(FileName
, CommandLine
, NULL
, NULL
, FALSE
, 0, LoadParams
->lpEnvAddress
,
739 NULL
, &StartupInfo
, &ProcessInformation
))
743 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
744 /* return the right value */
745 Error
= GetLastError();
748 case ERROR_BAD_EXE_FORMAT
:
750 return ERROR_BAD_FORMAT
;
752 case ERROR_FILE_NOT_FOUND
:
753 case ERROR_PATH_NOT_FOUND
:
761 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
763 /* Wait up to 15 seconds for the process to become idle */
764 if (NULL
!= lpfnGlobalRegisterWaitForInputIdle
)
766 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
, 15000);
769 NtClose(ProcessInformation
.hThread
);
770 NtClose(ProcessInformation
.hProcess
);