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