xref: /reactos/dll/win32/kernel32/client/loader.c (revision bd0a5498)
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
BasepInitializeTermsrvFpns(VOID)18 BasepInitializeTermsrvFpns(VOID)
19 {
20     UNIMPLEMENTED;
21     return STATUS_NOT_IMPLEMENTED;
22 }
23 
24 DWORD
25 WINAPI
BasepGetModuleHandleExParameterValidation(DWORD dwFlags,LPCWSTR lpwModuleName,HMODULE * phModule)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
BasepMapModuleHandle(HMODULE hModule,BOOLEAN AsDataFile)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
DisableThreadLibraryCalls(IN HMODULE hLibModule)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
LoadLibraryA(LPCSTR lpLibFileName)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
LoadLibraryExA(LPCSTR lpLibFileName,HANDLE hFile,DWORD dwFlags)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
LoadLibraryW(LPCWSTR lpLibFileName)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
BasepLoadLibraryAsDatafile(PWSTR Path,LPCWSTR Name,HMODULE * hModule)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
LoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags)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
GetProcAddress(HMODULE hModule,LPCSTR lpProcName)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
FreeLibrary(HINSTANCE hLibModule)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
FreeLibraryAndExitThread(HMODULE hLibModule,DWORD dwExitCode)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
GetModuleFileNameA(HINSTANCE hModule,LPSTR lpFilename,DWORD nSize)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
GetModuleFileNameW(HINSTANCE hModule,LPWSTR lpFilename,DWORD nSize)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
GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)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
BasepGetModuleHandleExW(BOOLEAN NoLock,DWORD dwPublicFlags,LPCWSTR lpwModuleName,HMODULE * phModule)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
GetModuleHandleA(LPCSTR lpModuleName)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
GetModuleHandleW(LPCWSTR lpModuleName)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
GetModuleHandleExW(IN DWORD dwFlags,IN LPCWSTR lpwModuleName OPTIONAL,OUT HMODULE * phModule)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
GetModuleHandleExA(IN DWORD dwFlags,IN LPCSTR lpModuleName OPTIONAL,OUT HMODULE * phModule)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
LoadModule(LPCSTR lpModuleName,LPVOID lpParameterBlock)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  */
DelayLoadFailureHook(LPCSTR pszDllName,LPCSTR pszProcName)1083 FARPROC WINAPI DelayLoadFailureHook(LPCSTR pszDllName, LPCSTR pszProcName)
1084 {
1085     STUB;
1086     return NULL;
1087 }
1088 
1089 /*
1090  * @unimplemented
1091  */
UTRegister(HMODULE hModule,LPSTR lpsz16BITDLL,LPSTR lpszInitName,LPSTR lpszProcName,FARPROC * ppfn32Thunk,FARPROC pfnUT32CallBack,LPVOID lpBuff)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  */
UTUnRegister(HMODULE hModule)1104 VOID WINAPI UTUnRegister( HMODULE hModule )
1105 {
1106     STUB;
1107 }
1108 
1109 /*
1110  * @unimplemented
1111  */
1112 BOOL
1113 WINAPI
BaseQueryModuleData(IN LPSTR ModuleName,IN LPSTR Unknown,IN PVOID Unknown2,IN PVOID Unknown3,IN PVOID Unknown4)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
BaseProcessInitPostImport(VOID)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