[CMAKE]
[reactos.git] / dll / win32 / kernel32 / misc / ldr.c
index 9e32478..b383f1d 100644 (file)
@@ -1,10 +1,9 @@
-/* $Id$
- *
+/*
  * COPYRIGHT: See COPYING in the top level directory
- * PROJECT  : ReactOS user mode libraries
+ * PROJECT  : ReactOS system libraries
  * MODULE   : kernel32.dll
- * FILE     : reactos/lib/kernel32/misc/ldr.c
- * AUTHOR   : Ariadne
+ * FILE     : reactos/dll/win32/kernel32/misc/ldr.c
+ * AUTHOR   : Aleksey Bragin <aleksey@reactos.org>
  */
 
 #include <k32.h>
 typedef struct tagLOADPARMS32 {
   LPSTR lpEnvAddress;
   LPSTR lpCmdLine;
-  LPSTR lpCmdShow;
+  WORD  wMagicValue;
+  WORD  wCmdShow;
   DWORD dwReserved;
 } LOADPARMS32;
 
 extern BOOLEAN InWindows;
 extern WaitForInputIdleType lpfnGlobalRegisterWaitForInputIdle;
 
+#define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR    1
+#define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS  2
+#define BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE 3
+
+VOID
+NTAPI
+BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry,
+                       IN PVOID Context,
+                       OUT BOOLEAN *StopEnumeration);
+
 /* FUNCTIONS ****************************************************************/
 
+DWORD
+WINAPI
+BasepGetModuleHandleExParameterValidation(DWORD dwFlags,
+                                          LPCWSTR lpwModuleName,
+                                          HMODULE *phModule)
+{
+    /* Set phModule to 0 if it's not a NULL pointer */
+    if (phModule) *phModule = 0;
+
+    /* Check for invalid flags combination */
+    if (dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN |
+                    GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+                    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) ||
+        ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) &&
+         (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) ||
+         (!lpwModuleName && (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
+        )
+    {
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
+        return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR;
+    }
+
+    /* Check 2nd parameter */
+    if (!phModule)
+    {
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER_2);
+        return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR;
+    }
+
+    /* Return what we have according to the module name */
+    if (lpwModuleName)
+    {
+        return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE;
+    }
+
+    /* No name given, so put ImageBaseAddress there */
+    *phModule = (HMODULE)NtCurrentPeb()->ImageBaseAddress;
+
+    return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS;
+}
+
+PVOID
+WINAPI
+BasepMapModuleHandle(HMODULE hModule, BOOLEAN AsDataFile)
+{
+    /* If no handle is provided - use current image base address */
+    if (!hModule) return NtCurrentPeb()->ImageBaseAddress;
+
+    /* Check if it's a normal or a datafile one */
+    if (LDR_IS_DATAFILE(hModule) && !AsDataFile)
+        return NULL;
+
+    /* It'a a normal DLL, just return its handle */
+    return hModule;
+}
+
 /**
  * @name GetDllLoadPath
  *
@@ -41,6 +107,8 @@ GetDllLoadPath(LPCWSTR lpModule)
        UNICODE_STRING ModuleName;
        DWORD LastError = GetLastError(); /* GetEnvironmentVariable changes LastError */
 
