[Bug 24624] Audacity v1.3 - v2.0.x treats all file type selections as "all files" when exporting with WinVer set to 'Windows XP'

WineHQ Bugzilla wine-bugs at winehq.org
Sun Apr 25 08:24:33 CDT 2021


https://bugs.winehq.org/show_bug.cgi?id=24624

--- Comment #7 from Damjan Jovanovic <damjan.jov at gmail.com> ---
In Audacity's git, tag Audacity-2.0.0, file
lib-src/FileDialog/win/FileDialogPrivate.cpp:

---snip---
   // We do not use the custom filter code on Windows 7 or higher since it now
   // handles filters larger than 260 characters.
   gs_customFilter = (major < 6 || minor < 1);

   wxString filterBuffer;

   for (i = 0; i < items ; i++)
   {
      filterBuffer += wildDescriptions[i];
      filterBuffer += wxT("|");
      filterBuffer += (gs_customFilter ? wxT("*.*") : m_FilterGroups[i]);
      filterBuffer += wxT("|");
   }
---snip---

(Each '|' eventually becomes '\0').

So the file type mask is always "*.*" on Windows < 6.1, presumably to save
space and allow many file type masks within the 260 character limit. That
"gs_customFilter" global variable is also checked when notifications are
delivered to its file dialog hook function:

---snip---
         else if (CDN_TYPECHANGE == (pNotifyCode->hdr).code && gs_customFilter)
         {
            OPENFILENAME *ofn = (OPENFILENAME *)
            GetWindowLongPtr(hDlg, GWLP_USERDATA);
            FileDialog *me = (FileDialog *) ofn->lCustData;
            me->ParseFilter(ofn->nFilterIndex);
            me->FilterFiles(hDlg, true);
         }
---snip---

So on Windows < 6.1, we run all that. The "me->ParseFilter()" will populate
"m_Filters" with the list of masks for the currently selected file type, while
"me->FilterFiles()" does the filtering work based on those masks. How?

The lengthy FileDialog::FilterFiles() method looks up the "lst2" listview on
the dialog box, iterates over its contents, then uses many shell32 APIs. In
brief, it allows folders, otherwise gets the filename and tries to match it
against each filter from the earlier "m_Filters", using wxMatchWild(). If no
filters matched, ListView_DeleteItem() deletes that filename from the listview.

Finally, where I believe things go wrong:

---snip---
   // On Vista and maybe XP, we seem to need to refresh the view after
   // changing the filters.  But, only refresh for type changes and not
   // selection changes since it causes additional selection change
   // events to occur.
   if (ishellview && refresh)
   {
      ishellview->Refresh();
   }
---snip---

To summarize, Audacity 2.0:
1. Expects the file save dialog listview to be fully populated when it is
called, with *.* as the filter.
2. Wants to decide which files do not match, and expects itself to be able to
delete them from the listview.
3. Expects IShellview::Refresh() not to change which files are displayed, after
it does the deletion.

(2) works as long as (1) is satisfied, but Wine fails (1) as it populates the
listview with IShellview::Refresh() AFTER sending CDN_TYPECHANGE, and fails (3)
as its IShellview::Refresh() does re-add deleted items.

To hack this into working, it is enough to comment the "ishellview->Refresh()"
from earlier, and patch Wine to call IShellView::Refresh() prior to sending
CDN_TYPECHANGE:

---snip---
diff --git a/dlls/comdlg32/filedlg.c b/dlls/comdlg32/filedlg.c
index 0ada09aad96..0ec1e2f3fe9 100644
--- a/dlls/comdlg32/filedlg.c
+++ b/dlls/comdlg32/filedlg.c
@@ -3194,13 +3194,18 @@ static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd,
WORD wNotifyCode)
           len = lstrlenW(lpstrFilter)+1;
           fodInfos->ShellInfos.lpstrCurrentFilter = heap_alloc( len *
sizeof(WCHAR) );
           lstrcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter);
+          /* Refresh the actual view to display the included items*/
+          if (fodInfos->Shell.FOIShellView)
+              IShellView_Refresh(fodInfos->Shell.FOIShellView);
           if(fodInfos->ofnInfos->Flags & OFN_EXPLORER)
               SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
       }
-
-      /* Refresh the actual view to display the included items*/
-      if (fodInfos->Shell.FOIShellView)
-        IShellView_Refresh(fodInfos->Shell.FOIShellView);
+      else
+      {
+          /* Refresh the actual view to display the included items*/
+          if (fodInfos->Shell.FOIShellView)
+              IShellView_Refresh(fodInfos->Shell.FOIShellView);
+      }
     }
   }
   return FALSE;
---snip---

A real fix would involve changes to IShellView::Refresh() itself, whose real
function is currently a mystery.

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list