Implement WH_MOUSE_LL hook
[reactos.git] / reactos / subsys / win32k / ntuser / callback.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/wndproc.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
27 * REVISION HISTORY:
28 * 06-06-2001 CSH Created
29 * NOTES: Please use the Callback Memory Management functions for
30 * callbacks to make sure, the memory is freed on thread
31 * termination!
32 */
33
34 /* INCLUDES ******************************************************************/
35
36 #include <w32k.h>
37
38 #define NDEBUG
39 #include <debug.h>
40
41 /* CALLBACK MEMORY MANAGEMENT ************************************************/
42
43 typedef struct _INT_CALLBACK_HEADER
44 {
45 /* list entry in the W32THREAD structure */
46 LIST_ENTRY ListEntry;
47 } INT_CALLBACK_HEADER, *PINT_CALLBACK_HEADER;
48
49 PVOID FASTCALL
50 IntCbAllocateMemory(ULONG Size)
51 {
52 PINT_CALLBACK_HEADER Mem;
53 PW32THREAD W32Thread;
54
55 if(!(Mem = ExAllocatePoolWithTag(PagedPool, Size + sizeof(INT_CALLBACK_HEADER),
56 TAG_CALLBACK)))
57 {
58 return NULL;
59 }
60
61 W32Thread = PsGetWin32Thread();
62 ASSERT(W32Thread);
63
64 /* insert the callback memory into the thread's callback list */
65
66 InsertTailList(&W32Thread->W32CallbackListHead, &Mem->ListEntry);
67
68 return (Mem + 1);
69 }
70
71 VOID FASTCALL
72 IntCbFreeMemory(PVOID Data)
73 {
74 PINT_CALLBACK_HEADER Mem;
75 PW32THREAD W32Thread;
76
77 ASSERT(Data);
78
79 Mem = ((PINT_CALLBACK_HEADER)Data - 1);
80
81 W32Thread = PsGetWin32Thread();
82 ASSERT(W32Thread);
83
84 /* remove the memory block from the thread's callback list */
85 RemoveEntryList(&Mem->ListEntry);
86
87 /* free memory */
88 ExFreePool(Mem);
89 }
90
91 VOID FASTCALL
92 IntCleanupThreadCallbacks(PW32THREAD W32Thread)
93 {
94 PLIST_ENTRY CurrentEntry;
95 PINT_CALLBACK_HEADER Mem;
96
97 while (!IsListEmpty(&W32Thread->W32CallbackListHead))
98 {
99 CurrentEntry = RemoveHeadList(&W32Thread->W32CallbackListHead);
100 Mem = CONTAINING_RECORD(CurrentEntry, INT_CALLBACK_HEADER,
101 ListEntry);
102
103 /* free memory */
104 ExFreePool(Mem);
105 }
106 }
107
108 /* FUNCTIONS *****************************************************************/
109
110 VOID STDCALL
111 IntCallSentMessageCallback(SENDASYNCPROC CompletionCallback,
112 HWND hWnd,
113 UINT Msg,
114 ULONG_PTR CompletionCallbackContext,
115 LRESULT Result)
116 {
117 SENDASYNCPROC_CALLBACK_ARGUMENTS Arguments;
118 NTSTATUS Status;
119
120 Arguments.Callback = CompletionCallback;
121 Arguments.Wnd = hWnd;
122 Arguments.Msg = Msg;
123 Arguments.Context = CompletionCallbackContext;
124 Arguments.Result = Result;
125 Status = NtW32Call(USER32_CALLBACK_SENDASYNCPROC,
126 &Arguments,
127 sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS),
128 NULL,
129 NULL);
130 if (!NT_SUCCESS(Status))
131 {
132 return;
133 }
134 return;
135 }
136
137 LRESULT STDCALL
138 IntCallWindowProc(WNDPROC Proc,
139 BOOLEAN IsAnsiProc,
140 HWND Wnd,
141 UINT Message,
142 WPARAM wParam,
143 LPARAM lParam,
144 INT lParamBufferSize)
145 {
146 WINDOWPROC_CALLBACK_ARGUMENTS StackArguments;
147 PWINDOWPROC_CALLBACK_ARGUMENTS Arguments;
148 NTSTATUS Status;
149 PVOID ResultPointer;
150 ULONG ResultLength;
151 ULONG ArgumentLength;
152 LRESULT Result;
153
154 if (0 < lParamBufferSize)
155 {
156 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + lParamBufferSize;
157 Arguments = IntCbAllocateMemory(ArgumentLength);
158 if (NULL == Arguments)
159 {
160 DPRINT1("Unable to allocate buffer for window proc callback\n");
161 return -1;
162 }
163 RtlMoveMemory((PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
164 (PVOID) lParam, lParamBufferSize);
165 }
166 else
167 {
168 Arguments = &StackArguments;
169 ArgumentLength = sizeof(WINDOWPROC_CALLBACK_ARGUMENTS);
170 }
171 Arguments->Proc = Proc;
172 Arguments->IsAnsiProc = IsAnsiProc;
173 Arguments->Wnd = Wnd;
174 Arguments->Msg = Message;
175 Arguments->wParam = wParam;
176 Arguments->lParam = lParam;
177 Arguments->lParamBufferSize = lParamBufferSize;
178 ResultPointer = Arguments;
179 ResultLength = ArgumentLength;
180 Status = NtW32Call(USER32_CALLBACK_WINDOWPROC,
181 Arguments,
182 ArgumentLength,
183 &ResultPointer,
184 &ResultLength);
185 if (!NT_SUCCESS(Status))
186 {
187 if (0 < lParamBufferSize)
188 {
189 IntCbFreeMemory(Arguments);
190 }
191 return -1;
192 }
193 Result = Arguments->Result;
194
195 if (0 < lParamBufferSize)
196 {
197 RtlMoveMemory((PVOID) lParam,
198 (PVOID) ((char *) Arguments + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)),
199 lParamBufferSize);
200 IntCbFreeMemory(Arguments);
201 }
202
203 return Result;
204 }
205
206 HMENU STDCALL
207 IntLoadSysMenuTemplate()
208 {
209 LRESULT Result;
210 NTSTATUS Status;
211 PVOID ResultPointer;
212 ULONG ResultLength;
213
214 ResultPointer = &Result;
215 ResultLength = sizeof(LRESULT);
216 Status = NtW32Call(USER32_CALLBACK_LOADSYSMENUTEMPLATE,
217 NULL,
218 0,
219 &ResultPointer,
220 &ResultLength);
221 if (!NT_SUCCESS(Status))
222 {
223 return(0);
224 }
225 return (HMENU)Result;
226 }
227
228 BOOL STDCALL
229 IntLoadDefaultCursors(VOID)
230 {
231 LRESULT Result;
232 NTSTATUS Status;
233 PVOID ResultPointer;
234 ULONG ResultLength;
235 BOOL DefaultCursor = TRUE;
236
237 ResultPointer = &Result;
238 ResultLength = sizeof(LRESULT);
239 Status = NtW32Call(USER32_CALLBACK_LOADDEFAULTCURSORS,
240 &DefaultCursor,
241 sizeof(BOOL),
242 &ResultPointer,
243 &ResultLength);
244 if (!NT_SUCCESS(Status))
245 {
246 return FALSE;
247 }
248 return TRUE;
249 }
250
251 LRESULT STDCALL
252 IntCallHookProc(INT HookId,
253 INT Code,
254 WPARAM wParam,
255 LPARAM lParam,
256 HOOKPROC Proc,
257 BOOLEAN Ansi,
258 PUNICODE_STRING ModuleName)
259 {
260 ULONG ArgumentLength;
261 PVOID Argument;
262 LRESULT Result;
263 NTSTATUS Status;
264 PVOID ResultPointer;
265 ULONG ResultLength;
266 PHOOKPROC_CALLBACK_ARGUMENTS Common;
267 CBT_CREATEWNDW *CbtCreateWnd;
268 PCHAR Extra;
269 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra;
270 PUNICODE_STRING WindowName;
271 PUNICODE_STRING ClassName;
272
273 ArgumentLength = sizeof(HOOKPROC_CALLBACK_ARGUMENTS) - sizeof(WCHAR)
274 + ModuleName->Length;
275 switch(HookId)
276 {
277 case WH_CBT:
278 switch(Code)
279 {
280 case HCBT_CREATEWND:
281 CbtCreateWnd = (CBT_CREATEWNDW *) lParam;
282 ArgumentLength += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS);
283 WindowName = (PUNICODE_STRING) (CbtCreateWnd->lpcs->lpszName);
284 ArgumentLength += WindowName->Length + sizeof(WCHAR);
285 ClassName = (PUNICODE_STRING) (CbtCreateWnd->lpcs->lpszClass);
286 if (! IS_ATOM(ClassName->Buffer))
287 {
288 ArgumentLength += ClassName->Length + sizeof(WCHAR);
289 }
290 break;
291 default:
292 DPRINT1("Trying to call unsupported CBT hook %d\n", Code);
293 return 0;
294 }
295 break;
296 case WH_KEYBOARD_LL:
297 ArgumentLength += sizeof(KBDLLHOOKSTRUCT);
298 break;
299 case WH_MOUSE_LL:
300 ArgumentLength += sizeof(MSLLHOOKSTRUCT);
301 break;
302 default:
303 DPRINT1("Trying to call unsupported window hook %d\n", HookId);
304 return 0;
305 }
306
307 Argument = IntCbAllocateMemory(ArgumentLength);
308 if (NULL == Argument)
309 {
310 DPRINT1("HookProc callback failed: out of memory\n");
311 return 0;
312 }
313 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Argument;
314 Common->HookId = HookId;
315 Common->Code = Code;
316 Common->wParam = wParam;
317 Common->lParam = lParam;
318 Common->Proc = Proc;
319 Common->Ansi = Ansi;
320 Common->ModuleNameLength = ModuleName->Length;
321 memcpy(Common->ModuleName, ModuleName->Buffer, ModuleName->Length);
322 Extra = (PCHAR) Common->ModuleName + Common->ModuleNameLength;
323
324 switch(HookId)
325 {
326 case WH_CBT:
327 switch(Code)
328 {
329 case HCBT_CREATEWND:
330 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
331 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS) Extra;
332 CbtCreatewndExtra->Cs = *(CbtCreateWnd->lpcs);
333 CbtCreatewndExtra->WndInsertAfter = CbtCreateWnd->hwndInsertAfter;
334 Extra = (PCHAR) (CbtCreatewndExtra + 1);
335 RtlCopyMemory(Extra, WindowName->Buffer, WindowName->Length);
336 CbtCreatewndExtra->Cs.lpszName = (LPCWSTR) (Extra - (PCHAR) CbtCreatewndExtra);
337 CbtCreatewndExtra->Cs.lpszClass = ClassName->Buffer;
338 Extra += WindowName->Length;
339 *((WCHAR *) Extra) = L'\0';
340 Extra += sizeof(WCHAR);
341 if (! IS_ATOM(ClassName->Buffer))
342 {
343 RtlCopyMemory(Extra, ClassName->Buffer, ClassName->Length);
344 CbtCreatewndExtra->Cs.lpszClass =
345 (LPCWSTR) MAKELONG(Extra - (PCHAR) CbtCreatewndExtra, 1);
346 Extra += ClassName->Length;
347 *((WCHAR *) Extra) = L'\0';
348 }
349 break;
350 }
351 break;
352 case WH_KEYBOARD_LL:
353 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
354 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
355 break;
356 case WH_MOUSE_LL:
357 RtlCopyMemory(Extra, (PVOID) lParam, sizeof(MSLLHOOKSTRUCT));
358 Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
359 break;
360 }
361
362 ResultPointer = &Result;
363 ResultLength = sizeof(LRESULT);
364 Status = NtW32Call(USER32_CALLBACK_HOOKPROC,
365 Argument,
366 ArgumentLength,
367 &ResultPointer,
368 &ResultLength);
369
370 IntCbFreeMemory(Argument);
371
372 if (!NT_SUCCESS(Status))
373 {
374 return 0;
375 }
376
377 return Result;
378 }
379
380 /* EOF */