1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: win32ss/user/user32/misc/usrapihk.c
5 * PURPOSE: User32.dll User32 Api Hook interface and support functions
6 * PROGRAMMER:
7 *
8 *
9 *
10 * Information:
11 * https://reactos.org/wiki/RegisterUserApiHook
12 *
13 */
14
15 #include <user32.h>
16
17 WINE_DEFAULT_DEBUG_CHANNEL(user32);
18
19 BOOL WINAPI RealAdjustWindowRectEx(LPRECT,DWORD,BOOL,DWORD);
20 LRESULT WINAPI RealDefWindowProcA(HWND,UINT,WPARAM,LPARAM);
21 LRESULT WINAPI RealDefWindowProcW(HWND,UINT,WPARAM,LPARAM);
22 BOOL WINAPI RealDrawFrameControl(HDC,LPRECT,UINT,UINT);
23 BOOL WINAPI RealGetScrollInfo(HWND,INT,LPSCROLLINFO);
24 int WINAPI RealGetSystemMetrics(int);
25 BOOL WINAPI RealMDIRedrawFrame(HWND,DWORD);
26 INT WINAPI RealSetScrollInfo(HWND,int,LPCSCROLLINFO,BOOL);
27 BOOL WINAPI RealSystemParametersInfoA(UINT,UINT,PVOID,UINT);
28 BOOL WINAPI RealSystemParametersInfoW(UINT,UINT,PVOID,UINT);
29 DWORD WINAPI GetRealWindowOwner(HWND);
30 BOOL WINAPI RealUserDrawCaption(HWND hWnd, HDC hDC, LPCRECT lpRc, UINT uFlags);
31
32 /* GLOBALS *******************************************************************/
33
34 DWORD gcLoadUserApiHook = 0;
35 LONG gcCallUserApiHook = 0;
36 DWORD gfUserApiHook = 0;
37 HINSTANCE ghmodUserApiHook = NULL;
38 USERAPIHOOKPROC gpfnInitUserApi;
39 RTL_CRITICAL_SECTION gcsUserApiHook;
40 // API Hooked Message group bitmaps
41 BYTE grgbDwpLiteHookMsg[128];
42 BYTE grgbWndLiteHookMsg[128];
43 BYTE grgbDlgLiteHookMsg[128];
44
45 /* INTERNAL ******************************************************************/
46
47 /*
48 Pre and Post Message handler stub.
49 */
50 LRESULT
51 WINAPI
DefaultOWP(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam,ULONG_PTR lResult,PDWORD pData)52 DefaultOWP(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR lResult, PDWORD pData)
53 {
54 return 0;
55 }
56
57 /*
58 Check for API Hooked Message Overrides. Using message bitmapping.. One bit
59 corresponds to one message number.
60 */
61 BOOL
62 FASTCALL
IsMsgOverride(UINT Msg,PUAHOWP puaowpOverride)63 IsMsgOverride( UINT Msg, PUAHOWP puaowpOverride)
64 {
65 UINT nMsg = Msg / 8; // Group Indexed, (Msg 1024) / 8 = (0 -> 127) bytes Max
66
67 if ( puaowpOverride && nMsg < puaowpOverride->Size )
68 {
69 return (puaowpOverride->MsgBitArray[nMsg] & (1 << (Msg & WM_SETFOCUS)));
70 }
71 return FALSE;
72 }
73
74 VOID
75 FASTCALL
CopyMsgMask(PUAHOWP Dest,PUAHOWP Src,PVOID hkmsg,DWORD Size)76 CopyMsgMask(PUAHOWP Dest, PUAHOWP Src, PVOID hkmsg, DWORD Size)
77 {
78 DWORD nSize;
79
80 if ( Src && Src->Size > 0 )
81 {
82 Dest->MsgBitArray = hkmsg;
83 nSize = Src->Size;
84 if ( Size < nSize) nSize = Size;
85 Dest->Size = nSize;
86 RtlCopyMemory(Dest->MsgBitArray, Src->MsgBitArray, nSize);
87 return;
88 }
89
90 Dest->MsgBitArray = NULL;
91 Dest->Size = 0;
92 return;
93 }
94
95
96 BOOL
97 FASTCALL
IsInsideUserApiHook(VOID)98 IsInsideUserApiHook(VOID)
99 {
100 if ( ghmodUserApiHook && gfUserApiHook ) return TRUE;
101 return FALSE;
102 }
103
104 BOOL
105 FASTCALL
BeginIfHookedUserApiHook(VOID)106 BeginIfHookedUserApiHook(VOID)
107 {
108 InterlockedIncrement(&gcCallUserApiHook);
109 if (IsInsideUserApiHook()) return TRUE;
110
111 InterlockedDecrement(&gcCallUserApiHook);
112 return FALSE;
113 }
114
115 BOOL
116 WINAPI
ForceResetUserApiHook(HINSTANCE hInstance)117 ForceResetUserApiHook(HINSTANCE hInstance)
118 {
119 if ( ghmodUserApiHook == hInstance &&
120 RtlIsThreadWithinLoaderCallout() )
121 {
122 ResetUserApiHook(&guah);
123 gpfnInitUserApi = NULL;
124 return TRUE;
125 }
126 return FALSE;
127 }
128
129 VOID
130 FASTCALL
ResetUserApiHook(PUSERAPIHOOK puah)131 ResetUserApiHook(PUSERAPIHOOK puah)
132 {
133 // Setup Structure.....
134 puah->size = sizeof(USERAPIHOOK);
135 puah->DefWindowProcA = RealDefWindowProcA;
136 puah->DefWindowProcW = RealDefWindowProcW;
137 puah->DefWndProcArray.MsgBitArray = NULL;
138 puah->DefWndProcArray.Size = 0;
139 puah->GetScrollInfo = RealGetScrollInfo;
140 puah->SetScrollInfo = RealSetScrollInfo;
141 puah->EnableScrollBar = NtUserEnableScrollBar;
142 puah->AdjustWindowRectEx = RealAdjustWindowRectEx;
143 puah->SetWindowRgn = NtUserSetWindowRgn;
144 puah->PreWndProc = DefaultOWP;
145 puah->PostWndProc = DefaultOWP;
146 puah->WndProcArray.MsgBitArray = NULL;
147 puah->WndProcArray.Size = 0;
148 puah->PreDefDlgProc = DefaultOWP;
149 puah->PostDefDlgProc = DefaultOWP;
150 puah->DlgProcArray.MsgBitArray = NULL;
151 puah->DlgProcArray.Size = 0;
152 puah->GetSystemMetrics = RealGetSystemMetrics;
153 puah->SystemParametersInfoA = RealSystemParametersInfoA;
154 puah->SystemParametersInfoW = RealSystemParametersInfoW;
155 puah->ForceResetUserApiHook = ForceResetUserApiHook;
156 puah->DrawFrameControl = RealDrawFrameControl;
157 puah->DrawCaption = RealUserDrawCaption;
158 puah->MDIRedrawFrame = RealMDIRedrawFrame;
159 puah->GetRealWindowOwner = GetRealWindowOwner;
160 }
161
162 BOOL
163 FASTCALL
EndUserApiHook(VOID)164 EndUserApiHook(VOID)
165 {
166 HMODULE hModule;
167 USERAPIHOOKPROC pfn;
168 BOOL Ret = FALSE;
169
170 if ( !InterlockedDecrement(&gcCallUserApiHook) )
171 {
172 if ( !gcLoadUserApiHook )
173 {
174 RtlEnterCriticalSection(&gcsUserApiHook);
175
176 pfn = gpfnInitUserApi;
177 hModule = ghmodUserApiHook;
178 ghmodUserApiHook = NULL;
179 gpfnInitUserApi = NULL;
180
181 RtlLeaveCriticalSection(&gcsUserApiHook);
182
183 if ( pfn ) Ret = pfn(uahStop, 0);
184
185 if ( hModule ) Ret = FreeLibrary(hModule);
186 }
187 }
188 return Ret;
189 }
190
191 BOOL
192 WINAPI
ClearUserApiHook(HINSTANCE hInstance)193 ClearUserApiHook(HINSTANCE hInstance)
194 {
195 HMODULE hModule;
196 USERAPIHOOKPROC pfn = NULL, pfn1 = NULL;
197
198 RtlEnterCriticalSection(&gcsUserApiHook);
199 hModule = ghmodUserApiHook;
200 if ( ghmodUserApiHook == hInstance )
201 {
202 pfn1 = gpfnInitUserApi;
203 if ( --gcLoadUserApiHook == 0 )
204 {
205 gfUserApiHook = 0;
206 ResetUserApiHook(&guah);
207 if ( gcCallUserApiHook )
208 {
209 hInstance = NULL;
210 pfn1 = NULL;
211 pfn = gpfnInitUserApi;
212 gcLoadUserApiHook = 1;
213 }
214 else
215 {
216 hInstance = hModule;
217 ghmodUserApiHook = NULL;
218 gpfnInitUserApi = NULL;
219 }
220 }
221 }
222 RtlLeaveCriticalSection(&gcsUserApiHook);
223
224 if ( pfn )
225 {
226 pfn(uahShutdown, 0); // Shutdown.
227
228 RtlEnterCriticalSection(&gcsUserApiHook);
229 pfn1 = gpfnInitUserApi;
230
231 if ( --gcLoadUserApiHook == 0 )
232 {
233 if ( gcCallUserApiHook )
234 {
235 hInstance = NULL;
236 pfn1 = NULL;
237 }
238 else
239 {
240 hInstance = ghmodUserApiHook;
241 ghmodUserApiHook = NULL;
242 gpfnInitUserApi = NULL;
243 }
244 }
245 RtlLeaveCriticalSection(&gcsUserApiHook);
246 }
247
248 if ( pfn1 ) pfn1(uahStop, 0);
249
250 return hInstance != 0;
251 }
252
253 BOOL
254 WINAPI
InitUserApiHook(HINSTANCE hInstance,USERAPIHOOKPROC pfn)255 InitUserApiHook(HINSTANCE hInstance, USERAPIHOOKPROC pfn)
256 {
257 USERAPIHOOK uah;
258
259 ResetUserApiHook(&uah);
260
261 RtlEnterCriticalSection(&gcsUserApiHook);
262
263 if (!pfn(uahLoadInit,&uah) || // Swap data, User32 to and Uxtheme from!
264 uah.ForceResetUserApiHook != ForceResetUserApiHook ||
265 uah.size <= 0 )
266 {
267 RtlLeaveCriticalSection(&gcsUserApiHook);
268 return FALSE;
269 }
270
271 if ( ghmodUserApiHook )
272 {
273 if ( ghmodUserApiHook != hInstance )
274 {
275 RtlLeaveCriticalSection(&gcsUserApiHook);
276 pfn(uahStop, 0);
277 return FALSE;
278 }
279 gcLoadUserApiHook++;
280 }
281 else
282 {
283 ghmodUserApiHook = hInstance;
284 // Do not over write GetRealWindowOwner.
285 RtlCopyMemory(&guah, &uah, sizeof(USERAPIHOOK) - sizeof(LONG));
286 gpfnInitUserApi = pfn;
287 gcLoadUserApiHook = 1;
288 gfUserApiHook = 1;
289 // Copy Message Masks
290 CopyMsgMask(&guah.DefWndProcArray,
291 &uah.DefWndProcArray,
292 &grgbDwpLiteHookMsg,
293 sizeof(grgbDwpLiteHookMsg));
294
295 CopyMsgMask(&guah.WndProcArray,
296 &uah.WndProcArray,
297 &grgbWndLiteHookMsg,
298 sizeof(grgbWndLiteHookMsg));
299
300 CopyMsgMask(&guah.DlgProcArray,
301 &uah.DlgProcArray,
302 &grgbDlgLiteHookMsg,
303 sizeof(grgbDlgLiteHookMsg));
304 }
305 RtlLeaveCriticalSection(&gcsUserApiHook);
306 return TRUE;
307 }
308
309 BOOL
310 WINAPI
RealMDIRedrawFrame(HWND hWnd,DWORD flags)311 RealMDIRedrawFrame(HWND hWnd, DWORD flags)
312 {
313 return NtUserxMDIRedrawFrame(hWnd);
314 }
315
316 BOOL
317 WINAPI
MDIRedrawFrame(HWND hWnd,DWORD flags)318 MDIRedrawFrame(HWND hWnd, DWORD flags)
319 {
320 BOOL Hook, Ret = FALSE;
321
322 LoadUserApiHook();
323
324 Hook = BeginIfHookedUserApiHook();
325
326 /* Bypass SEH and go direct. */
327 if (!Hook) return RealMDIRedrawFrame(hWnd, flags);
328
329 _SEH2_TRY
330 {
331 Ret = guah.MDIRedrawFrame(hWnd, flags);
332 }
333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
334 {
335 ERR("Got exception in hooked MDIRedrawFrame!\n");
336 }
337 _SEH2_END;
338
339 EndUserApiHook();
340
341 return Ret;
342 }
343
344 USERAPIHOOK guah =
345 {
346 sizeof(USERAPIHOOK),
347 RealDefWindowProcA,
348 RealDefWindowProcW,
349 {NULL, 0},
350 RealGetScrollInfo,
351 RealSetScrollInfo,
352 NtUserEnableScrollBar,
353 RealAdjustWindowRectEx,
354 NtUserSetWindowRgn,
355 DefaultOWP,
356 DefaultOWP,
357 {NULL, 0},
358 DefaultOWP,
359 DefaultOWP,
360 {NULL, 0},
361 RealGetSystemMetrics,
362 RealSystemParametersInfoA,
363 RealSystemParametersInfoW,
364 ForceResetUserApiHook,
365 RealDrawFrameControl,
366 NtUserDrawCaption,
367 RealMDIRedrawFrame,
368 GetRealWindowOwner,
369 };
370
371 /* FUNCTIONS *****************************************************************/
372
373 /*
374 * @implemented
375 */
RegisterUserApiHook(PUSERAPIHOOKINFO puah)376 BOOL WINAPI RegisterUserApiHook(PUSERAPIHOOKINFO puah)
377 {
378 UNICODE_STRING m_dllname1;
379 UNICODE_STRING m_funname1;
380
381 if (puah->m_size == sizeof(USERAPIHOOKINFO))
382 {
383 WARN("RegisterUserApiHook: %S and %S\n", puah->m_dllname1, puah->m_funname1);
384 RtlInitUnicodeString(&m_dllname1, puah->m_dllname1);
385 RtlInitUnicodeString(&m_funname1, puah->m_funname1);
386 return NtUserRegisterUserApiHook( &m_dllname1, &m_funname1, 0, 0);
387 }
388 return FALSE;
389 }
390
391 /*
392 * @implemented
393 */
UnregisterUserApiHook(VOID)394 BOOL WINAPI UnregisterUserApiHook(VOID)
395 {
396 return NtUserUnregisterUserApiHook();
397 }
398