+    // FIXME: This function is used only by SearchPathW, and is deprecated and will be deleted ASAP.
+
        if ((lpModule != NULL) && (wcslen(lpModule) > 2) && (lpModule[1] == ':'))
        {
                lpModuleEnd = lpModule + wcslen(lpModule);
@@ -102,19 +170,23 @@ GetDllLoadPath(LPCWSTR lpModule)
  */
 BOOL
 WINAPI
-DisableThreadLibraryCalls (
-       HMODULE hLibModule
-       )
+DisableThreadLibraryCalls(
+    IN HMODULE hLibModule)
 {
-       NTSTATUS Status;
+    NTSTATUS Status;
 
-       Status = LdrDisableThreadCalloutsForDll ((PVOID)hLibModule);
-       if (!NT_SUCCESS (Status))
-       {
-               SetLastErrorByStatus (Status);
-               return FALSE;
-       }
-       return TRUE;
+    /* 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;
 }
 
 
@@ -123,112 +195,188 @@ DisableThreadLibraryCalls (
  */
 HINSTANCE
 WINAPI
-LoadLibraryA (
-       LPCSTR  lpLibFileName
-       )
+LoadLibraryA(LPCSTR lpLibFileName)
 {
-       return LoadLibraryExA (lpLibFileName, 0, 0);
-}
+    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
-       )
+LoadLibraryExA(LPCSTR lpLibFileName,
+               HANDLE hFile,
+               DWORD dwFlags)
 {
-   PWCHAR FileNameW;
+    PUNICODE_STRING FileNameW;
 
-   if (!(FileNameW = FilenameA2W(lpLibFileName, FALSE)))
-      return FALSE;
+    /* Convert file name to unicode */
+    if (!(FileNameW = Basep8BitStringToStaticUnicodeString(lpLibFileName)))
+        return NULL;
 
-   return LoadLibraryExW(FileNameW, hFile, dwFlags);
+    /* And call W version of the API */
+    return LoadLibraryExW(FileNameW->Buffer, hFile, dwFlags);
 }
 
-
 /*
  * @implemented
  */
 HINSTANCE
 WINAPI
-LoadLibraryW (
-       LPCWSTR lpLibFileName
-       )
+LoadLibraryW(LPCWSTR lpLibFileName)
 {
-       return LoadLibraryExW (lpLibFileName, 0, 0);
+    /* Call Ex version of the API */
+    return LoadLibraryExW (lpLibFileName, 0, 0);
 }
 
 
 static
 NTSTATUS
-LoadLibraryAsDatafile(PWSTR path, LPCWSTR name, HMODULE* hmod)
+BasepLoadLibraryAsDatafile(PWSTR Path, LPCWSTR Name, HMODULE *hModule)
 {
-    static const WCHAR dotDLL[] = {'.','d','l','l',0};
-
-    WCHAR filenameW[MAX_PATH];
+    WCHAR FilenameW[MAX_PATH];
     HANDLE hFile = INVALID_HANDLE_VALUE;
-    HANDLE mapping;
-    HMODULE module;
-
-    *hmod = 0;
-
-    if (!SearchPathW( path, name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
-                     filenameW, NULL ))
+    HANDLE hMapping;
+    NTSTATUS Status;
+    PVOID lpBaseAddress = NULL;
+    SIZE_T ViewSize = 0;
+    //PUNICODE_STRING OriginalName;
+    //UNICODE_STRING dotDLL = RTL_CONSTANT_STRING(L".DLL");
+
+    /* Zero out handle value */
+    *hModule = 0;
+
+    DPRINT("BasepLoadLibraryAsDatafile(%S %S %p)\n", Path, Name, hModule);
+
+    /*Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
+                                                      Name,
+                                                      &dotDLL,
+                                                      RedirName,
+                                                      RedirName2,
+                                                      &OriginalName2,
+                                                      NULL,
+                                                      NULL,
+                                                      NULL);*/
+
+    /* Try to search for it */
+    if (!SearchPathW(Path,
+                     Name,
+                     L".DLL",
+                     sizeof(FilenameW) / sizeof(FilenameW[0]),
+                     FilenameW,
+                     NULL))
     {
+        /* Return last status value directly */
         return NtCurrentTeb()->LastStatusValue;
     }
 
-    hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
-                         NULL, OPEN_EXISTING, 0, 0 );
+    /* Open this file we found */
+    hFile = CreateFileW(FilenameW,
+                        GENERIC_READ,
+                        FILE_SHARE_READ | FILE_SHARE_DELETE,
+                        NULL,
+                        OPEN_EXISTING,
+                        0,
+                        0);
 
+    /* If opening failed - return last status value */
     if (hFile == INVALID_HANDLE_VALUE) return NtCurrentTeb()->LastStatusValue;
 
-    mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
-    CloseHandle( hFile );
-    if (!mapping) return NtCurrentTeb()->LastStatusValue;
+    /* Create file mapping */
+    hMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+
+    /* Close the file handle */
+    CloseHandle(hFile);
+
+    /* If creating file mapping failed - return last status value */
+    if (!hMapping) return NtCurrentTeb()->LastStatusValue;
 
-    module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
-    CloseHandle( mapping );
-    if (!module) return NtCurrentTeb()->LastStatusValue;
+    /* Map view of section */
+    Status = NtMapViewOfSection(hMapping,
+                                NtCurrentProcess(),
+                                &lpBaseAddress,
+                                0,
+                                0,
+                                0,
+                                &ViewSize,
+                                ViewShare,
+                                0,
+                                PAGE_READONLY);
 
-    /* make sure it's a valid PE file */
-    if (!RtlImageNtHeader(module))
+    /* Close handle to the section */
+    CloseHandle(hMapping);
+
+    /* If mapping view of section failed - return last status value */
+    if (!NT_SUCCESS(Status)) return NtCurrentTeb()->LastStatusValue;
+
+    /* Make sure it's a valid PE file */
+    if (!RtlImageNtHeader(lpBaseAddress))
     {
-        UnmapViewOfFile( module );
+        /* Unmap the view and return failure status */
+        UnmapViewOfFile(lpBaseAddress);
         return STATUS_INVALID_IMAGE_FORMAT;
     }
-    *hmod = (HMODULE)((char *)module + 1);  /* set low bit of handle to indicate datafile module */
+
+    /* Set low bit of handle to indicate datafile module */
+    *hModule = (HMODULE)((ULONG_PTR)lpBaseAddress | 1);
+
+    /* Load alternate resource module */
+    //LdrLoadAlternateResourceModule(*hModule, FilenameW);
+
     return STATUS_SUCCESS;
 }
 
