| /* |
| * COMMDLG - File Dialogs |
| * |
| * Copyright 1994 Martin Ayotte |
| * Copyright 1996 Albrecht Kleine |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wine/winbase16.h" |
| #include "winuser.h" |
| #include "wine/winuser16.h" |
| #include "wine/debug.h" |
| #include "cderr.h" |
| #include "commdlg.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(commdlg); |
| |
| #include "cdlg.h" |
| #include "cdlg16.h" |
| #include "filedlg31.h" |
| |
| typedef struct tagFD16_PRIVATE |
| { |
| HANDLE16 hDlgTmpl16; /* handle for resource 16 */ |
| HANDLE16 hResource16; /* handle for allocated resource 16 */ |
| HANDLE16 hGlobal16; /* 16 bits mem block (resources) */ |
| OPENFILENAME16 *ofn16; /* original structure if 16 bits dialog */ |
| } FD16_PRIVATE, *PFD16_PRIVATE; |
| |
| /************************************************************************ |
| * FD16_MapOfnStruct16 [internal] |
| * map a 16 bits structure to an Unicode one |
| */ |
| void FD16_MapOfnStruct16(LPOPENFILENAME16 ofn16, LPOPENFILENAMEW ofnW, BOOL open) |
| { |
| OPENFILENAMEA ofnA; |
| /* first convert to linear pointers */ |
| memset(&ofnA, 0, sizeof(OPENFILENAMEA)); |
| ofnA.lStructSize = sizeof(OPENFILENAMEA); |
| ofnA.hwndOwner = HWND_32(ofn16->hwndOwner); |
| ofnA.hInstance = HINSTANCE_32(ofn16->hInstance); |
| if (ofn16->lpstrFilter) |
| ofnA.lpstrFilter = MapSL(ofn16->lpstrFilter); |
| if (ofn16->lpstrCustomFilter) |
| ofnA.lpstrCustomFilter = MapSL(ofn16->lpstrCustomFilter); |
| ofnA.nMaxCustFilter = ofn16->nMaxCustFilter; |
| ofnA.nFilterIndex = ofn16->nFilterIndex; |
| ofnA.lpstrFile = MapSL(ofn16->lpstrFile); |
| ofnA.nMaxFile = ofn16->nMaxFile; |
| ofnA.lpstrFileTitle = MapSL(ofn16->lpstrFileTitle); |
| ofnA.nMaxFileTitle = ofn16->nMaxFileTitle; |
| ofnA.lpstrInitialDir = MapSL(ofn16->lpstrInitialDir); |
| ofnA.lpstrTitle = MapSL(ofn16->lpstrTitle); |
| ofnA.Flags = ofn16->Flags; |
| ofnA.nFileOffset = ofn16->nFileOffset; |
| ofnA.nFileExtension = ofn16->nFileExtension; |
| ofnA.lpstrDefExt = MapSL(ofn16->lpstrDefExt); |
| if (HIWORD(ofn16->lpTemplateName)) |
| ofnA.lpTemplateName = MapSL(ofn16->lpTemplateName); |
| else |
| ofnA.lpTemplateName = (LPSTR) ofn16->lpTemplateName; /* ressource number */ |
| /* now calls the 32 bits Ansi to Unicode version to complete the job */ |
| FD31_MapOfnStructA(&ofnA, ofnW, open); |
| } |
| |
| /*********************************************************************** |
| * FD16_GetTemplate [internal] |
| * |
| * Get a template (FALSE if failure) when 16 bits dialogs are used |
| * by a 16 bits application |
| * |
| */ |
| BOOL FD16_GetTemplate(PFD31_DATA lfs) |
| { |
| PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; |
| LPOPENFILENAME16 ofn16 = priv->ofn16; |
| LPCVOID template; |
| HGLOBAL16 hGlobal16 = 0; |
| |
| if (ofn16->Flags & OFN_ENABLETEMPLATEHANDLE) |
| priv->hDlgTmpl16 = ofn16->hInstance; |
| else if (ofn16->Flags & OFN_ENABLETEMPLATE) |
| { |
| HANDLE16 hResInfo; |
| if (!(hResInfo = FindResource16(ofn16->hInstance, |
| MapSL(ofn16->lpTemplateName), |
| (LPSTR)RT_DIALOG))) |
| { |
| COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); |
| return FALSE; |
| } |
| if (!(priv->hDlgTmpl16 = LoadResource16( ofn16->hInstance, hResInfo ))) |
| { |
| COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); |
| return FALSE; |
| } |
| priv->hResource16 = priv->hDlgTmpl16; |
| } |
| else |
| { /* get resource from (32 bits) own Wine resource; convert it to 16 */ |
| HRSRC hResInfo; |
| HGLOBAL hDlgTmpl32; |
| LPCVOID template32; |
| DWORD size; |
| |
| if (!(hResInfo = FindResourceA(COMDLG32_hInstance, |
| lfs->open ? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG))) |
| { |
| COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); |
| return FALSE; |
| } |
| if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || |
| !(template32 = LockResource( hDlgTmpl32 ))) |
| { |
| COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); |
| return FALSE; |
| } |
| size = SizeofResource(COMDLG32_hInstance, hResInfo); |
| hGlobal16 = GlobalAlloc16(0, size); |
| if (!hGlobal16) |
| { |
| COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); |
| ERR("alloc failure for %ld bytes\n", size); |
| return FALSE; |
| } |
| template = GlobalLock16(hGlobal16); |
| if (!template) |
| { |
| COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); |
| ERR("global lock failure for %x handle\n", hGlobal16); |
| GlobalFree16(hGlobal16); |
| return FALSE; |
| } |
| ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); |
| priv->hDlgTmpl16 = hGlobal16; |
| priv->hGlobal16 = hGlobal16; |
| } |
| return TRUE; |
| } |
| |
| /************************************************************************ |
| * FD16_Init [internal] |
| * called from the common 16/32 code to initialize 16 bit data |
| */ |
| static BOOL CALLBACK FD16_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data) |
| { |
| PFD16_PRIVATE priv; |
| |
| priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD16_PRIVATE)); |
| lfs->private1632 = priv; |
| if (NULL == lfs->private1632) return FALSE; |
| |
| priv->ofn16 = MapSL(lParam); |
| if (priv->ofn16->Flags & OFN_ENABLEHOOK) |
| if (priv->ofn16->lpfnHook) |
| lfs->hook = TRUE; |
| |
| FD16_MapOfnStruct16(priv->ofn16, &lfs->ofnW, lfs->open); |
| |
| if (! FD16_GetTemplate(lfs)) return FALSE; |
| |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * FD16_CallWindowProc [internal] |
| * |
| * called from the common 16/32 code to call the appropriate hook |
| */ |
| BOOL CALLBACK FD16_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, |
| LPARAM lParam) |
| { |
| PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; |
| |
| if (priv->ofn16) |
| { |
| return (BOOL16) CallWindowProc16( |
| (WNDPROC16)priv->ofn16->lpfnHook, HWND_16(lfs->hwnd), |
| (UINT16)wMsg, (WPARAM16)wParam, lParam); |
| } |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * FD31_UpdateResult [internal] |
| * update the real client structures |
| */ |
| static void CALLBACK FD16_UpdateResult(PFD31_DATA lfs) |
| { |
| PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; |
| LPOPENFILENAMEW ofnW = &lfs->ofnW; |
| |
| if (priv->ofn16) |
| { /* we have to convert to short (8.3) path */ |
| char tmp[1024]; /* MAX_PATHNAME_LEN */ |
| LPOPENFILENAME16 ofn16 = priv->ofn16; |
| char *dest = MapSL(ofn16->lpstrFile); |
| char *bs16; |
| if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1, |
| tmp, sizeof(tmp), NULL, NULL )) |
| tmp[sizeof(tmp)-1] = 0; |
| GetShortPathNameA(tmp, dest, ofn16->nMaxFile); |
| |
| /* the same procedure as every year... */ |
| if((bs16 = strrchr(dest, '\\')) != NULL) |
| ofn16->nFileOffset = bs16 - dest +1; |
| else |
| ofn16->nFileOffset = 0; |
| ofn16->nFileExtension = 0; |
| while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0') |
| ofn16->nFileExtension++; |
| if (dest[ofn16->nFileExtension] == '\0') |
| ofn16->nFileExtension = 0; |
| else |
| ofn16->nFileExtension++; |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * FD16_UpdateFileTitle [internal] |
| * update the real client structures |
| */ |
| static void CALLBACK FD16_UpdateFileTitle(PFD31_DATA lfs) |
| { |
| PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; |
| LPOPENFILENAMEW ofnW = &lfs->ofnW; |
| |
| if (priv->ofn16) |
| { |
| char *dest = MapSL(priv->ofn16->lpstrFileTitle); |
| if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1, |
| dest, ofnW->nMaxFileTitle, NULL, NULL )) |
| dest[ofnW->nMaxFileTitle-1] = 0; |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * FD16_SendLbGetCurSel [internal] |
| * retrieve selected listbox item |
| */ |
| static LRESULT CALLBACK FD16_SendLbGetCurSel(PFD31_DATA lfs) |
| { |
| return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL16, 0, 0); |
| } |
| |
| |
| /************************************************************************ |
| * FD16_Destroy [internal] |
| * called from the common 16/32 code to cleanup 32 bit data |
| */ |
| static void CALLBACK FD16_Destroy(PFD31_DATA lfs) |
| { |
| PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; |
| |
| /* free resources for a 16 bits dialog */ |
| if (NULL != priv) |
| { |
| if (priv->hResource16) FreeResource16(priv->hResource16); |
| if (priv->hGlobal16) |
| { |
| GlobalUnlock16(priv->hGlobal16); |
| GlobalFree16(priv->hGlobal16); |
| } |
| FD31_FreeOfnW(&lfs->ofnW); |
| } |
| } |
| |
| static void FD16_SetupCallbacks(PFD31_CALLBACKS callbacks) |
| { |
| callbacks->Init = FD16_Init; |
| callbacks->CWP = FD16_CallWindowProc; |
| callbacks->UpdateResult = FD16_UpdateResult; |
| callbacks->UpdateFileTitle = FD16_UpdateFileTitle; |
| callbacks->SendLbGetCurSel = FD16_SendLbGetCurSel; |
| callbacks->Destroy = FD16_Destroy; |
| } |
| |
| /*********************************************************************** |
| * FD16_MapDrawItemStruct [internal] |
| * map a 16 bits drawitem struct to 32 |
| */ |
| static void FD16_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis) |
| { |
| lpdis->CtlType = lpdis16->CtlType; |
| lpdis->CtlID = lpdis16->CtlID; |
| lpdis->itemID = lpdis16->itemID; |
| lpdis->itemAction = lpdis16->itemAction; |
| lpdis->itemState = lpdis16->itemState; |
| lpdis->hwndItem = HWND_32(lpdis16->hwndItem); |
| lpdis->hDC = HDC_32(lpdis16->hDC); |
| lpdis->rcItem.right = lpdis16->rcItem.right; |
| lpdis->rcItem.left = lpdis16->rcItem.left; |
| lpdis->rcItem.top = lpdis16->rcItem.top; |
| lpdis->rcItem.bottom = lpdis16->rcItem.bottom; |
| lpdis->itemData = lpdis16->itemData; |
| } |
| |
| |
| /*********************************************************************** |
| * FD16_WMMeasureItem16 [internal] |
| */ |
| static LONG FD16_WMMeasureItem(HWND16 hWnd, WPARAM16 wParam, LPARAM lParam) |
| { |
| LPMEASUREITEMSTRUCT16 lpmeasure; |
| |
| lpmeasure = MapSL(lParam); |
| lpmeasure->itemHeight = FD31_GetFldrHeight(); |
| return TRUE; |
| } |
| |
| /* ------------------ Dialog procedures ---------------------- */ |
| |
| /*********************************************************************** |
| * FileOpenDlgProc16 (COMMDLG.6) |
| */ |
| BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam) |
| { |
| HWND hWnd = HWND_32(hWnd16); |
| PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); |
| DRAWITEMSTRUCT dis; |
| |
| TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); |
| if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) |
| { |
| LRESULT lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); |
| if (lRet) |
| return lRet; /* else continue message processing */ |
| } |
| switch (wMsg) |
| { |
| case WM_INITDIALOG: |
| return FD31_WMInitDialog(hWnd, wParam, lParam); |
| |
| case WM_MEASUREITEM: |
| return FD16_WMMeasureItem(hWnd16, wParam, lParam); |
| |
| case WM_DRAWITEM: |
| FD16_MapDrawItemStruct(MapSL(lParam), &dis); |
| return FD31_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis); |
| |
| case WM_COMMAND: |
| return FD31_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs); |
| #if 0 |
| case WM_CTLCOLOR: |
| SetBkColor((HDC16)wParam, 0x00C0C0C0); |
| switch (HIWORD(lParam)) |
| { |
| case CTLCOLOR_BTN: |
| SetTextColor((HDC16)wParam, 0x00000000); |
| return hGRAYBrush; |
| case CTLCOLOR_STATIC: |
| SetTextColor((HDC16)wParam, 0x00000000); |
| return hGRAYBrush; |
| } |
| break; |
| #endif |
| } |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * FileSaveDlgProc16 (COMMDLG.7) |
| */ |
| BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam) |
| { |
| HWND hWnd = HWND_32(hWnd16); |
| PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); |
| DRAWITEMSTRUCT dis; |
| |
| TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); |
| if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) |
| { |
| LRESULT lRet; |
| lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); |
| if (lRet) |
| return lRet; /* else continue message processing */ |
| } |
| switch (wMsg) { |
| case WM_INITDIALOG: |
| return FD31_WMInitDialog(hWnd, wParam, lParam); |
| |
| case WM_MEASUREITEM: |
| return FD16_WMMeasureItem(hWnd16, wParam, lParam); |
| |
| case WM_DRAWITEM: |
| FD16_MapDrawItemStruct(MapSL(lParam), &dis); |
| return FD31_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis); |
| |
| case WM_COMMAND: |
| return FD31_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs); |
| } |
| |
| /* |
| case WM_CTLCOLOR: |
| SetBkColor((HDC16)wParam, 0x00C0C0C0); |
| switch (HIWORD(lParam)) |
| { |
| case CTLCOLOR_BTN: |
| SetTextColor((HDC16)wParam, 0x00000000); |
| return hGRAYBrush; |
| case CTLCOLOR_STATIC: |
| SetTextColor((HDC16)wParam, 0x00000000); |
| return hGRAYBrush; |
| } |
| return FALSE; |
| |
| */ |
| return FALSE; |
| } |
| |
| /* ------------------ APIs ---------------------- */ |
| |
| /*********************************************************************** |
| * GetOpenFileName (COMMDLG.1) |
| * |
| * Creates a dialog box for the user to select a file to open. |
| * |
| * RETURNS |
| * TRUE on success: user selected a valid file |
| * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. |
| * |
| * BUGS |
| * unknown, there are some FIXME's left. |
| */ |
| BOOL16 WINAPI GetOpenFileName16( |
| SEGPTR ofn /* [in/out] address of structure with data*/ |
| ) |
| { |
| HINSTANCE16 hInst; |
| BOOL bRet = FALSE; |
| LPOPENFILENAME16 lpofn = MapSL(ofn); |
| PFD31_DATA lfs; |
| FARPROC16 ptr; |
| FD31_CALLBACKS callbacks; |
| PFD16_PRIVATE priv; |
| |
| if (!lpofn || !FD31_Init()) return FALSE; |
| |
| FD16_SetupCallbacks(&callbacks); |
| lfs = FD31_AllocPrivate((LPARAM) ofn, OPEN_DIALOG, &callbacks, 0); |
| if (lfs) |
| { |
| priv = (PFD16_PRIVATE) lfs->private1632; |
| hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE ); |
| ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6); |
| bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner, |
| (DLGPROC16) ptr, (LPARAM) lfs); |
| FD31_DestroyPrivate(lfs); |
| } |
| |
| TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile)); |
| return bRet; |
| } |
| |
| /*********************************************************************** |
| * GetSaveFileName (COMMDLG.2) |
| * |
| * Creates a dialog box for the user to select a file to save. |
| * |
| * RETURNS |
| * TRUE on success: user enters a valid file |
| * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. |
| * |
| * BUGS |
| * unknown. There are some FIXME's left. |
| */ |
| BOOL16 WINAPI GetSaveFileName16( |
| SEGPTR ofn /* [in/out] addess of structure with data*/ |
| ) |
| { |
| HINSTANCE16 hInst; |
| BOOL bRet = FALSE; |
| LPOPENFILENAME16 lpofn = MapSL(ofn); |
| PFD31_DATA lfs; |
| FARPROC16 ptr; |
| FD31_CALLBACKS callbacks; |
| PFD16_PRIVATE priv; |
| |
| if (!lpofn || !FD31_Init()) return FALSE; |
| |
| FD16_SetupCallbacks(&callbacks); |
| lfs = FD31_AllocPrivate((LPARAM) ofn, SAVE_DIALOG, &callbacks, 0); |
| if (lfs) |
| { |
| priv = (PFD16_PRIVATE) lfs->private1632; |
| hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE ); |
| ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7); |
| bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner, |
| (DLGPROC16) ptr, (LPARAM) lfs); |
| FD31_DestroyPrivate(lfs); |
| } |
| |
| TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile)); |
| return bRet; |
| } |