source: trunk/src/user32/winproc.cpp@ 2803

Last change on this file since 2803 was 2803, checked in by sandervl, 26 years ago

Added new logging feature

File size: 9.5 KB
Line 
1/* $Id: winproc.cpp,v 1.4 2000-02-16 14:28:28 sandervl Exp $ */
2/*
3 * Window procedure callbacks
4 *
5 * Copyright 1999 Sander van Leeuwen (OS/2 Port)
6 *
7 * Based on Wine Windows code (windows\winproc.c) 991114
8 *
9 *
10 * Copyright 1995 Martin von Loewis
11 * Copyright 1996 Alexandre Julliard
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16
17#include <os2win.h>
18#include <string.h>
19#include <win\winproc.h>
20#include <win\debugtools.h>
21#include <heapcode.h>
22#include "win32wbase.h"
23
24#define DBG_LOCALLOG DBG_winproc
25#include "dbglocal.h"
26
27DECLARE_DEBUG_CHANNEL(relay)
28
29
30/* Simple jmp to call 32-bit procedure directly */
31#pragma pack(1)
32typedef struct
33{
34 BYTE jmp; /* jmp proc (relative jump) */
35 WNDPROC proc WINE_PACKED;
36} WINPROC_JUMP;
37#pragma pack()
38
39typedef struct tagWINDOWPROC
40{
41 WINPROC_JUMP jmp; /* Jump */
42 struct tagWINDOWPROC *next; /* Next window proc */
43 UINT magic; /* Magic number */
44 WINDOWPROCTYPE type; /* Function type */
45 WINDOWPROCUSER user; /* Function user */
46} WINDOWPROC;
47
48#define WINPROC_MAGIC ('W' | ('P' << 8) | ('R' << 16) | ('C' << 24))
49
50#define WINPROC_THUNKPROC(pproc) \
51 (WNDPROC)((LONG)(pproc)->jmp.proc + (LONG)(&(pproc)->jmp.proc+1))
52
53/**********************************************************************
54 * WINPROC_GetPtr
55 *
56 * Return a pointer to the win proc.
57 */
58static WINDOWPROC *WINPROC_GetPtr( WNDPROC handle )
59{
60 BYTE *ptr;
61 WINDOWPROC *proc;
62
63 if(ptr == NULL) {
64 return NULL;
65 }
66
67 ptr = (BYTE *)handle;
68 /* First check if it is the jmp address */
69// if (*ptr == 0xe9 /* jmp */) ptr -= (int)&((WINDOWPROC *)0)->jmp -
70// (int)&((WINDOWPROC *)0)->thunk;
71
72 /* Now we have a pointer to the WINDOWPROC struct */
73 if (((WINDOWPROC *)ptr)->magic == WINPROC_MAGIC)
74 return (WINDOWPROC *)ptr;
75
76 return NULL;
77}
78
79
80/**********************************************************************
81 * WINPROC_AllocWinProc
82 *
83 * Allocate a new window procedure.
84 */
85static WINDOWPROC *WINPROC_AllocWinProc( WNDPROC func, WINDOWPROCTYPE type,
86 WINDOWPROCUSER user )
87{
88 WINDOWPROC *proc, *oldproc;
89
90 /* Allocate a window procedure */
91
92 if (!(proc = (WINDOWPROC *)_cmalloc(sizeof(WINDOWPROC) ))) return 0;
93
94 /* Check if the function is already a win proc */
95
96 oldproc = WINPROC_GetPtr( func );
97 if (oldproc)
98 {
99 *proc = *oldproc;
100 }
101 else
102 {
103 switch(type)
104 {
105 case WIN_PROC_32A:
106 case WIN_PROC_32W:
107 proc->jmp.jmp = 0xe9;
108 /* Fixup relative jump */
109 proc->jmp.proc = (WNDPROC)((LONG)func - (LONG)(&proc->jmp.proc+1));
110 break;
111 default:
112 /* Should not happen */
113 break;
114 }
115 proc->magic = WINPROC_MAGIC;
116 proc->type = type;
117 proc->user = user;
118 }
119 proc->next = NULL;
120 return proc;
121}
122
123
124/**********************************************************************
125 * WINPROC_GetProc
126 *
127 * Get a window procedure pointer that can be passed to the Windows program.
128 */
129WNDPROC WINPROC_GetProc( HWINDOWPROC proc, WINDOWPROCTYPE type )
130{
131 WINDOWPROC *lpProc = (WINDOWPROC *)proc;
132
133 if (!lpProc) return NULL;
134
135 /* We want a 32-bit address */
136 return (WNDPROC)&lpProc->jmp;
137}
138
139
140/**********************************************************************
141 * WINPROC_SetProc
142 *
143 * Set the window procedure for a window or class. There are
144 * three tree classes of winproc callbacks:
145 *
146 * 1) class -> wp - not subclassed
147 * class -> wp -> wp -> wp -> wp - SetClassLong()
148 * / /
149 * 2) window -' / - not subclassed
150 * window -> wp -> wp ' - SetWindowLong()
151 *
152 * 3) timer -> wp - SetTimer()
153 *
154 * Initially, winproc of the window points to the current winproc
155 * thunk of its class. Subclassing prepends a new thunk to the
156 * window winproc chain at the head of the list. Thus, window thunk
157 * list includes class thunks and the latter are preserved when the
158 * window is destroyed.
159 *
160 */
161BOOL WINPROC_SetProc( HWINDOWPROC *pFirst, WNDPROC func,
162 WINDOWPROCTYPE type, WINDOWPROCUSER user )
163{
164 BOOL bRecycle = FALSE;
165 WINDOWPROC *proc, **ppPrev;
166
167 if(func == NULL) {
168 *(WINDOWPROC **)pFirst = 0;
169 return TRUE;
170 }
171
172 /* Check if function is already in the list */
173
174 ppPrev = (WINDOWPROC **)pFirst;
175 proc = WINPROC_GetPtr( func );
176 while (*ppPrev)
177 {
178 if (proc)
179 {
180 if (*ppPrev == proc)
181 {
182 if ((*ppPrev)->user != user)
183 {
184 /* terminal thunk is being restored */
185
186 WINPROC_FreeProc( *pFirst, (*ppPrev)->user );
187 *(WINDOWPROC **)pFirst = *ppPrev;
188 return TRUE;
189 }
190 bRecycle = TRUE;
191 break;
192 }
193 }
194 else
195 {
196 if (((*ppPrev)->type == type) &&
197 (func == WINPROC_THUNKPROC(*ppPrev)))
198 {
199 bRecycle = TRUE;
200 break;
201 }
202 }
203
204 /* WPF_CLASS thunk terminates window thunk list */
205 if ((*ppPrev)->user != user) break;
206 ppPrev = &(*ppPrev)->next;
207 }
208
209 if (bRecycle)
210 {
211 /* Extract this thunk from the list */
212 proc = *ppPrev;
213 *ppPrev = proc->next;
214 }
215 else /* Allocate a new one */
216 {
217 if (proc) /* Was already a win proc */
218 {
219 type = proc->type;
220 func = WINPROC_THUNKPROC(proc);
221 }
222 proc = WINPROC_AllocWinProc( func, type, user );
223 if (!proc) return FALSE;
224 }
225
226 /* Add the win proc at the head of the list */
227
228 proc->next = *(WINDOWPROC **)pFirst;
229 *(WINDOWPROC **)pFirst = proc;
230 return TRUE;
231}
232
233
234/**********************************************************************
235 * WINPROC_FreeProc
236 *
237 * Free a list of win procs.
238 */
239void WINPROC_FreeProc( HWINDOWPROC proc, WINDOWPROCUSER user )
240{
241 while (proc)
242 {
243 WINDOWPROC *next = ((WINDOWPROC *)proc)->next;
244 if (((WINDOWPROC *)proc)->user != user) break;
245 free( proc );
246 proc = next;
247 }
248}
249
250
251/**********************************************************************
252 * WINPROC_GetProcType
253 *
254 * Return the window procedure type.
255 */
256WINDOWPROCTYPE WINPROC_GetProcType( HWINDOWPROC proc )
257{
258 if (!proc ||
259 (((WINDOWPROC *)proc)->magic != WINPROC_MAGIC))
260 return WIN_PROC_INVALID;
261 return ((WINDOWPROC *)proc)->type;
262}
263
264/**********************************************************************
265 * CallWindowProc32A (USER32.18)
266 *
267 * The CallWindowProc() function invokes the windows procedure _func_,
268 * with _hwnd_ as the target window, the message specified by _msg_, and
269 * the message parameters _wParam_ and _lParam_.
270 *
271 * Some kinds of argument conversion may be done, I'm not sure what.
272 *
273 * CallWindowProc() may be used for windows subclassing. Use
274 * SetWindowLong() to set a new windows procedure for windows of the
275 * subclass, and handle subclassed messages in the new windows
276 * procedure. The new windows procedure may then use CallWindowProc()
277 * with _func_ set to the parent class's windows procedure to dispatch
278 * the message to the superclass.
279 *
280 * RETURNS
281 *
282 * The return value is message dependent.
283 *
284 * CONFORMANCE
285 *
286 * ECMA-234, Win32
287 */
288LRESULT WINAPI CallWindowProcA(
289 WNDPROC func, /* window procedure */
290 HWND hwnd, /* target window */
291 UINT msg, /* message */
292 WPARAM wParam, /* message dependent parameter */
293 LPARAM lParam /* message dependent parameter */
294) {
295 WINDOWPROC *proc = WINPROC_GetPtr( func );
296
297 Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(hwnd);
298 if(!window) {
299 dprintf(("CallWindowProcA, window %x not found", hwnd));
300 // return func( hwnd, msg, wParam, lParam );
301 return 0;
302 }
303
304 if (!proc) return func(hwnd, msg, wParam, lParam );
305
306#if testing
307 func = WINPROC_GetProc( (HWINDOWPROC)proc, WIN_PROC_32A );
308 return WINPROC_CallWndProc( func, hwnd, msg, wParam, lParam );
309#endif
310
311 switch(proc->type)
312 {
313 case WIN_PROC_32A:
314 return func(hwnd, msg, wParam, lParam );
315 case WIN_PROC_32W:
316 return WINPROC_CallProc32ATo32W( func, hwnd, msg, wParam, lParam );
317 default:
318 WARN_(relay)("Invalid proc %p\n", proc );
319 return 0;
320 }
321}
322
323
324/**********************************************************************
325 * CallWindowProc32W (USER32.19)
326 */
327LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
328 WPARAM wParam, LPARAM lParam )
329{
330 WINDOWPROC *proc = WINPROC_GetPtr( func );
331
332 Win32BaseWindow *window = Win32BaseWindow::GetWindowFromHandle(hwnd);
333 if(!window) {
334 dprintf(("CallWindowProcW, window %x not found", hwnd));
335 // return func( hwnd, msg, wParam, lParam );
336 return 0;
337 }
338
339 if (!proc) return func( hwnd, msg, wParam, lParam );
340
341#if testing
342 func = WINPROC_GetProc( (HWINDOWPROC)proc, WIN_PROC_32W );
343 return WINPROC_CallWndProc( func, hwnd, msg, wParam, lParam );
344#endif
345
346 switch(proc->type)
347 {
348 case WIN_PROC_32A:
349 return WINPROC_CallProc32WTo32A( func, hwnd, msg, wParam, lParam );
350 case WIN_PROC_32W:
351 return func(hwnd, msg, wParam, lParam );
352 default:
353 WARN_(relay)("Invalid proc %p\n", proc );
354 return 0;
355 }
356}
357
Note: See TracBrowser for help on using the repository browser.