Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

winproc.cpp

Go to the documentation of this file.
00001 /* $Id: winproc.cpp,v 1.7 2001/06/09 14:50:26 sandervl Exp $ */
00002 /*
00003  * Window procedure callbacks
00004  *
00005  * Copyright 1999 Sander van Leeuwen (OS/2 Port)
00006  *
00007  * Based on Wine Windows code (windows\winproc.c) 991114
00008  *
00009  *
00010  * Copyright 1995 Martin von Loewis
00011  * Copyright 1996 Alexandre Julliard
00012  *
00013  * Project Odin Software License can be found in LICENSE.TXT
00014  *
00015  */
00016 
00017 #include <os2win.h>
00018 #include <string.h>
00019 #include <win\winproc.h>
00020 #include <win\debugtools.h>
00021 #include <heapcode.h>
00022 #include "win32wbase.h"
00023 
00024 #define DBG_LOCALLOG    DBG_winproc
00025 #include "dbglocal.h"
00026 
00027 DECLARE_DEBUG_CHANNEL(relay)
00028 
00029 
00030 /* Simple jmp to call 32-bit procedure directly */
00031 #pragma pack(1)
00032 typedef struct
00033 {
00034     BYTE       jmp;                  /* jmp  proc (relative jump) */
00035     WNDPROC  proc WINE_PACKED;
00036 } WINPROC_JUMP;
00037 #pragma pack()
00038 
00039 typedef struct tagWINDOWPROC
00040 {
00041     WINPROC_JUMP          jmp;      /* Jump */
00042     struct tagWINDOWPROC *next;     /* Next window proc */
00043     UINT                magic;    /* Magic number */
00044     WINDOWPROCTYPE        type;     /* Function type */
00045     WINDOWPROCUSER        user;     /* Function user */
00046 } WINDOWPROC;
00047 
00048 #define WINPROC_MAGIC  ('W' | ('P' << 8) | ('R' << 16) | ('C' << 24))
00049 
00050 #define WINPROC_THUNKPROC(pproc) \
00051             (WNDPROC)((LONG)(pproc)->jmp.proc + (LONG)(&(pproc)->jmp.proc+1))
00052 
00053 /**********************************************************************
00054  *           WINPROC_GetPtr
00055  *
00056  * Return a pointer to the win proc.
00057  */
00058 static WINDOWPROC *WINPROC_GetPtr( WNDPROC handle )
00059 {
00060     BYTE *ptr;
00061     WINDOWPROC *proc;
00062 
00063     ptr = (BYTE *)handle;
00064     if(ptr == NULL) {
00065         DebugInt3();
00066         return NULL;
00067     }
00068 
00069     /* First check if it is the jmp address */
00070 //    if (*ptr == 0xe9 /* jmp */) ptr -= (int)&((WINDOWPROC *)0)->jmp -
00071 //                                       (int)&((WINDOWPROC *)0)->thunk;
00072 
00073     /* Now we have a pointer to the WINDOWPROC struct */
00074     if (((WINDOWPROC *)ptr)->magic == WINPROC_MAGIC)
00075          return (WINDOWPROC *)ptr;
00076 
00077     return NULL;
00078 }
00079 
00080 
00081 /**********************************************************************
00082  *           WINPROC_AllocWinProc
00083  *
00084  * Allocate a new window procedure.
00085  */
00086 static WINDOWPROC *WINPROC_AllocWinProc( WNDPROC func, WINDOWPROCTYPE type,
00087                                          WINDOWPROCUSER user )
00088 {
00089     WINDOWPROC *proc, *oldproc;
00090 
00091     /* Allocate a window procedure */
00092 
00093     if (!(proc = (WINDOWPROC *)_cmalloc(sizeof(WINDOWPROC) ))) return 0;
00094 
00095     /* Check if the function is already a win proc */
00096 
00097     oldproc = WINPROC_GetPtr( func );
00098     if (oldproc)
00099     {
00100         *proc = *oldproc;
00101     }
00102     else
00103     {
00104         switch(type)
00105         {
00106         case WIN_PROC_32A:
00107         case WIN_PROC_32W:
00108             proc->jmp.jmp  = 0xe9;
00109             /* Fixup relative jump */
00110             proc->jmp.proc = (WNDPROC)((LONG)func - (LONG)(&proc->jmp.proc+1));
00111             break;
00112         default:
00113             /* Should not happen */
00114             break;
00115         }
00116         proc->magic = WINPROC_MAGIC;
00117         proc->type  = type;
00118         proc->user  = user;
00119     }
00120     proc->next  = NULL;
00121     return proc;
00122 }
00123 
00124 
00125 /**********************************************************************
00126  *           WINPROC_GetProc
00127  *
00128  * Get a window procedure pointer that can be passed to the Windows program.
00129  */
00130 WNDPROC WINPROC_GetProc( HWINDOWPROC proc, WINDOWPROCTYPE type )
00131 {
00132  WINDOWPROC *lpProc = (WINDOWPROC *)proc;
00133 
00134     if(!lpProc) {
00135         DebugInt3();
00136         return NULL;
00137     }
00138 
00139     if(type != lpProc->type) {
00140          /* Have to return the jmp address if types don't match */
00141          return (WNDPROC)&lpProc->jmp;
00142     }
00143     else return WINPROC_THUNKPROC(lpProc); //return original window proc address if types match
00144 }
00145 
00146 
00147 /**********************************************************************
00148  *           WINPROC_SetProc
00149  *
00150  * Set the window procedure for a window or class. There are
00151  * three tree classes of winproc callbacks:
00152  *
00153  * 1) class  -> wp                      -       not subclassed
00154  *    class  -> wp -> wp -> wp -> wp    -       SetClassLong()
00155  *             /           /
00156  * 2) window -'           /             -       not subclassed
00157  *    window -> wp -> wp '              -       SetWindowLong()
00158  *
00159  * 3) timer  -> wp                      -       SetTimer()
00160  *
00161  * Initially, winproc of the window points to the current winproc
00162  * thunk of its class. Subclassing prepends a new thunk to the
00163  * window winproc chain at the head of the list. Thus, window thunk
00164  * list includes class thunks and the latter are preserved when the
00165  * window is destroyed.
00166  *
00167  */
00168 BOOL WINPROC_SetProc( HWINDOWPROC *pFirst, WNDPROC func,
00169                       WINDOWPROCTYPE type, WINDOWPROCUSER user )
00170 {
00171     BOOL bRecycle = FALSE;
00172     WINDOWPROC *proc, **ppPrev;
00173 
00174     if(func == NULL) {
00175         *(WINDOWPROC **)pFirst = 0;
00176         return TRUE;
00177     }
00178 
00179     /* Check if function is already in the list */
00180 
00181     ppPrev = (WINDOWPROC **)pFirst;
00182     proc = WINPROC_GetPtr( func );
00183     while (*ppPrev)
00184     {
00185         if (proc)
00186         {
00187             if (*ppPrev == proc)
00188             {
00189                 if ((*ppPrev)->user != user)
00190                 {
00191                     /* terminal thunk is being restored */
00192 
00193                     WINPROC_FreeProc( *pFirst, (*ppPrev)->user );
00194                     *(WINDOWPROC **)pFirst = *ppPrev;
00195                     return TRUE;
00196                 }
00197                 bRecycle = TRUE;
00198                 break;
00199             }
00200         }
00201         else
00202         {
00203             if (((*ppPrev)->type == type) &&
00204                 (func == WINPROC_THUNKPROC(*ppPrev)))
00205             {
00206                 bRecycle = TRUE;
00207                 break;
00208             }
00209         }
00210 
00211         /* WPF_CLASS thunk terminates window thunk list */
00212         if ((*ppPrev)->user != user) break;
00213         ppPrev = &(*ppPrev)->next;
00214     }
00215 
00216     if (bRecycle)
00217     {
00218         /* Extract this thunk from the list */
00219         proc = *ppPrev;
00220         *ppPrev = proc->next;
00221     }
00222     else  /* Allocate a new one */
00223     {
00224         if (proc)  /* Was already a win proc */
00225         {
00226             type = proc->type;
00227             func = WINPROC_THUNKPROC(proc);
00228         }
00229         proc = WINPROC_AllocWinProc( func, type, user );
00230         if (!proc) return FALSE;
00231     }
00232 
00233     /* Add the win proc at the head of the list */
00234 
00235     proc->next  = *(WINDOWPROC **)pFirst;
00236     *(WINDOWPROC **)pFirst = proc;
00237     return TRUE;
00238 }
00239 
00240 
00241 /**********************************************************************
00242  *           WINPROC_FreeProc
00243  *
00244  * Free a list of win procs.
00245  */
00246 void WINPROC_FreeProc( HWINDOWPROC proc, WINDOWPROCUSER user )
00247 {
00248     while (proc)
00249     {
00250         WINDOWPROC *next = ((WINDOWPROC *)proc)->next;
00251         if (((WINDOWPROC *)proc)->user != user) break;
00252         free( proc );
00253         proc = next;
00254     }
00255 }
00256 
00257 
00258 /**********************************************************************
00259  *           WINPROC_GetProcType
00260  *
00261  * Return the window procedure type.
00262  */
00263 WINDOWPROCTYPE WINPROC_GetProcType( HWINDOWPROC proc )
00264 {
00265     if (!proc ||
00266         (((WINDOWPROC *)proc)->magic != WINPROC_MAGIC))
00267         return WIN_PROC_INVALID;
00268     return ((WINDOWPROC *)proc)->type;
00269 }
00270 
00271 /**********************************************************************
00272  *           CallWindowProc32A    (USER32.18)
00273  *
00274  * The CallWindowProc() function invokes the windows procedure _func_,
00275  * with _hwnd_ as the target window, the message specified by _msg_, and
00276  * the message parameters _wParam_ and _lParam_.
00277  *
00278  * Some kinds of argument conversion may be done, I'm not sure what.
00279  *
00280  * CallWindowProc() may be used for windows subclassing. Use
00281  * SetWindowLong() to set a new windows procedure for windows of the
00282  * subclass, and handle subclassed messages in the new windows
00283  * procedure. The new windows procedure may then use CallWindowProc()
00284  * with _func_ set to the parent class's windows procedure to dispatch
00285  * the message to the superclass.
00286  *
00287  * RETURNS
00288  *
00289  *    The return value is message dependent.
00290  *
00291  * CONFORMANCE
00292  *
00293  *   ECMA-234, Win32
00294  */
00295 LRESULT WINAPI CallWindowProcA(
00296     WNDPROC func, /* window procedure */
00297     HWND hwnd, /* target window */
00298     UINT msg,  /* message */
00299     WPARAM wParam, /* message dependent parameter */
00300     LPARAM lParam    /* message dependent parameter */
00301 ) {
00302     WINDOWPROC *proc = WINPROC_GetPtr( func );
00303 
00304     if(proc) {
00305           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)));
00306     }
00307     else  dprintf2(("CallWindowProcA %x %x %x %x %x (unknown proc)", func, hwnd, msg, wParam, lParam));
00308    
00309     if(!IsWindow(hwnd)) {
00310         dprintf(("CallWindowProcA, window %x not found", hwnd));
00311         // return func( hwnd, msg, wParam, lParam );
00312         return 0;
00313     }
00314 
00315     if (!proc) return func(hwnd, msg, wParam, lParam );
00316 
00317     switch(proc->type)
00318     {
00319     case WIN_PROC_32A:
00320         return func(hwnd, msg, wParam, lParam );
00321     case WIN_PROC_32W:
00322         return WINPROC_CallProc32ATo32W( func, hwnd, msg, wParam, lParam );
00323     default:
00324         WARN_(relay)("Invalid proc %p\n", proc );
00325         return 0;
00326     }
00327 }
00328 
00329 
00330 /**********************************************************************
00331  *           CallWindowProc32W    (USER32.19)
00332  */
00333 LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
00334                                 WPARAM wParam, LPARAM lParam )
00335 {
00336     WINDOWPROC *proc = WINPROC_GetPtr( func );
00337 
00338     if(proc) {
00339           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)));
00340     }
00341     else  dprintf2(("CallWindowProcW %x %x %x %x %x (unknown proc)", func, hwnd, msg, wParam, lParam));
00342 
00343     if(!IsWindow(hwnd)) {
00344         dprintf(("CallWindowProcW, window %x not found", hwnd));
00345         // return func( hwnd, msg, wParam, lParam );
00346         return 0;
00347     }
00348 
00349     if (!proc) return func( hwnd, msg, wParam, lParam );
00350 
00351     switch(proc->type)
00352     {
00353     case WIN_PROC_32A:
00354         return WINPROC_CallProc32WTo32A( func, hwnd, msg, wParam, lParam );
00355     case WIN_PROC_32W:
00356         return func(hwnd, msg, wParam, lParam );
00357     default:
00358         WARN_(relay)("Invalid proc %p\n", proc );
00359         return 0;
00360     }
00361 }
00362 

Generated on Wed Jan 23 23:17:55 2002 for ODIN-user32 by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001