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/ldr... ============================================================================== --- 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 */