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