-
 /*
  * @implemented
  */
 HINSTANCE
 WINAPI
-LoadLibraryExW (
-       LPCWSTR lpLibFileName,
-       HANDLE  hFile,
-       DWORD   dwFlags
-       )
+LoadLibraryExW(LPCWSTR lpLibFileName,
+               HANDLE hFile,
+               DWORD dwFlags)
 {
-       UNICODE_STRING DllName;
-       HINSTANCE hInst;
-       NTSTATUS Status;
-       PWSTR SearchPath;
-    ULONG DllCharacteristics;
-       BOOL FreeString = FALSE;
-
-        (void)hFile;
-
-       if ( lpLibFileName == NULL )
-               return NULL;
+    UNICODE_STRING DllName;
+    HINSTANCE hInst;
+    NTSTATUS Status;
+    PWSTR SearchPath;
+    ULONG DllCharacteristics = 0;
+    BOOL FreeString = FALSE;
 
     /* Check for any flags LdrLoadDll might be interested in */
     if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
@@ -237,67 +385,101 @@ LoadLibraryExW (
         DllCharacteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
     }
 
-       dwFlags &=
-         DONT_RESOLVE_DLL_REFERENCES |
-         LOAD_LIBRARY_AS_DATAFILE |
-         LOAD_WITH_ALTERED_SEARCH_PATH;
-
-       SearchPath = GetDllLoadPath(
-         dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH ? lpLibFileName : NULL);
+    /* Build up a unicode dll name from null-terminated string */
+    RtlInitUnicodeString(&DllName, (LPWSTR)lpLibFileName);
 
-       RtlInitUnicodeString(&DllName, (LPWSTR)lpLibFileName);
+    /* Lazy-initialize BasepExeLdrEntry */
+    if (!BasepExeLdrEntry)
+        LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry, NtCurrentPeb()->ImageBaseAddress);
 
