xref: /reactos/dll/win32/kernel32/client/loader.c (revision b99f0b49)
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 (HIWORD(lpProcName) != 0)
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 = (ULONG)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         _SEH2_TRY
467         {
468             /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
469             NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1));
470         }
471         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
472         {
473             NtHeaders = NULL;
474         } _SEH2_END
475 
476         if (NtHeaders)
477         {
478             /* Unmap view */
479             Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
480 
481             /* Unload alternate resource module */
482             LdrUnloadAlternateResourceModule(hLibModule);
483         }
484         else
485             Status = STATUS_INVALID_IMAGE_FORMAT;
486     }
487     else
488     {
489         /* Just unload it */
490         Status = LdrUnloadDll((PVOID)hLibModule);
491     }
492 
493     /* Check what kind of status we got */
494     if (!NT_SUCCESS(Status))
495     {
496         /* Set last error */
497         BaseSetLastNTError(Status);
498 
499         /* Return failure */
500         return FALSE;
501     }
502 
503     /* Return success */
504     return TRUE;
505 }
506 
507 
508 /*
509  * @implemented
510  */
511 VOID
512 WINAPI
513 FreeLibraryAndExitThread(HMODULE hLibModule,
514                          DWORD dwExitCode)
515 {
516 
517     if (LDR_IS_DATAFILE(hLibModule))
518     {
519         /* This is a LOAD_LIBRARY_AS_DATAFILE module */
520         if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)))
521         {
522             /* Unmap view */
523             NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
524 
525             /* Unload alternate resource module */
526             LdrUnloadAlternateResourceModule(hLibModule);
527         }
528     }
529     else
530     {
531         /* Just unload it */
532         LdrUnloadDll((PVOID)hLibModule);
533     }
534 
535     /* Exit thread */
536     ExitThread(dwExitCode);
537 }
538 
539 
540 /*
541  * @implemented
542  */
543 DWORD
544 WINAPI
545 GetModuleFileNameA(HINSTANCE hModule,
546                    LPSTR lpFilename,
547                    DWORD nSize)
548 {
549     UNICODE_STRING FilenameW;
550     ANSI_STRING FilenameA;
551     NTSTATUS Status;
552     DWORD Length = 0, LengthToCopy;
553 
554     /* Allocate a unicode buffer */
555     FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR));
556     if (!FilenameW.Buffer)
557     {
558         BaseSetLastNTError(STATUS_NO_MEMORY);
559         return 0;
560     }
561 
562     /* Call unicode API */
563     FilenameW.Length = (USHORT)GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR);
564     FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR);
565 
566     if (FilenameW.Length)
567     {
568         /* Convert to ansi string */
569         Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE);
570         if (!NT_SUCCESS(Status))
571         {
572             /* Set last error, free string and return failure */
573             BaseSetLastNTError(Status);
574             RtlFreeUnicodeString(&FilenameW);
575             return 0;
576         }
577 
578         /* Calculate size to copy */
579         Length = min(nSize, FilenameA.Length);
580 
581         /* Include terminating zero */
582         if (nSize > Length)
583             LengthToCopy = Length + 1;
584         else
585             LengthToCopy = nSize;
586 
587         /* Now copy back to the caller amount he asked */
588         RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy);
589 
590         /* Free ansi filename */
591         RtlFreeAnsiString(&FilenameA);
592     }
593 
594     /* Free unicode filename */
595     RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer);
596 
597     /* Return length copied */
598     return Length;
599 }
600 
601 /*
602  * @implemented
603  */
604 DWORD
605 WINAPI
606 GetModuleFileNameW(HINSTANCE hModule,
607                    LPWSTR lpFilename,
608                    DWORD nSize)
609 {
610     PLIST_ENTRY ModuleListHead, Entry;
611     PLDR_DATA_TABLE_ENTRY Module;
612     ULONG Length = 0;
613     ULONG_PTR Cookie;
614     PPEB Peb;
615 
616     hModule = BasepMapModuleHandle(hModule, FALSE);
617 
618     /* Upscale nSize from chars to bytes */
619     nSize *= sizeof(WCHAR);
620 
621     _SEH2_TRY
622     {
623         /* We don't use per-thread cur dir now */
624         //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
625 
626         Peb = NtCurrentPeb ();
627 
628         /* Acquire a loader lock */
629         LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
630 
631         /* Traverse the module list */
632         ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
633         Entry = ModuleListHead->Flink;
634         while (Entry != ModuleListHead)
635         {
636             Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
637 
638             /* Check if this is the requested module */
639             if (Module->DllBase == (PVOID)hModule)
640             {
641                 /* Calculate size to copy */
642                 Length = min(nSize, Module->FullDllName.MaximumLength);
643 
644                 /* Copy contents */
645                 RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length);
646 
647                 /* Subtract a terminating zero */
648                 if (Length == Module->FullDllName.MaximumLength)
649                     Length -= sizeof(WCHAR);
650 
651                 /* Break out of the loop */
652                 break;
653             }
654 
655             /* Advance to the next entry */
656             Entry = Entry->Flink;
657         }
658     }
659     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
660     {
661         BaseSetLastNTError(_SEH2_GetExceptionCode());
662         Length = 0;
663     } _SEH2_END
664 
665     /* Release the loader lock */
666     LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
667 
668     return Length / sizeof(WCHAR);
669 }
670 
671 HMODULE
672 WINAPI
673 GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)
674 {
675     NTSTATUS Status;
676     PVOID Module;
677     LPWSTR DllPath;
678 
679     /* Try to get a handle with a magic value of 1 for DllPath */
680     Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module);
681 
682     /* If that succeeded - we're done */
683     if (NT_SUCCESS(Status)) return Module;
684 
685     /* If not, then the path should be computed */
686     DllPath = BaseComputeProcessDllPath(NULL, 0);
687     if (!DllPath)
688     {
689         Status = STATUS_NO_MEMORY;
690     }
691     else
692     {
693         _SEH2_TRY
694         {
695             Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module);
696         }
697         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
698         {
699             /* Fail with the SEH error */
700             Status = _SEH2_GetExceptionCode();
701         }
702         _SEH2_END;
703     }
704 
705     /* Free the DllPath */
706     RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
707 
708     /* In case of error set last win32 error and return NULL */
709     if (!NT_SUCCESS(Status))
710     {
711         DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status);
712         BaseSetLastNTError(Status);
713         Module = 0;
714     }
715 
716     /* Return module */
717     return (HMODULE)Module;
718 }
719 
720 BOOLEAN
721 WINAPI
722 BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule)
723 {
724     ULONG_PTR Cookie;
725     NTSTATUS Status = STATUS_SUCCESS, Status2;
726     HANDLE hModule = NULL;
727     UNICODE_STRING ModuleNameU;
728     DWORD dwValid;
729     BOOLEAN Redirected = FALSE; // FIXME
730 
731     /* Validate parameters */
732     dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule);
733     ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE);
734 
735     /* Acquire lock if necessary */
736     if (!NoLock)
737     {
738         Status = LdrLockLoaderLock(0, NULL, &Cookie);
739         if (!NT_SUCCESS(Status))
740         {
741             /* Fail */
742             BaseSetLastNTError(Status);
743             if (phModule) *phModule = NULL;
744             return NT_SUCCESS(Status);
745         }
746     }
747 
748     if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
749     {
750         /* Create a unicode string out of module name */
751         RtlInitUnicodeString(&ModuleNameU, lpwModuleName);
752 
753         // FIXME: Do some redirected DLL stuff?
754         if (Redirected)
755         {
756             UNIMPLEMENTED;
757         }
758 
759         if (!hModule)
760         {
761             hModule = GetModuleHandleForUnicodeString(&ModuleNameU);
762             if (!hModule)
763             {
764                 /* Last error is already set, so just return failure by setting status */
765                 Status = STATUS_DLL_NOT_FOUND;
766                 goto quickie;
767             }
768         }
769     }
770     else
771     {
772         /* Perform Pc to file header to get module instance */
773         hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName,
774                                              (PVOID*)&hModule);
775 
776         /* Check if it succeeded */
777         if (!hModule)
778         {
779             /* Set "dll not found" status and quit */
780             Status = STATUS_DLL_NOT_FOUND;
781             goto quickie;
782         }
783     }
784 
785     /* Check if changing reference is not forbidden */
786     if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
787     {
788         /* Add reference to this DLL */
789         Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_ADDREF_DLL_PIN : 0,
790                               hModule);
791     }
792 
793 quickie:
794     /* Set last error in case of failure */
795     if (!NT_SUCCESS(Status))
796         BaseSetLastNTError(Status);
797 
798     /* Unlock loader lock if it was acquired */
799     if (!NoLock)
800     {
801         Status2 = LdrUnlockLoaderLock(0, Cookie);
802         ASSERT(NT_SUCCESS(Status2));
803     }
804 
805     /* Set the module handle to the caller */
806     if (phModule) *phModule = hModule;
807 
808     /* Return TRUE on success and FALSE otherwise */
809     return NT_SUCCESS(Status);
810 }
811 
812 /*
813  * @implemented
814  */
815 HMODULE
816 WINAPI
817 DECLSPEC_HOTPATCH
818 GetModuleHandleA(LPCSTR lpModuleName)
819 {
820     PUNICODE_STRING ModuleNameW;
821     PTEB pTeb = NtCurrentTeb();
822 
823     /* Check if we have no name to convert */
824     if (!lpModuleName)
825         return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
826 
827     /* Convert module name to unicode */
828     ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
829 
830     /* Call W version if conversion was successful */
831     if (ModuleNameW)
832         return GetModuleHandleW(ModuleNameW->Buffer);
833 
834     /* Return failure */
835     return 0;
836 }
837 
838 
839 /*
840  * @implemented
841  */
842 HMODULE
843 WINAPI
844 GetModuleHandleW(LPCWSTR lpModuleName)
845 {
846     HMODULE hModule;
847     BOOLEAN Success;
848 
849     /* If current module is requested - return it right away */
850     if (!lpModuleName)
851         return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
852 
853     /* Use common helper routine */
854     Success = BasepGetModuleHandleExW(TRUE,
855                                       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
856                                       lpModuleName,
857                                       &hModule);
858 
859     /* If it wasn't successful - return NULL */
860     if (!Success) hModule = NULL;
861 
862     /* Return the handle */
863     return hModule;
864 }
865 
866 
867 /*
868  * @implemented
869  */
870 BOOL
871 WINAPI
872 GetModuleHandleExW(IN DWORD dwFlags,
873                    IN LPCWSTR lpwModuleName  OPTIONAL,
874                    OUT HMODULE* phModule)
875 {
876     DWORD dwValid;
877     BOOL Ret;
878 
879     /* Validate parameters */
880     dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule);
881 
882     /* If result is invalid parameter - return failure */
883     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
884 
885     /* If result is 2, there is no need to do anything - return success. */
886     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
887 
888     /* Use common helper routine */
889     Ret = BasepGetModuleHandleExW(FALSE,
890                                   dwFlags,
891                                   lpwModuleName,
892                                   phModule);
893 
894     return Ret;
895 }
896 
897 /*
898  * @implemented
899  */
900 BOOL
901 WINAPI
902 GetModuleHandleExA(IN DWORD dwFlags,
903                    IN LPCSTR lpModuleName OPTIONAL,
904                    OUT HMODULE* phModule)
905 {
906     PUNICODE_STRING lpModuleNameW;
907     DWORD dwValid;
908     BOOL Ret;
909 
910     /* Validate parameters */
911     dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
912 
913     /* If result is invalid parameter - return failure */
914     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
915 
916     /* If result is 2, there is no need to do anything - return success. */
917     if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
918 
919     /* Check if we don't need to convert the name */
920     if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
921     {
922         /* Call the extended version of the API without conversion */
923         Ret = BasepGetModuleHandleExW(FALSE,
924                                       dwFlags,
925                                       (LPCWSTR)lpModuleName,
926                                       phModule);
927     }
928     else
929     {
930         /* Convert module name to unicode */
931         lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
932 
933         /* Return FALSE if conversion failed */
934         if (!lpModuleNameW) return FALSE;
935 
936         /* Call the extended version of the API */
937         Ret = BasepGetModuleHandleExW(FALSE,
938                                       dwFlags,
939                                       lpModuleNameW->Buffer,
940                                       phModule);
941     }
942 
943     /* Return result */
944     return Ret;
945 }
946 
947 
948 /*
949  * @implemented
950  */
951 DWORD
952 WINAPI
953 LoadModule(LPCSTR lpModuleName,
954            LPVOID lpParameterBlock)
955 {
956     STARTUPINFOA StartupInfo;
957     PROCESS_INFORMATION ProcessInformation;
958     LOADPARMS32 *LoadParams;
959     char FileName[MAX_PATH];
960     LPSTR CommandLine;
961     DWORD Length, Error;
962     BOOL ProcessStatus;
963     ANSI_STRING AnsiStr;
964     UNICODE_STRING UnicStr;
965     RTL_PATH_TYPE PathType;
966     HANDLE Handle;
967 
968     LoadParams = (LOADPARMS32*)lpParameterBlock;
969 
970     /* Check load parameters */
971     if (LoadParams->dwReserved || LoadParams->wMagicValue != 2)
972     {
973         /* Fail with invalid param error */
974         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
975         return 0;
976     }
977 
978     /* Search path */
979     Length = SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL);
980 
981     /* Check if path was found */
982     if (Length && Length < MAX_PATH)
983     {
984         /* Build StartupInfo */
985         RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
986 
987         StartupInfo.cb = sizeof(STARTUPINFOA);
988         StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
989         StartupInfo.wShowWindow = LoadParams->wCmdShow;
990 
991         /* Allocate command line buffer */
992         CommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
993                                       HEAP_ZERO_MEMORY,
994                                       (ULONG)LoadParams->lpCmdLine[0] + Length + 2);
995 
996         /* Put module name there, then a space, and then copy provided command line,
997            and null-terminate it */
998         RtlCopyMemory(CommandLine, FileName, Length);
999         CommandLine[Length] = ' ';
1000         RtlCopyMemory(&CommandLine[Length + 1], &LoadParams->lpCmdLine[1], (ULONG)LoadParams->lpCmdLine[0]);
1001         CommandLine[Length + 1 + (ULONG)LoadParams->lpCmdLine[0]] = 0;
1002 
1003         /* Create the process */
1004         ProcessStatus = CreateProcessA(FileName,
1005                                        CommandLine,
1006                                        NULL,
1007                                        NULL,
1008                                        FALSE,
1009                                        0,
1010                                        LoadParams->lpEnvAddress,
1011                                        NULL,
1012                                        &StartupInfo,
1013                                        &ProcessInformation);
1014 
1015         /* Free the command line buffer */
1016         RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
1017 
1018         if (!ProcessStatus)
1019         {
1020             /* Creating process failed, return right error code */
1021             Error = GetLastError();
1022             switch(Error)
1023             {
1024             case ERROR_BAD_EXE_FORMAT:
1025                return ERROR_BAD_FORMAT;
1026 
1027             case ERROR_FILE_NOT_FOUND:
1028             case ERROR_PATH_NOT_FOUND:
1029                 return Error;
1030             }
1031 
1032             /* Return 0 otherwise */
1033             return 0;
1034         }
1035 
1036         /* Wait up to 30 seconds for the process to become idle */
1037         if (UserWaitForInputIdleRoutine)
1038         {
1039             UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 30000);
1040         }
1041 
1042         /* Close handles */
1043         NtClose(ProcessInformation.hThread);
1044         NtClose(ProcessInformation.hProcess);
1045 
1046         /* Return magic success value (33) */
1047         return 33;
1048     }
1049 
1050     /* The path was not found, create an ansi string from
1051         the module name and convert it to unicode */
1052     RtlInitAnsiString(&AnsiStr, lpModuleName);
1053     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicStr,&AnsiStr,TRUE)))
1054         return ERROR_FILE_NOT_FOUND;
1055 
1056     /* Determine path type */
1057     PathType = RtlDetermineDosPathNameType_U(UnicStr.Buffer);
1058 
1059     /* Free the unicode module name */
1060     RtlFreeUnicodeString(&UnicStr);
1061 
1062     /* If it's a relative path, return file not found */
1063     if (PathType == RtlPathTypeRelative)
1064         return ERROR_FILE_NOT_FOUND;
1065 
1066     /* If not, try to open it */
1067     Handle = CreateFile(lpModuleName,
1068                         GENERIC_READ,
1069                         FILE_SHARE_READ | FILE_SHARE_WRITE,
1070                         NULL,
1071                         OPEN_EXISTING,
1072                         FILE_ATTRIBUTE_NORMAL,
1073                         NULL);
1074 
1075     if (Handle != INVALID_HANDLE_VALUE)
1076     {
1077         /* Opening file succeeded for some reason, close the handle and return file not found anyway */
1078         CloseHandle(Handle);
1079         return ERROR_FILE_NOT_FOUND;
1080     }
1081 
1082     /* Return last error which CreateFile set during an attempt to open it */
1083     return GetLastError();
1084 }
1085 
1086 /*
1087  * @unimplemented
1088  */
1089 FARPROC WINAPI DelayLoadFailureHook(LPCSTR pszDllName, LPCSTR pszProcName)
1090 {
1091     STUB;
1092     return NULL;
1093 }
1094 
1095 /*
1096  * @unimplemented
1097  */
1098 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
1099                         LPSTR lpszInitName, LPSTR lpszProcName,
1100                         FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
1101                         LPVOID lpBuff )
1102 {
1103     STUB;
1104     return 0;
1105 }
1106 
1107 /*
1108  * @unimplemented
1109  */
1110 VOID WINAPI UTUnRegister( HMODULE hModule )
1111 {
1112     STUB;
1113 }
1114 
1115 /*
1116  * @unimplemented
1117  */
1118 BOOL
1119 WINAPI
1120 BaseQueryModuleData(IN LPSTR ModuleName,
1121                     IN LPSTR Unknown,
1122                     IN PVOID Unknown2,
1123                     IN PVOID Unknown3,
1124                     IN PVOID Unknown4)
1125 {
1126     DPRINT1("BaseQueryModuleData called: %s %s %p %p %p\n",
1127             ModuleName,
1128             Unknown,
1129             Unknown2,
1130             Unknown3,
1131             Unknown4);
1132     return FALSE;
1133 }
1134 
1135 /*
1136  * @implemented
1137  */
1138 NTSTATUS
1139 WINAPI
1140 BaseProcessInitPostImport(VOID)
1141 {
1142     /* Check if this is a terminal server */
1143     DPRINT1("Post-init called\n");
1144     if (SharedUserData->SuiteMask & VER_SUITE_TERMINAL)
1145     {
1146         /* Initialize TS pointers */
1147         return BasepInitializeTermsrvFpns();
1148     }
1149 
1150     /* FIXME: Initialize TS pointers */
1151     return STATUS_SUCCESS;
1152 }
1153 
1154 /* EOF */
1155