[PATCH 1/3] comdlg32: Optimize FILEDLG95_FILENAME_FillFromSelection.

Lauri Kenttä lauri.kentta at gmail.com
Thu Jun 23 06:29:54 CDT 2016


Related to bug 26803.

Previously the function would loop the files twice, first to count,
then to create a string from the names. This patch removes the
first pass and instead allocates a buffer that is always big enough.
This trades some memory for speed, but since currently selecting
1000 files takes over a minute but the required memory for those
1000 filenames is only 262 kB (worst case), this seems a reasonable
trade-off.

This gives 20% speed-up for selecting 253 files with shift-click.

Signed-off-by: Lauri Kenttä <lauri.kentta at gmail.com>
---
 dlls/comdlg32/filedlg.c | 114 +++++++++++++++++++-----------------------------
 1 file changed, 44 insertions(+), 70 deletions(-)

diff --git a/dlls/comdlg32/filedlg.c b/dlls/comdlg32/filedlg.c
index 282582b..8e64c1e 100644
--- a/dlls/comdlg32/filedlg.c
+++ b/dlls/comdlg32/filedlg.c
@@ -3626,86 +3626,60 @@ static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
  */
 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
 {
-    FileOpenDlgInfos *fodInfos;
-    LPITEMIDLIST      pidl;
-    UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
-    WCHAR             lpstrTemp[MAX_PATH];
-    LPWSTR            lpstrAllFile, lpstrCurrFile;
+  FileOpenDlgInfos *fodInfos;
+  LPITEMIDLIST pidl;
+  UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0, nTempLength;
+  WCHAR lpstrTemp[MAX_PATH];
+  LPWSTR lpstrAllFiles;
 
-    TRACE("\n");
-    fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
+  TRACE("\n");
+  fodInfos = GetPropA(hwnd,FileOpenDlgInfosStr);
 
-    /* Count how many files we have */
-    nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
+  /* Count how many files we have */
+  nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
 
-    /* calculate the string length, count files */
-    if (nFileSelected >= 1)
+  /* Allocate a buffer that is surely big enough; n * (MAX_PATH + quotes) + extra space at the end */
+  lpstrAllFiles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nFileSelected * (MAX_PATH + 2) + 1) * sizeof(WCHAR));
+  if (!lpstrAllFiles)
+    return;
+
+  /* Loop through the selection, handle only files (not folders) */
+  for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
+  {
+    pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
+    if (pidl)
     {
-      nLength += 3;	/* first and last quotes, trailing \0 */
-      for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
+      if (!IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl))
       {
-        pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
-
-        if (pidl)
-	{
-          /* get the total length of the selected file names */
-          lpstrTemp[0] = '\0';
-          GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
-
-          if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
-	  {
-            nLength += lstrlenW( lpstrTemp ) + 3;
-            nFiles++;
-	  }
-          COMDLG32_SHFree( pidl );
-	}
+        nFiles += 1;
+        lpstrTemp[0] = '\0';
+        GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
+        nTempLength = lstrlenW( lpstrTemp );
+
+        lpstrAllFiles[nLength++] = '"';
+        lstrcpyW( lpstrAllFiles + nLength, lpstrTemp );
+        nLength += nTempLength;
+        lpstrAllFiles[nLength++] = '"';
+        lpstrAllFiles[nLength++] = ' ';
+        lpstrAllFiles[nLength] = 0;
       }
+      COMDLG32_SHFree( pidl );
     }
+  }
 
-    /* allocate the buffer */
-    if (nFiles <= 1) nLength = MAX_PATH;
-    lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(WCHAR));
-
-    /* Generate the string for the edit control */
-    if(nFiles >= 1)
-    {
-      lpstrCurrFile = lpstrAllFile;
-      for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
-      {
-        pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
+  /* If there's only one file, use the name as-is without quotes */
+  if (nFiles == 1)
+    lstrcpyW( lpstrAllFiles, lpstrTemp );
 
-        if (pidl)
-	{
-	  /* get the file name */
-          lpstrTemp[0] = '\0';
-          GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp );
+  if (nFiles != 0)
+  {
+    SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFiles );
+    /* Select the file name like Windows does */
+    if (filename_is_edit( fodInfos ))
+      SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
+  }
 
-          if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
-	  {
-            if ( nFiles > 1)
-	    {
-              *lpstrCurrFile++ =  '\"';
-              lstrcpyW( lpstrCurrFile, lpstrTemp );
-              lpstrCurrFile += lstrlenW( lpstrTemp );
-              *lpstrCurrFile++ = '\"';
-              *lpstrCurrFile++ = ' ';
-              *lpstrCurrFile = 0;
-	    }
-	    else
-	    {
-              lstrcpyW( lpstrAllFile, lpstrTemp );
-	    }
-          }
-          COMDLG32_SHFree( pidl );
-	}
-      }
-      SetWindowTextW( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
-       
-      /* Select the file name like Windows does */
-      if (filename_is_edit( fodInfos ))
-          SendMessageW(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, 0, -1);
-    }
-    HeapFree(GetProcessHeap(),0, lpstrAllFile );
+  HeapFree(GetProcessHeap(), 0, lpstrAllFiles);
 }
 
 
-- 
2.9.0




More information about the wine-patches mailing list