xref: /reactos/win32ss/user/user32/misc/usrapihk.c (revision 09dde2cf)
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