comdlg32: Correctly handle filters with multiple file extensions in Save As dialogs.
This commit is contained in:
parent
7d9ce823c3
commit
7a34094e6e
|
@ -2533,12 +2533,12 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
|
|||
|
||||
/* Attach the file extension with file name*/
|
||||
ext = PathFindExtensionW(lpstrPathAndFile);
|
||||
if (! *ext)
|
||||
if (! *ext && fodInfos->defext)
|
||||
{
|
||||
/* if no extension is specified with file name, then */
|
||||
/* attach the extension from file filter or default one */
|
||||
|
||||
const WCHAR *filterExt = NULL;
|
||||
WCHAR *filterExt = NULL;
|
||||
LPWSTR lpstrFilter = NULL;
|
||||
static const WCHAR szwDot[] = {'.',0};
|
||||
int PathLength = lstrlenW(lpstrPathAndFile);
|
||||
|
@ -2548,15 +2548,39 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
|
|||
fodInfos->ofnInfos->nFilterIndex-1);
|
||||
|
||||
if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */
|
||||
filterExt = PathFindExtensionW(lpstrFilter);
|
||||
{
|
||||
WCHAR* filterAtSemicolon;
|
||||
filterExt = HeapAlloc(GetProcessHeap(), 0, lstrlenW(lpstrFilter) * sizeof(WCHAR) + sizeof(WCHAR));
|
||||
strcpyW(filterExt, lpstrFilter);
|
||||
|
||||
if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/
|
||||
filterExt = filterExt + 1;
|
||||
else if ( fodInfos->defext ) /* attach the default file extension*/
|
||||
filterExt = fodInfos->defext;
|
||||
/* if a semicolon-separated list of file extensions was given, do not include the
|
||||
semicolon or anything after it in the extension.
|
||||
example: if filterExt was "*.abc;*.def", it will become "*.abc" */
|
||||
filterAtSemicolon = strchrW(filterExt, ';');
|
||||
if (filterAtSemicolon)
|
||||
{
|
||||
filterAtSemicolon[0] = '\0';
|
||||
}
|
||||
|
||||
/* If extension contains a glob, ignore it */
|
||||
if ( filterExt && !strchrW(filterExt, '*') && !strchrW(filterExt, '?') )
|
||||
/* strip the * or anything else from the extension, "*.abc" becomes "abc" */
|
||||
strcpyW(filterExt, PathFindExtensionW(filterExt) + 1);
|
||||
|
||||
/* if the extension contains a glob, ignore it */
|
||||
if (strchrW(filterExt, '*') || strchrW(filterExt, '?'))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, filterExt);
|
||||
filterExt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!filterExt)
|
||||
{
|
||||
/* use the default file extension */
|
||||
filterExt = HeapAlloc(GetProcessHeap(), 0, lstrlenW(fodInfos->defext) * sizeof(WCHAR) + sizeof(WCHAR));
|
||||
strcpyW(filterExt, fodInfos->defext);
|
||||
}
|
||||
|
||||
if (*filterExt) /* ignore filterExt="" */
|
||||
{
|
||||
/* Attach the dot*/
|
||||
lstrcatW(lpstrPathAndFile, szwDot);
|
||||
|
@ -2564,20 +2588,19 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
|
|||
lstrcatW(lpstrPathAndFile, filterExt );
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, filterExt);
|
||||
|
||||
/* In Open dialog: if file does not exist try without extension */
|
||||
if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile))
|
||||
lpstrPathAndFile[PathLength] = '\0';
|
||||
}
|
||||
|
||||
if (fodInfos->defext) /* add default extension */
|
||||
{
|
||||
/* 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;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* In Save dialog: check if the file already exists */
|
||||
|
|
|
@ -1044,51 +1044,90 @@ static UINT_PTR WINAPI test_extension_wndproc(HWND dlg, UINT msg, WPARAM wParam,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static const char *defext_filters[] = {
|
||||
"TestFilter (*.pt*)\0*.pt*\0",
|
||||
"TestFilter (*.ab?)\0*.ab?\0",
|
||||
"TestFilter (*.*)\0*.*\0",
|
||||
NULL /* is a test, not an endmark! */
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
|
||||
static void test_extension_helper(OPENFILENAME* ofn, const char *filter,
|
||||
const char *expected_filename)
|
||||
{
|
||||
char *filename_ptr;
|
||||
DWORD ret;
|
||||
BOOL boolret;
|
||||
|
||||
strcpy(ofn->lpstrFile, "deadbeef");
|
||||
ofn->lpstrFilter = filter;
|
||||
|
||||
boolret = GetSaveFileNameA(ofn);
|
||||
ok(boolret, "%s: expected TRUE\n", filter);
|
||||
|
||||
ret = CommDlgExtendedError();
|
||||
ok(!ret, "%s: CommDlgExtendedError returned %#x\n", filter, ret);
|
||||
|
||||
filename_ptr = ofn->lpstrFile + ofn->nFileOffset;
|
||||
ok(strcmp(filename_ptr, expected_filename) == 0,
|
||||
"%s: Filename is %s, expected %s\n", filter, filename_ptr, expected_filename);
|
||||
}
|
||||
|
||||
static void test_extension(void)
|
||||
{
|
||||
OPENFILENAME ofn = { sizeof(OPENFILENAME)};
|
||||
char filename[1024] = {0};
|
||||
char curdir[MAX_PATH];
|
||||
char *filename_ptr;
|
||||
const char *test_file_name = "deadbeef";
|
||||
unsigned int i;
|
||||
DWORD ret;
|
||||
BOOL boolret;
|
||||
|
||||
const char *defext_concrete_filters[] = {
|
||||
"TestFilter (*.abc)\0*.abc\0",
|
||||
"TestFilter (*.abc;)\0*.abc;\0",
|
||||
"TestFilter (*.abc;*.def)\0*.abc;*.def\0",
|
||||
};
|
||||
|
||||
const char *defext_wildcard_filters[] = {
|
||||
"TestFilter (*.pt*)\0*.pt*\0",
|
||||
"TestFilter (*.pt*;*.abc)\0*.pt*;*.abc\0",
|
||||
"TestFilter (*.ab?)\0*.ab?\0",
|
||||
"TestFilter (*.*)\0*.*\0",
|
||||
NULL /* is a test, not an endmark! */
|
||||
};
|
||||
|
||||
boolret = GetCurrentDirectoryA(sizeof(curdir), curdir);
|
||||
ok(boolret, "Failed to get current dir err %d\n", GetLastError());
|
||||
|
||||
/* Ignore .* extension */
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = NULL;
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK;
|
||||
ofn.lpstrDefExt = NULL;
|
||||
ofn.lpstrInitialDir = curdir;
|
||||
ofn.lpfnHook = test_extension_wndproc;
|
||||
ofn.nFileExtension = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(defext_filters); i++) {
|
||||
ofn.lpstrFilter = defext_filters[i];
|
||||
strcpy(filename, test_file_name);
|
||||
boolret = GetSaveFileNameA(&ofn);
|
||||
ok(boolret, "%u: expected true\n", i);
|
||||
ret = CommDlgExtendedError();
|
||||
ok(!ret, "%u: CommDlgExtendedError returned %#x\n", i, ret);
|
||||
filename_ptr = ofn.lpstrFile + strlen( ofn.lpstrFile ) - strlen( test_file_name );
|
||||
ok( strlen(ofn.lpstrFile) >= strlen(test_file_name), "Filename %s is too short\n", ofn.lpstrFile );
|
||||
ok( strcmp(filename_ptr, test_file_name) == 0,
|
||||
"Filename is %s, expected %s\n", filename_ptr, test_file_name );
|
||||
ofn.lpstrDefExt = NULL;
|
||||
|
||||
/* Without lpstrDefExt, append no extension */
|
||||
test_extension_helper(&ofn, "TestFilter (*.abc) lpstrDefExt=NULL\0*.abc\0", "deadbeef");
|
||||
test_extension_helper(&ofn, "TestFilter (*.ab?) lpstrDefExt=NULL\0*.ab?\0", "deadbeef");
|
||||
|
||||
ofn.lpstrDefExt = "";
|
||||
|
||||
/* If lpstrDefExt="" and the filter has a concrete extension, append it */
|
||||
test_extension_helper(&ofn, "TestFilter (*.abc) lpstrDefExt=\"\"\0*.abc\0", "deadbeef.abc");
|
||||
|
||||
/* If lpstrDefExt="" and the filter has a wildcard extension, do nothing */
|
||||
test_extension_helper(&ofn, "TestFilter (*.ab?) lpstrDefExt=\"\"\0*.ab?\0", "deadbeef");
|
||||
|
||||
ofn.lpstrDefExt = "xyz";
|
||||
|
||||
/* Append concrete extensions from filters */
|
||||
for (i = 0; i < ARRAY_SIZE(defext_concrete_filters); i++) {
|
||||
test_extension_helper(&ofn, defext_concrete_filters[i], "deadbeef.abc");
|
||||
}
|
||||
|
||||
/* Append nothing from this filter */
|
||||
test_extension_helper(&ofn, "TestFilter (*.)\0*.\0", "deadbeef");
|
||||
|
||||
/* Ignore wildcard extensions in filters */
|
||||
for (i = 0; i < ARRAY_SIZE(defext_wildcard_filters); i++) {
|
||||
test_extension_helper(&ofn, defext_wildcard_filters[i], "deadbeef.xyz");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue