[PATCH] comdlg32: Correctly handle filters with multiple file extensions in Save As dialogs
Alex Henrie
alexhenrie24 at gmail.com
Mon Dec 19 01:35:37 CST 2011
Fixes bug 29362.
The MSDN documentation of this behavior can be found at
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646960%28v=vs.85%29.aspx#_win32_Filters
---
dlls/comdlg32/filedlg.c | 35 +++++++++++++++++++++++++++++------
dlls/comdlg32/tests/filedlg.c | 26 +++++++++++++++++++++-----
2 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/dlls/comdlg32/filedlg.c b/dlls/comdlg32/filedlg.c
index 9b725ba..b480044 100644
--- a/dlls/comdlg32/filedlg.c
+++ b/dlls/comdlg32/filedlg.c
@@ -2539,7 +2539,7 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
/* 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);
@@ -2549,12 +2549,30 @@ 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 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';
+ }
+
+ /* strip the * or anything else from the extension, "*.abc" becomes "abc" */
+ StrCpyW(filterExt, PathFindExtensionW(filterExt) + 1);
+ }
- 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 ( (!filterExt || !*filterExt) && fodInfos->defext )
+ {
+ /* use the default file extension */
+ filterExt = HeapAlloc(GetProcessHeap(), 0, lstrlenW(fodInfos->defext) * sizeof(WCHAR) + sizeof(WCHAR));
+ StrCpyW(filterExt, fodInfos->defext);
+ }
/* If extension contains a glob, ignore it */
if ( filterExt && !strchrW(filterExt, '*') && !strchrW(filterExt, '?') )
@@ -2565,6 +2583,11 @@ BOOL FILEDLG95_OnOpen(HWND hwnd)
lstrcatW(lpstrPathAndFile, filterExt );
}
+ if (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';
diff --git a/dlls/comdlg32/tests/filedlg.c b/dlls/comdlg32/tests/filedlg.c
index 8539d3d..9876e7e 100644
--- a/dlls/comdlg32/tests/filedlg.c
+++ b/dlls/comdlg32/tests/filedlg.c
@@ -1044,13 +1044,19 @@ static UINT_PTR WINAPI test_extension_wndproc(HWND dlg, UINT msg, WPARAM wParam,
return FALSE;
}
-static const char *defext_filters[] = {
+static const char *defext_wildcard_filters[] = {
"TestFilter (*.pt*)\0*.pt*\0",
"TestFilter (*.ab?)\0*.ab?\0",
"TestFilter (*.*)\0*.*\0",
NULL /* is a test, not an endmark! */
};
+static const char *defext_concrete_filters[] = {
+ "TestFilter (*.abc)\0*.abc\0",
+ "TestFilter (*.abc;)\0*.abc;\0",
+ "TestFilter (*.abc;*.def)\0*.abc;*.def\0",
+};
+
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
static void test_extension(void)
@@ -1067,7 +1073,7 @@ static void test_extension(void)
boolret = GetCurrentDirectoryA(sizeof(curdir), curdir);
ok(boolret, "Failed to get current dir err %d\n", GetLastError());
- /* Ignore .* extension */
+ /* Ignore wildcard extensions */
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = filename;
@@ -1078,8 +1084,8 @@ static void test_extension(void)
ofn.lpfnHook = test_extension_wndproc;
ofn.nFileExtension = 0;
- for (i = 0; i < ARRAY_SIZE(defext_filters); i++) {
- ofn.lpstrFilter = defext_filters[i];
+ for (i = 0; i < ARRAY_SIZE(defext_wildcard_filters); i++) {
+ ofn.lpstrFilter = defext_wildcard_filters[i];
strcpy(filename, test_file_name);
boolret = GetSaveFileNameA(&ofn);
ok(boolret, "%u: expected true\n", i);
@@ -1088,7 +1094,17 @@ static void test_extension(void)
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 );
+ "Filename is %s, expected %s\n from filter \"%s\"", filename_ptr, test_file_name, ofn.lpstrFilter );
+ }
+
+ /* Append concrete extensions */
+ for (i = 0; i < ARRAY_SIZE(defext_concrete_filters); i++) {
+ ofn.lpstrFilter = defext_concrete_filters[i];
+ strcpy(filename, "deadbeef");
+ GetSaveFileNameA(&ofn);
+ filename_ptr = ofn.lpstrFile + strlen( ofn.lpstrFile ) - strlen( "deadbeef.abc" );
+ ok( strcmp(filename_ptr, "deadbeef.abc") == 0,
+ "Filename ends in %s, expected deadbeef.abc from filter \"%s\"\n", filename_ptr, ofn.lpstrFilter );
}
}
--
1.7.4.1
More information about the wine-patches
mailing list