514 lines
16 KiB
C
514 lines
16 KiB
C
/*
|
|
* 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 ---------------------- */
|
|
|
|
/***********************************************************************
|
|
* 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;
|
|
}
|