ReactOS 0.4.16-dev-983-g23ad936
DllLoadNotification.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Test for DLL Load Notification API
5 * COPYRIGHT: Copyright 2024 Ratin Gao <ratin@knsoft.org>
6 */
7
8#define UNICODE
9
10#include "precomp.h"
11
12#include <winuser.h>
13
17static volatile LONG g_lDllLoadCount = 0;
18
19typedef
24 _In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
27
28typedef
33
35 _In_z_ PCWSTR SavePath,
36 _In_ PCWSTR ResourceType,
37 _In_ PCWSTR ResourceName)
38{
39 BOOL bSuccess;
40 DWORD dwWritten, dwSize;
41 HGLOBAL hGlobal;
44 HRSRC hRsrc;
45
46 /* Load resource */
47 if ((hRsrc = FindResourceW(NULL, ResourceName, ResourceType)) == NULL ||
48 (dwSize = SizeofResource(NULL, hRsrc)) == 0 ||
49 (hGlobal = LoadResource(NULL, hRsrc)) == NULL ||
50 (pData = LockResource(hGlobal)) == NULL)
51 {
52 return FALSE;
53 }
54
55 /* Save to file */
56 hFile = CreateFileW(SavePath,
59 NULL,
62 NULL);
64 {
65 return FALSE;
66 }
67 bSuccess = WriteFile(hFile, pData, dwSize, &dwWritten, NULL);
69 if (!bSuccess)
70 {
71 return FALSE;
72 }
73 else if (dwWritten != dwSize)
74 {
75 trace("Extract resource failed, written size (%lu) is not actual size (%lu)\n", dwWritten, dwSize);
76 DeleteFileW(SavePath);
78 return FALSE;
79 }
80 return TRUE;
81}
82
84 _In_ ULONG NotificationReason,
87{
88 LONG lRet;
89 HMODULE* phNotifiedDllBase = Context;
90
91 /*
92 * Verify the data,
93 * NotificationData->Loaded and NotificationData->Unloaded currently are the same.
94 */
95
96 /* Verify the FullDllName and BaseDllName */
97 ok_eq_ulong(NotificationData->Loaded.Flags, 0UL);
98 lRet = RtlCompareUnicodeString(NotificationData->Loaded.FullDllName,
100 TRUE);
101 ok_eq_long(lRet, 0L);
102 lRet = RtlCompareUnicodeString(NotificationData->Loaded.BaseDllName,
104 TRUE);
105 ok_eq_long(lRet, 0L);
106
107 /*
108 * Verify SizeOfImage and read SizeOfImage from PE header,
109 * make sure the DLL is not unmapped, the memory is still accessible.
110 */
111 ok_eq_ulong(NotificationData->Loaded.SizeOfImage,
112 RtlImageNtHeader(NotificationData->Loaded.DllBase)->OptionalHeader.SizeOfImage);
113
114 /* Reason can be load or unload */
115 ok(NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED ||
116 NotificationReason == LDR_DLL_NOTIFICATION_REASON_UNLOADED, "Incorrect NotificationReason\n");
117 if (NotificationReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
118 {
119 *phNotifiedDllBase = NotificationData->Loaded.DllBase;
121 }
122 else if (NotificationReason == LDR_DLL_NOTIFICATION_REASON_UNLOADED)
123 {
125 }
126}
127
128START_TEST(DllLoadNotification)
129{
132 HMODULE hNtDll, hTestDll, hNotifiedDllBase;
133 FN_LdrRegisterDllNotification* pfnLdrRegisterDllNotification;
134 FN_LdrUnregisterDllNotification* pfnLdrUnregisterDllNotification;
136 PVOID Cookie1, Cookie2;
137
138 /* Load functions */
139 hNtDll = GetModuleHandleW(L"ntdll.dll");
140 if (hNtDll == NULL)
141 {
142 skip("GetModuleHandleW for ntdll failed with 0x%08lX\n", GetLastError());
143 return;
144 }
145 pfnLdrRegisterDllNotification = (FN_LdrRegisterDllNotification*)GetProcAddress(hNtDll, "LdrRegisterDllNotification");
146 pfnLdrUnregisterDllNotification = (FN_LdrUnregisterDllNotification*)GetProcAddress(hNtDll, "LdrUnregisterDllNotification");
147 if (!pfnLdrRegisterDllNotification || !pfnLdrUnregisterDllNotification)
148 {
149 skip("ntdll.dll!Ldr[Un]RegisterDllNotification not found\n");
150 return;
151 }
152
153 /* Extract DLL to temp directory */
155 {
156 skip("GetTempPathW failed with 0x%08lX\n", GetLastError());
157 return;
158 }
159 if (GetTempFileNameW(szTempPath, L"DLN", 0, g_szDllPath) == 0)
160 {
161 skip("GetTempFileNameW failed with 0x%08lX\n", GetLastError());
162 return;
163 }
165 pszDllName = wcsrchr(g_szDllPath, L'\\') + 1;
166 if (pszDllName == NULL)
167 {
168 skip("Find file name of %ls failed\n", g_szDllPath);
169 return;
170 }
173 {
174 skip("ExtractResource failed with 0x%08lX\n", GetLastError());
175 return;
176 }
177
178 /* Register DLL load notification callback */
179 hNotifiedDllBase = NULL;
180 Cookie1 = NULL;
181 Cookie2 = NULL;
182 Status = pfnLdrRegisterDllNotification(0, DllLoadCallback, &hNotifiedDllBase, &Cookie1);
184 ok(Cookie1 != NULL, "Cookie1 is NULL\n");
185
186 /* Register the callback again is valid */
187 Status = pfnLdrRegisterDllNotification(0, DllLoadCallback, &hNotifiedDllBase, &Cookie2);
189 ok(Cookie2 != NULL, "Cookie2 is NULL\n");
190
191 /* Load the test DLL */
192 hTestDll = LoadLibraryW(g_szDllPath);
193 if (!hTestDll)
194 {
195 skip("LoadLibraryW failed with 0x%08lX\n", GetLastError());
196 goto _exit;
197 }
198
199 /* Verify the Dll base received in callback and returned via context */
200 ok_eq_pointer(hNotifiedDllBase, hTestDll);
201
202 /* The count should be 2 because the callback was registered twice */
204
205 /*
206 * Callback will not be triggered because following
207 * load and unload actions change the DLL reference count only
208 */
211 FreeLibrary(hTestDll);
213
214 /* Unregister the callback once */
215 Status = pfnLdrUnregisterDllNotification(Cookie1);
217
218 /* Unload the test DLL */
219 if (FreeLibrary(hTestDll))
220 {
221 /* The count will decrease 1 because the last callback still there */
223 }
224 else
225 {
226 skip("FreeLibrary failed with 0x%08lX\n", GetLastError());
227 }
228
229 /* Unregister the last callback */
230 Status = pfnLdrUnregisterDllNotification(Cookie2);
232
233_exit:
235}
static volatile LONG g_lDllLoadCount
static WCHAR g_szDllPath[MAX_PATH]
static UNICODE_STRING g_usDllPath
static UNICODE_STRING g_usDllName
static BOOL ExtractResource(_In_z_ PCWSTR SavePath, _In_ PCWSTR ResourceType, _In_ PCWSTR ResourceName)
NTSTATUS NTAPI FN_LdrUnregisterDllNotification(_In_ PVOID Cookie)
static VOID NTAPI DllLoadCallback(_In_ ULONG NotificationReason, _In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData, _In_opt_ PVOID Context)
NTSTATUS NTAPI FN_LdrRegisterDllNotification(_In_ ULONG Flags, _In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, _In_opt_ PVOID Context, _Out_ PVOID *Cookie)
void _exit(int exitcode)
Definition: _exit.c:25
#define ok_eq_pointer(value, expected)
Definition: apitest.h:40
#define ok_eq_ulong(value, expected)
Definition: apitest.h:44
#define ok_eq_long(value, expected)
Definition: apitest.h:43
#define ok_eq_bool(value, expected)
Definition: apitest.h:61
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define CloseHandle
Definition: compat.h:739
#define wcsrchr
Definition: compat.h:16
#define SetLastError(x)
Definition: compat.h:752
#define GetProcAddress(x, y)
Definition: compat.h:753
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define FreeLibrary(x)
Definition: compat.h:748
#define RtlImageNtHeader
Definition: compat.h:806
#define MAX_PATH
Definition: compat.h:34
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define LoadLibraryW(x)
Definition: compat.h:747
#define FILE_SHARE_READ
Definition: compat.h:136
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
DWORD WINAPI GetTempPathW(IN DWORD count, OUT LPWSTR path)
Definition: path.c:2080
HRSRC WINAPI FindResourceW(HINSTANCE hModule, LPCWSTR name, LPCWSTR type)
Definition: res.c:176
DWORD WINAPI SizeofResource(HINSTANCE hModule, HRSRC hRsrc)
Definition: res.c:568
LPVOID WINAPI LockResource(HGLOBAL handle)
Definition: res.c:550
HGLOBAL WINAPI LoadResource(HINSTANCE hModule, HRSRC hRsrc)
Definition: res.c:532
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
UINT WINAPI GetTempFileNameW(IN LPCWSTR lpPathName, IN LPCWSTR lpPrefixString, IN UINT uUnique, OUT LPWSTR lpTempFileName)
Definition: filename.c:84
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:25
#define LDR_DLL_NOTIFICATION_REASON_UNLOADED
Definition: ldrtypes.h:204
#define LDR_DLL_NOTIFICATION_REASON_LOADED
Definition: ldrtypes.h:203
VOID(NTAPI * PLDR_DLL_NOTIFICATION_FUNCTION)(_In_ ULONG NotificationReason, _In_ PCLDR_DLL_NOTIFICATION_DATA NotificationData, _In_opt_ PVOID Context)
Definition: ldrtypes.h:232
#define CREATE_ALWAYS
Definition: disk.h:72
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
static char szTempPath[MAX_PATH]
Definition: data.c:16
_In_ HANDLE hFile
Definition: mswsock.h:90
#define _In_z_
Definition: no_sal2.h:164
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define GENERIC_WRITE
Definition: nt_native.h:90
#define L(x)
Definition: ntvdm.h:50
#define RT_RCDATA
Definition: pedump.c:372
long LONG
Definition: pedump.c:60
char * pszDllName
Definition: spec2def.c:74
#define UL
Definition: tui.h:164
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG
Definition: typedefs.h:59
_In_ PCWDF_DEVICE_PNP_NOTIFICATION_DATA NotificationData
Definition: wdfdevice.h:782
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define ERROR_INCORRECT_SIZE
Definition: winerror.h:943
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_opt_ PVOID _Out_ PLARGE_INTEGER Cookie
Definition: cmfuncs.h:14
__wchar_t WCHAR
Definition: xmlstorage.h:180