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 (
111 Status
= LdrDisableThreadCalloutsForDll ((PVOID
)hLibModule
);
112 if (!NT_SUCCESS (Status
))
114 SetLastErrorByStatus (Status
);
130 return LoadLibraryExA (lpLibFileName
, 0, 0);
140 LPCSTR lpLibFileName
,
147 if (!(FileNameW
= FilenameA2W(lpLibFileName
, FALSE
)))
150 return LoadLibraryExW(FileNameW
, hFile
, dwFlags
);
160 LPCWSTR lpLibFileName
163 return LoadLibraryExW (lpLibFileName
, 0, 0);
169 LoadLibraryAsDatafile(PWSTR path
, LPCWSTR name
, HMODULE
* hmod
)
171 static const WCHAR dotDLL
[] = {'.','d','l','l',0};
173 WCHAR filenameW
[MAX_PATH
];
174 HANDLE hFile
= INVALID_HANDLE_VALUE
;
180 if (!SearchPathW( path
, name
, dotDLL
, sizeof(filenameW
) / sizeof(filenameW
[0]),
183 return NtCurrentTeb()->LastStatusValue
;
186 hFile
= CreateFileW( filenameW
, GENERIC_READ
, FILE_SHARE_READ
,
187 NULL
, OPEN_EXISTING
, 0, 0 );
189 if (hFile
== INVALID_HANDLE_VALUE
) return NtCurrentTeb()->LastStatusValue
;
191 mapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
192 CloseHandle( hFile
);
193 if (!mapping
) return NtCurrentTeb()->LastStatusValue
;
195 module
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
196 CloseHandle( mapping
);
197 if (!module
) return NtCurrentTeb()->LastStatusValue
;
199 /* make sure it's a valid PE file */
200 if (!RtlImageNtHeader(module
))
202 UnmapViewOfFile( module
);
203 return STATUS_INVALID_IMAGE_FORMAT
;
205 *hmod
= (HMODULE
)((char *)module
+ 1); /* set low bit of handle to indicate datafile module */
206 return STATUS_SUCCESS
;
216 LPCWSTR lpLibFileName
,
221 UNICODE_STRING DllName
;
225 ULONG DllCharacteristics
;
226 BOOL FreeString
= FALSE
;
230 if ( lpLibFileName
== NULL
)
233 /* Check for any flags LdrLoadDll might be interested in */
234 if (dwFlags
& DONT_RESOLVE_DLL_REFERENCES
)
236 /* Tell LDR to treat it as an EXE */
237 DllCharacteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
241 DONT_RESOLVE_DLL_REFERENCES
|
242 LOAD_LIBRARY_AS_DATAFILE
|
243 LOAD_WITH_ALTERED_SEARCH_PATH
;
245 SearchPath
= GetDllLoadPath(
246 dwFlags
& LOAD_WITH_ALTERED_SEARCH_PATH
? lpLibFileName
: NULL
);
248 RtlInitUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
250 if (DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
252 RtlCreateUnicodeString(&DllName
, (LPWSTR
)lpLibFileName
);
253 while (DllName
.Length
> sizeof(WCHAR
) &&
254 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
) - 1] == L
' ')
256 DllName
.Length
-= sizeof(WCHAR
);
258 DllName
.Buffer
[DllName
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
262 if (dwFlags
& LOAD_LIBRARY_AS_DATAFILE
)
264 Status
= LdrGetDllHandle(SearchPath
, NULL
, &DllName
, (PVOID
*)&hInst
);
265 if (!NT_SUCCESS(Status
))
267 /* The method in load_library_as_datafile allows searching for the
268 * 'native' libraries only
270 Status
= LoadLibraryAsDatafile(SearchPath
, DllName
.Buffer
, &hInst
);
278 /* Call the API Properly */
279 Status
= LdrLoadDll(SearchPath
,
286 /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */
287 Status
= LdrLoadDll(SearchPath
, &dwFlags
, &DllName
, (PVOID
*)&hInst
);
291 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
293 RtlFreeUnicodeString(&DllName
);
294 if ( !NT_SUCCESS(Status
))
296 SetLastErrorByStatus (Status
);
309 GetProcAddress( HMODULE hModule
, LPCSTR lpProcName
)
311 ANSI_STRING ProcedureName
;
312 FARPROC fnExp
= NULL
;
315 if (HIWORD(lpProcName
) != 0)
317 RtlInitAnsiString (&ProcedureName
,
319 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
326 Status
= LdrGetProcedureAddress ((PVOID
)hModule
,
332 if (!NT_SUCCESS(Status
))
334 SetLastErrorByStatus(Status
);
345 BOOL WINAPI
FreeLibrary(HINSTANCE hLibModule
)
351 SetLastError(ERROR_INVALID_HANDLE
);
355 if ((ULONG_PTR
)hLibModule
& 1)
357 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
358 char *ptr
= (char *)hLibModule
- 1;
359 UnmapViewOfFile(ptr
);
363 Status
= LdrUnloadDll(hLibModule
);
364 if (!NT_SUCCESS(Status
))
366 SetLastErrorByStatus(Status
);
379 FreeLibraryAndExitThread (
384 FreeLibrary(hLibModule
);
385 ExitThread(dwExitCode
);
400 ANSI_STRING FileName
;
401 PLIST_ENTRY ModuleListHead
;
403 PLDR_DATA_TABLE_ENTRY Module
;
407 Peb
= NtCurrentPeb ();
408 RtlEnterCriticalSection (Peb
->LoaderLock
);
411 hModule
= Peb
->ImageBaseAddress
;
413 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
414 Entry
= ModuleListHead
->Flink
;
416 while (Entry
!= ModuleListHead
)
418 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
419 if (Module
->DllBase
== (PVOID
)hModule
)
421 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
423 FileName
.MaximumLength
= (USHORT
)Length
* sizeof(WCHAR
);
424 FileName
.Buffer
= lpFilename
;
426 /* convert unicode string to ansi (or oem) */
428 RtlUnicodeStringToAnsiString (&FileName
,
429 &Module
->FullDllName
,
432 RtlUnicodeStringToOemString (&FileName
,
433 &Module
->FullDllName
,
437 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
439 lpFilename
[Length
] = '\0';
441 RtlLeaveCriticalSection (Peb
->LoaderLock
);
445 Entry
= Entry
->Flink
;
448 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
449 RtlLeaveCriticalSection (Peb
->LoaderLock
);
466 UNICODE_STRING FileName
;
467 PLIST_ENTRY ModuleListHead
;
469 PLDR_DATA_TABLE_ENTRY Module
;
473 Peb
= NtCurrentPeb ();
474 RtlEnterCriticalSection (Peb
->LoaderLock
);
477 hModule
= Peb
->ImageBaseAddress
;
479 ModuleListHead
= &Peb
->Ldr
->InLoadOrderModuleList
;
480 Entry
= ModuleListHead
->Flink
;
481 while (Entry
!= ModuleListHead
)
483 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
485 if (Module
->DllBase
== (PVOID
)hModule
)
487 Length
= min(nSize
, Module
->FullDllName
.Length
/ sizeof(WCHAR
));
489 FileName
.MaximumLength
= (USHORT
) Length
* sizeof(WCHAR
);
490 FileName
.Buffer
= lpFilename
;
492 RtlCopyUnicodeString (&FileName
,
493 &Module
->FullDllName
);
495 SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL
);
497 lpFilename
[Length
] = L
'\0';
499 RtlLeaveCriticalSection (Peb
->LoaderLock
);
504 Entry
= Entry
->Flink
;
507 SetLastErrorByStatus (STATUS_DLL_NOT_FOUND
);
508 RtlLeaveCriticalSection (Peb
->LoaderLock
);
519 GetModuleHandleA ( LPCSTR lpModuleName
)
521 ANSI_STRING ModuleName
;
523 PTEB pTeb
= NtCurrentTeb();
525 if (lpModuleName
== NULL
)
527 return ((HMODULE
)pTeb
->ProcessEnvironmentBlock
->ImageBaseAddress
);
530 RtlInitAnsiString(&ModuleName
, lpModuleName
);
532 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
536 if (NT_SUCCESS(Status
))
538 return GetModuleHandleW(pTeb
->StaticUnicodeString
.Buffer
);
541 SetLastErrorByStatus(Status
);
551 GetModuleHandleW (LPCWSTR lpModuleName
)
553 UNICODE_STRING ModuleName
;
557 if (lpModuleName
== NULL
)
558 return ((HMODULE
)NtCurrentPeb()->ImageBaseAddress
);
560 RtlInitUnicodeString (&ModuleName
,
561 (LPWSTR
)lpModuleName
);
563 Status
= LdrGetDllHandle (0,
567 if (!NT_SUCCESS(Status
))
569 SetLastErrorByStatus (Status
);
573 return ((HMODULE
)BaseAddress
);
582 GetModuleHandleExW(IN DWORD dwFlags
,
583 IN LPCWSTR lpModuleName OPTIONAL
,
584 OUT HMODULE
* phModule
)
590 if (phModule
== NULL
||
591 ((dwFlags
& (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)) ==
592 (GET_MODULE_HANDLE_EX_FLAG_PIN
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
)))
594 SetLastError(ERROR_INVALID_PARAMETER
);
598 if (lpModuleName
== NULL
)
600 hModule
= NtCurrentPeb()->ImageBaseAddress
;
604 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
606 hModule
= (HMODULE
)RtlPcToFileHeader((PVOID
)lpModuleName
,
610 SetLastErrorByStatus(STATUS_DLL_NOT_FOUND
);
615 hModule
= GetModuleHandleW(lpModuleName
);
621 if (!(dwFlags
& GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
))
623 Status
= LdrAddRefDll((dwFlags
& GET_MODULE_HANDLE_EX_FLAG_PIN
) ? LDR_PIN_MODULE
: 0,
626 if (NT_SUCCESS(Status
))
632 SetLastErrorByStatus(Status
);
649 GetModuleHandleExA(IN DWORD dwFlags
,
650 IN LPCSTR lpModuleName OPTIONAL
,
651 OUT HMODULE
* phModule
)
653 ANSI_STRING ModuleName
;
654 LPCWSTR lpModuleNameW
;
658 PTEB pTeb
= NtCurrentTeb();
660 if (dwFlags
& GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
)
662 lpModuleNameW
= (LPCWSTR
)lpModuleName
;
666 RtlInitAnsiString(&ModuleName
, lpModuleName
);
668 Status
= RtlAnsiStringToUnicodeString(&pTeb
->StaticUnicodeString
,
672 if (!NT_SUCCESS(Status
))
674 SetLastErrorByStatus(Status
);
678 lpModuleNameW
= pTeb
->StaticUnicodeString
.Buffer
;
681 Ret
= GetModuleHandleExW(dwFlags
,
696 LPVOID lpParameterBlock
699 STARTUPINFOA StartupInfo
;
700 PROCESS_INFORMATION ProcessInformation
;
701 LOADPARMS32
*LoadParams
;
702 char FileName
[MAX_PATH
];
703 char *CommandLine
, *t
;
706 LoadParams
= (LOADPARMS32
*)lpParameterBlock
;
707 if(!lpModuleName
|| !LoadParams
|| (((WORD
*)LoadParams
->lpCmdShow
)[0] != 2))
709 /* windows doesn't check parameters, we do */
710 SetLastError(ERROR_INVALID_PARAMETER
);
714 if(!SearchPathA(NULL
, lpModuleName
, ".exe", MAX_PATH
, FileName
, NULL
) &&
715 !SearchPathA(NULL
, lpModuleName
, NULL
, MAX_PATH
, FileName
, NULL
))
717 return ERROR_FILE_NOT_FOUND
;
720 Length
= (BYTE
)LoadParams
->lpCmdLine
[0];
721 if(!(CommandLine
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
722 strlen(lpModuleName
) + Length
+ 2)))
724 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
728 /* Create command line string */
729 strcpy(CommandLine
, lpModuleName
);
730 t
= CommandLine
+ strlen(CommandLine
);
732 memcpy(t
, LoadParams
->lpCmdLine
+ 1, Length
);
734 /* Build StartupInfo */
735 RtlZeroMemory(&StartupInfo
, sizeof(STARTUPINFOA
));
736 StartupInfo
.cb
= sizeof(STARTUPINFOA
);
737 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
738 StartupInfo
.wShowWindow
= ((WORD
*)LoadParams
->lpCmdShow
)[1];
740 if(!CreateProcessA(FileName
, CommandLine
, NULL
, NULL
, FALSE
, 0, LoadParams
->lpEnvAddress
,
741 NULL
, &StartupInfo
, &ProcessInformation
))
745 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
746 /* return the right value */
747 Error
= GetLastError();
750 case ERROR_BAD_EXE_FORMAT
:
752 return ERROR_BAD_FORMAT
;
754 case ERROR_FILE_NOT_FOUND
:
755 case ERROR_PATH_NOT_FOUND
:
763 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine
);
765 /* Wait up to 15 seconds for the process to become idle */
766 if (NULL
!= lpfnGlobalRegisterWaitForInputIdle
)
768 lpfnGlobalRegisterWaitForInputIdle(ProcessInformation
.hProcess
, 15000);
771 NtClose(ProcessInformation
.hThread
);
772 NtClose(ProcessInformation
.hProcess
);