[PATCH 1/3] comdlg32.dll - Make old-style OpenFileName() function display directory tree in the directory listbox, without square brackets around directory names. This matches the functionality for this listbox in winXP, 7 and 10. Also display open folder icon for selected folder.

Dirk Niggemann dirk.niggemann at gmail.com
Sun Feb 23 17:16:50 CST 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48589
Signed-off=-by: Dirk Niggemann <dirk.niggemann at gmail.com>
---
 dlls/comdlg32/filedlg31.c | 155 ++++++++++++++++++++++++++++++++------
 1 file changed, 131 insertions(+), 24 deletions(-)

diff --git a/dlls/comdlg32/filedlg31.c b/dlls/comdlg32/filedlg31.c
index 53ef3eeb48..0e8f316f52 100644
--- a/dlls/comdlg32/filedlg31.c
+++ b/dlls/comdlg32/filedlg31.c
@@ -48,6 +48,7 @@ static const WCHAR FILE_bslash[] = {'\\', 0};
 static const WCHAR FILE_specc[] = {'%','c',':', 0};
 static const int fldrHeight = 16;
 static const int fldrWidth = 20;
+static const int indentWidth = 5;
 
 static HICON hFolder = 0;
 static HICON hFolder2 = 0;
@@ -70,6 +71,7 @@ typedef struct tagFD31_DATA
     LPOPENFILENAMEW ofnW; /* pointer either to the original structure or
                              a W copy for A/16 API */
     LPOPENFILENAMEA ofnA; /* original structure if 32bits ansi dialog */
+    UINT curropen; /* position of currenly open folder */
 } FD31_DATA, *PFD31_DATA;
 
 /***********************************************************************
@@ -170,12 +172,60 @@ static LPCWSTR FD31_GetFileType(LPCWSTR cfptr, LPCWSTR fptr, const WORD index)
   return FILE_star; /* FIXME */
 }
 
+
+/***********************************************************************
+ *           FD31_Directory
+ */
+static LRESULT FD31_Directory( HWND hdlg, LPCWSTR filespec, int pos, int indent, int curropen, BOOL long_names )
+{
+    HANDLE handle;
+    LRESULT ret = LB_OKAY;
+    WIN32_FIND_DATAW entry;
+    LRESULT maxinsert = LB_ERR;
+    int n = 0;
+
+    /* scan directory */
+    if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
+    {
+        int le = GetLastError();
+        if ((le != ERROR_NO_MORE_FILES) && (le != ERROR_FILE_NOT_FOUND)) return LB_ERR;
+    }
+    else
+    {
+        do
+        {
+            WCHAR buffer[270];
+            if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+            {
+                static const WCHAR dotW[] = { '.',0 };
+                static const WCHAR dotdotW[] = { '.', '.', 0 };
+                if ( !lstrcmpW( entry.cFileName, dotW ) ) continue;
+                if ( !lstrcmpW( entry.cFileName, dotdotW ) ) continue;
+                if (!long_names && entry.cAlternateFileName[0])
+                    lstrcpyW( buffer, entry.cAlternateFileName );
+                else
+                    lstrcpyW( buffer , entry.cFileName );
+                if (!long_names) CharLowerW( buffer );
+                /* pos = LISTBOX_FindFileStrPos( descr, buffer ); */
+                SendMessageW(hdlg, LB_INSERTSTRING, pos+n, (LPARAM)buffer);
+                SendMessageW(hdlg, LB_SETITEMDATA, pos+n, curropen == (pos+n) ? indent | 0x10000 : indent);
+                if (ret <= maxinsert) maxinsert++; else maxinsert = ret;
+                n++;
+            }
+        } while (FindNextFileW( handle, &entry ));
+        FindClose( handle );
+    }
+    return ret;
+}
+
 /***********************************************************************
  * 				FD31_ScanDir                 [internal]
  */
