/* * Window procedure callbacks * * Copyright 1995 Martin von Loewis * Copyright 1996 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #include #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "wownt32.h" #include "wine/winbase16.h" #include "wine/winuser16.h" #include "controls.h" #include "win.h" #include "winproc.h" #include "user_private.h" #include "dde.h" #include "winternl.h" #include "wine/unicode.h" #include "wine/debug.h" WINE_DECLARE_DEBUG_CHANNEL(msg); WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DEFAULT_DEBUG_CHANNEL(win); typedef struct tagWINDOWPROC { WNDPROC16 proc16; /* 16-bit window proc */ WNDPROC procA; /* ASCII window proc */ WNDPROC procW; /* Unicode window proc */ } WINDOWPROC; #define WINPROC_HANDLE (~0UL >> 16) #define MAX_WINPROCS 8192 static WINDOWPROC winproc_array[MAX_WINPROCS]; static UINT winproc_used; static CRITICAL_SECTION winproc_cs; static CRITICAL_SECTION_DEBUG critsect_debug = { 0, 0, &winproc_cs, { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": winproc_cs") } }; static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; static inline void *get_buffer( void *static_buffer, size_t size, size_t need ) { if (size >= need) return static_buffer; return HeapAlloc( GetProcessHeap(), 0, need ); } static inline void free_buffer( void *static_buffer, void *buffer ) { if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); } /* find an existing winproc for a given 16-bit function and type */ /* FIXME: probably should do something more clever than a linear search */ static inline WINDOWPROC *find_winproc16( WNDPROC16 func ) { unsigned int i; for (i = 0; i < winproc_used; i++) { if (winproc_array[i].proc16 == func) return &winproc_array[i]; } return NULL; } /* find an existing winproc for a given function and type */ /* FIXME: probably should do something more clever than a linear search */ static inline WINDOWPROC *find_winproc( WNDPROC funcA, WNDPROC funcW ) { unsigned int i; for (i = 0; i < winproc_used; i++) { if (funcA && winproc_array[i].procA != funcA) continue; if (funcW && winproc_array[i].procW != funcW) continue; return &winproc_array[i]; } return NULL; } /* return the window proc for a given handle, or NULL for an invalid handle */ static inline WINDOWPROC *handle_to_proc( WNDPROC handle ) { UINT index = LOWORD(handle); if ((ULONG_PTR)handle >> 16 != WINPROC_HANDLE) return NULL; if (index >= winproc_used) return NULL; return &winproc_array[index]; } /* create a handle for a given window proc */ static inline WNDPROC proc_to_handle( WINDOWPROC *proc ) { return (WNDPROC)(ULONG_PTR)((proc - winproc_array) | (WINPROC_HANDLE << 16)); } /* allocate and initialize a new winproc */ static inline WINDOWPROC *alloc_winproc( WNDPROC funcA, WNDPROC funcW ) { WINDOWPROC *proc; /* check if the function is already a win proc */ if (funcA && (proc = handle_to_proc( funcA ))) return proc; if (funcW && (proc = handle_to_proc( funcW ))) return proc; if (!funcA && !funcW) return NULL; EnterCriticalSection( &winproc_cs ); /* check if we already have a winproc for that function */ if (!(proc = find_winproc( funcA, funcW ))) { if (winproc_used < MAX_WINPROCS) { proc = &winproc_array[winproc_used++]; proc->procA = funcA; proc->procW = funcW; TRACE( "allocated %p for %p/%p (%d/%d used)\n", proc_to_handle(proc), funcA, funcW, winproc_used, MAX_WINPROCS ); } else FIXME( "too many winprocs, cannot allocate one for %p/%p\n", funcA, funcW ); } else TRACE( "reusing %p for %p/%p\n", proc_to_handle(proc), funcA, funcW ); LeaveCriticalSection( &winproc_cs ); return proc; } #ifdef __i386__ #include "pshpack1.h" /* Window procedure 16-to-32-bit thunk */ typedef struct { BYTE popl_eax; /* popl %eax (return address) */ BYTE pushl_func; /* pushl $proc */ WINDOWPROC *proc; BYTE pushl_eax; /* pushl %eax */ BYTE ljmp; /* ljmp relay*/ DWORD relay_offset; /* __wine_call_wndproc */ WORD relay_sel; } WINPROC_THUNK; #include "poppack.h" #define MAX_THUNKS (0x10000 / sizeof(WINPROC_THUNK)) static WINPROC_THUNK *thunk_array; static UINT thunk_selector; static UINT thunk_used; /* return the window proc for a given handle, or NULL for an invalid handle */ static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle ) { if (HIWORD(handle) == thunk_selector) { UINT index = LOWORD(handle) / sizeof(WINPROC_THUNK); /* check alignment */ if (index * sizeof(WINPROC_THUNK) != LOWORD(handle)) return NULL; /* check array limits */ if (index >= thunk_used) return NULL; return thunk_array[index].proc; } return handle_to_proc( (WNDPROC)handle ); } /* allocate a 16-bit thunk for an existing window proc */ static WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc ) { static FARPROC16 relay; UINT i; if (proc->proc16) return proc->proc16; EnterCriticalSection( &winproc_cs ); if (!thunk_array) /* allocate the array and its selector */ { LDT_ENTRY entry; if (!(thunk_selector = wine_ldt_alloc_entries(1))) goto done; if (!(thunk_array = VirtualAlloc( NULL, MAX_THUNKS * sizeof(WINPROC_THUNK), MEM_COMMIT, PAGE_EXECUTE_READWRITE ))) goto done; wine_ldt_set_base( &entry, thunk_array ); wine_ldt_set_limit( &entry, MAX_THUNKS * sizeof(WINPROC_THUNK) - 1 ); wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT ); wine_ldt_set_entry( thunk_selector, &entry ); relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" ); } /* check if it already exists */ for (i = 0; i < thunk_used; i++) if (thunk_array[i].proc == proc) break; if (i == thunk_used) /* create a new one */ { WINPROC_THUNK *thunk; if (thunk_used >= MAX_THUNKS) goto done; thunk = &thunk_array[thunk_used++]; thunk->popl_eax = 0x58; /* popl %eax */ thunk->pushl_func = 0x68; /* pushl $proc */ thunk->proc = proc; thunk->pushl_eax = 0x50; /* pushl %eax */ thunk->ljmp = 0xea; /* ljmp relay*/ thunk->relay_offset = OFFSETOF(relay); thunk->relay_sel = SELECTOROF(relay); } proc->proc16 = (WNDPROC16)MAKESEGPTR( thunk_selector, i * sizeof(WINPROC_THUNK) ); done: LeaveCriticalSection( &winproc_cs ); return proc->proc16; } #else /* __i386__ */ static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle ) { return handle_to_proc( (WNDPROC)handle ); } static inline WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc ) { return 0; } #endif /* __i386__ */ #ifdef __i386__ /* Some window procedures modify register they shouldn't, or are not * properly declared stdcall; so we need a small assembly wrapper to * call them. */ extern LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); __ASM_GLOBAL_FUNC( WINPROC_wrapper, "pushl %ebp\n\t" "movl %esp,%ebp\n\t" "pushl %edi\n\t" "pushl %esi\n\t" "pushl %ebx\n\t" "subl $12,%esp\n\t" "pushl 24(%ebp)\n\t" "pushl 20(%ebp)\n\t" "pushl 16(%ebp)\n\t" "pushl 12(%ebp)\n\t" "movl 8(%ebp),%eax\n\t" "call *%eax\n\t" "leal -12(%ebp),%esp\n\t" "popl %ebx\n\t" "popl %esi\n\t" "popl %edi\n\t" "leave\n\t" "ret" ); #else static inline LRESULT WINPROC_wrapper( WNDPROC proc, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { return proc( hwnd, msg, wParam, lParam ); } #endif /* __i386__ */ static void RECT16to32( const RECT16 *from, RECT *to ) { to->left = from->left; to->top = from->top; to->right = from->right; to->bottom = from->bottom; } static void RECT32to16( const RECT *from, RECT16 *to ) { to->left = from->left; to->top = from->top; to->right = from->right; to->bottom = from->bottom; } static void MINMAXINFO32to16( const MINMAXINFO *from, MINMAXINFO16 *to ) { to->ptReserved.x = from->ptReserved.x; to->ptReserved.y = from->ptReserved.y; to->ptMaxSize.x = from->ptMaxSize.x; to->ptMaxSize.y = from->ptMaxSize.y; to->ptMaxPosition.x = from->ptMaxPosition.x; to->ptMaxPosition.y = from->ptMaxPosition.y; to->ptMinTrackSize.x = from->ptMinTrackSize.x; to->ptMinTrackSize.y = from->ptMinTrackSize.y; to->ptMaxTrackSize.x = from->ptMaxTrackSize.x; to->ptMaxTrackSize.y = from->ptMaxTrackSize.y; } static void MINMAXINFO16to32( const MINMAXINFO16 *from, MINMAXINFO *to ) { to->ptReserved.x = from->ptReserved.x; to->ptReserved.y = from->ptReserved.y; to->ptMaxSize.x = from->ptMaxSize.x; to->ptMaxSize.y = from->ptMaxSize.y; to->ptMaxPosition.x = from->ptMaxPosition.x; to->ptMaxPosition.y = from->ptMaxPosition.y; to->ptMinTrackSize.x = from->ptMinTrackSize.x; to->ptMinTrackSize.y = from->ptMinTrackSize.y; to->ptMaxTrackSize.x = from->ptMaxTrackSize.x; to->ptMaxTrackSize.y = from->ptMaxTrackSize.y; } static void WINDOWPOS32to16( const WINDOWPOS* from, WINDOWPOS16* to ) { to->hwnd = HWND_16(from->hwnd); to->hwndInsertAfter = HWND_16(from->hwndInsertAfter); to->x = from->x; to->y = from->y; to->cx = from->cx; to->cy = from->cy; to->flags = from->flags; } static void WINDOWPOS16to32( const WINDOWPOS16* from, WINDOWPOS* to ) { to->hwnd = WIN_Handle32(from->hwnd); to->hwndInsertAfter = (from->hwndInsertAfter == (HWND16)-1) ? HWND_TOPMOST : WIN_Handle32(from->hwndInsertAfter); to->x = from->x; to->y = from->y; to->cx = from->cx; to->cy = from->cy; to->flags = from->flags; } /* The strings are not copied */ static void CREATESTRUCT32Ato16( const CREATESTRUCTA* from, CREATESTRUCT16* to ) { to->lpCreateParams = (SEGPTR)from->lpCreateParams; to->hInstance = HINSTANCE_16(from->hInstance); to->hMenu = HMENU_16(from->hMenu); to->hwndParent = HWND_16(from->hwndParent); to->cy = from->cy; to->cx = from->cx; to->y = from->y; to->x = from->x; to->style = from->style; to->dwExStyle = from->dwExStyle; } static void CREATESTRUCT16to32A( const CREATESTRUCT16* from, CREATESTRUCTA *to ) { to->lpCreateParams = (LPVOID)from->lpCreateParams; to->hInstance = HINSTANCE_32(from->hInstance); to->hMenu = HMENU_32(from->hMenu); to->hwndParent = WIN_Handle32(from->hwndParent); to->cy = from->cy; to->cx = from->cx; to->y = from->y; to->x = from->x; to->style = from->style; to->dwExStyle = from->dwExStyle; to->lpszName = MapSL(from->lpszName); to->lpszClass = MapSL(from->lpszClass); } /* The strings are not copied */ static void MDICREATESTRUCT32Ato16( const MDICREATESTRUCTA* from, MDICREATESTRUCT16* to ) { to->hOwner = HINSTANCE_16(from->hOwner); to->x = from->x; to->y = from->y; to->cx = from->cx; to->cy = from->cy; to->style = from->style; to->lParam = from->lParam; } static void MDICREATESTRUCT16to32A( const MDICREATESTRUCT16* from, MDICREATESTRUCTA *to ) { to->hOwner = HINSTANCE_32(from->hOwner); to->x = from->x; to->y = from->y; to->cx = from->cx; to->cy = from->cy; to->style = from->style; to->lParam = from->lParam; to->szTitle = MapSL(from->szTitle); to->szClass = MapSL(from->szClass); } static WPARAM map_wparam_char_AtoW( WPARAM wParam, DWORD len ) { CHAR ch[2]; WCHAR wch; ch[0] = (wParam >> 8); ch[1] = wParam & 0xff; if (len > 1 && ch[0]) RtlMultiByteToUnicodeN( &wch, sizeof(wch), NULL, ch, 2 ); else RtlMultiByteToUnicodeN( &wch, sizeof(wch), NULL, ch + 1, 1 ); return MAKEWPARAM( wch, HIWORD(wParam) ); } static WPARAM map_wparam_char_WtoA( WPARAM wParam, DWORD len ) { WCHAR wch = wParam; BYTE ch[2]; RtlUnicodeToMultiByteN( (LPSTR)ch, len, &len, &wch, sizeof(wch) ); if (len == 2) return MAKEWPARAM( (ch[0] << 8) | ch[1], HIWORD(wParam) ); else return MAKEWPARAM( ch[0], HIWORD(wParam) ); } /* call a 32-bit window procedure */ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg ) { WNDPROC proc = arg; USER_CheckNotLock(); hwnd = WIN_GetFullHandle( hwnd ); if (TRACE_ON(relay)) DPRINTF( "%04lx:Call window proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n", GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp ); *result = WINPROC_wrapper( proc, hwnd, msg, wp, lp ); if (TRACE_ON(relay)) DPRINTF( "%04lx:Ret window proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx) retval=%08lx\n", GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, *result ); return *result; } /* call a 32-bit dialog procedure */ static LRESULT call_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg ) { WNDPROC proc = arg; LRESULT ret; USER_CheckNotLock(); hwnd = WIN_GetFullHandle( hwnd ); if (TRACE_ON(relay)) DPRINTF( "%04lx:Call dialog proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n", GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp ); ret = WINPROC_wrapper( proc, hwnd, msg, wp, lp ); *result = GetWindowLongPtrW( hwnd, DWLP_MSGRESULT ); if (TRACE_ON(relay)) DPRINTF( "%04lx:Ret dialog proc %p (hwnd=%p,msg=%s,wp=%08x,lp=%08lx) retval=%08lx result=%08lx\n", GetCurrentThreadId(), proc, hwnd, SPY_GetMsgName(msg, hwnd), wp, lp, ret, *result ); return ret; } /* call a 16-bit window procedure */ static LRESULT call_window_proc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg ) { WNDPROC16 proc = arg; CONTEXT86 context; size_t size = 0; struct { WORD params[5]; union { CREATESTRUCT16 cs16; DRAWITEMSTRUCT16 dis16; COMPAREITEMSTRUCT16 cis16; } u; } args; USER_CheckNotLock(); /* Window procedures want ax = hInstance, ds = es = ss */ memset(&context, 0, sizeof(context)); context.SegDs = context.SegEs = SELECTOROF(NtCurrentTeb()->WOW32Reserved); context.SegFs = wine_get_fs(); context.SegGs = wine_get_gs(); if (!(context.Eax = GetWindowWord( HWND_32(hwnd), GWLP_HINSTANCE ))) context.Eax = context.SegDs; context.SegCs = SELECTOROF(proc); context.Eip = OFFSETOF(proc); context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + (WORD)&((STACK16FRAME*)0)->bp; if (lParam) { /* Some programs (eg. the "Undocumented Windows" examples, JWP) only work if structures passed in lParam are placed in the stack/data segment. Programmers easily make the mistake of converting lParam to a near rather than a far pointer, since Windows apparently allows this. We copy the structures to the 16 bit stack; this is ugly but makes these programs work. */ switch (msg) { case WM_CREATE: case WM_NCCREATE: size = sizeof(CREATESTRUCT16); break; case WM_DRAWITEM: size = sizeof(DRAWITEMSTRUCT16); break; case WM_COMPAREITEM: size = sizeof(COMPAREITEMSTRUCT16); break; } if (size) { memcpy( &args.u, MapSL(lParam), size ); lParam = (SEGPTR)NtCurrentTeb()->WOW32Reserved - size; } } args.params[4] = hwnd; args.params[3] = msg; args.params[2] = wParam; args.params[1] = HIWORD(lParam); args.params[0] = LOWORD(lParam); WOWCallback16Ex( 0, WCB16_REGS, sizeof(args.params) + size, &args, (DWORD *)&context ); *result = MAKELONG( LOWORD(context.Eax), LOWORD(context.Edx) ); return *result; } /* call a 16-bit dialog procedure */ static LRESULT call_dialog_proc16( HWND16 hwnd, UINT16 msg, WPARAM16 wp, LPARAM lp, LRESULT *result, void *arg ) { LRESULT ret = call_window_proc16( hwnd, msg, wp, lp, result, arg ); *result = GetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT ); return LOWORD(ret); } /* helper callback for 32W->16 conversion */ static LRESULT call_window_proc_Ato16( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg ) { return WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wp, lp, result, arg ); } /* helper callback for 32W->16 conversion */ static LRESULT call_dialog_proc_Ato16( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg ) { return WINPROC_CallProc32ATo16( call_dialog_proc16, hwnd, msg, wp, lp, result, arg ); } /* helper callback for 16->32W conversion */ static LRESULT call_window_proc_AtoW( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg ) { return WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wp, lp, result, arg ); } /* helper callback for 16->32W conversion */ static LRESULT call_dialog_proc_AtoW( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result, void *arg ) { return WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wp, lp, result, arg ); } /********************************************************************** * WINPROC_GetProc16 * * Get a window procedure pointer that can be passed to the Windows program. */ WNDPROC16 WINPROC_GetProc16( WNDPROC proc, BOOL unicode ) { WINDOWPROC *ptr; if (unicode) ptr = alloc_winproc( NULL, proc ); else ptr = alloc_winproc( proc, NULL ); if (!ptr) return 0; return alloc_win16_thunk( ptr ); } /********************************************************************** * WINPROC_GetProc * * Get a window procedure pointer that can be passed to the Windows program. */ WNDPROC WINPROC_GetProc( WNDPROC proc, BOOL unicode ) { WINDOWPROC *ptr = handle_to_proc( proc ); if (!ptr) return proc; if (unicode) { if (ptr->procW) return ptr->procW; return proc; } else { if (ptr->procA) return ptr->procA; return proc; } } /********************************************************************** * WINPROC_AllocProc16 * * Allocate a window procedure for a window or class. * * Note that allocated winprocs are never freed; the idea is that even if an app creates a * lot of windows, it will usually only have a limited number of window procedures, so the * array won't grow too large, and this way we avoid the need to track allocations per window. */ WNDPROC WINPROC_AllocProc16( WNDPROC16 func ) { WINDOWPROC *proc; if (!func) return NULL; /* check if the function is already a win proc */ if (!(proc = handle16_to_proc( func ))) { EnterCriticalSection( &winproc_cs ); /* then check if we already have a winproc for that function */ if (!(proc = find_winproc16( func ))) { if (winproc_used < MAX_WINPROCS) { proc = &winproc_array[winproc_used++]; proc->proc16 = func; TRACE( "allocated %p for %p/16-bit (%d/%d used)\n", proc_to_handle(proc), func, winproc_used, MAX_WINPROCS ); } else FIXME( "too many winprocs, cannot allocate one for 16-bit %p\n", func ); } else TRACE( "reusing %p for %p/16-bit\n", proc_to_handle(proc), func ); LeaveCriticalSection( &winproc_cs ); } return proc_to_handle( proc ); } /********************************************************************** * WINPROC_AllocProc * * Allocate a window procedure for a window or class. * * Note that allocated winprocs are never freed; the idea is that even if an app creates a * lot of windows, it will usually only have a limited number of window procedures, so the * array won't grow too large, and this way we avoid the need to track allocations per window. */ WNDPROC WINPROC_AllocProc( WNDPROC funcA, WNDPROC funcW ) { WINDOWPROC *proc; if (!(proc = alloc_winproc( funcA, funcW ))) return NULL; return proc_to_handle( proc ); } /********************************************************************** * WINPROC_IsUnicode * * Return the window procedure type, or the default value if not a winproc handle. */ BOOL WINPROC_IsUnicode( WNDPROC proc, BOOL def_val ) { WINDOWPROC *ptr = handle_to_proc( proc ); if (!ptr) return def_val; if (ptr->procA && ptr->procW) return def_val; /* can be both */ return (ptr->procW != NULL); } /********************************************************************** * WINPROC_TestLBForStr * * Return TRUE if the lparam is a string */ inline static BOOL WINPROC_TestLBForStr( HWND hwnd, UINT msg ) { DWORD style = GetWindowLongA( hwnd, GWL_STYLE ); if (msg <= CB_MSGMAX) return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS)); else return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS)); } static UINT convert_handle_16_to_32(HANDLE16 src, unsigned int flags) { HANDLE dst; UINT sz = GlobalSize16(src); LPSTR ptr16, ptr32; if (!(dst = GlobalAlloc(flags, sz))) return 0; ptr16 = GlobalLock16(src); ptr32 = GlobalLock(dst); if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr32, ptr16, sz); GlobalUnlock16(src); GlobalUnlock(dst); return (UINT)dst; } static HANDLE16 convert_handle_32_to_16(UINT src, unsigned int flags) { HANDLE16 dst; UINT sz = GlobalSize((HANDLE)src); LPSTR ptr16, ptr32; if (!(dst = GlobalAlloc16(flags, sz))) return 0; ptr32 = GlobalLock((HANDLE)src); ptr16 = GlobalLock16(dst); if (ptr16 != NULL && ptr32 != NULL) memcpy(ptr16, ptr32, sz); GlobalUnlock((HANDLE)src); GlobalUnlock16(dst); return dst; } /********************************************************************** * WINPROC_MapMsg32ATo16 * * Map a message from 32-bit Ansi to 16-bit. * Return value is -1 on error, 0 if OK, 1 if an UnmapMsg call is needed. */ static INT WINPROC_MapMsg32ATo16( HWND hwnd, UINT msg32, WPARAM wParam32, UINT16 *pmsg16, WPARAM16 *pwparam16, LPARAM *plparam ) { *pmsg16 = (UINT16)msg32; *pwparam16 = (WPARAM16)LOWORD(wParam32); switch(msg32) { case SBM_SETRANGE: *pmsg16 = SBM_SETRANGE16; *plparam = MAKELPARAM(wParam32, *plparam); *pwparam16 = 0; return 0; case SBM_GETRANGE: *pmsg16 = SBM_GETRANGE16; return 1; case BM_GETCHECK: case BM_SETCHECK: case BM_GETSTATE: case BM_SETSTATE: case BM_SETSTYLE: *pmsg16 = (UINT16)msg32 + (BM_GETCHECK16 - BM_GETCHECK); return 0; case EM_GETSEL: case EM_GETRECT: case EM_SETRECT: case EM_SETRECTNP: case EM_SCROLL: case EM_LINESCROLL: case EM_SCROLLCARET: case EM_GETMODIFY: case EM_SETMODIFY: case EM_GETLINECOUNT: case EM_LINEINDEX: case EM_SETHANDLE: case EM_GETHANDLE: case EM_GETTHUMB: case EM_LINELENGTH: case EM_REPLACESEL: case EM_GETLINE: case EM_LIMITTEXT: case EM_CANUNDO: case EM_UNDO: case EM_FMTLINES: case EM_LINEFROMCHAR: case EM_SETTABSTOPS: case EM_SETPASSWORDCHAR: case EM_EMPTYUNDOBUFFER: case EM_GETFIRSTVISIBLELINE: case EM_SETREADONLY: case EM_SETWORDBREAKPROC: case EM_GETWORDBREAKPROC: case EM_GETPASSWORDCHAR: *pmsg16 = (UINT16)msg32 + (EM_GETSEL16 - EM_GETSEL); return 0; case LB_CARETOFF: case LB_CARETON: case LB_DELETESTRING: case LB_GETANCHORINDEX: case LB_GETCARETINDEX: case LB_GETCOUNT: case LB_GETCURSEL: case LB_GETHORIZONTALEXTENT: case LB_GETITEMDATA: case LB_GETITEMHEIGHT: case LB_GETSEL: case LB_GETSELCOUNT: case LB_GETTEXTLEN: case LB_GETTOPINDEX: case LB_RESETCONTENT: case LB_SELITEMRANGE: case LB_SELITEMRANGEEX: case LB_SETANCHORINDEX: case LB_SETCARETINDEX: case LB_SETCOLUMNWIDTH: case LB_SETCURSEL: case LB_SETHORIZONTALEXTENT: case LB_SETITEMDATA: case LB_SETITEMHEIGHT: case LB_SETSEL: case LB_SETTOPINDEX: *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING); return 0; case CB_DELETESTRING: case CB_GETCOUNT: case CB_GETLBTEXTLEN: case CB_LIMITTEXT: case CB_RESETCONTENT: case CB_SETEDITSEL: case CB_GETCURSEL: case CB_SETCURSEL: case CB_SHOWDROPDOWN: case CB_SETITEMDATA: case CB_SETITEMHEIGHT: case CB_GETITEMHEIGHT: case CB_SETEXTENDEDUI: case CB_GETEXTENDEDUI: case CB_GETDROPPEDSTATE: *pmsg16 = (UINT16)msg32 + (CB_GETEDITSEL16 - CB_GETEDITSEL); return 0; case CB_GETEDITSEL: *pmsg16 = CB_GETEDITSEL16; return 1; case LB_ADDSTRING: case LB_FINDSTRING: case LB_FINDSTRINGEXACT: case LB_INSERTSTRING: case LB_SELECTSTRING: case LB_DIR: case LB_ADDFILE: *plparam = (LPARAM)MapLS( (LPSTR)*plparam ); *pmsg16 = (UINT16)msg32 + (LB_ADDSTRING16 - LB_ADDSTRING); return 1; case CB_ADDSTRING: case CB_FINDSTRING: case CB_FINDSTRINGEXACT: case CB_INSERTSTRING: case CB_SELECTSTRING: case CB_DIR: *plparam = (LPARAM)MapLS( (LPSTR)*plparam ); *pmsg16 = (UINT16)msg32 + (CB_GETEDITSEL16 - CB_GETEDITSEL); return 1; case LB_GETITEMRECT: { RECT16 *rect = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT16) + sizeof(LPARAM) ); if (!rect) return -1; *(LPARAM *)(rect + 1) = *plparam; /* Store the previous lParam */ *plparam = MapLS( rect ); } *pmsg16 = LB_GETITEMRECT16; return 1; case LB_GETSELITEMS: { LPARAM *items; /* old LPARAM first, then *pwparam16 x INT16 entries */ *pwparam16 = (WPARAM16)min( wParam32, 0x7f80 ); /* Must be < 64K */ if (!(items = HeapAlloc( GetProcessHeap(), 0, *pwparam16 * sizeof(INT16) + sizeof(LPARAM)))) return -1; *items++ = *plparam; /* Store the previous lParam */ *plparam = MapLS( items ); } *pmsg16 = LB_GETSELITEMS16; return 1; case LB_SETTABSTOPS: if (wParam32) { INT i; LPINT16 stops; *pwparam16 = (WPARAM16)min( wParam32, 0x7f80 ); /* Must be < 64K */ if (!(stops = HeapAlloc( GetProcessHeap(), 0, *pwparam16 * sizeof(INT16) + sizeof(LPARAM)))) return -1; for (i = 0; i < *pwparam16; i++) stops[i] = *((LPINT)*plparam+i); *plparam = MapLS( stops ); return 1; } *pmsg16 = LB_SETTABSTOPS16; return 0; case CB_GETDROPPEDCONTROLRECT: { RECT16 *rect = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT16) + sizeof(LPARAM) ); if (!rect) return -1; *(LPARAM *)(rect + 1) = *plparam; /* Store the previous lParam */ *plparam = (LPARAM)MapLS(rect); } *pmsg16 = CB_GETDROPPEDCONTROLRECT16; return 1; case LB_GETTEXT: *plparam = (LPARAM)MapLS( (LPVOID)(*plparam) ); *pmsg16 = LB_GETTEXT16; return 1; case CB_GETLBTEXT: *plparam = (LPARAM)MapLS( (LPVOID)(*plparam) ); *pmsg16 = CB_GETLBTEXT16; return 1; case EM_SETSEL: *pwparam16 = 0; *plparam = MAKELONG( (INT16)(INT)wParam32, (INT16)*plparam ); *pmsg16 = EM_SETSEL16; return 0; case WM_ACTIVATE: case WM_CHARTOITEM: case WM_COMMAND: case WM_VKEYTOITEM: *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32) ); return 0; case WM_HSCROLL: case WM_VSCROLL: *plparam = MAKELPARAM( HIWORD(wParam32), (HWND16)*plparam ); return 0; case WM_CTLCOLORMSGBOX: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: *pmsg16 = WM_CTLCOLOR; *plparam = MAKELPARAM( (HWND16)*plparam, (WORD)msg32 - WM_CTLCOLORMSGBOX ); return 0; case WM_GETTEXT: case WM_ASKCBFORMATNAME: { LPARAM *str; /* store LPARAM, then *pwparam16 char space */ *pwparam16 = (WPARAM16)min( wParam32, 0xff80 ); /* Must be < 64K */ if (!(str = HeapAlloc( GetProcessHeap(), 0, *pwparam16 + sizeof(LPARAM)))) return -1; *str++ = *plparam; /* Store the previous lParam */ *plparam = MapLS( str ); } return 1; case WM_MENUSELECT: if(HIWORD(wParam32) & MF_POPUP) { HMENU hmenu; if (((UINT)HIWORD(wParam32) != 0xFFFF) || (*plparam)) { if((hmenu = GetSubMenu((HMENU)*plparam, *pwparam16))) *pwparam16=HMENU_16(hmenu); } } /* fall through */ case WM_MENUCHAR: *plparam = MAKELPARAM( HIWORD(wParam32), (HMENU16)*plparam ); return 0; case WM_PARENTNOTIFY: if ((LOWORD(wParam32)==WM_CREATE) || (LOWORD(wParam32)==WM_DESTROY)) *plparam = MAKELPARAM( (HWND16)*plparam, HIWORD(wParam32)); /* else nothing to do */ return 0; case WM_NOTIFY: *plparam = MapLS( (NMHDR *)*plparam ); /* NMHDR is already 32-bit */ return 1; case WM_SETTEXT: case WM_WININICHANGE: case WM_DEVMODECHANGE: *plparam = MapLS( (LPSTR)*plparam ); return 1; case WM_ACTIVATEAPP: if (*plparam) *plparam = HTASK_16( (HANDLE)*plparam ); return 0; case WM_PAINT: if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON )) { *pmsg16 = WM_PAINTICON; *pwparam16 = 1; } return 0; case WM_ERASEBKGND: if (IsIconic( hwnd ) && GetClassLongPtrW( hwnd, GCLP_HICON )) *pmsg16 = WM_ICONERASEBKGND; return 0; case WM_PAINTCLIPBOARD: case WM_SIZECLIPBOARD: FIXME_(msg)("message %04x needs translation\n", msg32 ); return -1; /* following messages should not be sent to 16-bit apps */ case WM_SIZING: case WM_MOVING: case WM_CAPTURECHANGED: case WM_STYLECHANGING: case WM_STYLECHANGED: return -1; case WM_DDE_INITIATE: case WM_DDE_TERMINATE: case WM_DDE_UNADVISE: case WM_DDE_REQUEST: *pwparam16 = HWND_16((HWND)wParam32); return 0; case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: { UINT_PTR lo32, hi; HANDLE16 lo16 = 0; *pwparam16 = HWND_16((HWND)wParam32); UnpackDDElParam(msg32, *plparam, &lo32, &hi); if (lo32 && !(lo16 = convert_handle_32_to_16(lo32, GMEM_DDESHARE))) return -1; *plparam = MAKELPARAM(lo16, hi); } return 0; /* FIXME don't know how to free allocated memory (handle) !! */ case WM_DDE_ACK: { UINT_PTR lo, hi; int flag = 0; char buf[2]; *pwparam16 = HWND_16((HWND)wParam32); UnpackDDElParam(msg32, *plparam, &lo, &hi); if (GlobalGetAtomNameA((ATOM)hi, buf, sizeof(buf)) > 0) flag |= 1; if (GlobalSize((HANDLE)hi) != 0) flag |= 2; switch (flag) { case 0: if (hi) { MESSAGE("DDE_ACK: neither atom nor handle!!!\n"); hi = 0; } break; case 1: break; /* atom, nothing to do */ case 3: MESSAGE("DDE_ACK: %x both atom and handle... choosing handle\n", hi); /* fall thru */ case 2: hi = convert_handle_32_to_16(hi, GMEM_DDESHARE); break; } *plparam = MAKELPARAM(lo, hi); } return 0; /* FIXME don't know how to free allocated memory (handle) !! */ case WM_DDE_EXECUTE: *plparam = convert_handle_32_to_16(*plparam, GMEM_DDESHARE); return 0; /* FIXME don't know how to free allocated memory (handle) !! */ default: /* No translation needed */ return 0; } } /********************************************************************** * WINPROC_UnmapMsg32ATo16 * * Unmap a message that was mapped from 32-bit Ansi to 16-bit. */ static void WINPROC_UnmapMsg32ATo16( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WPARAM16 wParam16, LPARAM lParam16, LRESULT *result ) { switch(msg) { case SBM_GETRANGE: *(LPINT)wParam = LOWORD(*result); *(LPINT)lParam = HIWORD(*result); break; case LB_ADDFILE: case LB_ADDSTRING: case LB_DIR: case LB_FINDSTRING: case LB_FINDSTRINGEXACT: case LB_INSERTSTRING: case LB_SELECTSTRING: case LB_GETTEXT: case CB_ADDSTRING: case CB_FINDSTRING: case CB_FINDSTRINGEXACT: case CB_INSERTSTRING: case CB_SELECTSTRING: case CB_DIR: case CB_GETLBTEXT: case WM_SETTEXT: case WM_WININICHANGE: case WM_DEVMODECHANGE: UnMapLS( (SEGPTR)lParam16 ); break; case LB_SETTABSTOPS: { void *ptr = MapSL( lParam16 ); UnMapLS( lParam16 ); HeapFree( GetProcessHeap(), 0, ptr ); } break; case CB_GETDROPPEDCONTROLRECT: case LB_GETITEMRECT: { RECT *r32; RECT16 *rect = MapSL(lParam16); UnMapLS( lParam16 ); lParam16 = *(LPARAM *)(rect + 1); r32 = (RECT *)lParam16; r32->left = rect->left; r32->top = rect->top; r32->right = rect->right; r32->bottom = rect->bottom; HeapFree( GetProcessHeap(), 0, rect ); } break; case LB_GETSELITEMS: { INT i; LPINT16 items = MapSL(lParam16); UnMapLS( lParam16 ); lParam16 = *((LPARAM *)items - 1); for (i = 0; i < wParam16; i++) *((LPINT)lParam16 + i) = items[i]; HeapFree( GetProcessHeap(), 0, (LPARAM *)items - 1 ); } break; case CB_GETEDITSEL: if( wParam ) *((PUINT)(wParam)) = LOWORD(*result); if( lParam ) *((PUINT)(lParam)) = HIWORD(*result); /* FIXME: substract 1? */ break; case WM_GETTEXT: case WM_ASKCBFORMATNAME: { LPSTR str = MapSL(lParam16); UnMapLS( lParam16 ); lParam16 = *((LPARAM *)str - 1); lstrcpynA( (LPSTR)lParam16, str, wParam16 ); HeapFree( GetProcessHeap(), 0, (LPARAM *)str - 1 ); } break; case WM_NOTIFY: UnMapLS(lParam16); break; } } /********************************************************************** * WINPROC_CallProcAtoW * * Call a window procedure, translating args from Ansi to Unicode. */ LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg ) { LRESULT ret = 0; TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n", hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam); switch(msg) { case WM_NCCREATE: case WM_CREATE: { WCHAR *ptr, buffer[512]; CREATESTRUCTA *csA = (CREATESTRUCTA *)lParam; CREATESTRUCTW csW = *(CREATESTRUCTW *)csA; MDICREATESTRUCTW mdi_cs; DWORD name_lenA = 0, name_lenW = 0, class_lenA = 0, class_lenW = 0; if (HIWORD(csA->lpszClass)) { class_lenA = strlen(csA->lpszClass) + 1; RtlMultiByteToUnicodeSize( &class_lenW, csA->lpszClass, class_lenA ); } if (HIWORD(csA->lpszName)) { name_lenA = strlen(csA->lpszName) + 1; RtlMultiByteToUnicodeSize( &name_lenW, csA->lpszName, name_lenA ); } if (!(ptr = get_buffer( buffer, sizeof(buffer), class_lenW + name_lenW ))) break; if (class_lenW) { csW.lpszClass = ptr; RtlMultiByteToUnicodeN( ptr, class_lenW, NULL, csA->lpszClass, class_lenA ); } if (name_lenW) { csW.lpszName = ptr + class_lenW/sizeof(WCHAR); RtlMultiByteToUnicodeN( ptr + class_lenW/sizeof(WCHAR), name_lenW, NULL, csA->lpszName, name_lenA ); } if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) { mdi_cs = *(MDICREATESTRUCTW *)csA->lpCreateParams; mdi_cs.szTitle = csW.lpszName; mdi_cs.szClass = csW.lpszClass; csW.lpCreateParams = &mdi_cs; } ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg ); free_buffer( buffer, ptr ); } break; case WM_MDICREATE: { WCHAR *ptr, buffer[512]; DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0; MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam; MDICREATESTRUCTW csW; memcpy( &csW, csA, sizeof(csW) ); if (HIWORD(csA->szTitle)) { title_lenA = strlen(csA->szTitle) + 1; RtlMultiByteToUnicodeSize( &title_lenW, csA->szTitle, title_lenA ); } if (HIWORD(csA->szClass)) { class_lenA = strlen(csA->szClass) + 1; RtlMultiByteToUnicodeSize( &class_lenW, csA->szClass, class_lenA ); } if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenW + class_lenW ))) break; if (title_lenW) { csW.szTitle = ptr; RtlMultiByteToUnicodeN( ptr, title_lenW, NULL, csA->szTitle, title_lenA ); } if (class_lenW) { csW.szClass = ptr + title_lenW/sizeof(WCHAR); RtlMultiByteToUnicodeN( ptr + title_lenW/sizeof(WCHAR), class_lenW, NULL, csA->szClass, class_lenA ); } ret = callback( hwnd, msg, wParam, (LPARAM)&csW, result, arg ); free_buffer( buffer, ptr ); } break; case WM_GETTEXT: case WM_ASKCBFORMATNAME: { WCHAR *ptr, buffer[512]; LPSTR str = (LPSTR)lParam; DWORD len = wParam * sizeof(WCHAR); if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break; ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg ); if (*result && wParam) { RtlUnicodeToMultiByteN( str, wParam - 1, &len, ptr, strlenW(ptr) * sizeof(WCHAR) ); str[len] = 0; *result = len; } free_buffer( buffer, ptr ); } break; case LB_ADDSTRING: case LB_INSERTSTRING: case LB_FINDSTRING: case LB_FINDSTRINGEXACT: case LB_SELECTSTRING: case CB_ADDSTRING: case CB_INSERTSTRING: case CB_FINDSTRING: case CB_FINDSTRINGEXACT: case CB_SELECTSTRING: if (!lParam || !WINPROC_TestLBForStr( hwnd, msg )) { ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; } /* fall through */ case WM_SETTEXT: case WM_WININICHANGE: case WM_DEVMODECHANGE: case CB_DIR: case LB_DIR: case LB_ADDFILE: case EM_REPLACESEL: if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg ); else { WCHAR *ptr, buffer[512]; LPCSTR strA = (LPCSTR)lParam; DWORD lenW, lenA = strlen(strA) + 1; RtlMultiByteToUnicodeSize( &lenW, strA, lenA ); if ((ptr = get_buffer( buffer, sizeof(buffer), lenW ))) { RtlMultiByteToUnicodeN( ptr, lenW, NULL, strA, lenA ); ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg ); free_buffer( buffer, ptr ); } } break; case LB_GETTEXT: case CB_GETLBTEXT: if (lParam && WINPROC_TestLBForStr( hwnd, msg )) { WCHAR buffer[512]; /* FIXME: fixed sized buffer */ ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg ); if (*result >= 0) { DWORD len; RtlUnicodeToMultiByteN( (LPSTR)lParam, ~0u, &len, buffer, (strlenW(buffer) + 1) * sizeof(WCHAR) ); *result = len - 1; } } else ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; case EM_GETLINE: { WCHAR *ptr, buffer[512]; WORD len = *(WORD *)lParam; if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break; *((WORD *)ptr) = len; /* store the length */ ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg ); if (*result) { DWORD reslen; RtlUnicodeToMultiByteN( (LPSTR)lParam, len, &reslen, ptr, *result * sizeof(WCHAR) ); if (reslen < len) ((LPSTR)lParam)[reslen] = 0; *result = reslen; } free_buffer( buffer, ptr ); } break; case WM_GETDLGCODE: if (lParam) { MSG newmsg = *(MSG *)lParam; switch(newmsg.message) { case WM_CHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: newmsg.wParam = map_wparam_char_AtoW( newmsg.wParam, 1 ); break; case WM_IME_CHAR: newmsg.wParam = map_wparam_char_AtoW( newmsg.wParam, 2 ); break; } ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg ); } else ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; case WM_CHARTOITEM: case WM_MENUCHAR: case WM_CHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: case EM_SETPASSWORDCHAR: ret = callback( hwnd, msg, map_wparam_char_AtoW(wParam,1), lParam, result, arg ); break; case WM_IME_CHAR: ret = callback( hwnd, msg, map_wparam_char_AtoW(wParam,2), lParam, result, arg ); break; case WM_GETTEXTLENGTH: case CB_GETLBTEXTLEN: case LB_GETTEXTLEN: ret = callback( hwnd, msg, wParam, lParam, result, arg ); if (*result >= 0) { WCHAR *ptr, buffer[512]; LRESULT tmp; DWORD len = *result + 1; /* Determine respective GETTEXT message */ UINT msgGetText = (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT : ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT); /* wParam differs between the messages */ WPARAM wp = (msg == WM_GETTEXTLENGTH) ? len : wParam; if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break; if (callback == call_window_proc) /* FIXME: hack */ callback( hwnd, msgGetText, wp, (LPARAM)ptr, &tmp, arg ); else tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr ); RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) ); *result = len; free_buffer( buffer, ptr ); } break; case WM_PAINTCLIPBOARD: case WM_SIZECLIPBOARD: FIXME_(msg)( "message %s (0x%x) needs translation, please report\n", SPY_GetMsgName(msg, hwnd), msg ); break; default: ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; } return ret; } /********************************************************************** * WINPROC_CallProcWtoA * * Call a window procedure, translating args from Unicode to Ansi. */ static LRESULT WINPROC_CallProcWtoA( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg ) { LRESULT ret = 0; TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n", hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam); switch(msg) { case WM_NCCREATE: case WM_CREATE: { /* csW->lpszName and csW->lpszClass are NOT supposed to be atoms * at this point. */ char buffer[1024], *cls, *name; CREATESTRUCTW *csW = (CREATESTRUCTW *)lParam; CREATESTRUCTA csA = *(CREATESTRUCTA *)csW; MDICREATESTRUCTA mdi_cs; DWORD name_lenA, name_lenW, class_lenA, class_lenW; class_lenW = strlenW(csW->lpszClass) * sizeof(WCHAR); RtlUnicodeToMultiByteSize(&class_lenA, csW->lpszClass, class_lenW); if (csW->lpszName) { name_lenW = strlenW(csW->lpszName) * sizeof(WCHAR); RtlUnicodeToMultiByteSize(&name_lenA, csW->lpszName, name_lenW); } else name_lenW = name_lenA = 0; if (!(cls = get_buffer( buffer, sizeof(buffer), class_lenA + name_lenA + 2 ))) break; RtlUnicodeToMultiByteN(cls, class_lenA, NULL, csW->lpszClass, class_lenW); cls[class_lenA] = 0; csA.lpszClass = cls; if (csW->lpszName) { name = cls + class_lenA + 1; RtlUnicodeToMultiByteN(name, name_lenA, NULL, csW->lpszName, name_lenW); name[name_lenA] = 0; csA.lpszName = name; } if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) { mdi_cs = *(MDICREATESTRUCTA *)csW->lpCreateParams; mdi_cs.szTitle = csA.lpszName; mdi_cs.szClass = csA.lpszClass; csA.lpCreateParams = &mdi_cs; } ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg ); free_buffer( buffer, cls ); } break; case WM_GETTEXT: case WM_ASKCBFORMATNAME: { char *ptr, buffer[512]; DWORD len = wParam * 2; if (!(ptr = get_buffer( buffer, sizeof(buffer), len ))) break; ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg ); if (*result && len) { RtlMultiByteToUnicodeN( (LPWSTR)lParam, wParam*sizeof(WCHAR), &len, ptr, strlen(ptr)+1 ); *result = len/sizeof(WCHAR) - 1; /* do not count terminating null */ ((LPWSTR)lParam)[*result] = 0; } free_buffer( buffer, ptr ); } break; case LB_ADDSTRING: case LB_INSERTSTRING: case LB_FINDSTRING: case LB_FINDSTRINGEXACT: case LB_SELECTSTRING: case CB_ADDSTRING: case CB_INSERTSTRING: case CB_FINDSTRING: case CB_FINDSTRINGEXACT: case CB_SELECTSTRING: if (!lParam || !WINPROC_TestLBForStr( hwnd, msg )) { ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; } /* fall through */ case WM_SETTEXT: case WM_WININICHANGE: case WM_DEVMODECHANGE: case CB_DIR: case LB_DIR: case LB_ADDFILE: case EM_REPLACESEL: if (!lParam) ret = callback( hwnd, msg, wParam, lParam, result, arg ); else { char *ptr, buffer[512]; LPCWSTR strW = (LPCWSTR)lParam; DWORD lenA, lenW = (strlenW(strW) + 1) * sizeof(WCHAR); RtlUnicodeToMultiByteSize( &lenA, strW, lenW ); if ((ptr = get_buffer( buffer, sizeof(buffer), lenA ))) { RtlUnicodeToMultiByteN( ptr, lenA, NULL, strW, lenW ); ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg ); free_buffer( buffer, ptr ); } } break; case WM_MDICREATE: { char *ptr, buffer[1024]; DWORD title_lenA = 0, title_lenW = 0, class_lenA = 0, class_lenW = 0; MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam; MDICREATESTRUCTA csA; memcpy( &csA, csW, sizeof(csA) ); if (HIWORD(csW->szTitle)) { title_lenW = (strlenW(csW->szTitle) + 1) * sizeof(WCHAR); RtlUnicodeToMultiByteSize( &title_lenA, csW->szTitle, title_lenW ); } if (HIWORD(csW->szClass)) { class_lenW = (strlenW(csW->szClass) + 1) * sizeof(WCHAR); RtlUnicodeToMultiByteSize( &class_lenA, csW->szClass, class_lenW ); } if (!(ptr = get_buffer( buffer, sizeof(buffer), title_lenA + class_lenA ))) break; if (title_lenA) { RtlUnicodeToMultiByteN( ptr, title_lenA, NULL, csW->szTitle, title_lenW ); csA.szTitle = ptr; } if (class_lenA) { RtlUnicodeToMultiByteN( ptr + title_lenA, class_lenA, NULL, csW->szClass, class_lenW ); csA.szClass = ptr + title_lenA; } ret = callback( hwnd, msg, wParam, (LPARAM)&csA, result, arg ); free_buffer( buffer, ptr ); } break; case LB_GETTEXT: case CB_GETLBTEXT: if (lParam && WINPROC_TestLBForStr( hwnd, msg )) { char buffer[512]; /* FIXME: fixed sized buffer */ ret = callback( hwnd, msg, wParam, (LPARAM)buffer, result, arg ); if (*result >= 0) { DWORD len; RtlMultiByteToUnicodeN( (LPWSTR)lParam, ~0u, &len, buffer, strlen(buffer) + 1 ); *result = len / sizeof(WCHAR) - 1; } } else ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; case EM_GETLINE: { char *ptr, buffer[512]; WORD len = *(WORD *)lParam; if (!(ptr = get_buffer( buffer, sizeof(buffer), len * 2 ))) break; *((WORD *)ptr) = len * 2; /* store the length */ ret = callback( hwnd, msg, wParam, (LPARAM)ptr, result, arg ); if (*result) { DWORD reslen; RtlMultiByteToUnicodeN( (LPWSTR)lParam, len*sizeof(WCHAR), &reslen, ptr, *result ); *result = reslen / sizeof(WCHAR); if (*result < len) ((LPWSTR)lParam)[*result] = 0; } free_buffer( buffer, ptr ); } break; case WM_GETDLGCODE: if (lParam) { MSG newmsg = *(MSG *)lParam; switch(newmsg.message) { case WM_CHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 1 ); break; case WM_IME_CHAR: newmsg.wParam = map_wparam_char_WtoA( newmsg.wParam, 2 ); break; } ret = callback( hwnd, msg, wParam, (LPARAM)&newmsg, result, arg ); } else ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; case WM_CHARTOITEM: case WM_MENUCHAR: case WM_CHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: case EM_SETPASSWORDCHAR: ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,1), lParam, result, arg ); break; case WM_IME_CHAR: ret = callback( hwnd, msg, map_wparam_char_WtoA(wParam,2), lParam, result, arg ); break; case WM_PAINTCLIPBOARD: case WM_SIZECLIPBOARD: FIXME_(msg)( "message %s (%04x) needs translation, please report\n", SPY_GetMsgName(msg, hwnd), msg ); break; default: ret = callback( hwnd, msg, wParam, lParam, result, arg ); break; } return ret; } /********************************************************************** * WINPROC_CallProc16To32A */ LRESULT WINPROC_CallProc16To32A( winproc_callback_t callback, HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam, LRESULT *result, void *arg ) { LRESULT ret = 0; HWND hwnd32 = WIN_Handle32( hwnd ); TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n", hwnd32, SPY_GetMsgName(msg, hwnd32), wParam, lParam); switch(msg) { case WM_NCCREATE: case WM_CREATE: { CREATESTRUCT16 *cs16 = MapSL(lParam); CREATESTRUCTA cs; MDICREATESTRUCTA mdi_cs; CREATESTRUCT16to32A( cs16, &cs ); if (GetWindowLongW(hwnd32, GWL_EXSTYLE) & WS_EX_MDICHILD) { MDICREATESTRUCT16 *mdi_cs16 = MapSL(cs16->lpCreateParams); MDICREATESTRUCT16to32A(mdi_cs16, &mdi_cs); cs.lpCreateParams = &mdi_cs; } ret = callback( hwnd32, msg, wParam, (LPARAM)&cs, result, arg ); CREATESTRUCT32Ato16( &cs, cs16 ); } break; case WM_MDICREATE: { MDICREATESTRUCT16 *cs16 = MapSL(lParam); MDICREATESTRUCTA cs; MDICREATESTRUCT16to32A( cs16, &cs ); ret = callback( hwnd32, msg, wParam, (LPARAM)&cs, result, arg ); MDICREATESTRUCT32Ato16( &cs, cs16 ); } break; case WM_MDIACTIVATE: if (lParam) ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32( HIWORD(lParam) ), (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg ); else /* message sent to MDI client */ ret = callback( hwnd32, msg, wParam, lParam, result, arg ); break; case WM_MDIGETACTIVE: { BOOL maximized = FALSE; ret = callback( hwnd32, msg, wParam, (LPARAM)&maximized, result, arg ); *result = MAKELRESULT( LOWORD(*result), maximized ); } break; case WM_MDISETMENU: ret = callback( hwnd32, wParam ? WM_MDIREFRESHMENU : WM_MDISETMENU, (WPARAM)HMENU_32(LOWORD(lParam)), (LPARAM)HMENU_32(HIWORD(lParam)), result, arg ); break; case WM_GETMINMAXINFO: { MINMAXINFO16 *mmi16 = MapSL(lParam); MINMAXINFO mmi; MINMAXINFO16to32( mmi16, &mmi ); ret = callback( hwnd32, msg, wParam, (LPARAM)&mmi, result, arg ); MINMAXINFO32to16( &mmi, mmi16 ); } break; case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGED: { WINDOWPOS16 *winpos16 = MapSL(lParam); WINDOWPOS winpos; WINDOWPOS16to32( winpos16, &winpos ); ret = callback( hwnd32, msg, wParam, (LPARAM)&winpos, result, arg ); WINDOWPOS32to16( &winpos, winpos16 ); } break; case WM_NCCALCSIZE: { NCCALCSIZE_PARAMS16 *nc16 = MapSL(lParam); NCCALCSIZE_PARAMS nc; WINDOWPOS winpos; RECT16to32( &nc16->rgrc[0], &nc.rgrc[0] ); if (wParam) { RECT16to32( &nc16->rgrc[1], &nc.rgrc[1] ); RECT16to32( &nc16->rgrc[2], &nc.rgrc[2] ); WINDOWPOS16to32( MapSL(nc16->lppos), &winpos ); nc.lppos = &winpos; } ret = callback( hwnd32, msg, wParam, (LPARAM)&nc, result, arg ); RECT32to16( &nc.rgrc[0], &nc16->rgrc[0] ); if (wParam) { RECT32to16( &nc.rgrc[1], &nc16->rgrc[1] ); RECT32to16( &nc.rgrc[2], &nc16->rgrc[2] ); WINDOWPOS32to16( &winpos, MapSL(nc16->lppos) ); } } break; case WM_COMPAREITEM: { COMPAREITEMSTRUCT16* cis16 = MapSL(lParam); COMPAREITEMSTRUCT cis; cis.CtlType = cis16->CtlType; cis.CtlID = cis16->CtlID; cis.hwndItem = WIN_Handle32( cis16->hwndItem ); cis.itemID1 = cis16->itemID1; cis.itemData1 = cis16->itemData1; cis.itemID2 = cis16->itemID2; cis.itemData2 = cis16->itemData2; cis.dwLocaleId = 0; /* FIXME */ ret = callback( hwnd32, msg, wParam, (LPARAM)&cis, result, arg ); } break; case WM_DELETEITEM: { DELETEITEMSTRUCT16* dis16 = MapSL(lParam); DELETEITEMSTRUCT dis; dis.CtlType = dis16->CtlType; dis.CtlID = dis16->CtlID; dis.hwndItem = WIN_Handle32( dis16->hwndItem ); dis.itemData = dis16->itemData; ret = callback( hwnd32, msg, wParam, (LPARAM)&dis, result, arg ); } break; case WM_MEASUREITEM: { MEASUREITEMSTRUCT16* mis16 = MapSL(lParam); MEASUREITEMSTRUCT mis; mis.CtlType = mis16->CtlType; mis.CtlID = mis16->CtlID; mis.itemID = mis16->itemID; mis.itemWidth = mis16->itemWidth; mis.itemHeight = mis16->itemHeight; mis.itemData = mis16->itemData; ret = callback( hwnd32, msg, wParam, (LPARAM)&mis, result, arg ); mis16->itemWidth = (UINT16)mis.itemWidth; mis16->itemHeight = (UINT16)mis.itemHeight; } break; case WM_DRAWITEM: { DRAWITEMSTRUCT16* dis16 = MapSL(lParam); DRAWITEMSTRUCT dis; dis.CtlType = dis16->CtlType; dis.CtlID = dis16->CtlID; dis.itemID = dis16->itemID; dis.itemAction = dis16->itemAction; dis.itemState = dis16->itemState; dis.hwndItem = (dis.CtlType == ODT_MENU) ? (HWND)HMENU_32(dis16->hwndItem) : WIN_Handle32( dis16->hwndItem ); dis.hDC = HDC_32(dis16->hDC); dis.itemData = dis16->itemData; dis.rcItem.left = dis16->rcItem.left; dis.rcItem.top = dis16->rcItem.top; dis.rcItem.right = dis16->rcItem.right; dis.rcItem.bottom = dis16->rcItem.bottom; ret = callback( hwnd32, msg, wParam, (LPARAM)&dis, result, arg ); } break; case WM_COPYDATA: { COPYDATASTRUCT16 *cds16 = MapSL(lParam); COPYDATASTRUCT cds; cds.dwData = cds16->dwData; cds.cbData = cds16->cbData; cds.lpData = MapSL(cds16->lpData); ret = callback( hwnd32, msg, wParam, (LPARAM)&cds, result, arg ); } break; case WM_GETDLGCODE: if (lParam) { MSG16 *msg16 = MapSL(lParam); MSG msg32; msg32.hwnd = WIN_Handle32( msg16->hwnd ); msg32.message = msg16->message; msg32.wParam = msg16->wParam; msg32.lParam = msg16->lParam; msg32.time = msg16->time; msg32.pt.x = msg16->pt.x; msg32.pt.y = msg16->pt.y; ret = callback( hwnd32, msg, wParam, (LPARAM)&msg32, result, arg ); } else ret = callback( hwnd32, msg, wParam, lParam, result, arg ); break; case WM_NEXTMENU: { MDINEXTMENU next; next.hmenuIn = (HMENU)lParam; next.hmenuNext = 0; next.hwndNext = 0; ret = callback( hwnd32, msg, wParam, (LPARAM)&next, result, arg ); *result = MAKELONG( HMENU_16(next.hmenuNext), HWND_16(next.hwndNext) ); } break; case WM_ACTIVATE: case WM_CHARTOITEM: case WM_COMMAND: case WM_VKEYTOITEM: ret = callback( hwnd32, msg, MAKEWPARAM( wParam, HIWORD(lParam) ), (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg ); break; case WM_HSCROLL: case WM_VSCROLL: ret = callback( hwnd32, msg, MAKEWPARAM( wParam, LOWORD(lParam) ), (LPARAM)WIN_Handle32( HIWORD(lParam) ), result, arg ); break; case WM_CTLCOLOR: if (HIWORD(lParam) <= CTLCOLOR_STATIC) ret = callback( hwnd32, WM_CTLCOLORMSGBOX + HIWORD(lParam), (WPARAM)HDC_32(wParam), (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg ); break; case WM_GETTEXT: case WM_SETTEXT: case WM_WININICHANGE: case WM_DEVMODECHANGE: case WM_ASKCBFORMATNAME: case WM_NOTIFY: ret = callback( hwnd32, msg, wParam, (LPARAM)MapSL(lParam), result, arg ); break; case WM_MENUCHAR: ret = callback( hwnd32, msg, MAKEWPARAM( wParam, LOWORD(lParam) ), (LPARAM)HMENU_32(HIWORD(lParam)), result, arg ); break; case WM_MENUSELECT: if((LOWORD(lParam) & MF_POPUP) && (LOWORD(lParam) != 0xFFFF)) { HMENU hmenu = HMENU_32(HIWORD(lParam)); UINT pos = MENU_FindSubMenu( &hmenu, HMENU_32(wParam) ); if (pos == 0xffff) pos = 0; /* NO_SELECTED_ITEM */ wParam = pos; } ret = callback( hwnd32, msg, MAKEWPARAM( wParam, LOWORD(lParam) ), (LPARAM)HMENU_32(HIWORD(lParam)), result, arg ); break; case WM_PARENTNOTIFY: if ((wParam == WM_CREATE) || (wParam == WM_DESTROY)) ret = callback( hwnd32, msg, MAKEWPARAM( wParam, HIWORD(lParam) ), (LPARAM)WIN_Handle32( LOWORD(lParam) ), result, arg ); else ret = callback( hwnd32, msg, wParam, lParam, result, arg ); break; case WM_ACTIVATEAPP: /* We need this when SetActiveWindow sends a Sendmessage16() to * a 32bit window. Might be superflous with 32bit interprocess * message queues. */ ret = callback( hwnd32, msg, wParam, HTASK_32(lParam), result, arg ); break; case WM_DDE_INITIATE: case WM_DDE_TERMINATE: case WM_DDE_UNADVISE: case WM_DDE_REQUEST: ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32(wParam), lParam, result, arg ); break; case WM_DDE_ADVISE: case WM_DDE_DATA: case WM_DDE_POKE: { HANDLE16 lo16 = LOWORD(lParam); UINT lo32 = 0; if (lo16 && !(lo32 = convert_handle_16_to_32(lo16, GMEM_DDESHARE))) break; lParam = PackDDElParam( msg, lo32, HIWORD(lParam) ); ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32(wParam), lParam, result, arg ); } break; /* FIXME don't know how to free allocated memory (handle) !! */ case WM_DDE_ACK: { UINT lo = LOWORD(lParam); UINT hi = HIWORD(lParam); int flag = 0; char buf[2]; if (GlobalGetAtomNameA(hi, buf, 2) > 0) flag |= 1; if (GlobalSize16(hi) != 0) flag |= 2; switch (flag) { case 0: if (hi) { MESSAGE("DDE_ACK: neither atom nor handle!!!\n"); hi = 0; } break; case 1: break; /* atom, nothing to do */ case 3: MESSAGE("DDE_ACK: %x both atom and handle... choosing handle\n", hi); /* fall thru */ case 2: hi = convert_handle_16_to_32(hi, GMEM_DDESHARE); break; } lParam = PackDDElParam( WM_DDE_ACK, lo, hi ); ret = callback( hwnd32, msg, (WPARAM)WIN_Handle32(wParam), lParam, result, arg ); } break; /* FIXME don't know how to free allocated memory (handle) !! */ case WM_DDE_EXECUTE: lParam = convert_handle_16_to_32( lParam, GMEM_DDESHARE ); ret = callback( hwnd32, msg, wParam, lParam, result, arg ); break; /* FIXME don't know how to free allocated memory (handle) !! */ case WM_PAINTCLIPBOARD: case WM_SIZECLIPBOARD: FIXME_(msg)( "message %04x needs translation\n", msg ); break; default: ret = callback( hwnd32, msg, wParam, lParam, result, arg ); break; } return ret; } /********************************************************************** * __wine_call_wndproc (USER.1010) */ LRESULT WINAPI __wine_call_wndproc( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam, WINDOWPROC *proc ) { LRESULT result; if (proc->procA) WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA ); else WINPROC_CallProc16To32A( call_window_proc_AtoW, hwnd, msg, wParam, lParam, &result, proc->procW ); return result; } /********************************************************************** * WINPROC_CallProc32ATo16 * * Call a 16-bit window procedure, translating the 32-bit args. */ LRESULT WINPROC_CallProc32ATo16( winproc_callback16_t callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg ) { LRESULT ret = 0; TRACE_(msg)("(hwnd=%p,msg=%s,wp=%08x,lp=%08lx)\n", hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam); switch(msg) { case WM_NCCREATE: case WM_CREATE: { CREATESTRUCTA *cs32 = (CREATESTRUCTA *)lParam; CREATESTRUCT16 cs; MDICREATESTRUCT16 mdi_cs16; BOOL mdi_child = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD); CREATESTRUCT32Ato16( cs32, &cs ); cs.lpszName = MapLS( cs32->lpszName ); cs.lpszClass = MapLS( cs32->lpszClass ); if (mdi_child) { MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs32->lpCreateParams; MDICREATESTRUCT32Ato16( mdi_cs, &mdi_cs16 ); mdi_cs16.szTitle = MapLS( mdi_cs->szTitle ); mdi_cs16.szClass = MapLS( mdi_cs->szClass ); cs.lpCreateParams = MapLS( &mdi_cs16 ); } lParam = MapLS( &cs ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); UnMapLS( cs.lpszName ); UnMapLS( cs.lpszClass ); if (mdi_child) { UnMapLS( cs.lpCreateParams ); UnMapLS( mdi_cs16.szTitle ); UnMapLS( mdi_cs16.szClass ); } } break; case WM_MDICREATE: { MDICREATESTRUCTA *cs32 = (MDICREATESTRUCTA *)lParam; MDICREATESTRUCT16 cs; MDICREATESTRUCT32Ato16( cs32, &cs ); cs.szTitle = MapLS( cs32->szTitle ); cs.szClass = MapLS( cs32->szClass ); lParam = MapLS( &cs ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); UnMapLS( cs.szTitle ); UnMapLS( cs.szClass ); } break; case WM_MDIACTIVATE: if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MDICHILD) ret = callback( HWND_16(hwnd), msg, ((HWND)lParam == hwnd), MAKELPARAM( LOWORD(lParam), LOWORD(wParam) ), result, arg ); else ret = callback( HWND_16(hwnd), msg, HWND_16( (HWND)wParam ), 0, result, arg ); break; case WM_MDIGETACTIVE: ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); if (lParam) *(BOOL *)lParam = (BOOL16)HIWORD(*result); *result = (LRESULT)WIN_Handle32( LOWORD(*result) ); break; case WM_MDISETMENU: ret = callback( HWND_16(hwnd), msg, (lParam == 0), MAKELPARAM( LOWORD(wParam), LOWORD(lParam) ), result, arg ); break; case WM_GETMINMAXINFO: { MINMAXINFO *mmi32 = (MINMAXINFO *)lParam; MINMAXINFO16 mmi; MINMAXINFO32to16( mmi32, &mmi ); lParam = MapLS( &mmi ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); MINMAXINFO16to32( &mmi, mmi32 ); } break; case WM_NCCALCSIZE: { NCCALCSIZE_PARAMS *nc32 = (NCCALCSIZE_PARAMS *)lParam; NCCALCSIZE_PARAMS16 nc; WINDOWPOS16 winpos; RECT32to16( &nc32->rgrc[0], &nc.rgrc[0] ); if (wParam) { RECT32to16( &nc32->rgrc[1], &nc.rgrc[1] ); RECT32to16( &nc32->rgrc[2], &nc.rgrc[2] ); WINDOWPOS32to16( nc32->lppos, &winpos ); nc.lppos = MapLS( &winpos ); } lParam = MapLS( &nc ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); RECT16to32( &nc.rgrc[0], &nc32->rgrc[0] ); if (wParam) { RECT16to32( &nc.rgrc[1], &nc32->rgrc[1] ); RECT16to32( &nc.rgrc[2], &nc32->rgrc[2] ); WINDOWPOS16to32( &winpos, nc32->lppos ); UnMapLS( nc.lppos ); } } break; case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGED: { WINDOWPOS *winpos32 = (WINDOWPOS *)lParam; WINDOWPOS16 winpos; WINDOWPOS32to16( winpos32, &winpos ); lParam = MapLS( &winpos ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); WINDOWPOS16to32( &winpos, winpos32 ); } break; case WM_COMPAREITEM: { COMPAREITEMSTRUCT *cis32 = (COMPAREITEMSTRUCT *)lParam; COMPAREITEMSTRUCT16 cis; cis.CtlType = cis32->CtlType; cis.CtlID = cis32->CtlID; cis.hwndItem = HWND_16( cis32->hwndItem ); cis.itemID1 = cis32->itemID1; cis.itemData1 = cis32->itemData1; cis.itemID2 = cis32->itemID2; cis.itemData2 = cis32->itemData2; lParam = MapLS( &cis ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); } break; case WM_DELETEITEM: { DELETEITEMSTRUCT *dis32 = (DELETEITEMSTRUCT *)lParam; DELETEITEMSTRUCT16 dis; dis.CtlType = dis32->CtlType; dis.CtlID = dis32->CtlID; dis.itemID = dis32->itemID; dis.hwndItem = (dis.CtlType == ODT_MENU) ? (HWND16)LOWORD(dis32->hwndItem) : HWND_16( dis32->hwndItem ); dis.itemData = dis32->itemData; lParam = MapLS( &dis ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); } break; case WM_DRAWITEM: { DRAWITEMSTRUCT *dis32 = (DRAWITEMSTRUCT *)lParam; DRAWITEMSTRUCT16 dis; dis.CtlType = dis32->CtlType; dis.CtlID = dis32->CtlID; dis.itemID = dis32->itemID; dis.itemAction = dis32->itemAction; dis.itemState = dis32->itemState; dis.hwndItem = HWND_16( dis32->hwndItem ); dis.hDC = HDC_16(dis32->hDC); dis.itemData = dis32->itemData; dis.rcItem.left = dis32->rcItem.left; dis.rcItem.top = dis32->rcItem.top; dis.rcItem.right = dis32->rcItem.right; dis.rcItem.bottom = dis32->rcItem.bottom; lParam = MapLS( &dis ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); } break; case WM_MEASUREITEM: { MEASUREITEMSTRUCT *mis32 = (MEASUREITEMSTRUCT *)lParam; MEASUREITEMSTRUCT16 mis; mis.CtlType = mis32->CtlType; mis.CtlID = mis32->CtlID; mis.itemID = mis32->itemID; mis.itemWidth = mis32->itemWidth; mis.itemHeight = mis32->itemHeight; mis.itemData = mis32->itemData; lParam = MapLS( &mis ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); mis32->itemWidth = mis.itemWidth; mis32->itemHeight = mis.itemHeight; } break; case WM_COPYDATA: { COPYDATASTRUCT *cds32 = (COPYDATASTRUCT *)lParam; COPYDATASTRUCT16 cds; cds.dwData = cds32->dwData; cds.cbData = cds32->cbData; cds.lpData = MapLS( cds32->lpData ); lParam = MapLS( &cds ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); UnMapLS( cds.lpData ); } break; case WM_GETDLGCODE: if (lParam) { MSG *msg32 = (MSG *)lParam; MSG16 msg16; msg16.hwnd = HWND_16( msg32->hwnd ); msg16.message = msg32->message; msg16.wParam = msg32->wParam; msg16.lParam = msg32->lParam; msg16.time = msg32->time; msg16.pt.x = msg32->pt.x; msg16.pt.y = msg32->pt.y; lParam = MapLS( &msg16 ); ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); UnMapLS( lParam ); } else ret = callback( HWND_16(hwnd), msg, wParam, lParam, result, arg ); break; case WM_NEXTMENU: { MDINEXTMENU *next = (MDINEXTMENU *)lParam; ret = callback( HWND_16(hwnd), msg, wParam, (LPARAM)next->hmenuIn, result, arg ); next->hmenuNext = HMENU_32( LOWORD(*result) ); next->hwndNext = WIN_Handle32( HIWORD(*result) ); *result = 0; } break; default: { UINT16 msg16; WPARAM16 wParam16; LPARAM lParam16 = lParam; if (WINPROC_MapMsg32ATo16( hwnd, msg, wParam, &msg16, &wParam16, &lParam16 ) != -1) { ret = callback( HWND_16(hwnd), msg16, wParam16, lParam16, result, arg ); WINPROC_UnmapMsg32ATo16( hwnd, msg, wParam, lParam, wParam16, lParam16, result ); } } break; } return ret; } /********************************************************************** * CallWindowProc (USER.122) */ LRESULT WINAPI CallWindowProc16( WNDPROC16 func, HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam ) { WINDOWPROC *proc; LRESULT result; if (!func) return 0; if (!(proc = handle16_to_proc( func ))) call_window_proc16( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procA) WINPROC_CallProc16To32A( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA ); else if (proc->procW) WINPROC_CallProc16To32A( call_window_proc_AtoW, hwnd, msg, wParam, lParam, &result, proc->procW ); else call_window_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 ); return result; } /********************************************************************** * CallWindowProcA (USER32.@) * * The CallWindowProc() function invokes the windows procedure _func_, * with _hwnd_ as the target window, the message specified by _msg_, and * the message parameters _wParam_ and _lParam_. * * Some kinds of argument conversion may be done, I'm not sure what. * * CallWindowProc() may be used for windows subclassing. Use * SetWindowLong() to set a new windows procedure for windows of the * subclass, and handle subclassed messages in the new windows * procedure. The new windows procedure may then use CallWindowProc() * with _func_ set to the parent class's windows procedure to dispatch * the message to the superclass. * * RETURNS * * The return value is message dependent. * * CONFORMANCE * * ECMA-234, Win32 */ LRESULT WINAPI CallWindowProcA( WNDPROC func, /* [in] window procedure */ HWND hwnd, /* [in] target window */ UINT msg, /* [in] message */ WPARAM wParam, /* [in] message dependent parameter */ LPARAM lParam /* [in] message dependent parameter */ ) { WINDOWPROC *proc; LRESULT result; if (!func) return 0; if (!(proc = handle_to_proc( func ))) call_window_proc( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procA) call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA ); else if (proc->procW) WINPROC_CallProcAtoW( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procW ); else WINPROC_CallProc32ATo16( call_window_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 ); return result; } /********************************************************************** * CallWindowProcW (USER32.@) * * See CallWindowProcA. */ LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { WINDOWPROC *proc; LRESULT result; if (!func) return 0; if (!(proc = handle_to_proc( func ))) call_window_proc( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procW) call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW ); else if (proc->procA) WINPROC_CallProcWtoA( call_window_proc, hwnd, msg, wParam, lParam, &result, proc->procA ); else WINPROC_CallProcWtoA( call_window_proc_Ato16, hwnd, msg, wParam, lParam, &result, proc->proc16 ); return result; } /********************************************************************** * WINPROC_CallDlgProc16 */ INT_PTR WINPROC_CallDlgProc16( DLGPROC16 func, HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam ) { WINDOWPROC *proc; LRESULT result; INT_PTR ret; if (!func) return 0; if (!(proc = handle16_to_proc( (WNDPROC16)func ))) { ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, func ); } else if (proc->procA) { ret = WINPROC_CallProc16To32A( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procA ); SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result ); } else if (proc->procW) { ret = WINPROC_CallProc16To32A( call_dialog_proc_AtoW, hwnd, msg, wParam, lParam, &result, proc->procW ); SetWindowLongPtrW( WIN_Handle32(hwnd), DWLP_MSGRESULT, result ); } else { ret = call_dialog_proc16( hwnd, msg, wParam, lParam, &result, proc->proc16 ); } return ret; } /********************************************************************** * WINPROC_CallDlgProcA */ INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { WINDOWPROC *proc; LRESULT result; INT_PTR ret; if (!func) return 0; if (!(proc = handle_to_proc( (WNDPROC)func ))) ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procA) ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA ); else if (proc->procW) { ret = WINPROC_CallProcAtoW( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procW ); SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result ); } else { ret = WINPROC_CallProc32ATo16( call_dialog_proc16, hwnd, msg, wParam, lParam, &result, proc->proc16 ); SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result ); } return ret; } /********************************************************************** * WINPROC_CallDlgProcW */ INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { WINDOWPROC *proc; LRESULT result; INT_PTR ret; if (!func) return 0; if (!(proc = handle_to_proc( (WNDPROC)func ))) ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procW) ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW ); else if (proc->procA) { ret = WINPROC_CallProcWtoA( call_dialog_proc, hwnd, msg, wParam, lParam, &result, proc->procA ); SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result ); } else { ret = WINPROC_CallProcWtoA( call_dialog_proc_Ato16, hwnd, msg, wParam, lParam, &result, proc->proc16 ); SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, result ); } return ret; }