|  | /* | 
|  | * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 | 
|  | */ | 
|  | static void FD16_MapOfnStruct16(const OPENFILENAME16 *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 | 
|  | * | 
|  | */ | 
|  | static BOOL FD16_GetTemplate(const FD31_DATA *lfs) | 
|  | { | 
|  | PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; | 
|  | LPOPENFILENAME16 ofn16 = priv->ofn16; | 
|  | LPVOID 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 %d 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(template32, size, 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; | 
|  |  | 
|  | lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW)); | 
|  | 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 | 
|  | */ | 
|  | static BOOL CALLBACK FD16_CallWindowProc(const FD31_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(const FD31_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(const FD31_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(const FD31_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(const FD31_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); | 
|  | HeapFree(GetProcessHeap(), 0, 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(const DRAWITEMSTRUCT16 *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 ---------------------- */ | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           FileOpenDlgProc   (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; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           FileSaveDlgProc   (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; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *	GetFileTitle		(COMMDLG.27) | 
|  | */ | 
|  | short WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf) | 
|  | { | 
|  | return GetFileTitleA(lpFile, lpTitle, cbBuf); | 
|  | } |