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