Skip to content

Commit f7f6356

Browse files
committed
fix: add windows delay hook code
1 parent 17428f7 commit f7f6356

File tree

2 files changed

+89
-10
lines changed

2 files changed

+89
-10
lines changed

CMakeLists.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
6868
cmake_policy(SET CMP0135 NEW)
6969
endif()
7070

71+
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
72+
7173
# Add project_options from https://github.com/aminya/project_options Change the
7274
# version in the following URL to update the package (watch the releases of the
7375
# repository for future updates)
@@ -97,15 +99,8 @@ project(addon LANGUAGES C CXX)
9799

98100
project_options(ENABLE_CACHE ENABLE_COMPILE_COMMANDS_SYMLINK)
99101

100-
add_library(
101-
addon SHARED
102-
"src/context.cc"
103-
"src/incoming_msg.cc"
104-
"src/module.cc"
105-
"src/observer.cc"
106-
"src/outgoing_msg.cc"
107-
"src/proxy.cc"
108-
"src/socket.cc")
102+
file(GLOB_RECURSE SOURCES "./src/*.cc")
103+
add_library(addon SHARED ${SOURCES})
109104

110105
target_link_libraries(addon PRIVATE project_options project_warnings)
111106

@@ -129,12 +124,17 @@ target_compile_definitions(addon PRIVATE V8_31BIT_SMIS_ON_64BIT_ARCH)
129124
target_compile_definitions(addon PRIVATE V8_REVERSE_JSARGS)
130125
target_compile_definitions(addon PRIVATE BUILDING_NODE_EXTENSION)
131126
target_compile_definitions(addon PRIVATE NAPI_CPP_EXCEPTIONS)
127+
if(WIN32)
128+
target_compile_definitions(addon PRIVATE "NOMINMAX")
129+
target_compile_definitions(addon PRIVATE "NOGDI")
130+
target_compile_definitions(addon PRIVATE "WIN32_LEAN_AND_MEAN")
131+
endif()
132132

133133
# Use `.node` for the library without any "lib" prefix
134134
set_target_properties(addon PROPERTIES PREFIX "" SUFFIX ".node")
135135

136136
# Windows workaround
137137
if(WIN32)
138-
set_property(TARGET addon PROPERTY DELAY_LOAD_DLLS "NODE.EXE")
138+
set_property(TARGET addon PROPERTY LINK_FLAGS "-Xlinker /DELAYLOAD:NODE.EXE")
139139
target_link_libraries(addon PRIVATE "ShLwApi.lib" "delayimp.lib")
140140
endif()

src/win_delay_load_hook.cc

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#ifdef _MSC_VER
2+
3+
#ifndef WIN32_LEAN_AND_MEAN
4+
#define WIN32_LEAN_AND_MEAN
5+
#endif
6+
7+
// clang-format off
8+
#include <windows.h>
9+
#include <delayimp.h>
10+
// clang-format on
11+
12+
static HMODULE NODE_DLL = nullptr; // NOLINT(*-avoid-non-const-global-variables)
13+
static HMODULE NW_DLL = nullptr; // NOLINT(*-avoid-non-const-global-variables)
14+
15+
/**
16+
* @brief A hook function for handling delay-loaded DLL events.
17+
*
18+
* This function is called by the delay load helper for various events during the
19+
* delay loading process. It handles pre-loading of libraries, retrieving procedure
20+
* addresses, and initialization tasks.
21+
*
22+
* @param event The delay load event type. Possible values include:
23+
* - dliNotePreGetProcAddress: Called before GetProcAddress is called
24+
* - dliStartProcessing: Called when delay loading begins
25+
* - dliNotePreLoadLibrary: Called before loading a delayed DLL
26+
* @param info A pointer to a DelayLoadInfo structure containing information about
27+
* the DLL being loaded and the requested function.
28+
*
29+
* @return FARPROC A function pointer if the event was handled successfully,
30+
* or nullptr if the event was not handled or an error occurred.
31+
*/
32+
static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {
33+
if (info == nullptr) {
34+
return nullptr;
35+
}
36+
37+
switch (event) {
38+
// If pre-getting a procedure address.
39+
case dliNotePreGetProcAddress: {
40+
const char* procName = info->dlp.szProcName;
41+
if (procName == nullptr) {
42+
return nullptr;
43+
}
44+
FARPROC ret = GetProcAddress(NODE_DLL, procName);
45+
if (ret != nullptr) {
46+
return ret;
47+
}
48+
return GetProcAddress(NW_DLL, procName);
49+
}
50+
// If starting the delay loading process.
51+
case dliStartProcessing: {
52+
NODE_DLL = GetModuleHandleA("node.dll");
53+
NW_DLL = GetModuleHandleA("nw.dll");
54+
return nullptr;
55+
}
56+
// If pre-loading a delayed DLL.
57+
case dliNotePreLoadLibrary: {
58+
if (info->szDll == nullptr) {
59+
return nullptr;
60+
}
61+
if (_stricmp(info->szDll, "node.exe") != 0) {
62+
return nullptr;
63+
}
64+
if (NODE_DLL == nullptr) {
65+
NODE_DLL = GetModuleHandleA(nullptr);
66+
}
67+
// NOLINTNEXTLINE(*-pro-type-reinterpret-cast)
68+
return reinterpret_cast<FARPROC>(NODE_DLL);
69+
}
70+
// Othwese, return nullptr.
71+
default:
72+
return nullptr;
73+
}
74+
}
75+
76+
// NOLINTNEXTLINE(*-avoid-non-const-global-variables,*-reserved-identifier,cert-dcl51-cpp,cert-dcl37-c)
77+
decltype(__pfnDliNotifyHook2) __pfnDliNotifyHook2 = load_exe_hook;
78+
79+
#endif

0 commit comments

Comments
 (0)