-static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
+static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath,
+                        int curropen)
 {
     WCHAR   buffer[BUFFILE];
+    WCHAR   currpath[BUFFILE];
     HWND    hdlg;
     LRESULT lRet = TRUE;
     HCURSOR hCursorWait, oldCursor;
@@ -183,6 +233,7 @@ static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
     TRACE("Trying to change to %s\n", debugstr_w(newPath));
     if  ( newPath[0] && !SetCurrentDirectoryW( newPath ))
         return FALSE;
+    GetCurrentDirectoryW(BUFFILE, currpath);
 
     /* get the list of spec files */
     lstrcpynW(buffer, FD31_GetFileType(ofn->lpstrCustomFilter,
@@ -211,9 +262,35 @@ static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
 
     /* list of directories */
     lstrcpyW(buffer, FILE_star);
-
-    if (GetDlgItem(hWnd, lst2) != 0) {
-        lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY);
+    if ((hdlg = GetDlgItem(hWnd, lst2)) != 0) {
+        WCHAR * dir = currpath;
+        WCHAR * sepptr;
+        UINT n = 0;
+        WCHAR pathcomp[BUFFILE];
+	SendMessageW(hdlg, LB_RESETCONTENT, 0, 0);
+        while (dir)
+        {
+           sepptr = wcschr(dir, FILE_bslash[0]);
+           if (sepptr) *sepptr = 0;
+           if (!*dir)
+           {
+	      dir = (sepptr) ? (sepptr + 1) : 0;
+              continue;
+           }
+           lstrcpyW(pathcomp, dir);
+           if( dir[lstrlenW(dir) -1] == ':' )
+              lstrcatW(pathcomp, FILE_bslash);
+	   TRACE("Using path comp  %s\n", debugstr_w(pathcomp));
+	   SendMessageW(hdlg, LB_INSERTSTRING, n, (LPARAM)pathcomp);
+	   dir = (sepptr) ? (sepptr + 1) : 0;
+           /* last entry sets open folder if -1 */
+           if (curropen == -1 && !dir)
+	      SendMessageW(hdlg, LB_SETITEMDATA, n, n | 0x10000 );
+           else
+	      SendMessageW(hdlg, LB_SETITEMDATA, n,n == curropen ? n | 0x10000 : n);
+           n++;
+        }
+        FD31_Directory(hdlg, buffer, n, n, curropen, TRUE);
     }
     SetCursor(oldCursor);
     return lRet;
@@ -223,12 +300,17 @@ static BOOL FD31_ScanDir(const OPENFILENAMEW *ofn, HWND hWnd, LPCWSTR newPath)
  *                              FD31_WMDrawItem              [internal]
  */
 static LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
-			    int savedlg, const DRAWITEMSTRUCT *lpdis)
+			    int savedlg, int curropen, const DRAWITEMSTRUCT *lpdis)
 {
     WCHAR *str;
     HICON hIcon;
     COLORREF oldText = 0, oldBk = 0;
+    ULONG indent = 0;
 
+    if (lpdis->itemData) 
+    {
+        indent = lpdis->itemData & 0xffff;
+    }
     if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1)
     {
         if (!(str = heap_alloc(BUFFILEALLOC))) return FALSE;
@@ -271,7 +353,7 @@ static LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
 	    oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) );
 	    oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
 	}
-	ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth,
+	ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth + indent*indentWidth,
                   lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED,
                   &(lpdis->rcItem), str, lstrlenW(str), NULL);
 
@@ -283,7 +365,10 @@ static LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam,
 	    SetBkColor( lpdis->hDC, oldBk );
 	    SetTextColor( lpdis->hDC, oldText );
 	}
-	DrawIconEx( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder, 16, 16, 0, 0, DI_NORMAL );
+        if (lpdis->itemData & 0x10000)
+	    DrawIconEx( lpdis->hDC, lpdis->rcItem.left + indent*indentWidth, lpdis->rcItem.top, hFolder2, 16, 16, 0, 0, DI_NORMAL );
+        else
+	    DrawIconEx( lpdis->hDC, lpdis->rcItem.left + indent*indentWidth, lpdis->rcItem.top, hFolder, 16, 16, 0, 0, DI_NORMAL );
         heap_free(str);
 	return TRUE;
     }
@@ -408,30 +493,50 @@ static void FD31_UpdateFileTitle(const FD31_DATA *lfs)
 /***********************************************************************
  *                              FD31_DirListDblClick         [internal]
  */
-static LRESULT FD31_DirListDblClick( const FD31_DATA *lfs )
+static LRESULT FD31_DirListDblClick( FD31_DATA *lfs )
 {
   LONG lRet;
+  LONG currindent;
   HWND hWnd = lfs->hwnd;
   LPWSTR pstr;
   WCHAR tmpstr[BUFFILE];
+  WCHAR tmpstr2[BUFFILE];
+  int n, indent;
 
   /* get the raw string (with brackets) */
   lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0);
   if (lRet == LB_ERR) return TRUE;
   pstr = heap_alloc(BUFFILEALLOC);
-  SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet,
-		     (LPARAM)pstr);
+  SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet, (LPARAM)pstr);
+  currindent = SendDlgItemMessageW(hWnd, lst2, LB_GETITEMDATA, lRet, 0) & 0xffff;
+  lfs->curropen = currindent;
   lstrcpyW( tmpstr, pstr );
-  heap_free(pstr);
   /* get the selected directory in tmpstr */
   if (tmpstr[0] == '[')
     {
       tmpstr[lstrlenW(tmpstr) - 1] = 0;
       lstrcpyW(tmpstr,tmpstr+1);
     }
+  n = lRet -1;
+  while (n >= 0)
+  {
+     SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, n, (LPARAM)pstr);
+     indent = SendDlgItemMessageW(hWnd, lst2, LB_GETITEMDATA, n, 0) & 0xffff;
+     if (indent < currindent)
+     {
+       lstrcpyW(tmpstr2, pstr);
+       lstrcatW(tmpstr2, FILE_bslash);
+       lstrcatW(tmpstr2, tmpstr);
+       lstrcpyW(tmpstr, tmpstr2);
+       currindent = indent;
+     }
+     n--;
+  }
+  heap_free(pstr);
   lstrcatW(tmpstr, FILE_bslash);
