[COMDLG32] GetOpen/GetSaveFileName: Improve extension handling (#5640)

- Improve GetOpenFileName and GetSaveFileName
  functions.
- Add FILEDLG95_GetFallbackExtension and
  FILEDLG95_AddDotExtIfNeeded helper functions.
- Modify FILEDLG95_ValidatePathAction and
  FILEDLG95_OnOpen functions.
CORE-19148, CORE-15020
This commit is contained in:
Katayama Hirofumi MZ 2023-09-04 21:11:24 +09:00 committed by GitHub
parent f0995dac58
commit d55e33d0f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 118 additions and 95 deletions

View file

@ -199,8 +199,14 @@ HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
/* Shared helper functions */
void COMDLG32_GetCanonicalPath(PCIDLIST_ABSOLUTE pidlAbsCurrent, LPWSTR lpstrFile, LPWSTR lpstrPathAndFile) DECLSPEC_HIDDEN;
#ifdef __REACTOS__
struct FileOpenDlgInfos;
int FILEDLG95_ValidatePathAction(struct FileOpenDlgInfos *fodInfos, LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction) DECLSPEC_HIDDEN;
#else
int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction) DECLSPEC_HIDDEN;
#endif
int COMDLG32_SplitFileNames(LPWSTR lpstrEdit, UINT nStrLen, LPWSTR *lpstrFileList, UINT *sizeUsed) DECLSPEC_HIDDEN;
void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText) DECLSPEC_HIDDEN;

View file

