[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