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