Skip to content

Commit ff87209

Browse files
committed
[REACTOS] Delay-load the setuplib DLL and control the path it's loaded from.
The setuplib DLL, used also by the text-mode USETUP, isn't placed in the standard DLL search paths list. It isn't in the "current" directory nor in the one where reactos.exe is, nor in the running OS' SystemRoot or System32 directories. The DLL is instead placed in the System32 sub-directory of the ReactOS installation source. Note that this isn't a problem for USETUP, because it is already started from that directory. To control its loading, delay-load the DLL and use a delay-load hook, following the technique explained in: https://stackoverflow.com/a/75325443 https://devblogs.microsoft.com/oldnewthing/20170126-00/?p=95265 The hook is also invoked in case of loading failure, showing a more user-friendly hard-error popup and killing the installer, instead of throwing a debugger exception.
1 parent fa92d95 commit ff87209

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

base/setup/reactos/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ add_pch(reactos reactos.h SOURCE)
2222
set_module_type(reactos win32gui UNICODE)
2323
target_link_libraries(reactos uuid)
2424
target_link_libraries(reactos zlib_solo) ## We use USETUP's cabinet implementation
25-
add_importlibs(reactos advapi32 gdi32 user32 comctl32 shlwapi setupapi setuplib msvcrt kernel32 ntdll)
25+
add_delay_importlibs(reactos setuplib)
26+
add_importlibs(reactos advapi32 gdi32 user32 comctl32 shlwapi setupapi msvcrt kernel32 ntdll)
2627
add_cd_file(TARGET reactos DESTINATION reactos NO_CAB FOR bootcd)

base/setup/reactos/reactos.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2838,6 +2838,132 @@ HotkeyThread(LPVOID Parameter)
28382838
return 0;
28392839
}
28402840

2841+
2842+
static PCWSTR
2843+
GetLocalSetupDllPath(VOID)
2844+
{
2845+
static WCHAR SetupDllPath[MAX_PATH] = L"";
2846+
static BOOL Init = FALSE;
2847+
BOOL Success;
2848+
DWORD PathSize;
2849+
2850+
/* Don't rebuild the path if we did it already */
2851+
if (Init)
2852+
return SetupDllPath;
2853+
Init = TRUE;
2854+
2855+
/*
2856+
* Retrieve the full path of the current running Setup instance.
2857+
* From this we build the suitable path to the Setup DLL.
2858+
*/
2859+
PathSize = GetModuleFileNameW(NULL, SetupDllPath, _countof(SetupDllPath));
2860+
SetupDllPath[_countof(SetupDllPath) - 1] = UNICODE_NULL; // Ensure NULL-termination (see WinXP bug)
2861+
2862+
Success = ((PathSize != 0) && (PathSize < _countof(SetupDllPath)) &&
2863+
(GetLastError() != ERROR_INSUFFICIENT_BUFFER));
2864+
if (Success)
2865+
{
2866+
/* Find the last path separator, remove it as well as the file name */
2867+
PWCHAR pch = wcsrchr(SetupDllPath, L'\\');
2868+
if (!pch)
2869+
pch = SetupDllPath;
2870+
2871+
/* The Setup DLL is inside the System32 sub-directory */
2872+
PathSize = _countof(SetupDllPath) - (pch - SetupDllPath);
2873+
Success = SUCCEEDED(StringCchCopyW(pch, PathSize, L"\\system32"));
2874+
}
2875+
if (!Success)
2876+
{
2877+
/* Failure: invalidate the path; the DLL won't be found and delay-loaded */
2878+
*SetupDllPath = UNICODE_NULL;
2879+
}
2880+
2881+
return SetupDllPath;
2882+
}
2883+
2884+
#ifndef DECLARE_UNICODE_STRING_SIZE
2885+
#define DECLARE_UNICODE_STRING_SIZE(_var, _size) \
2886+
WCHAR _var ## _buffer[_size]; \
2887+
UNICODE_STRING _var = { 0, (_size) * sizeof(WCHAR) , _var ## _buffer }
2888+
#endif
2889+
#include <ndk/exfuncs.h> // For NtRaiseHardError()
2890+
#define DELAYIMP_INSECURE_WRITABLE_HOOKS
2891+
#include <delayimp.h>
2892+
2893+
/**
2894+
* @brief
2895+
* Controls the delay-loading of Setup DLLs from a suitable path.
2896+
*
2897+
* @see
2898+
* https://stackoverflow.com/a/75325443
2899+
* https://devblogs.microsoft.com/oldnewthing/20170126-00/?p=95265
2900+
**/
2901+
static FARPROC
2902+
WINAPI setupDelayHook(unsigned dliNotify, PDelayLoadInfo pdli)
2903+
{
2904+
static CHAR dllPath[MAX_PATH];
2905+
static PCWSTR setupDllPath = NULL;
2906+
2907+
switch (dliNotify)
2908+
{
2909+
case dliNotePreLoadLibrary:
2910+
{
2911+
// NOTE: Add any other needed setup-specific DLLs there.
2912+
if (_stricmp(pdli->szDll, "setuplib.dll") == 0)
2913+
{
2914+
if (!setupDllPath)
2915+
setupDllPath = GetLocalSetupDllPath();
2916+
if (setupDllPath && *setupDllPath &&
2917+
SUCCEEDED(StringCchPrintfA(dllPath, _countof(dllPath), "%S\\%s",
2918+
setupDllPath, pdli->szDll)))
2919+
{
2920+
pdli->szDll = dllPath; /* Set szDll to the new path */
2921+
}
2922+
}
2923+
break; /* Load the DLL using the modified path */
2924+
}
2925+
2926+
case dliFailLoadLib:
2927+
{
2928+
/*
2929+
* Library loading failed.
2930+
* Raise a hard error instead of the default
2931+
* exception, and "cleanly" kill the process.
2932+
*/
2933+
ANSI_STRING DllPathA;
2934+
DECLARE_UNICODE_STRING_SIZE(DllPathU, MAX_PATH);
2935+
ULONG_PTR Parameters[] = {(ULONG_PTR)&DllPathU};
2936+
ULONG Response;
2937+
2938+
RtlInitAnsiString(&DllPathA, pdli->szDll);
2939+
RtlAnsiStringToUnicodeString(&DllPathU, &DllPathA, FALSE);
2940+
NtRaiseHardError(STATUS_DLL_NOT_FOUND | HARDERROR_OVERRIDE_ERRORMODE,
2941+
_countof(Parameters),
2942+
0x1,
2943+
Parameters,
2944+
OptionOk,
2945+
&Response);
2946+
ExitProcess(-1);
2947+
break;
2948+
}
2949+
2950+
default:
2951+
break;
2952+
}
2953+
2954+
return NULL;
2955+
}
2956+
2957+
/**
2958+
* @brief
2959+
* Custom delay-loading hooks for loading the Setup DLLs from a suitable path.
2960+
**/
2961+
// NOTE: MSVC 2015 Update 3 makes this a const variable.
2962+
// #if (_MSC_VER > 1900) || (_MSC_VER == 1900 && _MSC_FULL_VER >= 190024210) ...
2963+
/*ExternC*/ PfnDliHook __pfnDliNotifyHook2 = setupDelayHook;
2964+
/*ExternC*/ PfnDliHook __pfnDliFailureHook2 = setupDelayHook;
2965+
2966+
28412967
int WINAPI
28422968
_tWinMain(HINSTANCE hInst,
28432969
HINSTANCE hPrevInstance,

0 commit comments

Comments
 (0)