Sync with trunk r62754.
[reactos.git] / 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'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 = 0;
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 = 0;
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 /* Set last error in case of failure */
793 if (!NT_SUCCESS(Status))
794 BaseSetLastNTError(Status);
795
796 quickie:
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 NTSTATUS Status;
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 Status = BasepGetModuleHandleExW(TRUE,
854 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
855 lpModuleName,
856 &hModule);
857
858 /* If it wasn't successful - return 0 */
859 if (!NT_SUCCESS(Status)) hModule = 0;
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 NTSTATUS Status;
876 DWORD dwValid;
877 BOOL Ret = FALSE;
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 Status = BasepGetModuleHandleExW(FALSE,
890 dwFlags,
891 lpwModuleName,
892 phModule);
893
894 /* Return TRUE in case of success */
895 if (NT_SUCCESS(Status)) Ret = TRUE;
896
897 return Ret;
898 }
899
900 /*
901 * @implemented
902 */
903 BOOL
904 WINAPI
905 GetModuleHandleExA(IN DWORD dwFlags,
906 IN LPCSTR lpModuleName OPTIONAL,
907 OUT HMODULE* phModule)
908 {
909 PUNICODE_STRING lpModuleNameW;
910 DWORD dwValid;
911 BOOL Ret = FALSE;
912 NTSTATUS Status;
913
914 /* Validate parameters */
915 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
916
917 /* If result is invalid parameter - return failure */
918 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
919
920 /* If result is 2, there is no need to do anything - return success. */
921 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
922
923 /* Check if we don't need to convert the name */
924 if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
925 {
926 /* Call the extended version of the API without conversion */
927 Status = BasepGetModuleHandleExW(FALSE,
928 dwFlags,
929 (LPCWSTR)lpModuleName,
930 phModule);
931 }
932 else
933 {
934 /* Convert module name to unicode */
935 lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
936
937 /* Return FALSE if conversion failed */
938 if (!lpModuleNameW) return FALSE;
939
940 /* Call the extended version of the API */
941 Status = BasepGetModuleHandleExW(FALSE,
942 dwFlags,
943 lpModuleNameW->Buffer,
944 phModule);
945 }
946
947 /* If result was successful - return true */
948 if (NT_SUCCESS(Status))
949 Ret = TRUE;
950
951 /* Return result */
952 return Ret;
953 }
954
955
956 /*
957 * @implemented
958 */
959 DWORD
960 WINAPI
961 LoadModule(LPCSTR lpModuleName,
962 LPVOID lpParameterBlock)
963 {
964 STARTUPINFOA StartupInfo;
965 PROCESS_INFORMATION ProcessInformation;
966 LOADPARMS32 *LoadParams;
967 char FileName[MAX_PATH];
968 LPSTR CommandLine;
969 DWORD Length, Error;
970 BOOL ProcessStatus;
971 ANSI_STRING AnsiStr;
972 UNICODE_STRING UnicStr;
973 RTL_PATH_TYPE PathType;
974 HANDLE Handle;
975
976 LoadParams = (LOADPARMS32*)lpParameterBlock;
977
978 /* Check load parameters */
979 if (LoadParams->dwReserved || LoadParams->wMagicValue != 2)
980 {
981 /* Fail with invalid param error */
982 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
983 return 0;
984 }
985
986 /* Search path */
987 Length = SearchPathA(NULL, lpModuleName, ".exe", MAX_PATH, FileName, NULL);
988
989 /* Check if path was found */
990 if (Length && Length < MAX_PATH)
991 {
992 /* Build StartupInfo */
993 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
994
995 StartupInfo.cb = sizeof(STARTUPINFOA);
996 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
997 StartupInfo.wShowWindow = LoadParams->wCmdShow;
998
999 /* Allocate command line buffer */
1000 CommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
1001 HEAP_ZERO_MEMORY,
1002 (ULONG)LoadParams->lpCmdLine[0] + Length + 2);
1003
1004 /* Put module name there, then a space, and then copy provided command line,
1005 and null-terminate it */
1006 RtlCopyMemory(CommandLine, FileName, Length);
1007 CommandLine[Length] = ' ';
1008 RtlCopyMemory(&CommandLine[Length + 1], &LoadParams->lpCmdLine[1], (ULONG)LoadParams->lpCmdLine[0]);
1009 CommandLine[Length + 1 + (ULONG)LoadParams->lpCmdLine[0]] = 0;
1010
1011 /* Create the process */
1012 ProcessStatus = CreateProcessA(FileName,
1013 CommandLine,
1014 NULL,
1015 NULL,
1016 FALSE,
1017 0,
1018 LoadParams->lpEnvAddress,
1019 NULL,
1020 &StartupInfo,
1021 &ProcessInformation);
1022
1023 /* Free the command line buffer */
1024 RtlFreeHeap(RtlGetProcessHeap(), 0, CommandLine);
1025
1026 if (!ProcessStatus)
1027 {
1028 /* Creating process failed, return right error code */
1029 Error = GetLastError();
1030 switch(Error)
1031 {
1032 case ERROR_BAD_EXE_FORMAT:
1033 return ERROR_BAD_FORMAT;
1034
1035 case ERROR_FILE_NOT_FOUND:
1036 case ERROR_PATH_NOT_FOUND:
1037 return Error;
1038 }
1039
1040 /* Return 0 otherwise */
1041 return 0;
1042 }
1043
1044 /* Wait up to 30 seconds for the process to become idle */
1045 if (UserWaitForInputIdleRoutine)
1046 {
1047 UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 30000);
1048 }
1049
1050 /* Close handles */
1051 NtClose(ProcessInformation.hThread);
1052 NtClose(ProcessInformation.hProcess);
1053
1054 /* Return magic success value (33) */
1055 return 33;
1056 }
1057
1058 /* The path was not found, create an ansi string from
1059 the module name and convert it to unicode */
1060 RtlInitAnsiString(&AnsiStr, lpModuleName);
1061 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicStr,&AnsiStr,TRUE)))
1062 return ERROR_FILE_NOT_FOUND;
1063
1064 /* Determine path type */
1065 PathType = RtlDetermineDosPathNameType_U(UnicStr.Buffer);
1066
1067 /* Free the unicode module name */
1068 RtlFreeUnicodeString(&UnicStr);
1069
1070 /* If it's a relative path, return file not found */
1071 if (PathType == RtlPathTypeRelative)
1072 return ERROR_FILE_NOT_FOUND;
1073
1074 /* If not, try to open it */
1075 Handle = CreateFile(lpModuleName,
1076 GENERIC_READ,
1077 FILE_SHARE_READ | FILE_SHARE_WRITE,
1078 NULL,
1079 OPEN_EXISTING,
1080 FILE_ATTRIBUTE_NORMAL,
1081 NULL);
1082
1083 if (Handle != INVALID_HANDLE_VALUE)
1084 {
1085 /* Opening file succeeded for some reason, close the handle and return file not found anyway */
1086 CloseHandle(Handle);
1087 return ERROR_FILE_NOT_FOUND;
1088 }
1089
1090 /* Return last error which CreateFile set during an attempt to open it */
1091 return GetLastError();
1092 }
1093
1094 /*
1095 * @unimplemented
1096 */
1097 FARPROC WINAPI DelayLoadFailureHook(LPCSTR pszDllName, LPCSTR pszProcName)
1098 {
1099 STUB;
1100 return NULL;
1101 }
1102
1103 /*
1104 * @unimplemented
1105 */
1106 BOOL WINAPI UTRegister( HMODULE hModule, LPSTR lpsz16BITDLL,
1107 LPSTR lpszInitName, LPSTR lpszProcName,
1108 FARPROC *ppfn32Thunk, FARPROC pfnUT32CallBack,
1109 LPVOID lpBuff )
1110 {
1111 STUB;
1112 return 0;
1113 }
1114
1115 /*
1116 * @unimplemented
1117 */
1118 VOID WINAPI UTUnRegister( HMODULE hModule )
1119 {
1120 STUB;
1121 }
1122
1123 /*
1124 * @unimplemented
1125 */
1126 BOOL
1127 WINAPI
1128 BaseQueryModuleData(IN LPSTR ModuleName,
1129 IN LPSTR Unknown,
1130 IN PVOID Unknown2,
1131 IN PVOID Unknown3,
1132 IN PVOID Unknown4)
1133 {
1134 DPRINT1("BaseQueryModuleData called: %s %s %p %p %p\n",
1135 ModuleName,
1136 Unknown,
1137 Unknown2,
1138 Unknown3,
1139 Unknown4);
1140 return FALSE;
1141 }
1142
1143 /*
1144 * @implemented
1145 */
1146 NTSTATUS
1147 WINAPI
1148 BaseProcessInitPostImport(VOID)
1149 {
1150 /* Check if this is a terminal server */
1151 DPRINT1("Post-init called\n");
1152 if (SharedUserData->SuiteMask & VER_SUITE_TERMINAL)
1153 {
1154 /* Initialize TS pointers */
1155 return BasepInitializeTermsrvFpns();
1156 }
1157
1158 /* FIXME: Initialize TS pointers */
1159 return STATUS_SUCCESS;
1160 }
1161
1162 /* EOF */