diff --git a/dlls/commdlg.dll16/filedlg.c b/dlls/commdlg.dll16/filedlg.c index 1238dc9b892..99da47a229d 100644 --- a/dlls/commdlg.dll16/filedlg.c +++ b/dlls/commdlg.dll16/filedlg.c @@ -132,6 +132,408 @@ static LPDLGTEMPLATEA convert_dialog( const char *p, DWORD size ) return dlg; } +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 = HWND_32(from->hwnd); + to->hwndInsertAfter = (from->hwndInsertAfter == (HWND16)-1) ? + HWND_TOPMOST : HWND_32(from->hwndInsertAfter); + to->x = from->x; + to->y = from->y; + to->cx = from->cx; + to->cy = from->cy; + to->flags = from->flags; +} + +static void CREATESTRUCT32Ato16( const CREATESTRUCTA* from, CREATESTRUCT16* to ) +{ + to->lpCreateParams = (SEGPTR)from->lpCreateParams; + to->hInstance = 0; + 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 LRESULT call_hook16( WNDPROC16 hook, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + CONTEXT context; + WORD params[5]; + + TRACE( "%p: %p %08x %lx %lx: stub\n", hook, hwnd, msg, wp, lp ); + + memset( &context, 0, sizeof(context) ); + context.SegDs = context.SegEs = SELECTOROF( NtCurrentTeb()->WOW32Reserved ); + context.SegFs = wine_get_fs(); + context.SegGs = wine_get_gs(); + context.SegCs = SELECTOROF( hook ); + context.Eip = OFFSETOF( hook ); + context.Ebp = OFFSETOF( NtCurrentTeb()->WOW32Reserved ) + FIELD_OFFSET( STACK16FRAME, bp ); + context.Eax = context.SegDs; + + params[4] = HWND_16( hwnd ); + params[3] = msg; + params[2] = wp; + params[1] = HIWORD( lp ); + params[0] = LOWORD( lp ); + WOWCallback16Ex( 0, WCB16_REGS, sizeof(params), params, (DWORD *)&context ); + return LOWORD( context.Eax ); +} + +static UINT_PTR CALLBACK call_hook_proc( WNDPROC16 hook, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + LRESULT ret = 0; + + switch (msg) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTA *cs32 = (CREATESTRUCTA *)lp; + CREATESTRUCT16 cs; + + CREATESTRUCT32Ato16( cs32, &cs ); + cs.lpszName = MapLS( cs32->lpszName ); + cs.lpszClass = MapLS( cs32->lpszClass ); + lp = MapLS( &cs ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + UnMapLS( cs.lpszName ); + UnMapLS( cs.lpszClass ); + } + break; + case WM_GETMINMAXINFO: + { + MINMAXINFO *mmi32 = (MINMAXINFO *)lp; + MINMAXINFO16 mmi; + + MINMAXINFO32to16( mmi32, &mmi ); + lp = MapLS( &mmi ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + MINMAXINFO16to32( &mmi, mmi32 ); + } + break; + case WM_NCCALCSIZE: + { + NCCALCSIZE_PARAMS *nc32 = (NCCALCSIZE_PARAMS *)lp; + NCCALCSIZE_PARAMS16 nc; + WINDOWPOS16 winpos; + + RECT32to16( &nc32->rgrc[0], &nc.rgrc[0] ); + if (wp) + { + RECT32to16( &nc32->rgrc[1], &nc.rgrc[1] ); + RECT32to16( &nc32->rgrc[2], &nc.rgrc[2] ); + WINDOWPOS32to16( nc32->lppos, &winpos ); + nc.lppos = MapLS( &winpos ); + } + lp = MapLS( &nc ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + RECT16to32( &nc.rgrc[0], &nc32->rgrc[0] ); + if (wp) + { + 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 *)lp; + WINDOWPOS16 winpos; + + WINDOWPOS32to16( winpos32, &winpos ); + lp = MapLS( &winpos ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + WINDOWPOS16to32( &winpos, winpos32 ); + } + break; + case WM_COMPAREITEM: + { + COMPAREITEMSTRUCT *cis32 = (COMPAREITEMSTRUCT *)lp; + 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; + lp = MapLS( &cis ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + } + break; + case WM_DELETEITEM: + { + DELETEITEMSTRUCT *dis32 = (DELETEITEMSTRUCT *)lp; + 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; + lp = MapLS( &dis ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + } + break; + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *dis32 = (DRAWITEMSTRUCT *)lp; + 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; + lp = MapLS( &dis ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + } + break; + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT *mis32 = (MEASUREITEMSTRUCT *)lp; + 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; + lp = MapLS( &mis ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + mis32->itemWidth = mis.itemWidth; + mis32->itemHeight = mis.itemHeight; + } + break; + case WM_COPYDATA: + { + COPYDATASTRUCT *cds32 = (COPYDATASTRUCT *)lp; + COPYDATASTRUCT16 cds; + + cds.dwData = cds32->dwData; + cds.cbData = cds32->cbData; + cds.lpData = MapLS( cds32->lpData ); + lp = MapLS( &cds ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + UnMapLS( cds.lpData ); + } + break; + case WM_GETDLGCODE: + if (lp) + { + MSG *msg32 = (MSG *)lp; + 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; + lp = MapLS( &msg16 ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + } + else + ret = call_hook16( hook, hwnd, msg, wp, lp ); + break; + case WM_NEXTMENU: + { + LRESULT result; + MDINEXTMENU *next = (MDINEXTMENU *)lp; + ret = call_hook16( hook, hwnd, msg, wp, (LPARAM)next->hmenuIn ); + result = GetWindowLongPtrW( hwnd, DWLP_MSGRESULT ); + next->hmenuNext = HMENU_32( LOWORD(result) ); + next->hwndNext = HWND_32( HIWORD(result) ); + SetWindowLongPtrW( hwnd, DWLP_MSGRESULT, 0 ); + } + break; + case WM_GETTEXT: + case WM_ASKCBFORMATNAME: + wp = min( wp, 0xff80 ); /* Must be < 64K */ + /* fall through */ + case WM_NOTIFY: + case WM_SETTEXT: + case WM_WININICHANGE: + case WM_DEVMODECHANGE: + lp = MapLS( (void *)lp ); + ret = call_hook16( hook, hwnd, msg, wp, lp ); + UnMapLS( lp ); + break; + case WM_ACTIVATE: + case WM_CHARTOITEM: + case WM_COMMAND: + case WM_VKEYTOITEM: + ret = call_hook16( hook, hwnd, msg, wp, MAKELPARAM( (HWND16)lp, HIWORD(wp) )); + break; + case WM_HSCROLL: + case WM_VSCROLL: + ret = call_hook16( hook, hwnd, msg, wp, MAKELPARAM( HIWORD(wp), (HWND16)lp )); + break; + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + ret = call_hook16( hook, hwnd, WM_CTLCOLOR, wp, MAKELPARAM( (HWND16)lp, msg - WM_CTLCOLORMSGBOX )); + break; + case WM_MENUSELECT: + if(HIWORD(wp) & MF_POPUP) + { + HMENU hmenu; + if ((HIWORD(wp) != 0xffff) || lp) + { + if ((hmenu = GetSubMenu( (HMENU)lp, LOWORD(wp) ))) + { + ret = call_hook16( hook, hwnd, msg, HMENU_16(hmenu), + MAKELPARAM( HIWORD(wp), (HMENU16)lp ) ); + break; + } + } + } + /* fall through */ + case WM_MENUCHAR: + ret = call_hook16( hook, hwnd, msg, wp, MAKELPARAM( HIWORD(wp), (HMENU16)lp )); + break; + case WM_PARENTNOTIFY: + if ((LOWORD(wp) == WM_CREATE) || (LOWORD(wp) == WM_DESTROY)) + ret = call_hook16( hook, hwnd, msg, wp, MAKELPARAM( (HWND16)lp, HIWORD(wp) )); + else + ret = call_hook16( hook, hwnd, msg, wp, lp ); + break; + case WM_ACTIVATEAPP: + ret = call_hook16( hook, hwnd, msg, wp, HTASK_16( lp )); + break; + default: + ret = call_hook16( hook, hwnd, msg, wp, lp ); + break; + } + return LOWORD(ret); +} + + +#include "pshpack1.h" +struct hook_proc +{ + BYTE popl_eax; /* popl %eax */ + BYTE pushl_hook; /* pushl $hook_ptr */ + LPOFNHOOKPROC16 hook_ptr; + BYTE pushl_eax; /* pushl %eax */ + BYTE jmp; /* jmp call_hook */ + DWORD call_hook; +}; +#include "poppack.h" + +static LPOFNHOOKPROC alloc_hook( LPOFNHOOKPROC16 hook16 ) +{ + static struct hook_proc *hooks; + static unsigned int count; + SIZE_T size = 0x1000; + unsigned int i; + + if (!hooks && NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&hooks, 12, &size, + MEM_COMMIT, PAGE_EXECUTE_READWRITE )) + return NULL; + + for (i = 0; i < count; i++) + if (hooks[i].hook_ptr == hook16) + return (LPOFNHOOKPROC)&hooks[i]; + + if (count >= size / sizeof(*hooks)) + { + FIXME( "all hooks are in use\n" ); + return NULL; + } + + hooks[count].popl_eax = 0x58; + hooks[count].pushl_hook = 0x68; + hooks[count].hook_ptr = hook16; + hooks[count].pushl_eax = 0x50; + hooks[count].jmp = 0xe9; + hooks[count].call_hook = (char *)call_hook_proc - (char *)(&hooks[count].call_hook + 1); + return (LPOFNHOOKPROC)&hooks[count++]; +} + static UINT_PTR CALLBACK dummy_hook( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) { return FALSE; @@ -210,8 +612,7 @@ BOOL16 WINAPI GetOpenFileName16( SEGPTR ofn ) /* [in/out] address of structure w FreeResource16( handle ); } - if (lpofn->Flags & OFN_ENABLEHOOK) - FIXME( "custom hook %p no longer supported\n", lpofn->lpfnHook ); + if (lpofn->Flags & OFN_ENABLEHOOK) ofn32.lpfnHook = alloc_hook( lpofn->lpfnHook ); if ((ret = GetOpenFileNameA( &ofn32 ))) { @@ -278,8 +679,7 @@ BOOL16 WINAPI GetSaveFileName16( SEGPTR ofn ) /* [in/out] address of structure w FreeResource16( handle ); } - if (lpofn->Flags & OFN_ENABLEHOOK) - FIXME( "custom hook %p no longer supported\n", lpofn->lpfnHook ); + if (lpofn->Flags & OFN_ENABLEHOOK) ofn32.lpfnHook = alloc_hook( lpofn->lpfnHook ); if ((ret = GetSaveFileNameA( &ofn32 ))) {