xref: /reactos/dll/win32/kernel32/client/loader.c (revision c2d0d784)
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT  : ReactOS system libraries
4  * MODULE   : kernel32.dll
5  * FILE     : reactos/dll/win32/kernel32/misc/ldr.c
6  * AUTHOR   : Aleksey Bragin <aleksey@reactos.org>
7  */
8 
9 #include <k32.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 /* FUNCTIONS ****************************************************************/
15 
16 DWORD
17 WINAPI
18 BasepGetModuleHandleExParameterValidation(DWORD dwFlags,
19                                           LPCWSTR lpwModuleName,
20                                           HMODULE *phModule)
21 {
22     /* Set phModule to 0 if it's not a NULL pointer */
23     if (phModule) *phModule = 0;
24 
25     /* Check for invalid flags combination */
26     if (dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN |
27                     GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
28                     GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) ||
29         ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) &&
30          (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) ||
31          (!lpwModuleName && (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
32         )
33     {
34         BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
35         return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR;
36     }
37 
38     /* Check 2nd parameter */
39     if (!phModule)
40     {
41         BaseSetLastNTError(STATUS_INVALID_PARAMETER_2);
42         return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR;
43     }
44 
45     /* Return what we have according to the module name */
46     if (lpwModuleName)
47     {
48         return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE;
49     }
50 
51     /* No name given, so put ImageBaseAddress there */
52     *phModule = (HMODULE)NtCurrentPeb()->ImageBaseAddress;
53 
54     return BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS;
55 }
56 
57 PVOID
58 WINAPI
59 BasepMapModuleHandle(HMODULE hModule, BOOLEAN AsDataFile)
60 {
61     /* If no handle is provided - use current image base address */
62     if (!hModule) return NtCurrentPeb()->ImageBaseAddress;
63 
64     /* Check if it's a normal or a datafile one */
65     if (LDR_IS_DATAFILE(hModule) && !AsDataFile)
66         return NULL;
67 
68     /* It'a a normal DLL, just return its handle */
69     return hModule;
70 }
71 
72 /*
73  * @implemented
74  */
75 BOOL
76 WINAPI
77 DisableThreadLibraryCalls(
78     IN HMODULE hLibModule)
79 {
80     NTSTATUS Status;
81 
82     /* Disable thread library calls */
83     Status = LdrDisableThreadCalloutsForDll((PVOID)hLibModule);
84 
85     /* If it wasn't success - set last error and return failure */
86     if (!NT_SUCCESS(Status))
87     {
88         BaseSetLastNTError(Status);
89         return FALSE;
90     }
91 
92     /* Return success */
93     return TRUE;
94 }
95 
96 
97 /*
98  * @implemented
99  */
100 HINSTANCE
101 WINAPI
102 LoadLibraryA(LPCSTR lpLibFileName)
103 {
104     LPSTR PathBuffer;
105     UINT Len;
106     HINSTANCE Result;
107 
108     /* Treat twain_32.dll in a special way (what a surprise...) */
109     if (lpLibFileName && !_strcmpi(lpLibFileName, "twain_32.dll"))
110     {
111         /* Allocate space for the buffer */
112         PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH);
113         if (PathBuffer)
114         {
115             /* Get windows dir in this buffer */
116             Len = GetWindowsDirectoryA(PathBuffer, MAX_PATH - 13); /* 13 is sizeof of '\\twain_32.dll' */
117             if (Len && Len < (MAX_PATH - 13))
118             {
119                 /* We successfully got windows directory. Concatenate twain_32.dll to it */
120                 strncat(PathBuffer, "\\twain_32.dll", 13);
121 
122                 /* And recursively call ourselves with a new string */
123                 Result = LoadLibraryA(PathBuffer);
124 
125                 /* If it was successful -  free memory and return result */
126                 if (Result)
127                 {
128                     RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
129                     return Result;
130                 }
131             }
132 
133             /* Free allocated buffer */
134             RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
135         }
136     }
137 
138     /* Call the Ex version of the API */
139     return LoadLibraryExA(lpLibFileName, 0, 0);
140 }
141 
142 /*
143  * @implemented
144  */
145 HINSTANCE
146 WINAPI
147 LoadLibraryExA(LPCSTR lpLibFileName,
148                HANDLE hFile,
149                DWORD dwFlags)
150 {
151     PUNICODE_STRING FileNameW;
152 
153     /* Convert file name to unicode */
154     if (!(FileNameW = Basep8BitStringToStaticUnicodeString(lpLibFileName)))
155         return NULL;
156 
157     /* And call W version of the API */
158     return LoadLibraryExW(FileNameW->Buffer, hFile, dwFlags);
159 }
160 
161 /*
162  * @implemented
163  */
164 HINSTANCE
165 WINAPI
166 LoadLibraryW(LPCWSTR lpLibFileName)
167 {
168     /* Call Ex version of the API */
169     return LoadLibraryExW (lpLibFileName, 0, 0);
170 }
171 
172 
173 static
174 NTSTATUS
175 BasepLoadLibraryAsDatafile(PWSTR Path, LPCWSTR Name, HMODULE *hModule)
176 {
177     WCHAR FilenameW[MAX_PATH];
178     HANDLE hFile = INVALID_HANDLE_VALUE;
179     HANDLE hMapping;
180     NTSTATUS Status;
181     PVOID lpBaseAddress = NULL;
182     SIZE_T ViewSize = 0;
183     //PUNICODE_STRING OriginalName;
184     //UNICODE_STRING dotDLL = RTL_CONSTANT_STRING(L".DLL");
185 
186     /* Zero out handle value */
187     *hModule = 0;
188 
189     DPRINT("BasepLoadLibraryAsDatafile(%S %S %p)\n", Path, Name, hModule);
190 
191     /*Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
192                                                       Name,
193                                                       &dotDLL,
194                                                       RedirName,
195                                                       RedirName2,
196                                                       &OriginalName2,
197                                                       NULL,
198                                                       NULL,
199                                                       NULL);*/
200 
201     /* Try to search for it */
202     if (!SearchPathW(Path,
203                      Name,
204                      L".DLL",
205                      sizeof(FilenameW) / sizeof(FilenameW[0]),
206                      FilenameW,
207                      NULL))
208     {
209         /* Return last status value directly */
210         return NtCurrentTeb()->LastStatusValue;
211     }
212 
213     /* Open this file we found */
214     hFile = CreateFileW(FilenameW,
215                         GENERIC_READ,
216                         FILE_SHARE_READ | FILE_SHARE_DELETE,
217                         NULL,
218                         OPEN_EXISTING,
219                         0,
220                         0);
221 
222     /* If opening failed - return last status value */
223     if (hFile == INVALID_HANDLE_VALUE) return NtCurrentTeb()->LastStatusValue;
224 
225     /* Create file mapping */
226     hMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
227 
228     /* Close the file handle */
229     CloseHandle(hFile);
230 
231     /* If creating file mapping failed - return last status value */
232     if (!hMapping) return NtCurrentTeb()->LastStatusValue;
233 
234     /* Map view of section */
235     Status = NtMapViewOfSection(hMapping,
236                                 NtCurrentProcess(),
237                                 &lpBaseAddress,
238                                 0,
239                                 0,
240                                 0,
241                                 &ViewSize,
242                                 ViewShare,
243                                 0,
244                                 PAGE_READONLY);
245 
246     /* Close handle to the section */
247     CloseHandle(hMapping);
248 
249     /* If mapping view of section failed - return last status value */
250     if (!NT_SUCCESS(Status)) return NtCurrentTeb()->LastStatusValue;
251 
252     /* Make sure it's a valid PE file */
253     if (!RtlImageNtHeader(lpBaseAddress))
254     {
255         /* Unmap the view and return failure status */
256         UnmapViewOfFile(lpBaseAddress);
257         return STATUS_INVALID_IMAGE_FORMAT;
258     }
259 
260     /* Set low bit of handle to indicate datafile module */
261     *hModule = (HMODULE)((ULONG_PTR)lpBaseAddress | 1);
262 
263     /* Load alternate resource module */
264     //LdrLoadAlternateResourceModule(*hModule, FilenameW);
265 
266     return STATUS_SUCCESS;
267 }
268 
269 /*
270  * @implemented
271  */
272 HINSTANCE
273 WINAPI
274 LoadLibraryExW(LPCWSTR lpLibFileName,
275                HANDLE hFile,
276                DWORD dwFlags)
277 {
278     UNICODE_STRING DllName;
279     HINSTANCE hInst;
280     NTSTATUS Status;
281     PWSTR SearchPath;
282     ULONG DllCharacteristics = 0;
283     BOOL FreeString = FALSE;
284 
285     /* Check for any flags LdrLoadDll might be interested in */
286     if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
287     {
288         /* Tell LDR to treat it as an EXE */
289         DllCharacteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
290     }
291 
292     /* Build up a unicode dll name from null-terminated string */
293     RtlInitUnicodeString(&DllName, (LPWSTR)lpLibFileName);
294 
295     /* Lazy-initialize BasepExeLdrEntry */
296     if (!BasepExeLdrEntry)
297         LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry, NtCurrentPeb()->ImageBaseAddress);
298 
299     /* Check if that module is our exe*/
300     if (BasepExeLdrEntry && !(dwFlags & LOAD_LIBRARY_AS_DATAFILE) &&
301         DllName.Length == BasepExeLdrEntry->FullDllName.Length)
302     {
303         /* Lengths match and it's not a datafile, so perform name comparison */
304         if (RtlEqualUnicodeString(&DllName, &BasepExeLdrEntry->FullDllName, TRUE))
305         {
306             /* That's us! */
307             return BasepExeLdrEntry->DllBase;
308         }
309     }
310 
311     /* Check for trailing spaces and remove them if necessary */
312     if (DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
313     {
314         RtlCreateUnicodeString(&DllName, (LPWSTR)lpLibFileName);
315         while (DllName.Length > sizeof(WCHAR) &&
316             DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
317         {
318             DllName.Length -= sizeof(WCHAR);
319         }
320         DllName.Buffer[DllName.Length/sizeof(WCHAR)] = UNICODE_NULL;
321         FreeString = TRUE;
322     }
323 
324     /* Compute the load path */
325     SearchPath = BaseComputeProcessDllPath((dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) ?
326                                            DllName.Buffer : NULL,
327                                            NULL);
328     if (!SearchPath)
329     {
330         /* Getting DLL path failed, so set last error, free mem and return */
331         BaseSetLastNTError(STATUS_NO_MEMORY);
332         if (FreeString) RtlFreeUnicodeString(&DllName);
333         return NULL;
334     }
335 
336     _SEH2_TRY
337     {
338         if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
339         {
340             /* If the image is loaded as a datafile, try to get its handle */
341             Status = LdrGetDllHandleEx(0, SearchPath, NULL, &DllName, (PVOID*)&hInst);
342             if (!NT_SUCCESS(Status))
343             {
344                 /* It's not loaded yet - so load it up */
345                 Status = BasepLoadLibraryAsDatafile(SearchPath, DllName.Buffer, &hInst);
346             }
347             _SEH2_YIELD(goto done;)
348         }
349 
350         /* Call the API Properly */
351         Status = LdrLoadDll(SearchPath,
352                             &DllCharacteristics,
353                             &DllName,
354                             (PVOID*)&hInst);
355     }
356     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
357     {
358         Status = _SEH2_GetExceptionCode();
359     } _SEH2_END;
360 
361 
362 done:
363     /* Free SearchPath buffer */
364     RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
365 
366     /* Free DllName string if it was dynamically allocated */
367     if (FreeString) RtlFreeUnicodeString(&DllName);
368 
369     /* Set last error in failure case */
370     if (!NT_SUCCESS(Status))
371     {
372         BaseSetLastNTError(Status);
373         return NULL;
374     }
375 
376     /* Return loaded module handle */
377     return hInst;
378 }
379 
380 
381 /*
382  * @implemented
383  */
384 FARPROC
385 WINAPI
386 GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
387 {
388     ANSI_STRING ProcedureName, *ProcNamePtr = NULL;
389     FARPROC fnExp = NULL;
390     NTSTATUS Status;
391     PVOID hMapped;
392     ULONG Ordinal = 0;
393 
394     if (HIWORD(lpProcName) != 0)
395     {
396         /* Look up by name */
397         RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
398         ProcNamePtr = &ProcedureName;
399     }
400     else
401     {
402         /* Look up by ordinal */
403         Ordinal = (ULONG)lpProcName;
404     }
405 
406     /* Map provided handle */
407     hMapped = BasepMapModuleHandle(hModule, FALSE);
408 
409     /* Get the proc address */
410     Status = LdrGetProcedureAddress(hMapped,
411                                     ProcNamePtr,
412                                     Ordinal,
413                                     (PVOID*)&fnExp);
414 
415     if (!NT_SUCCESS(Status))
416     {
417         BaseSetLastNTError(Status);
418         return NULL;
419     }
420 
421     /* Check for a special case when returned pointer is
422        the same as iamge's base address */
423     if (fnExp == hMapped)
424     {
425         /* Set correct error code */
426         if (HIWORD(lpProcName) != 0)
427             BaseSetLastNTError(STATUS_ENTRYPOINT_NOT_FOUND);
428         else
429             BaseSetLastNTError(STATUS_ORDINAL_NOT_FOUND);
430 
431         return NULL;
432     }
433 
434     /* All good, return procedure pointer */
435     return fnExp;
436 }
437 
438 
439 /*
440  * @implemented
441  */
442 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
443 {
444     NTSTATUS Status;
445     PIMAGE_NT_HEADERS NtHeaders;
446 
447     if (LDR_IS_DATAFILE(hLibModule))
448     {
449         // FIXME: This SEH should go inside RtlImageNtHeader instead
450         _SEH2_TRY
451         {
452             /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
453             NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1));
454         }
455         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
456         {
457             NtHeaders = NULL;
458         } _SEH2_END
459 
460         if (NtHeaders)
461         {
462             /* Unmap view */
463             Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
464 
465             /* Unload alternate resource module */
466             LdrUnloadAlternateResourceModule(hLibModule);
467         }
468         else
469             Status = STATUS_INVALID_IMAGE_FORMAT;
470     }
471     else
472     {
473         /* Just unload it */
474         Status = LdrUnloadDll((PVOID)hLibModule);
475     }
476 
477     /* Check what kind of status we got */
478     if (!NT_SUCCESS(Status))
479     {
480         /* Set last error */
481         BaseSetLastNTError(Status);
482 
483         /* Return failure */
484         return FALSE;
485     }
486 
487     /* Return success */
488     return TRUE;
489 }
490 
491 
492 /*
493  * @implemented
494  */
495 VOID
496 WINAPI
497 FreeLibraryAndExitThread(HMODULE hLibModule,
498                          DWORD dwExitCode)
499 {
500 
501     if (LDR_IS_DATAFILE(hLibModule))
502     {
503         /* This is a LOAD_LIBRARY_AS_DATAFILE module */
504         if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)))
505         {
506             /* Unmap view */
507             NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
508 
509             /* Unload alternate resource module */
510             LdrUnloadAlternateResourceModule(hLibModule);
511         }
512     }
513     else
514     {
515         /* Just unload it */
516         LdrUnloadDll((PVOID)hLibModule);
517     }
518 
519     /* Exit thread */
520     ExitThread(dwExitCode);
521 }
522 
523 
524 /*
525  * @implemented
526  */
527 DWORD
528 WINAPI
529 GetModuleFileNameA(HINSTANCE hModule,
530                    LPSTR lpFilename,
531                    DWORD nSize)
532 {
533     UNICODE_STRING FilenameW;
534     ANSI_STRING FilenameA;
535     NTSTATUS Status;
536     DWORD Length = 0, LengthToCopy;
537 
538     /* Allocate a unicode buffer */
539     FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR));
540     if (!FilenameW.Buffer)
541     {
542         BaseSetLastNTError(STATUS_NO_MEMORY);
543         return 0;
544     }
545 
546     /* Call unicode API */
547     FilenameW.Length = GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR);
548     FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR);
549 
550     if (FilenameW.Length)
551     {
552         /* Convert to ansi string */
553         Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE);
554         if (!NT_SUCCESS(Status))
555         {
556             /* Set last error, free string and retun failure */
557             BaseSetLastNTError(Status);
558             RtlFreeUnicodeString(&FilenameW);
559             return 0;
560         }
561 
562         /* Calculate size to copy */
563         Length = min(nSize, FilenameA.Length);
564 
565         /* Include terminating zero */
566         if (nSize > Length)
567             LengthToCopy = Length + 1;
568         else
569             LengthToCopy = nSize;
570 
571         /* Now copy back to the caller amount he asked */
572         RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy);
573 
574         /* Free ansi filename */
575         RtlFreeAnsiString(&FilenameA);
576     }
577 
578     /* Free unicode filename */
579     RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer);
580 
581     /* Return length copied */
582     return Length;
583 }
584 
585 /*
586  * @implemented
587  */
588 DWORD
589 WINAPI
590 GetModuleFileNameW(HINSTANCE hModule,
591                    LPWSTR lpFilename,
592                    DWORD nSize)
593 {
594     PLIST_ENTRY ModuleListHead, Entry;
595     PLDR_DATA_TABLE_ENTRY Module;
596     ULONG Length = 0;
597     ULONG Cookie;
598     PPEB Peb;
599 
600     hModule = BasepMapModuleHandle(hModule, FALSE);
601 
602     /* Upscale nSize from chars to bytes */
603     nSize *= sizeof(WCHAR);
604 
605     _SEH2_TRY
606     {
607         /* We don't use per-thread cur dir now */
608         //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
609 
610         Peb = NtCurrentPeb ();
611 
612         /* Acquire a loader lock */
613         LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
614 
615         /* Traverse the module list */
616         ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
617         Entry = ModuleListHead->Flink;
618         while (Entry != ModuleListHead)
619         {
620             Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
621 
622             /* Check if this is the requested module */
623             if (Module->DllBase == (PVOID)hModule)
624             {
625                 /* Calculate size to copy */
626                 Length = min(nSize, Module->FullDllName.MaximumLength);
627 
628                 /* Copy contents */
629                 RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length);
630 
631                 /* Subtract a terminating zero */
632                 if (Length == Module->FullDllName.MaximumLength)
633                     Length -= sizeof(WCHAR);
634 
635                 /* Break out of the loop */
636                 break;
637             }
638 
639             /* Advance to the next entry */
640             Entry = Entry->Flink;
641         }
642     }
643     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
644     {
645         BaseSetLastNTError(_SEH2_GetExceptionCode());
646         Length = 0;
647     } _SEH2_END
648 
649     /* Release the loader lock */
650     LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
651 
652     return Length / sizeof(WCHAR);
653 }
654 
655 HMODULE
656 WINAPI
657 GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)
658 {
659     NTSTATUS Status;
660     PVOID Module;
661     LPWSTR DllPath;
662 
663     /* Try to get a handle with a magic value of 1 for DllPath */
664     Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module);
665 
666     /* If that succeeded - we're done */
667     if (NT_SUCCESS(Status)) return Module;
668 
669     /* If not, then the path should be computed */
670     DllPath = BaseComputeProcessDllPath(NULL, 0);
671     if (!DllPath)
672     {
673         Status = STATUS_NO_MEMORY;
674     }
675     else
676     {
677         _SEH2_TRY
678         {
679             Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module);
680         }
681         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
682         {
683             /* Fail with the SEH error */
684             Status = _SEH2_GetExceptionCode();
685         }
686         _SEH2_END;
687     }
688 
689     /* Free the DllPath */
690     RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
691 
692     /* In case of error set last win32 error and return NULL */
693     if (!NT_SUCCESS(Status))
694     {
695         DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status);
696         BaseSetLastNTError(Status);
697         Module = 0;
698     }
699 
700     /* Return module */
701     return (HMODULE)Module;
702 }
703 
704 BOOLEAN
705 WINAPI
706 BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule)
707 {
708     DWORD Cookie;
709     NTSTATUS Status = STATUS_SUCCESS, Status2;
710     HANDLE hModule = 0;
711     UNICODE_STRING ModuleNameU;
712     DWORD dwValid;
713     BOOLEAN Redirected = FALSE; // FIXME
714 
715     /* Validate parameters */
716     dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule);
717     ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE);
718 
719     /* Acquire lock if necessary */
720     if (!NoLock)
721     {
722         Status = LdrLockLoaderLock(0, NULL, &Cookie);
723         if (!NT_SUCCESS(Status))
724         {
725             /* Fail */
726             BaseSetLastNTError(Status);
727             if (phModule) *phModule = 0;
728             return NT_SUCCESS(Status);
729         }
730     }
731 
732     if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
733     {
734         /* Create a unicode string out of module name */
735         RtlInitUnicodeString(&ModuleNameU, lpwModuleName);
736 
737         // FIXME: Do some redirected DLL stuff?
738         if (Redirected)
739         {
740             UNIMPLEMENTED;
741         }
742 
743         if (!hModule)
744         {
745             hModule = GetModuleHandleForUnicodeString(&ModuleNameU);
746             if (!hModule)
747             {
748                 /* Last error is already set, so just return failure by setting status */
749                 Status = STATUS_DLL_NOT_FOUND;
750                 goto quickie;
751             }
752         }
753     }
754     else
755     {
756         /* Perform Pc to file header to get module instance */
757         hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName,
758                                              (PVOID*)&hModule);
759 
760         /* Check if it succeeded */
761         if (!hModule)
762         {
763             /* Set "dll not found" status and quit */
764             Status = STATUS_DLL_NOT_FOUND;
765             goto quickie;
766         }
767     }
768 
769     /* Check if changing reference is not forbidden */
770     if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
771     {
772         /* Add reference to this DLL */
773         Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_ADDREF_DLL_PIN : 0,
774                               hModule);
775     }
776 
777     /* Set last error in case of failure */
778     if (!NT_SUCCESS(Status))
779         BaseSetLastNTError(Status);
780 
781 quickie:
782     /* Unlock loader lock if it was acquired */
783     if (!NoLock)
784     {
785         Status2 = LdrUnlockLoaderLock(0, Cookie);
786         ASSERT(NT_SUCCESS(Status2));
787     }
788 
789     /* Set the module handle to the caller */
790     if (phModule) *phModule = hModule;
791 
792     /* Return TRUE on success and FALSE otherwise */
793     return NT_SUCCESS(Status);
794 }
795 
796 /*
797  * @implemented
798  */
799 HMODULE
800 WINAPI
801 GetModuleHandleA(LPCSTR lpModuleName)
802 {
803     PUNICODE_STRING ModuleNameW;
804     PTEB pTeb = NtCurrentTeb();
805 
806     /* Check if we have no name to convert */
807     if (!lpModuleName)
808         return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
809 
810     /* Convert module name to unicode */
811     ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
812 
813     /* Call W version if conversion was successful */
814     if (ModuleNameW)
815         return GetModuleHandleW(ModuleNameW->Buffer);
816 
817     /* Return failure */
818     return 0;
819 }
820 
821 
822 /*
823  * @implemented
824  */
825 HMODULE
826 WINAPI
827 GetModuleHandleW(LPCWSTR lpModuleName)
828 {
829     HMODULE hModule;
830     NTSTATUS Status;
831 
832     /* If current module is requested - return it right away */
833     if (!lpModuleName)
834         return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
835 
836     /* Use common helper routine */
837     Status = BasepGetModuleHandleExW(TRUE,
838                                      GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
839                                      lpModuleName,
840                                      &hModule);
841 
842     /* If it wasn't successful - return 0 */
843     if (!NT_SUCCESS(Status)) hModule = 0;
844 
845     /* Return the handle */
846     return hModule;
847 }
848 
849 
850 /*
851  * @implemented
852  */
853 BOOL
854 WINAPI
855 GetModuleHandleExW(IN DWORD dwFlags,
856                    IN LPCWSTR lpwModuleName  OPTIONAL,
857                    OUT HMODULE* phModule)
858 {
859     NTSTATUS Status;
860     DWORD dwValid;
861     BOOL Ret = FALSE;
862 
863     /* Validate parameters */
864     dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule);
865 
866     /* If result is invalid parameter - return failure */
867     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
868 
869     /* If result is 2, there is no need to do anything - return success. */
870     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
871 
872     /* Use common helper routine */
873     Status = BasepGetModuleHandleExW(FALSE,
874                                      dwFlags,
875                                      lpwModuleName,
876                                      phModule);
877 
878     /* Return TRUE in case of success */
879     if (NT_SUCCESS(Status)) Ret = TRUE;
880 
881     return Ret;
882 }
883 
884 /*
885  * @implemented
886  */
887 BOOL
888 WINAPI
889 GetModuleHandleExA(IN DWORD dwFlags,
890                    IN LPCSTR lpModuleName OPTIONAL,
891                    OUT HMODULE* phModule)
892 {
893     PUNICODE_STRING lpModuleNameW;
894     DWORD dwValid;
895     BOOL Ret = FALSE;
896     NTSTATUS Status;
897 
898     /* Validate parameters */
899     dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
900 
901     /* If result is invalid parameter - return failure */
902     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
903 
904     /* If result is 2, there is no need to do anything - return success. */
905     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
906 
907     /* Check if we don't need to convert the name */
908     if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
909     {
910         /* Call the extended version of the API without conversion */
911         Status = BasepGetModuleHandleExW(FALSE,
912                                          dwFlags,
913                                          (LPCWSTR)lpModuleName,
914                                          phModule);
915     }
916     else
917     {
918         /* Convert module name to unicode */
919         lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
920 
921         /* Return FALSE if conversion failed */
922         if (!lpModuleNameW) return FALSE;
923 
924         /* Call the extended version of the API */
925         Status = BasepGetModuleHandleExW(FALSE,
926                                          dwFlags,
927                                          lpModuleNameW->Buffer,
928                                          phModule);
929     }
930 
931     /* If result was successful - return true */
932     if (NT_SUCCESS(Status))
933         Ret = TRUE;
934 
935     /* Return result */
936     return Ret;
937 }
938 
939 
940 /*
941  * @implemented
942  */
943 DWORD
944 WINAPI
945 LoadModule(LPCSTR lpModuleName,
946            LPVOID lpParameterBlock)
947 {
948     STARTUPINFOA StartupInfo;
949     PROCESS_INFORMATION ProcessInformation;
950     LOADPARMS32 *LoadParams;
951     char FileName[MAX_PATH];
952     LPSTR CommandLine;
953     DWORD Length, Error;
954     BOOL ProcessStatus;
955     ANSI_STRING AnsiStr;
956     UNICODE_STRING UnicStr;
957     RTL_PATH_TYPE PathType;
958     HANDLE Handle;
959 
960     LoadParams = (LOADPARMS32*)lpParameterBlock;
961 
962     /* Check load parameters */
963     if (LoadParams->dwReserved || LoadParams->wMagicValue != 2)
964     {
965         /* Fail with invalid param error */
966         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
967         return 0;
968     }
969 
970     /* Search path */
971     Length = SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL);
972 
973     /* Check if path was found */
974     if (Length && Length < MAX_PATH)
975     {
976         /* Build StartupInfo */
977         RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
978 
979         StartupInfo.cb = sizeof(STARTUPINFOA);
980         StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
981         StartupInfo.wShowWindow = LoadParams->wCmdShow;
982 
983         /* Allocate command line buffer */
984         CommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
985                                       HEAP_ZERO_MEMORY,
986                                       (ULONG)LoadParams->lpCmdLine[0] + Length + 2);
987 
988         /* Put module name there, then a space, and then copy provided command line,
989            and null-terminate it */
990         RtlCopyMemory(CommandLine, FileName, Length);
991         CommandLine[Length] = ' ';
992         RtlCopyMemory(&CommandLine[Length + 1], &LoadParams->lpCmdLine[1], (ULONG)LoadParams->lpCmdLine[0]);
993         CommandLine[Length + 1 + (ULONG)LoadParams->lpCmdLine[0]] = 0;
994 
995         /* Create the process */
996         ProcessStatus = CreateProcessA(FileName,
997                                        CommandLine,
998                                        NULL,
999                                        NULL,
1000                                        FALSE,
1001                                        0,
1002                                        LoadParams->lpEnvAddress,
1003                                        NULL,
1004                                        &StartupInfo,
1005                                        &ProcessInformation);
1006 
1007         /* Free the command line buffer */
1008         RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
1009 
1010         if (!ProcessStatus)
1011         {
1012             /* Creating process failed, return right error code */
1013             Error = GetLastError();
1014             switch(Error)
1015             {
1016             case ERROR_BAD_EXE_FORMAT:
1017                return ERROR_BAD_FORMAT;
1018 
1019             case ERROR_FILE_NOT_FOUND:
1020             case ERROR_PATH_NOT_FOUND:
1021                 return Error;
1022             }
1023 
1024             /* Return 0 otherwise */
1025             return 0;
1026         }
1027 
1028         /* Wait up to 30 seconds for the process to become idle */
1029         if (lpfnGlobalRegisterWaitForInputIdle)
1030         {
1031             lpfnGlobalRegisterWaitForInputIdle(ProcessInformation.hProcess, 30000);
1032         }
1033 
1034         /* Close handles */
1035         NtClose(ProcessInformation.hThread);
1036         NtClose(ProcessInformation.hProcess);
1037 
1038         /* Return magic success value (33) */
1039         return 33;
1040     }
1041 
1042     /* The path was not found, create an ansi string from
1043         the module name and convert it to unicode */
1044     RtlInitAnsiString(&AnsiStr, lpModuleName);
1045     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicStr,&AnsiStr,TRUE)))
1046         return ERROR_FILE_NOT_FOUND;
1047 
1048     /* Determine path type */
1049     PathType = RtlDetermineDosPathNameType_U(UnicStr.Buffer);
1050 
1051     /* Free the unicode module name */
1052     RtlFreeUnicodeString(&UnicStr);
1053 
1054     /* If it's a relative path, return file not found */
1055     if (PathType == RtlPathTypeRelative)
1056         return ERROR_FILE_NOT_FOUND;
1057 
1058     /* If not, try to open it */
1059     Handle = CreateFile(lpModuleName,
1060                         GENERIC_READ,
1061                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1062                         NULL,
1063                         OPEN_EXISTING,
1064                         FILE_ATTRIBUTE_NORMAL,
1065                         NULL);
1066 
1067     if (Handle != INVALID_HANDLE_VALUE)
1068     {
1069         /* Opening file succeeded for some reason, close the handle and return file not found anyway */
1070         CloseHandle(Handle);
1071         return ERROR_FILE_NOT_FOUND;
1072     }
1073 
1074     /* Return last error which CreateFile set during an attempt to open it */
1075     return GetLastError();
1076 }
1077 
1078 /*
1079  * @unimplemented
1080  */
1081 FARPROC WINAPI DelayLoadFailureHook(LPCSTR pszDllName, LPCSTR pszProcName)
1082 {
1083     STUB;
1084     return NULL;
1085 }
1086 
1087 /*
1088  * @unimplemented
1089  */
1090 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
1091                         LPSTR lpszInitName, LPSTR lpszProcName,
1092                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
1093                         LPVOID lpBuff )
1094 {
1095     STUB;
1096     return 0;
1097 }
1098 
1099 /*
1100  * @unimplemented
1101  */
1102 VOID WINAPI UTUnRegister( HMODULE hModule )
1103 {
1104     STUB;
1105 }
1106 
1107 /*
1108  * @unimplemented
1109  */
1110 BOOL
1111 WINAPI
1112 BaseQueryModuleData(IN LPSTR ModuleName,
1113                     IN LPSTR Unknown,
1114                     IN PVOID Unknown2,
1115                     IN PVOID Unknown3,
1116                     IN PVOID Unknown4)
1117 {
1118     DPRINT1("BaseQueryModuleData called: %s %s %x %x %x\n",
1119             ModuleName,
1120             Unknown,
1121             Unknown2,
1122             Unknown3,
1123             Unknown4);
1124     return FALSE;
1125 }
1126 
1127 /*
1128  * @unimplemented
1129  */
1130 NTSTATUS
1131 WINAPI
1132 BaseProcessInitPostImport(VOID)
1133 {
1134     /* FIXME: Initialize TS pointers */
1135     return STATUS_SUCCESS;
1136 }
1137 
1138 /* EOF */
1139