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

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

* empty log message *

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