@ -2826,8 +2826,98 @@ void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
}
#ifdef __REACTOS__
/* The return value needs LocalFree */
static LPWSTR FILEDLG95_GetFallbackExtension(FileOpenDlgInfos *fodInfos, LPWSTR lpstrPathAndFile)
{
LPWSTR lpstrFilter, the_ext = NULL, pchDot = NULL;
/* Without lpstrDefExt, append no extension */
if (!fodInfos->defext)
return NULL;
/* Get filter extensions */
lpstrFilter = (LPWSTR)CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
fodInfos->ofnInfos->nFilterIndex - 1);
if (lpstrFilter != (LPWSTR)CB_ERR && lpstrFilter && *lpstrFilter)
{
LPWSTR pchSemicolon = wcschr(lpstrFilter, L';');
if (pchSemicolon)
*pchSemicolon = UNICODE_NULL;
pchDot = wcschr(lpstrFilter, L'.');
if (pchDot && pchDot[1] && !wcschr(pchDot, L'*') && !wcschr(pchDot, L'?'))
the_ext = StrDupW(pchDot + 1);
if (pchSemicolon)
*pchSemicolon = L';';
}
if (!the_ext && (!pchDot || pchDot[1]))
{
/* use default extension if no extension in filter */
the_ext = StrDupW(fodInfos->defext);
}
return the_ext;
}
static BOOL
FILEDLG95_AddDotExtIfNeeded(FileOpenDlgInfos *fodInfos, LPWSTR lpstrPathAndFile)
{
BOOL ret = FALSE;
LPWSTR ext = PathFindExtensionW(lpstrPathAndFile);
int PathLength = lstrlenW(lpstrPathAndFile);
LPWSTR the_ext = FILEDLG95_GetFallbackExtension(fodInfos, lpstrPathAndFile);
if (the_ext && *the_ext &&
(*ext == UNICODE_NULL || lstrcmpiW(ext + 1, the_ext) != 0))
{
if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <=
fodInfos->ofnInfos->nMaxFile)
{
/* Make the extension lowercase */
CharLowerW(the_ext);
/* Append it (with dot) to the file */
lstrcatW(lpstrPathAndFile, L".");
lstrcatW(lpstrPathAndFile, the_ext);
/* update ext */
ext = PathFindExtensionW(lpstrPathAndFile);
ret = TRUE;
}
}
LocalFree(the_ext);
/* In Open dialog: if file does not exist try without extension */
if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
{
lpstrPathAndFile[PathLength] = UNICODE_NULL;
ret = FALSE;
}
/* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
if (*ext)
ext++;
if (!lstrcmpiW(fodInfos->defext, ext))
fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
else
fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
return ret;
}
#endif
#ifdef __REACTOS__
int FILEDLG95_ValidatePathAction(struct FileOpenDlgInfos *fodInfos, LPWSTR lpstrPathAndFile,
IShellFolder **ppsf, HWND hwnd, DWORD flags, BOOL isSaveDlg,
int defAction)
#else
int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
HWND hwnd, DWORD flags, BOOL isSaveDlg, int defAction)
#endif
{
int nOpenAction = defAction;
LPWSTR lpszTemp, lpszTemp1;
@ -2924,8 +3014,17 @@ int FILEDLG95_ValidatePathAction(LPWSTR lpstrPathAndFile, IShellFolder **ppsf,
{
if( (flags & OFN_FILEMUSTEXIST) && !isSaveDlg )
{
#ifdef __REACTOS__
FILEDLG95_AddDotExtIfNeeded(fodInfos, lpstrPathAndFile);
if (!PathFileExistsW(lpstrPathAndFile))
{
FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
break;
}
#else
FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
break;
#endif
}
}
/* change to the current folder */
@ -3011,7 +3110,11 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
else
nOpenAction = ONOPEN_BROWSE;
#ifdef __REACTOS__
nOpenAction = FILEDLG95_ValidatePathAction(fodInfos, lpstrPathAndFile, &lpsf, hwnd,
#else
nOpenAction = FILEDLG95_ValidatePathAction(lpstrPathAndFile, &lpsf, hwnd,
#endif
fodInfos->ofnInfos->Flags,
fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG,
nOpenAction);
@ -3088,7 +3191,9 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
case ONOPEN_OPEN: /* fill in the return struct and close the dialog */
TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile));
{
#ifndef __REACTOS__
WCHAR *ext = NULL;
#endif
/* update READONLY check box flag */
if ((SendMessageW(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED)
@ -3097,104 +3202,13 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
fodInfos->ofnInfos->Flags &= ~OFN_READONLY;
/* Attach the file extension with file name*/
ext = PathFindExtensionW(lpstrPathAndFile);
#ifdef __REACTOS__
if (*ext == UNICODE_NULL && fodInfos->defext)
{
LPWSTR filterExt = NULL, lpstrFilter = NULL, pch, pchNext;
LPCWSTR the_ext = NULL;
static const WCHAR szwDot[] = {'.',0};
int PathLength = lstrlenW(lpstrPathAndFile);
/* get filter extensions */
lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
fodInfos->ofnInfos->nFilterIndex - 1);
if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
{
LPWSTR filterSearchIndex, pchFirst = NULL;
filterExt = heap_alloc((lstrlenW(lpstrFilter) + 1) * sizeof(WCHAR));
if (filterExt)
{
strcpyW(filterExt, lpstrFilter);
if (ext && *ext)
{
/* find ext in filter */
for (pch = filterExt; pch && *pch; pch = pchNext)
{
filterSearchIndex = strchrW(pch, ';');
if (filterSearchIndex)
{
filterSearchIndex[0] = 0;
pchNext = filterSearchIndex + 1;
}
else
{
pchNext = NULL;
}
while (*pch == '*' || *pch == '.' || *pch == '?')
{
++pch;
}
if (!pchFirst)
pchFirst = pch;
if (lstrcmpiW(pch, &ext[1]) == 0)
{
the_ext = pch;
break;
}
}
/* use first one if not found */
if (!the_ext && pchFirst && *pchFirst)
{
the_ext = pchFirst;
}
}
}
}
if (!the_ext)
{
/* use default extension if no extension in filter */
the_ext = fodInfos->defext;
}
if (the_ext && *the_ext && lstrcmpiW(&ext[1], the_ext) != 0)
{
if (strlenW(lpstrPathAndFile) + 1 + strlenW(the_ext) + 1 <=
fodInfos->ofnInfos->nMaxFile)
{
/* append the dot */
lstrcatW(lpstrPathAndFile, szwDot);
/* append the extension */
lstrcatW(lpstrPathAndFile, the_ext);
/* update ext */
ext = PathFindExtensionW(lpstrPathAndFile);
}
}
heap_free(filterExt);
/* In Open dialog: if file does not exist try without extension */
if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
lpstrPathAndFile[PathLength] = 0;
/* Set/clear the output OFN_EXTENSIONDIFFERENT flag */
if (*ext)
ext++;
if (!lstrcmpiW(fodInfos->defext, ext))
fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT;
else
fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT;
}
/* Add extension if necessary */
FILEDLG95_AddDotExtIfNeeded(fodInfos, lpstrPathAndFile);
/* update dialog data */
SetWindowTextW(fodInfos->DlgInfos.hwndFileName, PathFindFileNameW(lpstrPathAndFile));
#else /* __REACTOS__ */
ext = PathFindExtensionW(lpstrPathAndFile);
if (! *ext && fodInfos->defext)
{
/* if no extension is specified with file name, then */

View file

@ -47,8 +47,11 @@
* Data structure
*/
#ifdef __REACTOS__
typedef struct FileOpenDlgInfos
#else
typedef struct
#endif
{
LPOPENFILENAMEW ofnInfos;
BOOL unicode;