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