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