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

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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