[KERNEL32][CONSRV]
[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'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 LoadLibraryA(LPCSTR lpLibFileName)
111 {
112 LPSTR PathBuffer;
113 UINT Len;
114 HINSTANCE Result;
115
116 /* Treat twain_32.dll in a special way (what a surprise...) */
117 if (lpLibFileName && !_strcmpi(lpLibFileName, "twain_32.dll"))
118 {
119 /* Allocate space for the buffer */
120 PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH);
121 if (PathBuffer)
122 {
123 /* Get windows dir in this buffer */
124 Len = GetWindowsDirectoryA(PathBuffer, MAX_PATH - 13); /* 13 is sizeof of '\\twain_32.dll' */
125 if (Len && Len < (MAX_PATH - 13))
126 {
127 /* We successfully got windows directory. Concatenate twain_32.dll to it */
128 strncat(PathBuffer, "\\twain_32.dll", 13);
129
130 /* And recursively call ourselves with a new string */
131 Result = LoadLibraryA(PathBuffer);
132
133 /* If it was successful - free memory and return result */
134 if (Result)
135 {
136 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
137 return Result;
138 }
139 }
140
141 /* Free allocated buffer */
142 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
143 }
144 }
145
146 /* Call the Ex version of the API */
147 return LoadLibraryExA(lpLibFileName, 0, 0);
148 }
149
150 /*
151 * @implemented
152 */
153 HINSTANCE
154 WINAPI
155 LoadLibraryExA(LPCSTR lpLibFileName,
156 HANDLE hFile,
157 DWORD dwFlags)
158 {
159 PUNICODE_STRING FileNameW;
160
161 /* Convert file name to unicode */
162 if (!(FileNameW = Basep8BitStringToStaticUnicodeString(lpLibFileName)))
163 return NULL;
164
165 /* And call W version of the API */
166 return LoadLibraryExW(FileNameW->Buffer, hFile, dwFlags);
167 }
168
169 /*
170 * @implemented
171 */
172 HINSTANCE
173 WINAPI
174 LoadLibraryW(LPCWSTR lpLibFileName)
175 {
176 /* Call Ex version of the API */
177 return LoadLibraryExW (lpLibFileName, 0, 0);
178 }
179
180
181 static
182 NTSTATUS
183 BasepLoadLibraryAsDatafile(PWSTR Path, LPCWSTR Name, HMODULE *hModule)
184 {
185 WCHAR FilenameW[MAX_PATH];
186 HANDLE hFile = INVALID_HANDLE_VALUE;
187 HANDLE hMapping;
188 NTSTATUS Status;
189 PVOID lpBaseAddress = NULL;
190 SIZE_T ViewSize = 0;
191 //PUNICODE_STRING OriginalName;
192 //UNICODE_STRING dotDLL = RTL_CONSTANT_STRING(L".DLL");
193
194 /* Zero out handle value */
195 *hModule = 0;
196
197 DPRINT("BasepLoadLibraryAsDatafile(%S %S %p)\n", Path, Name, hModule);
198
199 /*Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
200 Name,
201 &dotDLL,
202 RedirName,
203 RedirName2,
204 &OriginalName2,
205 NULL,
206 NULL,
207 NULL);*/
208
209 /* Try to search for it */
210 if (!SearchPathW(Path,
211 Name,
212 L".DLL",
213 sizeof(FilenameW) / sizeof(FilenameW[0]),
214 FilenameW,
215 NULL))
216 {
217 /* Return last status value directly */
218 return NtCurrentTeb()->LastStatusValue;
219 }
220
221 /* Open this file we found */
222 hFile = CreateFileW(FilenameW,
223 GENERIC_READ,
224 FILE_SHARE_READ | FILE_SHARE_DELETE,
225 NULL,
226 OPEN_EXISTING,
227 0,
228 0);
229
230 /* If opening failed - return last status value */
231 if (hFile == INVALID_HANDLE_VALUE) return NtCurrentTeb()->LastStatusValue;
232
233 /* Create file mapping */
234 hMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
235
236 /* Close the file handle */
237 CloseHandle(hFile);
238
239 /* If creating file mapping failed - return last status value */
240 if (!hMapping) return NtCurrentTeb()->LastStatusValue;
241
242 /* Map view of section */
243 Status = NtMapViewOfSection(hMapping,
244 NtCurrentProcess(),
245 &lpBaseAddress,
246 0,
247 0,
248 0,
249 &ViewSize,
250 ViewShare,
251 0,
252 PAGE_READONLY);
253
254 /* Close handle to the section */
255 CloseHandle(hMapping);
256
257 /* If mapping view of section failed - return last status value */
258 if (!NT_SUCCESS(Status)) return NtCurrentTeb()->LastStatusValue;
259
260 /* Make sure it's a valid PE file */
261 if (!RtlImageNtHeader(lpBaseAddress))
262 {
263 /* Unmap the view and return failure status */
264 UnmapViewOfFile(lpBaseAddress);
265 return STATUS_INVALID_IMAGE_FORMAT;
266 }
267
268 /* Set low bit of handle to indicate datafile module */
269 *hModule = (HMODULE)((ULONG_PTR)lpBaseAddress | 1);
270
271 /* Load alternate resource module */
272 //LdrLoadAlternateResourceModule(*hModule, FilenameW);
273
274 return STATUS_SUCCESS;
275 }
276
277 /*
278 * @implemented
279 */
280 HINSTANCE
281 WINAPI
282 LoadLibraryExW(LPCWSTR lpLibFileName,
283 HANDLE hFile,
284 DWORD dwFlags)
285 {
286 UNICODE_STRING DllName;
287 HINSTANCE hInst;
288 NTSTATUS Status;
289 PWSTR SearchPath;
290 ULONG DllCharacteristics = 0;
291 BOOL FreeString = FALSE;
292
293 /* Check for any flags LdrLoadDll might be interested in */
294 if (dwFlags & DONT_RESOLVE_DLL_REFERENCES)
295 {
296 /* Tell LDR to treat it as an EXE */
297 DllCharacteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
298 }
299
300 /* Build up a unicode dll name from null-terminated string */
301 RtlInitUnicodeString(&DllName, (LPWSTR)lpLibFileName);
302
303 /* Lazy-initialize BasepExeLdrEntry */
304 if (!BasepExeLdrEntry)
305 LdrEnumerateLoadedModules(0, BasepLocateExeLdrEntry, NtCurrentPeb()->ImageBaseAddress);
306
307 /* Check if that module is our exe*/
308 if (BasepExeLdrEntry && !(dwFlags & LOAD_LIBRARY_AS_DATAFILE) &&
309 DllName.Length == BasepExeLdrEntry->FullDllName.Length)
310 {
311 /* Lengths match and it's not a datafile, so perform name comparison */
312 if (RtlEqualUnicodeString(&DllName, &BasepExeLdrEntry->FullDllName, TRUE))
313 {
314 /* That's us! */
315 return BasepExeLdrEntry->DllBase;
316 }
317 }
318
319 /* Check for trailing spaces and remove them if necessary */
320 if (DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
321 {
322 RtlCreateUnicodeString(&DllName, (LPWSTR)lpLibFileName);
323 while (DllName.Length > sizeof(WCHAR) &&
324 DllName.Buffer[DllName.Length/sizeof(WCHAR) - 1] == L' ')
325 {
326 DllName.Length -= sizeof(WCHAR);
327 }
328 DllName.Buffer[DllName.Length/sizeof(WCHAR)] = UNICODE_NULL;
329 FreeString = TRUE;
330 }
331
332 /* Compute the load path */
333 SearchPath = BaseComputeProcessDllPath((dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) ?
334 DllName.Buffer : NULL,
335 NULL);
336 if (!SearchPath)
337 {
338 /* Getting DLL path failed, so set last error, free mem and return */
339 BaseSetLastNTError(STATUS_NO_MEMORY);
340 if (FreeString) RtlFreeUnicodeString(&DllName);
341 return NULL;
342 }
343
344 _SEH2_TRY
345 {
346 if (dwFlags & LOAD_LIBRARY_AS_DATAFILE)
347 {
348 /* If the image is loaded as a datafile, try to get its handle */
349 Status = LdrGetDllHandleEx(0, SearchPath, NULL, &DllName, (PVOID*)&hInst);
350 if (!NT_SUCCESS(Status))
351 {
352 /* It's not loaded yet - so load it up */
353 Status = BasepLoadLibraryAsDatafile(SearchPath, DllName.Buffer, &hInst);
354 }
355 _SEH2_YIELD(goto done;)
356 }
357
358 /* Call the API Properly */
359 Status = LdrLoadDll(SearchPath,
360 &DllCharacteristics,
361 &DllName,
362 (PVOID*)&hInst);
363 }
364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
365 {
366 Status = _SEH2_GetExceptionCode();
367 } _SEH2_END;
368
369
370 done:
371 /* Free SearchPath buffer */
372 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
373
374 /* Free DllName string if it was dynamically allocated */
375 if (FreeString) RtlFreeUnicodeString(&DllName);
376
377 /* Set last error in failure case */
378 if (!NT_SUCCESS(Status))
379 {
380 BaseSetLastNTError(Status);
381 return NULL;
382 }
383
384 /* Return loaded module handle */
385 return hInst;
386 }
387
388
389 /*
390 * @implemented
391 */
392 FARPROC
393 WINAPI
394 GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
395 {
396 ANSI_STRING ProcedureName, *ProcNamePtr = NULL;
397 FARPROC fnExp = NULL;
398 NTSTATUS Status;
399 PVOID hMapped;
400 ULONG Ordinal = 0;
401
402 if (HIWORD(lpProcName) != 0)
403 {
404 /* Look up by name */
405 RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
406 ProcNamePtr = &ProcedureName;
407 }
408 else
409 {
410 /* Look up by ordinal */
411 Ordinal = (ULONG)lpProcName;
412 }
413
414 /* Map provided handle */
415 hMapped = BasepMapModuleHandle(hModule, FALSE);
416
417 /* Get the proc address */
418 Status = LdrGetProcedureAddress(hMapped,
419 ProcNamePtr,
420 Ordinal,
421 (PVOID*)&fnExp);
422
423 if (!NT_SUCCESS(Status))
424 {
425 BaseSetLastNTError(Status);
426 return NULL;
427 }
428
429 /* Check for a special case when returned pointer is
430 the same as iamge's base address */
431 if (fnExp == hMapped)
432 {
433 /* Set correct error code */
434 if (HIWORD(lpProcName) != 0)
435 BaseSetLastNTError(STATUS_ENTRYPOINT_NOT_FOUND);
436 else
437 BaseSetLastNTError(STATUS_ORDINAL_NOT_FOUND);
438
439 return NULL;
440 }
441
442 /* All good, return procedure pointer */
443 return fnExp;
444 }
445
446
447 /*
448 * @implemented
449 */
450 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
451 {
452 NTSTATUS Status;
453 PIMAGE_NT_HEADERS NtHeaders;
454
455 if (LDR_IS_DATAFILE(hLibModule))
456 {
457 // FIXME: This SEH should go inside RtlImageNtHeader instead
458 _SEH2_TRY
459 {
460 /* This is a LOAD_LIBRARY_AS_DATAFILE module, check if it's a valid one */
461 NtHeaders = RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1));
462 }
463 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
464 {
465 NtHeaders = NULL;
466 } _SEH2_END
467
468 if (NtHeaders)
469 {
470 /* Unmap view */
471 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
472
473 /* Unload alternate resource module */
474 LdrUnloadAlternateResourceModule(hLibModule);
475 }
476 else
477 Status = STATUS_INVALID_IMAGE_FORMAT;
478 }
479 else
480 {
481 /* Just unload it */
482 Status = LdrUnloadDll((PVOID)hLibModule);
483 }
484
485 /* Check what kind of status we got */
486 if (!NT_SUCCESS(Status))
487 {
488 /* Set last error */
489 BaseSetLastNTError(Status);
490
491 /* Return failure */
492 return FALSE;
493 }
494
495 /* Return success */
496 return TRUE;
497 }
498
499
500 /*
501 * @implemented
502 */
503 VOID
504 WINAPI
505 FreeLibraryAndExitThread(HMODULE hLibModule,
506 DWORD dwExitCode)
507 {
508
509 if (LDR_IS_DATAFILE(hLibModule))
510 {
511 /* This is a LOAD_LIBRARY_AS_DATAFILE module */
512 if (RtlImageNtHeader((PVOID)((ULONG_PTR)hLibModule & ~1)))
513 {
514 /* Unmap view */
515 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)((ULONG_PTR)hLibModule & ~1));
516
517 /* Unload alternate resource module */
518 LdrUnloadAlternateResourceModule(hLibModule);
519 }
520 }
521 else
522 {
523 /* Just unload it */
524 LdrUnloadDll((PVOID)hLibModule);
525 }
526
527 /* Exit thread */
528 ExitThread(dwExitCode);
529 }
530
531
532 /*
533 * @implemented
534 */
535 DWORD
536 WINAPI
537 GetModuleFileNameA(HINSTANCE hModule,
538 LPSTR lpFilename,
539 DWORD nSize)
540 {
541 UNICODE_STRING FilenameW;
542 ANSI_STRING FilenameA;
543 NTSTATUS Status;
544 DWORD Length = 0, LengthToCopy;
545
546 /* Allocate a unicode buffer */
547 FilenameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nSize * sizeof(WCHAR));
548 if (!FilenameW.Buffer)
549 {
550 BaseSetLastNTError(STATUS_NO_MEMORY);
551 return 0;
552 }
553
554 /* Call unicode API */
555 FilenameW.Length = (USHORT)GetModuleFileNameW(hModule, FilenameW.Buffer, nSize) * sizeof(WCHAR);
556 FilenameW.MaximumLength = FilenameW.Length + sizeof(WCHAR);
557
558 if (FilenameW.Length)
559 {
560 /* Convert to ansi string */
561 Status = BasepUnicodeStringTo8BitString(&FilenameA, &FilenameW, TRUE);
562 if (!NT_SUCCESS(Status))
563 {
564 /* Set last error, free string and retun failure */
565 BaseSetLastNTError(Status);
566 RtlFreeUnicodeString(&FilenameW);
567 return 0;
568 }
569
570 /* Calculate size to copy */
571 Length = min(nSize, FilenameA.Length);
572
573 /* Include terminating zero */
574 if (nSize > Length)
575 LengthToCopy = Length + 1;
576 else
577 LengthToCopy = nSize;
578
579 /* Now copy back to the caller amount he asked */
580 RtlMoveMemory(lpFilename, FilenameA.Buffer, LengthToCopy);
581
582 /* Free ansi filename */
583 RtlFreeAnsiString(&FilenameA);
584 }
585
586 /* Free unicode filename */
587 RtlFreeHeap(RtlGetProcessHeap(), 0, FilenameW.Buffer);
588
589 /* Return length copied */
590 return Length;
591 }
592
593 /*
594 * @implemented
595 */
596 DWORD
597 WINAPI
598 GetModuleFileNameW(HINSTANCE hModule,
599 LPWSTR lpFilename,
600 DWORD nSize)
601 {
602 PLIST_ENTRY ModuleListHead, Entry;
603 PLDR_DATA_TABLE_ENTRY Module;
604 ULONG Length = 0;
605 ULONG Cookie;
606 PPEB Peb;
607
608 hModule = BasepMapModuleHandle(hModule, FALSE);
609
610 /* Upscale nSize from chars to bytes */
611 nSize *= sizeof(WCHAR);
612
613 _SEH2_TRY
614 {
615 /* We don't use per-thread cur dir now */
616 //PRTL_PERTHREAD_CURDIR PerThreadCurdir = (PRTL_PERTHREAD_CURDIR)teb->NtTib.SubSystemTib;
617
618 Peb = NtCurrentPeb ();
619
620 /* Acquire a loader lock */
621 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
622
623 /* Traverse the module list */
624 ModuleListHead = &Peb->Ldr->InLoadOrderModuleList;
625 Entry = ModuleListHead->Flink;
626 while (Entry != ModuleListHead)
627 {
628 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
629
630 /* Check if this is the requested module */
631 if (Module->DllBase == (PVOID)hModule)
632 {
633 /* Calculate size to copy */
634 Length = min(nSize, Module->FullDllName.MaximumLength);
635
636 /* Copy contents */
637 RtlMoveMemory(lpFilename, Module->FullDllName.Buffer, Length);
638
639 /* Subtract a terminating zero */
640 if (Length == Module->FullDllName.MaximumLength)
641 Length -= sizeof(WCHAR);
642
643 /* Break out of the loop */
644 break;
645 }
646
647 /* Advance to the next entry */
648 Entry = Entry->Flink;
649 }
650 }
651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
652 {
653 BaseSetLastNTError(_SEH2_GetExceptionCode());
654 Length = 0;
655 } _SEH2_END
656
657 /* Release the loader lock */
658 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
659
660 return Length / sizeof(WCHAR);
661 }
662
663 HMODULE
664 WINAPI
665 GetModuleHandleForUnicodeString(PUNICODE_STRING ModuleName)
666 {
667 NTSTATUS Status;
668 PVOID Module;
669 LPWSTR DllPath;
670
671 /* Try to get a handle with a magic value of 1 for DllPath */
672 Status = LdrGetDllHandle((LPWSTR)1, NULL, ModuleName, &Module);
673
674 /* If that succeeded - we're done */
675 if (NT_SUCCESS(Status)) return Module;
676
677 /* If not, then the path should be computed */
678 DllPath = BaseComputeProcessDllPath(NULL, 0);
679 if (!DllPath)
680 {
681 Status = STATUS_NO_MEMORY;
682 }
683 else
684 {
685 _SEH2_TRY
686 {
687 Status = LdrGetDllHandle(DllPath, NULL, ModuleName, &Module);
688 }
689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
690 {
691 /* Fail with the SEH error */
692 Status = _SEH2_GetExceptionCode();
693 }
694 _SEH2_END;
695 }
696
697 /* Free the DllPath */
698 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath);
699
700 /* In case of error set last win32 error and return NULL */
701 if (!NT_SUCCESS(Status))
702 {
703 DPRINT("Failure acquiring DLL module '%wZ' handle, Status 0x%08X\n", ModuleName, Status);
704 BaseSetLastNTError(Status);
705 Module = 0;
706 }
707
708 /* Return module */
709 return (HMODULE)Module;
710 }
711
712 BOOLEAN
713 WINAPI
714 BasepGetModuleHandleExW(BOOLEAN NoLock, DWORD dwPublicFlags, LPCWSTR lpwModuleName, HMODULE *phModule)
715 {
716 DWORD Cookie;
717 NTSTATUS Status = STATUS_SUCCESS, Status2;
718 HANDLE hModule = 0;
719 UNICODE_STRING ModuleNameU;
720 DWORD dwValid;
721 BOOLEAN Redirected = FALSE; // FIXME
722
723 /* Validate parameters */
724 dwValid = BasepGetModuleHandleExParameterValidation(dwPublicFlags, lpwModuleName, phModule);
725 ASSERT(dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_CONTINUE);
726
727 /* Acquire lock if necessary */
728 if (!NoLock)
729 {
730 Status = LdrLockLoaderLock(0, NULL, &Cookie);
731 if (!NT_SUCCESS(Status))
732 {
733 /* Fail */
734 BaseSetLastNTError(Status);
735 if (phModule) *phModule = 0;
736 return NT_SUCCESS(Status);
737 }
738 }
739
740 if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
741 {
742 /* Create a unicode string out of module name */
743 RtlInitUnicodeString(&ModuleNameU, lpwModuleName);
744
745 // FIXME: Do some redirected DLL stuff?
746 if (Redirected)
747 {
748 UNIMPLEMENTED;
749 }
750
751 if (!hModule)
752 {
753 hModule = GetModuleHandleForUnicodeString(&ModuleNameU);
754 if (!hModule)
755 {
756 /* Last error is already set, so just return failure by setting status */
757 Status = STATUS_DLL_NOT_FOUND;
758 goto quickie;
759 }
760 }
761 }
762 else
763 {
764 /* Perform Pc to file header to get module instance */
765 hModule = (HMODULE)RtlPcToFileHeader((PVOID)lpwModuleName,
766 (PVOID*)&hModule);
767
768 /* Check if it succeeded */
769 if (!hModule)
770 {
771 /* Set "dll not found" status and quit */
772 Status = STATUS_DLL_NOT_FOUND;
773 goto quickie;
774 }
775 }
776
777 /* Check if changing reference is not forbidden */
778 if (!(dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
779 {
780 /* Add reference to this DLL */
781 Status = LdrAddRefDll((dwPublicFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_ADDREF_DLL_PIN : 0,
782 hModule);
783 }
784
785 /* Set last error in case of failure */
786 if (!NT_SUCCESS(Status))
787 BaseSetLastNTError(Status);
788
789 quickie:
790 /* Unlock loader lock if it was acquired */
791 if (!NoLock)
792 {
793 Status2 = LdrUnlockLoaderLock(0, Cookie);
794 ASSERT(NT_SUCCESS(Status2));
795 }
796
797 /* Set the module handle to the caller */
798 if (phModule) *phModule = hModule;
799
800 /* Return TRUE on success and FALSE otherwise */
801 return NT_SUCCESS(Status);
802 }
803
804 /*
805 * @implemented
806 */
807 HMODULE
808 WINAPI
809 GetModuleHandleA(LPCSTR lpModuleName)
810 {
811 PUNICODE_STRING ModuleNameW;
812 PTEB pTeb = NtCurrentTeb();
813
814 /* Check if we have no name to convert */
815 if (!lpModuleName)
816 return ((HMODULE)pTeb->ProcessEnvironmentBlock->ImageBaseAddress);
817
818 /* Convert module name to unicode */
819 ModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
820
821 /* Call W version if conversion was successful */
822 if (ModuleNameW)
823 return GetModuleHandleW(ModuleNameW->Buffer);
824
825 /* Return failure */
826 return 0;
827 }
828
829
830 /*
831 * @implemented
832 */
833 HMODULE
834 WINAPI
835 GetModuleHandleW(LPCWSTR lpModuleName)
836 {
837 HMODULE hModule;
838 NTSTATUS Status;
839
840 /* If current module is requested - return it right away */
841 if (!lpModuleName)
842 return ((HMODULE)NtCurrentPeb()->ImageBaseAddress);
843
844 /* Use common helper routine */
845 Status = BasepGetModuleHandleExW(TRUE,
846 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
847 lpModuleName,
848 &hModule);
849
850 /* If it wasn't successful - return 0 */
851 if (!NT_SUCCESS(Status)) hModule = 0;
852
853 /* Return the handle */
854 return hModule;
855 }
856
857
858 /*
859 * @implemented
860 */
861 BOOL
862 WINAPI
863 GetModuleHandleExW(IN DWORD dwFlags,
864 IN LPCWSTR lpwModuleName OPTIONAL,
865 OUT HMODULE* phModule)
866 {
867 NTSTATUS Status;
868 DWORD dwValid;
869 BOOL Ret = FALSE;
870
871 /* Validate parameters */
872 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, lpwModuleName, phModule);
873
874 /* If result is invalid parameter - return failure */
875 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
876
877 /* If result is 2, there is no need to do anything - return success. */
878 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
879
880 /* Use common helper routine */
881 Status = BasepGetModuleHandleExW(FALSE,
882 dwFlags,
883 lpwModuleName,
884 phModule);
885
886 /* Return TRUE in case of success */
887 if (NT_SUCCESS(Status)) Ret = TRUE;
888
889 return Ret;
890 }
891
892 /*
893 * @implemented
894 */
895 BOOL
896 WINAPI
897 GetModuleHandleExA(IN DWORD dwFlags,
898 IN LPCSTR lpModuleName OPTIONAL,
899 OUT HMODULE* phModule)
900 {
901 PUNICODE_STRING lpModuleNameW;
902 DWORD dwValid;
903 BOOL Ret = FALSE;
904 NTSTATUS Status;
905
906 /* Validate parameters */
907 dwValid = BasepGetModuleHandleExParameterValidation(dwFlags, (LPCWSTR)lpModuleName, phModule);
908
909 /* If result is invalid parameter - return failure */
910 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_ERROR) return FALSE;
911
912 /* If result is 2, there is no need to do anything - return success. */
913 if (dwValid == BASEP_GET_MODULE_HANDLE_EX_PARAMETER_VALIDATION_SUCCESS) return TRUE;
914
915 /* Check if we don't need to convert the name */
916 if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
917 {
918 /* Call the extended version of the API without conversion */
919 Status = BasepGetModuleHandleExW(FALSE,
920 dwFlags,
921 (LPCWSTR)lpModuleName,
922 phModule);
923 }
924 else
925 {
926 /* Convert module name to unicode */
927 lpModuleNameW = Basep8BitStringToStaticUnicodeString(lpModuleName);
928
929 /* Return FALSE if conversion failed */
930 if (!lpModuleNameW) return FALSE;
931
932 /* Call the extended version of the API */
933 Status = BasepGetModuleHandleExW(FALSE,
934 dwFlags,
935 lpModuleNameW->Buffer,
936 phModule);
937 }
938
939 /* If result was successful - return true */
940 if (NT_SUCCESS(Status))
941 Ret = TRUE;
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 */