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

Last change on this file since 6502 was 5935, checked in by sandervl, 24 years ago

reference count (window + class objects) rewrite

File size: 9.9 KB
Line 
1/* $Id: winproc.cpp,v 1.7 2001-06-09 14:50:26 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 ptr = (BYTE *)handle;
64 if(ptr == NULL) {
65 DebugInt3();
66 return NULL;
67 }
68
69 /* First check if it is the jmp address */
70// if (*ptr == 0xe9 /* jmp */) ptr -= (int)&((WINDOWPROC *)0)->jmp -
71// (int)&((WINDOWPROC *)0)->thunk;
72
73 /* Now we have a pointer to the WINDOWPROC struct */
74 if (((WINDOWPROC *)ptr)->magic == WINPROC_MAGIC)
75 return (WINDOWPROC *)ptr;
76
77 return NULL;
78}
79
80
81/**********************************************************************
82 * WINPROC_AllocWinProc
83 *
84 * Allocate a new window procedure.
85 */
86static WINDOWPROC *WINPROC_AllocWinProc( WNDPROC func, WINDOWPROCTYPE type,
87 WINDOWPROCUSER user )
88{
89 WINDOWPROC *proc, *oldproc;
90
91 /* Allocate a window procedure */
92
93 if (!(proc = (WINDOWPROC *)_cmalloc(sizeof(WINDOWPROC) ))) return 0;
94
95 /* Check if the function is already a win proc */
96
97 oldproc = WINPROC_GetPtr( func );
98 if (oldproc)
99 {
100 *proc = *oldproc;
101 }
102 else
103 {
104 switch(type)
105 {
106 case WIN_PROC_32A:
107 case WIN_PROC_32W:
108 proc->jmp.jmp = 0xe9;
109 /* Fixup relative jump */
110 proc->jmp.proc = (WNDPROC)((LONG)func - (LONG)(&proc->jmp.proc+1));
111 break;
112 default:
113 /* Should not happen */
114 break;
115 }
116 proc->magic = WINPROC_MAGIC;
117 proc->type = type;
118 proc->user = user;
119 }
120 proc->next = NULL;
121 return proc;
122}
123
124
125/**********************************************************************
126 * WINPROC_GetProc
127 *
128 * Get a window procedure pointer that can be passed to the Windows program.
129 */
130WNDPROC WINPROC_GetProc( HWINDOWPROC proc, WINDOWPROCTYPE type )
131{
132 WINDOWPROC *lpProc = (WINDOWPROC *)proc;
133
134 if(!lpProc) {
135 DebugInt3();
136 return NULL;
137 }
138
139 if(type != lpProc->type) {
140 /* Have to return the jmp address if types don't match */
141 return (WNDPROC)&lpProc->jmp;
142 }
143 else return WINPROC_THUNKPROC(lpProc); //return original window proc address if types match
144}
145
146
147/**********************************************************************
148 * WINPROC_SetProc
149 *
150 * Set the window procedure for a window or class. There are
151 * three tree classes of winproc callbacks:
152 *
153 * 1) class -> wp - not subclassed
154 * class -> wp -> wp -> wp -> wp - SetClassLong()
155 * / /
156 * 2) window -' / - not subclassed
157 * window -> wp -> wp ' - SetWindowLong()
158 *
159 * 3) timer -> wp - SetTimer()
160 *
161 * Initially, winproc of the window points to the current winproc
162 * thunk of its class. Subclassing prepends a new thunk to the
163 * window winproc chain at the head of the list. Thus, window thunk
164 * list includes class thunks and the latter are preserved when the
165 * window is destroyed.
166 *
167 */
168BOOL WINPROC_SetProc( HWINDOWPROC *pFirst, WNDPROC func,
169 WINDOWPROCTYPE type, WINDOWPROCUSER user )
170{
171 BOOL bRecycle = FALSE;
172 WINDOWPROC *proc, **ppPrev;
173
174 if(func == NULL) {
175 *(WINDOWPROC **)pFirst = 0;
176 return TRUE;
177 }
178
179 /* Check if function is already in the list */
180
181 ppPrev = (WINDOWPROC **)pFirst;
182 proc = WINPROC_GetPtr( func );
183 while (*ppPrev)
184 {
185 if (proc)
186 {
187 if (*ppPrev == proc)
188 {
189 if ((*ppPrev)->user != user)
190 {
191 /* terminal thunk is being restored */
192
193 WINPROC_FreeProc( *pFirst, (*ppPrev)->user );
194 *(WINDOWPROC **)pFirst = *ppPrev;
195 return TRUE;
196 }
197 bRecycle = TRUE;
198 break;
199 }
200 }
201 else
202 {
203 if (((*ppPrev)->type == type) &&
204 (func == WINPROC_THUNKPROC(*ppPrev)))
205 {
206 bRecycle = TRUE;
207 break;
208 }
209 }
210
211 /* WPF_CLASS thunk terminates window thunk list */
212 if ((*ppPrev)->user != user) break;
213 ppPrev = &(*ppPrev)->next;
214 }
215
216 if (bRecycle)
217 {
218 /* Extract this thunk from the list */
219 proc = *ppPrev;
220 *ppPrev = proc->next;
221 }
222 else /* Allocate a new one */
223 {
224 if (proc) /* Was already a win proc */
225 {
226 type = proc->type;
227 func = WINPROC_THUNKPROC(proc);
228 }
229 proc = WINPROC_AllocWinProc( func, type, user );
230 if (!proc) return FALSE;
231 }
232
233 /* Add the win proc at the head of the list */
234
235 proc->next = *(WINDOWPROC **)pFirst;
236 *(WINDOWPROC **)pFirst = proc;
237 return TRUE;
238}
239
240
241/**********************************************************************
242 * WINPROC_FreeProc
243 *
244 * Free a list of win procs.
245 */
246void WINPROC_FreeProc( HWINDOWPROC proc, WINDOWPROCUSER user )
247{
248 while (proc)
249 {
250 WINDOWPROC *next = ((WINDOWPROC *)proc)->next;
251 if (((WINDOWPROC *)proc)->user != user) break;
252 free( proc );
253 proc = next;
254 }
255}
256
257
258/**********************************************************************
259 * WINPROC_GetProcType
260 *
261 * Return the window procedure type.
262 */
263WINDOWPROCTYPE WINPROC_GetProcType( HWINDOWPROC proc )
264{
265 if (!proc ||
266 (((WINDOWPROC *)proc)->magic != WINPROC_MAGIC))
267 return WIN_PROC_INVALID;
268 return ((WINDOWPROC *)proc)->type;
269}
270
271/**********************************************************************
272 * CallWindowProc32A (USER32.18)
273 *
274 * The CallWindowProc() function invokes the windows procedure _func_,
275 * with _hwnd_ as the target window, the message specified by _msg_, and
276 * the message parameters _wParam_ and _lParam_.
277 *
278 * Some kinds of argument conversion may be done, I'm not sure what.
279 *
280 * CallWindowProc() may be used for windows subclassing. Use
281 * SetWindowLong() to set a new windows procedure for windows of the
282 * subclass, and handle subclassed messages in the new windows
283 * procedure. The new windows procedure may then use CallWindowProc()
284 * with _func_ set to the parent class's windows procedure to dispatch
285 * the message to the superclass.
286 *
287 * RETURNS
288 *
289 * The return value is message dependent.
290 *
291 * CONFORMANCE
292 *
293 * ECMA-234, Win32
294 */
295LRESULT WINAPI CallWindowProcA(
296 WNDPROC func, /* window procedure */
297 HWND hwnd, /* target window */
298 UINT msg, /* message */
299 WPARAM wParam, /* message dependent parameter */
300 LPARAM lParam /* message dependent parameter */
301) {
302 WINDOWPROC *proc = WINPROC_GetPtr( func );
303
304 if(proc) {
305 dprintf2(("CallWindowProcA %x %x %x %x %x -> proc %x, type %d, org func %x", func, hwnd, msg, wParam, lParam, proc, proc->type, WINPROC_THUNKPROC(proc)));
306 }
307 else dprintf2(("CallWindowProcA %x %x %x %x %x (unknown proc)", func, hwnd, msg, wParam, lParam));
308
309 if(!IsWindow(hwnd)) {
310 dprintf(("CallWindowProcA, window %x not found", hwnd));
311 // return func( hwnd, msg, wParam, lParam );
312 return 0;
313 }
314
315 if (!proc) return func(hwnd, msg, wParam, lParam );
316
317 switch(proc->type)
318 {
319 case WIN_PROC_32A:
320 return func(hwnd, msg, wParam, lParam );
321 case WIN_PROC_32W:
322 return WINPROC_CallProc32ATo32W( func, hwnd, msg, wParam, lParam );
323 default:
324 WARN_(relay)("Invalid proc %p\n", proc );
325 return 0;
326 }
327}
328
329
330/**********************************************************************
331 * CallWindowProc32W (USER32.19)
332 */
333LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
334 WPARAM wParam, LPARAM lParam )
335{
336 WINDOWPROC *proc = WINPROC_GetPtr( func );
337
338 if(proc) {
339 dprintf2(("CallWindowProcW %x %x %x %x %x -> proc %x, type %d, org func %x", func, hwnd, msg, wParam, lParam, proc, proc->type, WINPROC_THUNKPROC(proc)));
340 }
341 else dprintf2(("CallWindowProcW %x %x %x %x %x (unknown proc)", func, hwnd, msg, wParam, lParam));
342
343 if(!IsWindow(hwnd)) {
344 dprintf(("CallWindowProcW, window %x not found", hwnd));
345 // return func( hwnd, msg, wParam, lParam );
346 return 0;
347 }
348
349 if (!proc) return func( hwnd, msg, wParam, lParam );
350
351 switch(proc->type)
352 {
353 case WIN_PROC_32A:
354 return WINPROC_CallProc32WTo32A( func, hwnd, msg, wParam, lParam );
355 case WIN_PROC_32W:
356 return func(hwnd, msg, wParam, lParam );
357 default:
358 WARN_(relay)("Invalid proc %p\n", proc );
359 return 0;
360 }
361}
362
Note: See TracBrowser for help on using the repository browser.