Alex Henrie : comdlg32: Correctly handle filters with multiple file extensions in Save As dialogs.

Alexandre Julliard julliard at winehq.org
Mon Jan 23 13:01:13 CST 2012


Module: wine
Branch: master
Commit: 7a34094e6e3e8a321148c64b0c9e2b986e63a7d9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=7a34094e6e3e8a321148c64b0c9e2b986e63a7d9

Author: Alex Henrie <alexhenrie24 at gmail.com>
Date:   Fri Jan 20 14:52:18 2012 -0700

comdlg32: Correctly handle filters with multiple file extensions in Save As dialogs.

---

 dlls/comdlg32/filedlg.c       |   61 ++++++++++++++++++++---------
 dlls/comdlg32/tests/filedlg.c |   85 ++++++++++++++++++++++++++++++-----------
 2 files changed, 104 insertions(+), 42 deletions(-)

diff --git a/dlls/comdlg32/filedlg.c b/dlls/comdlg32/filedlg.c
index 43df312..c31641b 100644
--- a/dlls/comdlg32/filedlg.c
+++ b/dlls/comdlg32/filedlg.c
@@ -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 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 the extension contains a glob, ignore it */
+                if (strchrW(filterExt, '*') || strchrW(filterExt, '?'))
+                {
+                    HeapFree(GetProcessHeap(), 0, filterExt);
+                    filterExt = NULL;
+                }
+            }
 
-            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)
+            {
+                /* 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, '?') )
+            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 */
diff --git a/dlls/comdlg32/tests/filedlg.c b/dlls/comdlg32/tests/filedlg.c
index 8539d3d..0d1112f 100644
--- a/dlls/comdlg32/tests/filedlg.c
+++ b/dlls/comdlg32/tests/filedlg.c
@@ -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");
     }
 }
 




More information about the wine-cvs mailing list