Fix for shell32.SHBrowseForFolder (proper Desktop tree + BFFM_SETSELECTION implemented)

Wolfgang Scherer Wolfgang.Scherer at gmx.de
Mon Apr 11 18:03:29 CDT 2005


 
Problem
-------
DVD Shrink 3.2 uses SHBrowseForFolder for opening and saving.
With wine (HEAD as of 2005-04-12), only a "Desktop" entry without any
children is shown in the TreeView.  DVD Shrink also remembers the last
used directory and tries to set the selection accordingly.

Solution
--------
Fix TreeView setup behavior. Implement BFFM_SETSELECTION
functionality.

Details
-------
1. The BFFM_SETSELECTION functionality is completely missing.
   This patch implements it.
2. The logic for setting up a default directory tree with "Desktop" as root
   is faulty.
   This patch corrects it.
3. The spec says to ignore BIF_VALIDATE, when BIF_EDITBOX is not set.
   This patch reduces the unnecessary and misleading error message
   noise in this case.
4. My personal preference is to have the current selection always visible,
   even when the tree view does not have the focus.
   Since this is a matter of taste, setting the the style to TVS_SHOWSELALWAYS
   can be removed.
5. Forcing focus and highlight by posting TVM_EDITLABELW and 
   TVM_ENDEDITLABELNOW may not be the best way to do this.
   Please enlighten me and correct it.
 
ChangeLog:
	* dlls/shell32/brsfolder.c: Wolfgang Scherer <Wolfgang.Scherer at gmx.de>
        SHBrowseForFolders -- BFFM_SETSELECTION functionality implemented.
        Logic for setting up a default directory tree with "Desktop" as root fixed.
        The spec says to ignore BIF_VALIDATE, when BIF_EDITBOX is not set.
        TreeView style set to TVS_SHOWSELALWAYS.
        Force focus and highlight by posting TVM_EDITLABELW and 
        TVM_ENDEDITLABELNOW.
 
Index: dlls/shell32/brsfolder.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/brsfolder.c,v
retrieving revision 1.56
diff -u -3 -p -u -p -r1.56 brsfolder.c
--- dlls/shell32/brsfolder.c	1 Mar 2005 11:45:32 -0000	1.56
+++ dlls/shell32/brsfolder.c	11 Apr 2005 21:43:58 -0000
@@ -79,6 +79,14 @@ static void InitializeTreeView(HWND hwnd
         FIXME("Could not get handle to treeview control! Error: %08lx\n", GetLastError());
         return;
     }
+    {
+        /* Always show selection */
+        LONG_PTR dlg_style;
+        dlg_style = GetWindowLongPtrW(hwndTreeView, GWL_STYLE);
+        dlg_style |= TVS_SHOWSELALWAYS;
+        SetWindowLongPtrW(hwndTreeView, GWL_STYLE, dlg_style );
+    }
+
     Shell_GetImageList(NULL, &hImageList);
 
     if (hImageList)