+  TRACE("%s\n",debugstr_w(tmpstr));
 
-  FD31_ScanDir(lfs->ofnW, hWnd, tmpstr);
+  FD31_ScanDir(lfs->ofnW, hWnd, tmpstr, lfs->curropen);
   /* notify the app */
   if (lfs->hook)
     {
@@ -485,7 +590,8 @@ static LRESULT FD31_TestPath( const FD31_DATA *lfs, LPWSTR path )
     LPWSTR pBeginFileName, pstr2;
     WCHAR tmpstr2[BUFFILE];
 
-    pBeginFileName = wcsrchr(path, '\\');
+    TRACE("initial path=%s\n", debugstr_w(path));
+    pBeginFileName = wcsrchr(path, FILE_bslash[0]);
     if (pBeginFileName == NULL)
 	pBeginFileName = wcsrchr(path, ':');
 
@@ -506,19 +612,18 @@ static LRESULT FD31_TestPath( const FD31_DATA *lfs, LPWSTR path )
 
         TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2));
         SetDlgItemTextW( hWnd, edt1, tmpstr2 );
-        FD31_ScanDir(lfs->ofnW, hWnd, path);
+        FD31_ScanDir(lfs->ofnW, hWnd, path, lfs->curropen);
         return (lfs->ofnW->Flags & OFN_NOVALIDATE) != 0;
     }
 
     /* no wildcards, we might have a directory or a filename */
     /* try appending a wildcard and reading the directory */
-
     pstr2 = path + lstrlenW(path);
     if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0)
         lstrcatW(path, FILE_bslash);
 
     /* if ScanDir succeeds, we have changed the directory */
-    if (FD31_ScanDir(lfs->ofnW, hWnd, path))
+    if (FD31_ScanDir(lfs->ofnW, hWnd, path, lfs->curropen))
         return FALSE; /* and path is not a valid file name */
 
     /* if not, this must be a filename */
@@ -533,7 +638,7 @@ static LRESULT FD31_TestPath( const FD31_DATA *lfs, LPWSTR path )
 
         lstrcpynW(tmpstr2, pBeginFileName + 1, ARRAY_SIZE(tmpstr2));
         /* Should we MessageBox() if this fails? */
-        if (!FD31_ScanDir(lfs->ofnW, hWnd, path))
+        if (!FD31_ScanDir(lfs->ofnW, hWnd, path, lfs->curropen))
         {
             return FALSE;
         }
@@ -571,7 +676,10 @@ static LRESULT FD31_Validate( const FD31_DATA *lfs, LPCWSTR path, UINT control,
     if (control != lst1)
     {
         if (!FD31_TestPath( lfs, filename) )
+        {
+           TRACE ("not in file list %s\n", debugstr_w(filename));
            return FALSE;
+        }
     }
     FD31_UpdateResult(lfs, filename);
 
@@ -658,7 +766,7 @@ static LRESULT FD31_FileTypeChange( const FD31_DATA *lfs )
  *                              FD31_WMCommand               [internal]
  */
 static LRESULT FD31_WMCommand( HWND hWnd, LPARAM lParam, UINT notification,
-			       UINT control, const FD31_DATA *lfs )
+			       UINT control, FD31_DATA *lfs )
 {
     switch (control)
     {
@@ -951,7 +1059,7 @@ static PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, BOOL IsUnicode)
     }
     lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
     lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
-
+    lfs->curropen = 0;
     return lfs;
 }
 
@@ -972,7 +1080,6 @@ static LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
   ofn = lfs->ofnW;
 
   TRACE("flags=%x initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir));
-
   SetWindowTextW( hWnd, ofn->lpstrTitle );
   /* read custom filter information */
   if (ofn->lpstrCustomFilter)
@@ -1048,9 +1155,9 @@ static LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
     }
   else
     *tmpstr = 0;
-  if (!FD31_ScanDir(ofn, hWnd, tmpstr)) {
+  if (!FD31_ScanDir(ofn, hWnd, tmpstr, -1)) {
     *tmpstr = 0;
-    if (!FD31_ScanDir(ofn, hWnd, tmpstr))
+    if (!FD31_ScanDir(ofn, hWnd, tmpstr, -1))
       WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr));
   }
   /* select current drive in combo 2, omit missing drives */
@@ -1071,7 +1178,7 @@ static LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
   if (ofn->Flags & OFN_HIDEREADONLY)
     ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE);
   if (lfs->hook)
-      return FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
+     return FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam);
   return TRUE;
 }
 
@@ -1118,7 +1225,7 @@ static INT_PTR CALLBACK FD31_FileOpenDlgProc(HWND hWnd, UINT wMsg,
         return FD31_WMMeasureItem( lParam );
 
     case WM_DRAWITEM:
-        return FD31_WMDrawItem( hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam );
+        return FD31_WMDrawItem( hWnd, wParam, lParam, !lfs->open, lfs->curropen, (DRAWITEMSTRUCT *)lParam );
 
     case WM_COMMAND:
         return FD31_WMCommand( hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs );
-- 
2.17.2 (Apple Git-113)




More information about the wine-devel mailing list