-       if (DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
-       {
-               RtlCreateUnicodeString(&DllName, (LPWSTR)lpLibFileName);
-               while (DllName.Length > sizeof(WCHAR) &&
-                               DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
-               {
-                       DllName.Length -= sizeof(WCHAR);
-               }
-               DllName.Buffer[DllName.Length/sizeof(WCHAR)] = UNICODE_NULL;
-               FreeString = TRUE;
-       }
+    /* Check if that module is our exe*/
+    if (BasepExeLdrEntry && !(dwFlags & LOAD_LIBRARY_AS_DATAFILE) &&
+        DllName.Length == BasepExeLdrEntry->FullDllName.Length)
+    {
+        /* Lengths match and it's not a datafile, so perform name comparison */
+        if (RtlEqualUnicodeString(&DllName, &BasepExeLdrEntry->FullDllName, TRUE))
+        {
+            /* That's us! */
+            return BasepExeLdrEntry->DllBase;
+        }
+    }
 
-    if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
+    /* Check for trailing spaces and remove them if necessary */
+    if (DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
     {
-        Status = LdrGetDllHandle(SearchPath, NULL, &DllName, (PVOID*)&hInst);
-        if (!NT_SUCCESS(Status))
+        RtlCreateUnicodeString(&DllName, (LPWSTR)lpLibFileName);
+        while (DllName.Length > sizeof(WCHAR) &&
+            DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
         {
-            /* The method in load_library_as_datafile allows searching for the
-             * 'native' libraries only
-             */
-            Status = LoadLibraryAsDatafile(SearchPath, DllName.Buffer, &hInst);
-            goto done;
+            DllName.Length -= sizeof(WCHAR);
         }
+        DllName.Buffer[DllName.Length/sizeof(WCHAR)] = UNICODE_NULL;
+        FreeString = TRUE;
     }
 
-    /* HACK!!! FIXME */
-    if (InWindows)
+    /* Compute the load path */
+    SearchPath = BasepGetDllPath((dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) ? (LPWSTR)lpLibFileName : NULL,
+                                 NULL);
+
+    if (!SearchPath)
     {
-        /* Call the API Properly */
-        Status = LdrLoadDll(SearchPath,
-                            &DllCharacteristics,
-                            &DllName,
-                            (PVOID*)&hInst);
+        /* Getting DLL path failed, so set last error, free mem and return */
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        if (FreeString) RtlFreeUnicodeString(&DllName);
+        return NULL;
     }
-    else
+
+    _SEH2_TRY
     {
-        /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */
-        Status = LdrLoadDll(SearchPath, &dwFlags, &DllName, (PVOID*)&hInst);
+        if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
+        {
+            /* If the image is loaded as a datafile, try to get its handle */
+            Status = LdrGetDllHandle(SearchPath, NULL, &DllName, (PVOID*)&hInst);
+            if (!NT_SUCCESS(Status))
+            {
+                /* It's not loaded yet - so load it up */
+                Status = BasepLoadLibraryAsDatafile(SearchPath, DllName.Buffer, &hInst);
+                _SEH2_YIELD(goto done;)
+            }
+        }
+
+        /* HACK!!! FIXME */
+        if (InWindows)
+        {
+            /* Call the API Properly */
+            Status = LdrLoadDll(SearchPath,
+                                &DllCharacteristics,
+                                &DllName,
+                                (PVOID*)&hInst);
+        }
+        else
+        {
+            /* Call the ROS API. NOTE: Don't fix this, I have a patch to merge later. */
+            Status = LdrLoadDll(SearchPath, &dwFlags, &DllName, (PVOID*)&hInst);
+        }
     }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    } _SEH2_END
+
 
 done:
-       RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
-       if (FreeString)
-               RtlFreeUnicodeString(&DllName);
-       if ( !NT_SUCCESS(Status))
-       {
-               SetLastErrorByStatus (Status);
-               return NULL;
-       }
+    /* Free SearchPath buffer */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
+
+    /* Free DllName string if it was dynamically allocated */
+    if (FreeString) RtlFreeUnicodeString(&DllName);
+
+    /* Set last error in failure case */
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return NULL;
+    }
 
-       return hInst;
+    /* Return loaded module handle */
+    return hInst;
 }
 
 
@@ -306,36 +488,56 @@ done:
  */
 FARPROC
 WINAPI
-GetProcAddress( HMODULE hModule, LPCSTR lpProcName )
+GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
 {
-       ANSI_STRING ProcedureName;
-       FARPROC fnExp = NULL;
-       NTSTATUS Status;
+    ANSI_STRING ProcedureName, *ProcNamePtr = NULL;
+    FARPROC fnExp = NULL;
+    NTSTATUS Status;
+    PVOID hMapped;
+    ULONG Ordinal = 0;
 
-       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 (HIWORD(lpProcName) != 0)
+    {
+        /* Look up by name */
+        RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
+        ProcNamePtr = &ProcedureName;
+    }
+    else
+    {
+        /* Look up by ordinal */
+        Ordinal = (ULONG)lpProcName;
+    }
 
-       if (!NT_SUCCESS(Status))
-       {
-               SetLastErrorByStatus(Status);
-               fnExp = NULL;
-       }
+    /* Map provided handle */
+    hMapped = BasepMapModuleHandle(hModule, FALSE);
 
-       return fnExp;
+    /* 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;
 }
 
 
@@ -345,28 +547,49 @@ GetProcAddress( HMODULE hModule, LPCSTR lpProcName )
 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
 {
     NTSTATUS Status;
+    PIMAGE_NT_HEADERS NtHeaders;
 
-    if (!hLibModule)
+    if (LDR_IS_DATAFILE(hLibModule))
     {
-        SetLastError(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
+        // FIXME: This SEH should go inside RtlImageNtHeader instead
+        _SEH2_TRY
+        {
+            /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
+            NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            NtHeaders = NULL;
+        } _SEH2_END
 
-    if ((ULONG_PTR)hLibModule & 1)
+        if (NtHeaders)
+        {
+            /* Unmap view */
+            Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
+
+            /* Unload alternate resource module */
+            LdrUnloadAlternateResourceModule(hLibModule);
+        }
+        else
+            Status = STATUS_INVALID_IMAGE_FORMAT;
+    }
+    else
     {
-        /* this is a LOAD_LIBRARY_AS_DATAFILE module */
-        char *ptr = (char *)hLibModule - 1;
-        UnmapViewOfFile(ptr);
-        return TRUE;
+        /* Just unload it */
+        Status = LdrUnloadDll((PVOID)hLibModule);
     }
 
-    Status = LdrUnloadDll(hLibModule);
+    /* Check what kind of status we got */
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        /* Set last error */
+        BaseSetLastNTError(Status);
+
+        /* Return failure */
         return FALSE;
     }
 
+    /* Return success */
     return TRUE;
 }
 
@@ -376,12 +599,30 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
  */
 VOID
 WINAPI
