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