@@ -102,6 +110,10 @@ static void InitializeTreeView(HWND hwnd
     
     if (_ILIsDesktop(pidlParent)) {
         hr = SHGetDesktopFolder(&lpsfParent);
+        ILFree( pidlParent );
+        ILFree( pidlChild );
+        pidlParent = NULL;
+        pidlChild = NULL;
     } else {
         IShellFolder *lpsfDesktop;
         hr = SHGetDesktopFolder(&lpsfDesktop);
@@ -118,7 +130,7 @@ static void InitializeTreeView(HWND hwnd
         return;
     }
 
-    if (pidlChild && pidlChild->mkid.cb) {
+    if (!_ILIsDesktop( pidlChild )) {
         hr = IShellFolder_BindToObject(lpsfParent, pidlChild, 0, &IID_IShellFolder, (LPVOID*)&lpsfRoot);
     } else {
         lpsfRoot = lpsfParent;
@@ -141,6 +153,17 @@ static void InitializeTreeView(HWND hwnd
 
     TreeView_DeleteAllItems(hwndTreeView);
     TreeView_Expand(hwndTreeView, InsertTreeViewItem(lpsfParent, pidlChild, pidlParent, pEnumChildren,  TVI_ROOT), TVE_EXPAND);
+    {
+         /* Force focus on tree item */
+         HTREEITEM cur_it;
+         SetFocus(hwndTreeView);
+         cur_it = TreeView_GetRoot( hwndTreeView );
+         if ( cur_it )
+         {
+             PostMessageW(hwndTreeView, TVM_EDITLABELW, 0, (LPARAM)cur_it);
+             PostMessageA(hwndTreeView, TVM_ENDEDITLABELNOW, (WPARAM)TRUE, 0);
+         }
+    }
 
     IShellFolder_Release(lpsfRoot);
     IShellFolder_Release(lpsfParent);
@@ -257,7 +280,7 @@ static HTREEITEM InsertTreeViewItem(IShe
 	IShellFolder_AddRef(lpsf);
 	lptvid->lpsfParent = lpsf;
 	lptvid->lpi	= ILClone(pidl);
-	lptvid->lpifq	= pidlParent ? ILCombine(pidlParent, pidl) : ILClone(pidl);
+	lptvid->lpifq	= ILCombine(pidlParent, pidl);
 	lptvid->pEnumIL = pEnumIL;
 	GetNormalAndSelectedIcons(lptvid->lpifq, &tvi);
 
@@ -387,8 +410,8 @@ static LRESULT MsgNotify(HWND hWnd,  UIN
 	        IShellFolder_Release(lptvid->lpsfParent);
 	        if (lptvid->pEnumIL)
 	          IEnumIDList_Release(lptvid->pEnumIL);
-	        SHFree(lptvid->lpi);
-	        SHFree(lptvid->lpifq);
+	        ILFree(lptvid->lpi);
+	        ILFree(lptvid->lpifq);
 	        SHFree(lptvid);
 	        break;
 
@@ -400,24 +423,41 @@ static LRESULT MsgNotify(HWND hWnd,  UIN
 	            break;
 
 	          lptvid=(LPTV_ITEMDATA)pnmtv->itemNew.lParam;
-	          if (SUCCEEDED(IShellFolder_BindToObject(lptvid->lpsfParent, lptvid->lpi,0,(REFIID)&IID_IShellFolder,(LPVOID *)&lpsf2)))
-	          { FillTreeView( lpsf2, lptvid->lpifq, pnmtv->itemNew.hItem, lptvid->pEnumIL);
+                  if ( _ILIsDesktop( lptvid->lpi ))
+                  {
+                      /* Always fill Desktop node without binding to object */
+                      FillTreeView( lptvid->lpsfParent, lptvid->lpifq, pnmtv->itemNew.hItem, lptvid->pEnumIL);
+                  }
+                  else if (SUCCEEDED(IShellFolder_BindToObject(
+                                         lptvid->lpsfParent, lptvid->lpifq,
+                                         0, (REFIID)&IID_IShellFolder,(LPVOID *)&lpsf2)))
+	          {
+                      FillTreeView( lpsf2, lptvid->lpifq, pnmtv->itemNew.hItem, lptvid->pEnumIL);
 	          }
 	          /* My Computer is already sorted and trying to do a simple text
 	           * sort will only mess things up */
 	          if (!_ILIsMyComputer(lptvid->lpi))
-	            TreeView_SortChildren(hwndTreeView, pnmtv->itemNew.hItem, FALSE);
+                      TreeView_SortChildren(hwndTreeView, pnmtv->itemNew.hItem, FALSE);
 		}
 	        break;
 	      case TVN_SELCHANGEDA:
 	      case TVN_SELCHANGEDW:
-	        lptvid=(LPTV_ITEMDATA)pnmtv->itemNew.lParam;
-		pidlRet = lptvid->lpifq;
-		if (lpBrowseInfo->lpfn)
-		   (lpBrowseInfo->lpfn)(hWnd, BFFM_SELCHANGED, (LPARAM)pidlRet, lpBrowseInfo->lParam);
-		BrsFolder_CheckValidSelection(hWnd, lptvid);
-	        break;
-
+              {
+                  /* Record selected PIDL. */
+                  LPITEMIDLIST alloc_pidl = NULL;
+                  lptvid=(LPTV_ITEMDATA)pnmtv->itemNew.lParam;
+                  pidlRet = lptvid->lpifq;
+                  if ( !pidlRet )
+                  {
+                      alloc_pidl = _ILCreateDesktop();
+                  }
+                  pdump ( pidlRet );
+                  if (lpBrowseInfo->lpfn)
+                      (lpBrowseInfo->lpfn)(hWnd, BFFM_SELCHANGED, (LPARAM)alloc_pidl, lpBrowseInfo->lParam);
+                  BrsFolder_CheckValidSelection(hWnd, lptvid);
+                  ILFree( alloc_pidl );
+                  break;
+              }
 	      default:
 	        WARN("unhandled (%d)\n", pnmtv->hdr.code);
 		break;
@@ -444,8 +484,14 @@ static INT_PTR CALLBACK BrsFolderDlgProc
 	{ case WM_INITDIALOG:
 	    pidlRet = NULL;
 	    lpBrowseInfo = (LPBROWSEINFOW) lParam;
-	    if (lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS)
-	      FIXME("flags %x not implemented\n", lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS);
+            /** The spec says to ignore BIF_VALIDATE, when BIF_EDITBOX is not set. */
+            if (( lpBrowseInfo->ulFlags & BIF_VALIDATE )
+                && ( lpBrowseInfo->ulFlags & BIF_EDITBOX ) == 0 ) {
+                lpBrowseInfo->ulFlags &= ~( BIF_VALIDATE );
+            }
+            if (lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS) {
+                FIXME("flags %x not implemented\n", lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS);
+            }
 	    if (lpBrowseInfo->lpszTitle) {
 	       SetWindowTextW(GetDlgItem(hWnd, IDD_TITLE), lpBrowseInfo->lpszTitle);
 	    } else {
@@ -468,12 +514,20 @@ static INT_PTR CALLBACK BrsFolderDlgProc
 	  case WM_COMMAND:
 	    switch (wParam)
 	    { case IDOK:
-	        pdump ( pidlRet );
-		if (lpBrowseInfo->pszDisplayName)
-	            SHGetPathFromIDListW(pidlRet, lpBrowseInfo->pszDisplayName);
-	        EndDialog(hWnd, (DWORD) ILClone(pidlRet));
-	        return TRUE;
-
+              {
+                  LPITEMIDLIST alloc_pidl = NULL;
+                  if ( !pidlRet )
+                  {
+                      pidlRet = _ILCreateDesktop();
+                      alloc_pidl = pidlRet;
+                  }
+                  pdump ( pidlRet );
+                  if (lpBrowseInfo->pszDisplayName)
+                      SHGetPathFromIDListW(pidlRet, lpBrowseInfo->pszDisplayName);
+                  EndDialog(hWnd, (DWORD) ILClone(pidlRet));
+                  ILFree( alloc_pidl );
+                  return TRUE;
+              }
 	      case IDCANCEL:
 	        EndDialog(hWnd, 0);
 	        return TRUE;
@@ -496,17 +550,79 @@ static INT_PTR CALLBACK BrsFolderDlgProc
 	   SetWindowTextW(GetDlgItem(hWnd, 1), (LPWSTR)wParam);
 	   break;
 	case BFFM_SETSELECTIONA:
-	   if (wParam)
-	      FIXME("Set selection %s\n", debugstr_a((LPSTR)lParam));
-	   else
-	      FIXME("Set selection %p\n", (void*)lParam);
-	   break;
 	case BFFM_SETSELECTIONW:
-	   if (wParam)
-	      FIXME("Set selection %s\n", debugstr_w((LPWSTR)lParam));
-	   else
-	      FIXME("Set selection %p\n", (void*)lParam);
-	   break;
+        {
+            /* Set current selection */
+            LPITEMIDLIST alloc_pidl = NULL;
+            LPITEMIDLIST pidl = NULL;
+            
+            if (wParam) {
+                /* Path text unicode/ascii */
+                if ( msg == BFFM_SETSELECTIONW )
+                {
+                    pidl = ILCreateFromPathW((LPWSTR)lParam);
+                }
+                else
+                {
+                    pidl = ILCreateFromPathA((LPSTR)lParam);
+                }
+                alloc_pidl = pidl;
+            } else {
+                /* PIDL */
+                pidl = (LPITEMIDLIST) lParam;
+            }
+            if ( pidl )
+            {
+                HTREEITEM cur_it;
+                SetFocus(hwndTreeView);
+                cur_it = TreeView_GetRoot( hwndTreeView );
+                if ( cur_it )
+                {
+                    HTREEITEM prev_it = cur_it;
+                    TreeView_Expand(hwndTreeView, cur_it, TVE_EXPAND);
+                    cur_it = TreeView_GetChild(hwndTreeView, cur_it);
+                    while ( cur_it )
+                    {
+                        TVITEMW tvi;
+                        LPTV_ITEMDATA lptvid;
+                        tvi.mask = TVIF_PARAM;
+                        tvi.hItem = cur_it;
+                        if ( !TreeView_GetItemW( hwndTreeView, &tvi ) )
+                        {
+                            cur_it = TreeView_GetNextSibling(hwndTreeView, cur_it);
+                            continue;
+                        }
+                        lptvid = (LPTV_ITEMDATA)tvi.lParam;
+                        if (ILIsEqual(lptvid->lpifq, pidl))
+                        {
+                            PostMessageW(hwndTreeView, TVM_EDITLABELW, 0, (LPARAM)cur_it);
+                            PostMessageA(hwndTreeView, TVM_ENDEDITLABELNOW, (WPARAM)TRUE, 0);
+                            break;
+                        }
+                        if (ILIsParent(lptvid->lpifq, pidl, FALSE))
+                        {
+                            prev_it = cur_it;
+                            TreeView_Expand(hwndTreeView, cur_it, TVE_EXPAND);
+                            cur_it = TreeView_GetChild(hwndTreeView, cur_it);
+                            if ( !cur_it )
+                            {
+                                break;
+                            }
+                        }
+                        else
+                        {
+                            prev_it = cur_it;
+                            cur_it = TreeView_GetNextSibling(hwndTreeView, cur_it);
+                        }
+                    }
+                }
+            }
+            if ( alloc_pidl )
+            {
+                ILFree ( alloc_pidl );
+            }
+            break;
+        }
 	case BFFM_SETEXPANDED: /* unicode only */
 	   if (wParam)
 	      FIXME("Set expanded %s\n", debugstr_w((LPWSTR)lParam));



More information about the wine-patches mailing list