-FreeLibraryAndExitThread (
-       HMODULE hLibModule,
-       DWORD   dwExitCode
-       )
+FreeLibraryAndExitThread(HMODULE hLibModule,
+                         DWORD dwExitCode)
 {
-    FreeLibrary(hLibModule);
+    NTSTATUS Status;
+
+    if (LDR_IS_DATAFILE(hLibModule))
+    {
+        /* This is a LOAD_LIBRARY_AS_DATAFILE module */
+        if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)))
+        {
+            /* Unmap view */
+            Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
+
+            /* Unload alternate resource module */
+            LdrUnloadAlternateResourceModule(hLibModule);
+        }
+    }
+    else
+    {
+        /* Just unload it */
+        Status = LdrUnloadDll((PVOID)hLibModule);
+    }
+
+    /* Exit thread */
     ExitThread(dwExitCode);
 }
 
@@ -391,155 +632,292 @@ FreeLibraryAndExitThread (
  */
 DWORD
 WINAPI
-GetModuleFileNameA (
-       HINSTANCE       hModule,
-       LPSTR           lpFilename,
-       DWORD           nSize
-       )
+GetModuleFileNameA(HINSTANCE hModule,
+                   LPSTR lpFilename,
+                   DWORD nSize)
 {
-       ANSI_STRING FileName;
-       PLIST_ENTRY ModuleListHead;
-       PLIST_ENTRY Entry;
-       PLDR_DATA_TABLE_ENTRY Module;
-       PPEB Peb;
-       ULONG Length = 0;
+    UNICODE_STRING FilenameW;
+    ANSI_STRING FilenameA;
+    NTSTATUS Status;
+    DWORD Length = 0, LengthToCopy;
 
-       Peb = NtCurrentPeb ();
-       RtlEnterCriticalSection (Peb->LoaderLock);
+    /* Allocate a unicode buffer */
+    FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR));
+    if (!FilenameW.Buffer)
+    {
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        return 0;
+    }
 
-       if (hModule == NULL)
-               hModule = Peb->ImageBaseAddress;
+    /* Call unicode API */
+    FilenameW.Length = GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR);
+    FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR);
 
-       ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
-       Entry = ModuleListHead->Flink;
+    if (FilenameW.Length)
+    {
+        /* Convert to ansi string */
+        Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Set last error, free string and retun failure */
+            BaseSetLastNTError(Status);
+            RtlFreeUnicodeString(&FilenameW);
+            return 0;
+        }
 
-       while (Entry != ModuleListHead)
-       {
-               Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
-               if (Module->DllBase == (PVOID)hModule)
-               {
-                       Length = min(nSize, Module->FullDllName.Length / sizeof(WCHAR));
-                       FileName.Length = 0;
-                       FileName.MaximumLength = (USHORT)Length * sizeof(WCHAR);
-                       FileName.Buffer = lpFilename;
-
-                       /* convert unicode string to ansi (or oem) */
-                       if (bIsFileApiAnsi)
-                               RtlUnicodeStringToAnsiString (&FileName,
-                                                             &Module->FullDllName,
-                                                             FALSE);
-                       else
-                               RtlUnicodeStringToOemString (&FileName,
-                                                            &Module->FullDllName,
-                                                            FALSE);
-                               
-                       if (nSize < Length)
-                               SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL);
-                       else
-                               lpFilename[Length] = '\0';
-
-                       RtlLeaveCriticalSection (Peb->LoaderLock);
-                       return Length;
-               }
+        /* Calculate size to copy */
+        Length = min(nSize, FilenameA.Length);
 
-               Entry = Entry->Flink;
-       }
+        /* Include terminating zero */
+        if (nSize > Length)
+            LengthToCopy = Length + 1;
+        else
+            LengthToCopy = nSize;
 
-       SetLastErrorByStatus (STATUS_DLL_NOT_FOUND);
-       RtlLeaveCriticalSection (Peb->LoaderLock);
+        /* Now copy back to the caller amount he asked */
+        RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy);
 
-       return 0;
-}
+        /* Free ansi filename */
+        RtlFreeAnsiString(&FilenameA);
+    }
+
+    /* Free unicode filename */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer);
 
+    /* Return length copied */
+    return Length;
+}
 
 /*
  * @implemented
  */
 DWORD
 WINAPI
