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