Author: fireball
Date: Wed Apr 6 19:03:20 2011
New Revision: 51270
URL:
http://svn.reactos.org/svn/reactos?rev=51270&view=rev
Log:
[KERNEL32]
- Rewrite most of kernel32 module loading APIs (except for LoadLibraryExW, for testing
purposes it's gonna be committed in a separate commit). Rewritten parts include:
* Better definition of LOADPARMS32 structure for LoadModule, and rewritten LoadModule
which is now a well structured function with proper parameters validation, proper work
algorithm and setting proper last error values in failure cases. Optimization of
allocating MAX_PATH buffer on stack instead of in the heap is saved from the old version
of the function.
* LoadLibraryA, added a path-hack (present at least up to Windows 2003) for twain_32.dll
loading (not that important, but still a compatibility issue).
* Make GetProcAddress() use BasepMapModuleHandle for mapping the passed-in handle
(including properly handling NULL module handle which was incorrectly handled by the old
implementation), and check for a special failure case when LdrGetProcedureAddress returns
pointer to the image base address.
Modified:
trunk/reactos/dll/win32/kernel32/misc/ldr.c
Modified: trunk/reactos/dll/win32/kernel32/misc/ldr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/misc/ld…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/misc/ldr.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/misc/ldr.c [iso-8859-1] Wed Apr 6 19:03:20 2011
@@ -15,7 +15,8 @@
typedef struct tagLOADPARMS32 {
LPSTR lpEnvAddress;
LPSTR lpCmdLine;
- LPSTR lpCmdShow;
+ WORD wMagicValue;
+ WORD wCmdShow;
DWORD dwReserved;
} LOADPARMS32;
@@ -167,12 +168,17 @@
{
NTSTATUS Status;
+ /* Disable thread library calls */
Status = LdrDisableThreadCalloutsForDll((PVOID)hLibModule);
+
+ /* If it wasn't success - set last error and return failure */
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
return FALSE;
}
+
+ /* Return success */
return TRUE;
}
@@ -182,43 +188,74 @@
*/
HINSTANCE
WINAPI
-LoadLibraryA (
- LPCSTR lpLibFileName
- )
-{
- return LoadLibraryExA (lpLibFileName, 0, 0);
-}
-
+LoadLibraryA(LPCSTR lpLibFileName)
+{
+ LPSTR PathBuffer;
+ UINT Len;
+ HINSTANCE Result;
+
+ /* Treat twain_32.dll in a special way (what a surprise...) */
+ if (lpLibFileName && !_strcmpi(lpLibFileName, "twain_32.dll"))
+ {
+ /* Allocate space for the buffer */
+ PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH);
+ if (PathBuffer)
+ {
+ /* Get windows dir in this buffer */
+ Len = GetWindowsDirectoryA(PathBuffer, MAX_PATH - 13); /* 13 is sizeof of
'\\twain_32.dll' */
+ if (Len && Len < (MAX_PATH - 13))
+ {
+ /* We successfully got windows directory. Concatenate twain_32.dll to it
*/
+ strncat(PathBuffer, "\\twain_32.dll", 13);
+
+ /* And recursively call ourselves with a new string */
+ Result = LoadLibraryA(PathBuffer);
+
+ /* If it was successful - free memory and return result */
+ if (Result)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
+ return Result;
+ }
+ }
+
+ /* Free allocated buffer */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
+ }
+ }
+
+ /* Call the Ex version of the API */
+ return LoadLibraryExA(lpLibFileName, 0, 0);
+}
/*
* @implemented
*/
HINSTANCE
WINAPI
-LoadLibraryExA(
- LPCSTR lpLibFileName,
- HANDLE hFile,
- DWORD dwFlags)
-{
- PUNICODE_STRING FileNameW;
-
+LoadLibraryExA(LPCSTR lpLibFileName,
+ HANDLE hFile,
+ DWORD dwFlags)
+{
+ PUNICODE_STRING FileNameW;
+
+ /* Convert file name to unicode */
if (!(FileNameW = Basep8BitStringToStaticUnicodeString(lpLibFileName)))
return NULL;
+ /* And call W version of the API */
return LoadLibraryExW(FileNameW->Buffer, hFile, dwFlags);
}
-
/*
* @implemented
*/
HINSTANCE
WINAPI
-LoadLibraryW (
- LPCWSTR lpLibFileName
- )
-{
- return LoadLibraryExW (lpLibFileName, 0, 0);
+LoadLibraryW(LPCWSTR lpLibFileName)
+{
+ /* Call Ex version of the API */
+ return LoadLibraryExW (lpLibFileName, 0, 0);
}
@@ -364,42 +401,56 @@
*/
FARPROC
WINAPI
-GetProcAddress( HMODULE hModule, LPCSTR lpProcName )
-{
- ANSI_STRING ProcedureName;
- FARPROC fnExp = NULL;
- NTSTATUS Status;
-
- if (!hModule)
- {
- SetLastError(ERROR_PROC_NOT_FOUND);
- return NULL;
- }
-
- if (HIWORD(lpProcName) != 0)
- {
- RtlInitAnsiString (&ProcedureName,
- (LPSTR)lpProcName);
- Status = LdrGetProcedureAddress ((PVOID)hModule,
- &ProcedureName,
- 0,
- (PVOID*)&fnExp);
- }
- else
- {
- Status = LdrGetProcedureAddress ((PVOID)hModule,
- NULL,
- (ULONG)lpProcName,
- (PVOID*)&fnExp);
- }
-
- if (!NT_SUCCESS(Status))
- {
- SetLastErrorByStatus(Status);
- fnExp = NULL;
- }
-
- return fnExp;
+GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
+{
+ ANSI_STRING ProcedureName, *ProcNamePtr = NULL;
+ FARPROC fnExp = NULL;
+ NTSTATUS Status;
+ PVOID hMapped;
+ ULONG Ordinal = 0;
+
+ if (HIWORD(lpProcName) != 0)
+ {
+ /* Look up by name */
+ RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
+ ProcNamePtr = &ProcedureName;
+ }
+ else
+ {
+ /* Look up by ordinal */
+ Ordinal = (ULONG)lpProcName;
+ }
+
+ /* Map provided handle */
+ hMapped = BasepMapModuleHandle(hModule, FALSE);
+
+ /* Get the proc address */
+ Status = LdrGetProcedureAddress(hMapped,
+ ProcNamePtr,
+ Ordinal,
+ (PVOID*)&fnExp);
+
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+ return NULL;
+ }
+
+ /* Check for a special case when returned pointer is
+ the same as iamge's base address */
+ if (fnExp == hMapped)
+ {
+ /* Set correct error code */
+ if (HIWORD(lpProcName) != 0)
+ BaseSetLastNTError(STATUS_ENTRYPOINT_NOT_FOUND);
+ else
+ BaseSetLastNTError(STATUS_ORDINAL_NOT_FOUND);
+
+ return NULL;
+ }
+
+ /* All good, return procedure pointer */
+ return fnExp;
}
@@ -906,87 +957,137 @@
*/
DWORD
WINAPI
-LoadModule (
- LPCSTR lpModuleName,
- LPVOID lpParameterBlock
- )
-{
- STARTUPINFOA StartupInfo;
- PROCESS_INFORMATION ProcessInformation;
- LOADPARMS32 *LoadParams;
- char FileName[MAX_PATH];
- char *CommandLine, *t;
- BYTE Length;
-
- LoadParams = (LOADPARMS32*)lpParameterBlock;
- if(!lpModuleName || !LoadParams || (((WORD*)LoadParams->lpCmdShow)[0] != 2))
- {
- /* windows doesn't check parameters, we do */
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
- }
-
- if(!SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL)
&&
- !SearchPathA(NULL, lpModuleName, NULL, MAX_PATH, FileName, NULL))
- {
- return ERROR_FILE_NOT_FOUND;
- }
-
- Length = (BYTE)LoadParams->lpCmdLine[0];
- if(!(CommandLine = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
- strlen(lpModuleName) + Length + 2)))
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return 0;
- }
-
- /* Create command line string */
- strcpy(CommandLine, lpModuleName);
- t = CommandLine + strlen(CommandLine);
- *(t++) = ' ';
- memcpy(t, LoadParams->lpCmdLine + 1, Length);
-
- /* Build StartupInfo */
- RtlZeroMemory(&StartupInfo, sizeof(STARTUPINFOA));
- StartupInfo.cb = sizeof(STARTUPINFOA);
- StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
- StartupInfo.wShowWindow = ((WORD*)LoadParams->lpCmdShow)[1];
-
- if(!CreateProcessA(FileName, CommandLine, NULL, NULL, FALSE, 0,
LoadParams->lpEnvAddress,
- NULL, &StartupInfo, &ProcessInformation))
- {
- DWORD Error;
-
- RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
- /* return the right value */
- Error = GetLastError();
- switch(Error)
- {
- case ERROR_BAD_EXE_FORMAT:
- {
- return ERROR_BAD_FORMAT;
- }
- case ERROR_FILE_NOT_FOUND:
- case ERROR_PATH_NOT_FOUND:
- {
- return Error;
- }
- }
- return 0;
- }
-
- RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
-
- /* Wait up to 15 seconds for the process to become idle */
- if (NULL != lpfnGlobalRegisterWaitForInputIdle)
- {
- lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess, 15000);
- }
-
- NtClose(ProcessInformation.hThread);
- NtClose(ProcessInformation.hProcess);
-
- return 33;
+LoadModule(LPCSTR lpModuleName,
+ LPVOID lpParameterBlock)
+{
+ STARTUPINFOA StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ LOADPARMS32 *LoadParams;
+ char FileName[MAX_PATH];
+ LPSTR CommandLine;
+ DWORD Length, Error;
+ BOOL ProcessStatus;
+ ANSI_STRING AnsiStr;
+ UNICODE_STRING UnicStr;
+ RTL_PATH_TYPE PathType;
+ HANDLE Handle;
+
+ LoadParams = (LOADPARMS32*)lpParameterBlock;
+
+ /* Check load parameters */
+ if (LoadParams->dwReserved || LoadParams->wMagicValue != 2)
+ {
+ /* Fail with invalid param error */
+ BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+ return 0;
+ }
+
+ /* Search path */
+ Length = SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName,
NULL);
+
+ /* Check if path was found */
+ if (Length && Length < MAX_PATH)
+ {
+ /* Build StartupInfo */
+ RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
+
+ StartupInfo.cb = sizeof(STARTUPINFOA);
+ StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+ StartupInfo.wShowWindow = LoadParams->wCmdShow;
+
+ /* Allocate command line buffer */
+ CommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ULONG)LoadParams->lpCmdLine[0] + Length + 2);
+
+ /* Put module name there, then a space, and then copy provided command line,
+ and null-terminate it */
+ RtlCopyMemory(CommandLine, FileName, Length);
+ CommandLine[Length] = ' ';
+ RtlCopyMemory(&CommandLine[Length + 1], &LoadParams->lpCmdLine[1],
(ULONG)LoadParams->lpCmdLine[0]);
+ CommandLine[Length + 1 + (ULONG)LoadParams->lpCmdLine[0]] = 0;
+
+ /* Create the process */
+ ProcessStatus = CreateProcessA(FileName,
+ CommandLine,
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ LoadParams->lpEnvAddress,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation);
+
+ /* Free the command line buffer */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
+
+ if (!ProcessStatus)
+ {
+ /* Creating process failed, return right error code */
+ Error = GetLastError();
+ switch(Error)
+ {
+ case ERROR_BAD_EXE_FORMAT:
+ return ERROR_BAD_FORMAT;
+
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ return Error;
+ }
+
+ /* Return 0 otherwise */
+ return 0;
+ }
+
+ /* Wait up to 30 seconds for the process to become idle */
+ if (lpfnGlobalRegisterWaitForInputIdle)
+ {
+ lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess, 30000);
+ }
+
+ /* Close handles */
+ NtClose(ProcessInformation.hThread);
+ NtClose(ProcessInformation.hProcess);
+
+ /* Return magic success value (33) */
+ return 33;
+ }
+
+ /* The path was not found, create an ansi string from
+ the module name and convert it to unicode */
+ RtlInitAnsiString(&AnsiStr, lpModuleName);
+ if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicStr,&AnsiStr,TRUE)))
+ return ERROR_FILE_NOT_FOUND;
+
+ /* Determine path type */
+ PathType = RtlDetermineDosPathNameType_U(UnicStr.Buffer);
+
+ /* Free the unicode module name */
+ RtlFreeUnicodeString(&UnicStr);
+
+ /* If it's a relative path, return file not found */
+ if (PathType == RtlPathTypeRelative)
+ return ERROR_FILE_NOT_FOUND;
+
+ /* If not, try to open it */
+ Handle = CreateFile(lpModuleName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (Handle != INVALID_HANDLE_VALUE)
+ {
+ /* Opening file succeeded for some reason, close the handle and return file not
found anyway */
+ CloseHandle(Handle);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+ /* Return last error which CreateFile set during an attempt to open it */
+ return GetLastError();
}
/* EOF */