-GetModuleFileNameW (
-       HINSTANCE       hModule,
-       LPWSTR          lpFilename,
-       DWORD           nSize
-       )
+GetModuleFileNameW(HINSTANCE hModule,
+                   LPWSTR lpFilename,
+                   DWORD nSize)
 {
-       UNICODE_STRING FileName;
-       PLIST_ENTRY ModuleListHead;
-       PLIST_ENTRY Entry;
-       PLDR_DATA_TABLE_ENTRY Module;
-       PPEB Peb;
-       ULONG Length = 0;
-
-       Peb = NtCurrentPeb ();
-       RtlEnterCriticalSection (Peb->LoaderLock);
-
-       if (hModule == NULL)
-               hModule = Peb->ImageBaseAddress;
-
-       ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
-       Entry = ModuleListHead->Flink;
-       while (Entry != ModuleListHead)
-       {
-               Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+    PLIST_ENTRY ModuleListHead, Entry;
+    PLDR_DATA_TABLE_ENTRY Module;
+    ULONG Length = 0;
+    ULONG Cookie;
+    PPEB Peb;
 
-               if (Module->DllBase == (PVOID)hModule)
-               {
-                       Length = min(nSize, Module->FullDllName.Length / sizeof(WCHAR));
-                       FileName.Length = 0;
-                       FileName.MaximumLength = (USHORT) Length * sizeof(WCHAR);
-                       FileName.Buffer = lpFilename;
+    hModule = BasepMapModuleHandle(hModule, FALSE);
 
-                       RtlCopyUnicodeString (&FileName,
-                                             &Module->FullDllName);
-                       if (nSize < Length)
-                               SetLastErrorByStatus (STATUS_BUFFER_TOO_SMALL);
-                       else
-                               lpFilename[Length] = L'\0';
+    /* Upscale nSize from chars to bytes */
+    nSize *= sizeof(WCHAR);
 
-                       RtlLeaveCriticalSection (Peb->LoaderLock);
+    _SEH2_TRY
+    {
+        /* We don't use per-thread cur dir now */
+        //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
 
-                       return Length;
-               }
+        Peb = NtCurrentPeb ();
 
-               Entry = Entry->Flink;
-       }
+        /* Acquire a loader lock */
+        LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
+
+        /* Traverse the module list */
+        ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
+        Entry = ModuleListHead->Flink;
+        while (Entry != ModuleListHead)
+        {
+            Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+
+            /* Check if this is the requested module */
+            if (Module->DllBase == (PVOID)hModule)
+            {
+                /* Calculate size to copy */
+                Length = min(nSize, Module->FullDllName.MaximumLength);
 
-       SetLastErrorByStatus (STATUS_DLL_NOT_FOUND);
-       RtlLeaveCriticalSection (Peb->LoaderLock);
+                /* Copy contents */
+                RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length);
 
-       return 0;
+                /* Subtract a terminating zero */
+                if (Length == Module->FullDllName.MaximumLength)
+                    Length -= sizeof(WCHAR);
+
+                /* Break out of the loop */
+                break;
+            }
+
+            /* Advance to the next entry */
+            Entry = Entry->Flink;
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        BaseSetLastNTError(_SEH2_GetExceptionCode());
+        Length = 0;
+    } _SEH2_END
+
+    /* Release the loader lock */
+    LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+
+    return Length / sizeof(WCHAR);
 }
 
+HMODULE
+WINAPI
+GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)
+{
+    NTSTATUS Status;
+    PVOID Module;
+    LPWSTR DllPath;
+
+    /* Try to get a handle with a magic value of 1 for DllPath */
+    Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module);
+
+    /* If that succeeded - we're done */
+    if (NT_SUCCESS(Status)) return Module;
+
+    /* If not, then the path should be computed */
+    DllPath = BasepGetDllPath(NULL, 0);
+
+    /* Call LdrGetHandle() again providing the computed DllPath
+       and wrapped into SEH */
+    _SEH2_TRY
+    {
+        Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* Fail with the SEH error */
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    /* Free the DllPath */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
+
+    /* In case of error set last win32 error and return NULL */
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status);
+        SetLastErrorByStatus(Status);
+        Module = 0;
+    }
+
+    /* Return module */
+    return (HMODULE)Module;
+}
+
+BOOLEAN
+WINAPI
+BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule)
+{
+    DWORD Cookie;
+    NTSTATUS Status = STATUS_SUCCESS, Status2;
+    HANDLE hModule = 0;
+    UNICODE_STRING ModuleNameU;
+    DWORD dwValid;
+    BOOLEAN Redirected = FALSE; // FIXME
+
+    /* Validate parameters */
+    dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule);
+    ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE);
+
+    /* Acquire lock if necessary */
+    if (!NoLock)
+    {
+        Status = LdrLockLoaderLock(0, NULL, &Cookie);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Fail */
+            SetLastErrorByStatus(Status);
+            if (phModule) *phModule = 0;
+            return Status;
+        }
+    }
+
+    if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
+    {
+        /* Create a unicode string out of module name */
+        RtlInitUnicodeString(&ModuleNameU, lpwModuleName);
+
+        // FIXME: Do some redirected DLL stuff?
+        if (Redirected)
+        {
+            UNIMPLEMENTED;
+        }
+
+        if (!hModule)
+        {
+            hModule = GetModuleHandleForUnicodeString(&ModuleNameU);
+            if (!hModule)
+            {
+                /* Last error is already set, so just return failure by setting status */
+                Status = STATUS_DLL_NOT_FOUND;
+                goto quickie;
+            }
+        }
+    }
+    else
+    {
+        /* Perform Pc to file header to get module instance */
+        hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName,
+                                             (PVOID*)&hModule);
+
+        /* Check if it succeeded */
+        if (!hModule)
+        {
+            /* Set "dll not found" status and quit */
+            Status = STATUS_DLL_NOT_FOUND;
+            goto quickie;
+        }
+    }
+
+    /* Check if changing reference is not forbidden */
+    if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
+    {
+        /* Add reference to this DLL */
+        Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_PIN_MODULE : 0,
+                              hModule);
+    }
+
+    /* Set last error in case of failure */
+    if (!NT_SUCCESS(Status))
+        SetLastErrorByStatus(Status);
+
+quickie:
+    /* Unlock loader lock if it was acquired */
+    if (!NoLock)
+    {
+        Status2 = LdrUnlockLoaderLock(0, Cookie);
+        ASSERT(NT_SUCCESS(Status2));
+    }
+
+    /* Set the module handle to the caller */
+    if (phModule) *phModule = hModule;
+
+    /* Return TRUE on success and FALSE otherwise */
+    return NT_SUCCESS(Status);
+}
 
 /*
  * @implemented
  */
 HMODULE
 WINAPI
-GetModuleHandleA ( LPCSTR lpModuleName )
+GetModuleHandleA(LPCSTR lpModuleName)
 {
-       ANSI_STRING ModuleName;
-       NTSTATUS Status;
-       PTEB pTeb = NtCurrentTeb();
-
-       if (lpModuleName == NULL)
-       {
-               return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
-       }
+    PUNICODE_STRING ModuleNameW;
+    PTEB pTeb = NtCurrentTeb();
 
-       RtlInitAnsiString(&ModuleName, lpModuleName);
+    /* Check if we have no name to convert */
+    if (!lpModuleName)
+        return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
 
-       Status = RtlAnsiStringToUnicodeString(&pTeb->StaticUnicodeString,
-                                             &ModuleName,
-                                             FALSE);
+    /* Convert module name to unicode */
+    ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
 
-       if (NT_SUCCESS(Status))
-       {
-               return GetModuleHandleW(pTeb->StaticUnicodeString.Buffer);
-       }
+    /* Call W version if conversion was successful */
+    if (ModuleNameW)
+        return GetModuleHandleW(ModuleNameW->Buffer);
 
-       SetLastErrorByStatus(Status);
-       return FALSE;
+    /* Return failure */
+    return 0;
 }
 
 
@@ -548,29 +926,26 @@ GetModuleHandleA ( LPCSTR lpModuleName )
  */
 HMODULE
 WINAPI
-GetModuleHandleW (LPCWSTR lpModuleName)
+GetModuleHandleW(LPCWSTR lpModuleName)
 {
-       UNICODE_STRING ModuleName;
-       PVOID BaseAddress;
-       NTSTATUS Status;
+    HMODULE hModule;
+    NTSTATUS Status;
 
-       if (lpModuleName == NULL)
-               return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
+    /* If current module is requested - return it right away */
+    if (!lpModuleName)
+        return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
 
-       RtlInitUnicodeString (&ModuleName,
-                             (LPWSTR)lpModuleName);
+    /* Use common helper routine */
+    Status = BasepGetModuleHandleExW(TRUE,
+                                     GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                                     lpModuleName,
+                                     &hModule);
 
-       Status = LdrGetDllHandle (0,
-                                 0,
-                                 &ModuleName,
-                                 &BaseAddress);
-       if (!NT_SUCCESS(Status))
-       {
-               SetLastErrorByStatus (Status);
-               return NULL;
-       }
+    /* If it wasn't successful - return 0 */
+    if (!NT_SUCCESS(Status)) hModule = 0;
 
-       return ((HMODULE)BaseAddress);
+    /* Return the handle */
+    return hModule;
 }
 
 
@@ -580,64 +955,31 @@ GetModuleHandleW (LPCWSTR lpModuleName)
 BOOL
 WINAPI
 GetModuleHandleExW(IN DWORD dwFlags,
-                   IN LPCWSTR lpModuleName  OPTIONAL,
+                   IN LPCWSTR lpwModuleName  OPTIONAL,
                    OUT HMODULE* phModule)
 {
-    HMODULE hModule;
     NTSTATUS Status;
+    DWORD dwValid;
     BOOL Ret = FALSE;
 
-    if (phModule == NULL ||
-        ((dwFlags & (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) ==
-         (GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)))
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
+    /* Validate parameters */
+    dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule);
 
-    if (lpModuleName == NULL)
-    {
-        hModule = NtCurrentPeb()->ImageBaseAddress;
-    }
-    else
-    {
-        if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
-        {
-            hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpModuleName,
-                                                 (PVOID*)&hModule);
-            if (hModule == NULL)
-            {
-                SetLastErrorByStatus(STATUS_DLL_NOT_FOUND);
-            }
-        }
-        else
-        {
-            hModule = GetModuleHandleW(lpModuleName);
-        }
-    }
+    /* If result is invalid parameter - return failure */
+    if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
 
-    if (hModule != NULL)
-    {
-        if (!(dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
-        {
-            Status = LdrAddRefDll((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_PIN_MODULE : 0,
-                                  hModule);
+    /* If result is 2, there is no need to do anything - return success. */
+    if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
 
-            if (NT_SUCCESS(Status))
-            {
-                Ret = TRUE;
-            }
-            else
-            {
-                SetLastErrorByStatus(Status);
-                hModule = NULL;
-            }
-        }
-        else
-            Ret = TRUE;
-    }
+    /* Use common helper routine */
+    Status = BasepGetModuleHandleExW(FALSE,
+                                     dwFlags,
+                                     lpwModuleName,
+                                     phModule);
+
+    /* Return TRUE in case of success */
+    if (NT_SUCCESS(Status)) Ret = TRUE;
 
-    *phModule = hModule;
     return Ret;
 }
 
@@ -647,41 +989,52 @@ GetModuleHandleExW(IN DWORD dwFlags,
 BOOL
 WINAPI
 GetModuleHandleExA(IN DWORD dwFlags,
-                   IN LPCSTR lpModuleName  OPTIONAL,
+                   IN LPCSTR lpModuleName OPTIONAL,
                    OUT HMODULE* phModule)
 {
-    ANSI_STRING ModuleName;
-    LPCWSTR lpModuleNameW;
+    PUNICODE_STRING lpModuleNameW;
+    DWORD dwValid;
+    BOOL Ret = FALSE;
     NTSTATUS Status;
-    BOOL Ret;
 
-    PTEB pTeb = NtCurrentTeb();
+    /* Validate parameters */
+    dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
+
+    /* If result is invalid parameter - return failure */
+    if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
 
+    /* If result is 2, there is no need to do anything - return success. */
+    if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
+
+    /* Check if we don't need to convert the name */
     if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
     {
-        lpModuleNameW = (LPCWSTR)lpModuleName;
+        /* Call the extended version of the API without conversion */
+        Status = BasepGetModuleHandleExW(FALSE,
+                                         dwFlags,
+                                         (LPCWSTR)lpModuleName,
+                                         phModule);
     }
     else
     {
-        RtlInitAnsiString(&ModuleName, lpModuleName);
+        /* Convert module name to unicode */
+        lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
 
-        Status = RtlAnsiStringToUnicodeString(&pTeb->StaticUnicodeString,
-                                              &ModuleName,
-                                              FALSE);
+        /* Return FALSE if conversion failed */
+        if (!lpModuleNameW) return FALSE;
 
-        if (!NT_SUCCESS(Status))
-        {
-            SetLastErrorByStatus(Status);
-            return FALSE;
-        }
-
-        lpModuleNameW = pTeb->StaticUnicodeString.Buffer;
+        /* Call the extended version of the API */
+        Status = BasepGetModuleHandleExW(FALSE,
+                                         dwFlags,
+                                         lpModuleNameW->Buffer,
+                                         phModule);
     }
 
-    Ret = GetModuleHandleExW(dwFlags,
-                             lpModuleNameW,
-                             phModule);
+    /* If result was successful - return true */
+    if (NT_SUCCESS(Status))
+        Ret = TRUE;
 
+    /* Return result */
     return Ret;
 }
 
@@ -691,87 +1044,137 @@ GetModuleHandleExA(IN DWORD dwFlags,
  */
 DWORD
 WINAPI
-LoadModule (
-    LPCSTR  lpModuleName,
-    LPVOID  lpParameterBlock
-    )
+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;
-      }
+    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;
     }
-    return 0;
-  }
 
-  RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
+    /* 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);
+        }
 
-  /* Wait up to 15 seconds for the process to become idle */
-  if (NULL != lpfnGlobalRegisterWaitForInputIdle)
-  {
-    lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess, 15000);
-  }
+        /* Close handles */
+        NtClose(ProcessInformation.hThread);
+        NtClose(ProcessInformation.hProcess);
 
-  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 33;
+    /* Return last error which CreateFile set during an attempt to open it */
+    return GetLastError();
 }
 
 /* EOF */