* Sync up to trunk head (r65147).
authorAmine Khaldi <amine.khaldi@reactos.org>
Fri, 31 Oct 2014 15:27:51 +0000 (15:27 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Fri, 31 Oct 2014 15:27:51 +0000 (15:27 +0000)
svn path=/branches/shell-experiments/; revision=65148

31 files changed:
1  2 
base/applications/logoff/logoff.c
base/applications/network/finger/finger.c
base/applications/network/finger/net.c
base/applications/network/ftp/ftp.c
base/applications/network/ipconfig/ipconfig.c
boot/bootdata/hivedef.inf
boot/freeldr/freeldr/include/arch/pc/x86common.h
dll/cpl/appwiz/addons.c
dll/cpl/appwiz/appwiz.c
dll/cpl/appwiz/appwiz.h
dll/cpl/intl/generalp.c
dll/opengl/opengl32/opengl32.h
dll/win32/shell32/CMakeLists.txt
dll/win32/shell32/brsfolder.cpp
dll/win32/shell32/folders/recyclebin.h
dll/win32/shell32/shell32_main.h
dll/win32/shell32/shellstring.c
dll/win32/shell32/shlfileop.cpp
dll/win32/syssetup/classinst.c
dll/win32/syssetup/wizard.c
drivers/filesystems/fastfat/cleanup.c
drivers/filesystems/fastfat/create.c
drivers/filesystems/fastfat/finfo.c
drivers/filesystems/fastfat/fsctl.c
drivers/filesystems/fastfat/vfat.h
drivers/filesystems/ntfs/fsctl.c
lib/fslib/vfatlib/vfatlib.c
ntoskrnl/io/iomgr/file.c
ntoskrnl/io/iomgr/rawfs.c
ntoskrnl/se/token.c
win32ss/gdi/ntgdi/freetype.c

@@@ -30,6 -30,7 +30,7 @@@ static void PrintUsage() 
  
        if (AllocAndLoadString(&lpUsage, GetModuleHandle(NULL), IDS_USAGE)) {
                _putts(lpUsage);
+               LocalFree(lpUsage);
        }
  
  }
@@@ -88,8 -89,10 +89,10 @@@ BOOL ParseCommandLine(int argc, TCHAR *
                        }
                default:
                        //Invalid parameter detected
-                       if (AllocAndLoadString(&lpIllegalMsg, GetModuleHandle(NULL), IDS_ILLEGAL_PARAM))
-                       _putts(lpIllegalMsg);
+                       if (AllocAndLoadString(&lpIllegalMsg, GetModuleHandle(NULL), IDS_ILLEGAL_PARAM)) {
+                               _putts(lpIllegalMsg);
+                               LocalFree(lpIllegalMsg);
+                       }
                        return FALSE;
                }
        }
@@@ -151,6 -151,8 +151,8 @@@ userlist(int argc, char **argv
                /* Tell the user that we couldn't find a usable */
                /* WinSock DLL.                                  */
                fprintf(stderr, "WSAStartup failed\n");
+               free(nargv);
+               free(used);
                return;
        }
  
@@@ -128,4 -128,5 +128,5 @@@ netfinger(char *name
        if (lastc != '\n')
                putchar('\n');
        putchar('\n');
+       (void)closesocket(s);
  }
@@@ -674,6 -674,7 +674,7 @@@ null();//  (void) signal(SIGINT, oldintr
  null();//             (void) signal(SIGPIPE, oldintp);
        if (!cpend) {
                code = -1;
+               (*closefunc)(fin);
                return;
        }
        if (data >= 0) {
@@@ -232,6 -232,7 +232,7 @@@ LPTSTR GetConnectionType(LPTSTR lpClass
                  }
  
                  if (ConType) CharToOem(ConTypeTmp, ConType);
+                 HeapFree(ProcessHeap, 0, ConTypeTmp);
              }
          }
      }
@@@ -366,6 -367,7 +367,7 @@@ LPTSTR GetConnectionDescription(LPTSTR 
                                     (PBYTE)lpConDesc,
                                     &dwDataSize) != ERROR_SUCCESS)
                  {
+                     HeapFree(ProcessHeap, 0, lpConDesc);
                      lpConDesc = NULL;
                      goto CLEANUP;
                  }
@@@ -382,9 -384,9 +384,9 @@@ CLEANUP
          RegCloseKey(hBaseKey);
      if (hClassKey != NULL)
          RegCloseKey(hClassKey);
-     if (lpConDesc != NULL)
+     if (lpPath != NULL)
          HeapFree(ProcessHeap, 0, lpPath);
-     if (lpConDesc != NULL)
+     if (lpKeyClass != NULL)
          HeapFree(ProcessHeap, 0, lpKeyClass);
  
      return lpConDesc;
@@@ -714,7 -716,9 +716,9 @@@ VOID Usage(VOID
                             Size))
              {
                  _tprintf(_T("%s"), lpUsage);
-             }            
+             }
+             HeapFree(ProcessHeap, 0, lpUsage);
          }
      }
  
@@@ -2675,8 -2675,8 +2675,8 @@@ DESKTOP_SCHEME_18="Ardezie
  DESKTOP_SCHEME_19="Furtună"
  DESKTOP_SCHEME_20="Turcoaz"
  DESKTOP_SCHEME_21="Grâu"
- DESKTOP_SCHEME_SIZE_0="Default size"
- TEMP_DIR="%USERPROFILE%\PreferinÈ›e locale\Temp"
+ DESKTOP_SCHEME_SIZE_0="Dimensiune implicită"
+ TEMP_DIR="%USERPROFILE%\Preferinte locale\Temp"
  
  
  ; LANG_RUSSIAN SUBLANG_NEUTRAL
  #define FREELDR_BASE        HEX(F800)
  #define FREELDR_PE_BASE    HEX(10000)
  #define DISKREADBUFFER     HEX(8E000) /* Buffer to store data read in from the disk via the BIOS */
- #define MEMORY_MARGIN      HEX(9E000) /* Highest usable address */
+ #define MEMORY_MARGIN      HEX(9C000) /* Highest usable address */
  /* 9F000- 9FFFF is reserved for the EBDA */
- #define DISKREADBUFFER_SIZE HEX(10000)
  
  #define BIOSCALLBUFSEGMENT (BIOSCALLBUFFER/16) /* Buffer to store temporary data for any Int386() call */
  #define BIOSCALLBUFOFFSET   HEX(0000) /* Buffer to store temporary data for any Int386() call */
  #define BIOSCALLBUFSIZE     PAGE_SIZE /* max is sizeof(VESA_SVGA_INFO) = 512 */
  #define MAX_FREELDR_PE_SIZE (DISKREADBUFFER - FREELDR_PE_BASE)
+ #define DISKREADBUFFER_SIZE (MEMORY_MARGIN - DISKREADBUFFER)
  
  /* These addresses specify the realmode "BSS section" layout */
  #define BSS_RealModeEntry        (BSS_START +  0)
diff --combined dll/cpl/appwiz/addons.c
@@@ -397,7 -397,7 +397,7 @@@ static INT_PTR CALLBACK installer_proc(
      return FALSE;
  }
  
- BOOL install_addon(addon_t addon_type)
+ BOOL install_addon(addon_t addon_type, HWND hwnd_parent)
  {
  
      if(!*ARCH_STRING)
       * - download the package
       */
      if (install_from_registered_dir() == INSTALL_NEXT)
-         DialogBoxW(hApplet, addon->dialog_template, 0, installer_proc);
+         DialogBoxW(hApplet, addon->dialog_template, hwnd_parent, installer_proc);
  
      return TRUE;
  }
diff --combined dll/cpl/appwiz/appwiz.c
@@@ -14,7 -14,7 +14,7 @@@
  
  HINSTANCE hApplet = NULL;
  
- static LONG start_params(const WCHAR *params)
+ static LONG start_params(const WCHAR *params, HWND hwnd_parent)
  {
      static const WCHAR install_geckoW[] = {'i','n','s','t','a','l','l','_','g','e','c','k','o',0};
      static const WCHAR install_monoW[] = {'i','n','s','t','a','l','l','_','m','o','n','o',0};
          return FALSE;
  
      if(!strcmpW(params, install_geckoW)) {
-         install_addon(ADDON_GECKO);
+         install_addon(ADDON_GECKO, hwnd_parent);
          return TRUE;
      }
  
      if(!strcmpW(params, install_monoW)) {
-         install_addon(ADDON_MONO);
+         install_addon(ADDON_MONO, hwnd_parent);
          return TRUE;
      }
  
@@@ -51,7 -51,7 +51,7 @@@ CPlApplet(HWND hwndCPl, UINT uMsg, LPAR
              return 1;
  
          case CPL_STARTWPARMSW:
-             return start_params((const WCHAR *)lParam2);
+             return start_params((const WCHAR *)lParam2, hwndCPl);
  
          case CPL_INQUIRE:
              CPlInfo = (CPLINFO*)lParam2;
diff --combined dll/cpl/appwiz/appwiz.h
@@@ -50,7 -50,7 +50,7 @@@ typedef enum 
      ADDON_MONO
  } addon_t;
  
- BOOL install_addon(addon_t) DECLSPEC_HIDDEN;
+ BOOL install_addon(addon_t, HWND hwnd_parent) DECLSPEC_HIDDEN;
  
  extern HINSTANCE hInst DECLSPEC_HIDDEN;
  
diff --combined dll/cpl/intl/generalp.c
@@@ -234,7 -234,9 +234,9 @@@ LocationsEnumProc(GEOID gId
      TCHAR loc[MAX_STR_SIZE];
      INT index;
  
-     GetGeoInfo(gId, GEO_FRIENDLYNAME, loc, MAX_STR_SIZE, LANG_SYSTEM_DEFAULT);
+     if(GetGeoInfo(gId, GEO_FRIENDLYNAME, loc, MAX_STR_SIZE, LANG_SYSTEM_DEFAULT) == 0)
+         return TRUE;
      index = (INT)SendMessage(hGeoList,
                               CB_ADDSTRING,
                               0,
@@@ -137,7 -137,7 +137,7 @@@ HGLR
  IntGetCurrentRC(void)
  {
      struct Opengl32_ThreadData* data = TlsGetValue(OglTlsIndex);
-     return data->hglrc;
+     return data ? data->hglrc : NULL;
  }
  
  static inline
index 47f9575,0000000..5b9fa9a
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,90 @@@
-     shellstring.cpp
 +PROJECT(SHELL)
 +
 +set_cpp(WITH_RUNTIME)
 +spec2def(shell32.dll shell32.spec ADD_IMPORTLIB)
 +
 +remove_definitions(-D_WIN32_WINNT=0x502)
 +add_definitions(-D_WIN32_WINNT=0x600)
 +
 +add_definitions(
 +    -D_SHELL32_
 +    -D_WINE)
 +
 +include_directories(
 +    ${REACTOS_SOURCE_DIR}/lib/recyclebin
 +    ${REACTOS_SOURCE_DIR}/lib/atl
 +    ${REACTOS_SOURCE_DIR})
 +
 +list(APPEND SOURCE
 +    #authors.cpp
 +    autocomplete.cpp
 +    brsfolder.cpp
 +    changenotify.cpp
 +    classes.cpp
 +    clipboard.cpp
 +    control.cpp
 +    CMenuBand.cpp
 +    CMenuDeskBar.cpp
 +    dataobject.cpp
 +    dde.cpp
 +    debughlp.cpp
 +    desktop.cpp
 +    dialogs.cpp
 +    dragdrophelper.cpp
 +    enumidlist.cpp
 +    extracticon.cpp
 +    folders.cpp
 +    iconcache.cpp
 +    pidl.cpp
 +    shell32_main.cpp
 +    shellitem.cpp
 +    shelllink.cpp
 +    shellole.cpp
 +    shellord.cpp
 +    shellpath.cpp
 +    shellreg.cpp
 +    folders/desktop.cpp
 +    folders/fs.cpp
 +    folders/mycomp.cpp
 +    folders/mydocuments.cpp
 +    folders/printers.cpp
 +    folders/admintools.cpp
 +    folders/netplaces.cpp
 +    folders/fonts.cpp
 +    folders/cpanel.cpp
 +    folders/recyclebin.cpp
 +    droptargets/CexeDropHandler.cpp
 +    shlexec.cpp
 +    shlfileop.cpp
 +    shlfolder.cpp
 +    shlfsbind.cpp
 +    shlmenu.cpp
 +    shlview.cpp
 +    shpolicy.cpp
 +    stubs.cpp
 +    systray.cpp
 +    fprop.cpp
 +    drive.cpp
 +    defcontextmenu.cpp
 +    openwithmenu.cpp
 +    newmenu.cpp
 +    startmenu.cpp
 +    folder_options.cpp
 +    filedefext.cpp
 +    drvdefext.cpp
 +    precomp.h)
 +
 +add_library(shell32 SHARED
 +    ${SOURCE}
++    shellstring.c
 +    vista.c
 +    shell32.rc
 +    ${CMAKE_CURRENT_BINARY_DIR}/shell32_stubs.c
 +    ${CMAKE_CURRENT_BINARY_DIR}/shell32.def)
 +
 +set_module_type(shell32 win32dll UNICODE HOTPATCHABLE)
 +target_link_libraries(shell32 atlnew wine uuid recyclebin)
 +add_delay_importlibs(shell32 ole32 version fmifs)
 +add_importlibs(shell32 advapi32 browseui gdi32 user32 powrprof comctl32 comdlg32 shdocvw shlwapi devmgr winspool winmm msvcrt kernel32 ntdll)
 +add_pch(shell32 precomp.h SOURCE)
 +add_cd_file(TARGET shell32 DESTINATION reactos/system32 FOR all)
index 678d3b4,0000000..2213993
mode 100644,000000..100644
--- /dev/null
@@@ -1,1114 -1,0 +1,1114 @@@
-     lptvid = (TV_ITEMDATA *)SHAlloc( sizeof(TV_ITEMDATA) );
-     if (!lptvid)
 +/*
 + * Copyright 1999 Juergen Schmied
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + *
 + * FIXME:
 + *  - many memory leaks
 + *  - many flags unimplemented
 + *    - implement new dialog style "make new folder" button
 + *    - implement editbox
 + *    - implement new dialog style resizing
 + */
 +
 +#include "precomp.h"
 +
 +WINE_DEFAULT_DEBUG_CHANNEL(shell);
 +
 +/* original margins and control size */
 +typedef struct tagLAYOUT_DATA
 +{
 +    LONG left, width, right;
 +    LONG top, height, bottom;
 +} LAYOUT_DATA;
 +
 +typedef struct tagbrowse_info
 +{
 +    HWND          hWnd;
 +    HWND          hwndTreeView;
 +    LPBROWSEINFOW lpBrowseInfo;
 +    LPITEMIDLIST  pidlRet;
 +    LAYOUT_DATA  *layout;  /* filled by LayoutInit, used by LayoutUpdate */
 +    SIZE          szMin;
 +} browse_info;
 +
 +typedef struct tagTV_ITEMDATA
 +{
 +   IShellFolder* lpsfParent; /* IShellFolder of the parent */
 +   LPITEMIDLIST  lpi;        /* PIDL relative to parent */
 +   LPITEMIDLIST  lpifq;      /* Fully qualified PIDL */
 +   IEnumIDList*  pEnumIL;    /* Children iterator */
 +} TV_ITEMDATA, *LPTV_ITEMDATA;
 +
 +typedef struct tagLAYOUT_INFO
 +{
 +    int iItemId;          /* control id */
 +    DWORD dwAnchor;       /* BF_* flags specifying which margins should remain constant */
 +} LAYOUT_INFO;
 +
 +static const LAYOUT_INFO g_layout_info[] =
 +{
 +    {IDC_BROWSE_FOR_FOLDER_TITLE,         BF_TOP|BF_LEFT|BF_RIGHT},
 +    {IDC_BROWSE_FOR_FOLDER_STATUS,        BF_TOP|BF_LEFT|BF_RIGHT},
 +    {IDC_BROWSE_FOR_FOLDER_FOLDER,        BF_TOP|BF_LEFT|BF_RIGHT},
 +    {IDC_BROWSE_FOR_FOLDER_TREEVIEW,      BF_TOP|BF_BOTTOM|BF_LEFT|BF_RIGHT},
 +    {IDC_BROWSE_FOR_FOLDER_FOLDER,        BF_BOTTOM|BF_LEFT},
 +    {IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT,    BF_BOTTOM|BF_LEFT|BF_RIGHT},
 +    {IDC_BROWSE_FOR_FOLDER_NEW_FOLDER, BF_BOTTOM|BF_LEFT},
 +    {IDOK,              BF_BOTTOM|BF_RIGHT},
 +    {IDCANCEL,          BF_BOTTOM|BF_RIGHT}
 +};
 +
 +#define LAYOUT_INFO_COUNT (sizeof(g_layout_info)/sizeof(g_layout_info[0]))
 +
 +#define SUPPORTEDFLAGS (BIF_STATUSTEXT | \
 +                        BIF_BROWSEFORCOMPUTER | \
 +                        BIF_RETURNFSANCESTORS | \
 +                        BIF_RETURNONLYFSDIRS | \
 +                        BIF_NONEWFOLDERBUTTON | \
 +                        BIF_NEWDIALOGSTYLE | \
 +                        BIF_BROWSEINCLUDEFILES)
 +
 +static void FillTreeView(browse_info*, IShellFolder*,
 +               LPITEMIDLIST, HTREEITEM, IEnumIDList*);
 +static HTREEITEM InsertTreeViewItem( browse_info*, IShellFolder*,
 +               LPCITEMIDLIST, LPCITEMIDLIST, IEnumIDList*, HTREEITEM);
 +
 +static const WCHAR szBrowseFolderInfo[] = L"__WINE_BRSFOLDERDLG_INFO";
 +
 +static DWORD __inline BrowseFlagsToSHCONTF(UINT ulFlags)
 +{
 +    return SHCONTF_FOLDERS | (ulFlags & BIF_BROWSEINCLUDEFILES ? SHCONTF_NONFOLDERS : 0);
 +}
 +
 +static void browsefolder_callback( LPBROWSEINFOW lpBrowseInfo, HWND hWnd,
 +                                   UINT msg, LPARAM param )
 +{
 +    if (!lpBrowseInfo->lpfn)
 +        return;
 +    lpBrowseInfo->lpfn( hWnd, msg, param, lpBrowseInfo->lParam );
 +}
 +
 +static LAYOUT_DATA *LayoutInit(HWND hwnd, const LAYOUT_INFO *layout_info, int layout_count)
 +{
 +    LAYOUT_DATA *data;
 +    RECT rcWnd;
 +    int i;
 +
 +    GetClientRect(hwnd, &rcWnd);
 +    data = (LAYOUT_DATA *)SHAlloc(sizeof(LAYOUT_DATA)*layout_count);
 +    for (i = 0; i < layout_count; i++)
 +    {
 +        RECT r;
 +        HWND hItem = GetDlgItem(hwnd, layout_info[i].iItemId);
 +
 +        if (hItem == NULL)
 +            ERR("Item %d not found\n", i);
 +        GetWindowRect(hItem, &r);
 +        MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&r, 2);
 +
 +        data[i].left = r.left;
 +        data[i].right = rcWnd.right - r.right;
 +        data[i].width = r.right - r.left;
 +
 +        data[i].top = r.top;
 +        data[i].bottom = rcWnd.bottom - r.bottom;
 +        data[i].height = r.bottom - r.top;
 +    }
 +    return data;
 +}
 +
 +static void LayoutUpdate(HWND hwnd, LAYOUT_DATA *data, const LAYOUT_INFO *layout_info, int layout_count)
 +{
 +    RECT rcWnd;
 +    int i;
 +
 +    GetClientRect(hwnd, &rcWnd);
 +    for (i = 0; i < layout_count; i++)
 +    {
 +        RECT r;
 +        HWND hItem = GetDlgItem(hwnd, layout_info[i].iItemId);
 +
 +        GetWindowRect(hItem, &r);
 +        MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&r, 2);
 +
 +        if (layout_info[i].dwAnchor & BF_RIGHT)
 +        {
 +            r.right = rcWnd.right - data[i].right;
 +            if (!(layout_info[i].dwAnchor & BF_LEFT))
 +                r.left = r.right - data[i].width;
 +        }
 +
 +        if (layout_info[i].dwAnchor & BF_BOTTOM)
 +        {
 +            r.bottom = rcWnd.bottom - data[i].bottom;
 +            if (!(layout_info[i].dwAnchor & BF_TOP))
 +                r.top = r.bottom - data[i].height;
 +        }
 +
 +        SetWindowPos(hItem, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER);
 +    }
 +}
 +
 +
 +/******************************************************************************
 + * InitializeTreeView [Internal]
 + *
 + * Called from WM_INITDIALOG handler.
 + *
 + * PARAMS
 + *  hwndParent [I] The BrowseForFolder dialog
 + *  root       [I] ITEMIDLIST of the root shell folder
 + */
 +static void InitializeTreeView( browse_info *info )
 +{
 +    LPITEMIDLIST pidlParent, pidlChild;
 +    HIMAGELIST hImageList;
 +    HRESULT hr;
 +    CComPtr<IShellFolder> lpsfParent;
 +    CComPtr<IShellFolder> lpsfRoot;
 +    CComPtr<IEnumIDList> pEnumChildren;
 +    HTREEITEM item;
 +    DWORD flags;
 +    LPCITEMIDLIST root = info->lpBrowseInfo->pidlRoot;
 +
 +    TRACE("%p\n", info );
 +
 +    Shell_GetImageLists(NULL, &hImageList);
 +
 +    if (hImageList)
 +        SendMessageW( info->hwndTreeView, TVM_SETIMAGELIST, 0, (LPARAM)hImageList );
 +
 +    /* We want to call InsertTreeViewItem down the code, in order to insert
 +     * the root item of the treeview. Due to InsertTreeViewItem's signature,
 +     * we need the following to do this:
 +     *
 +     * + An ITEMIDLIST corresponding to _the parent_ of root.
 +     * + An ITEMIDLIST, which is a relative path from root's parent to root
 +     *   (containing a single SHITEMID).
 +     * + An IShellFolder interface pointer of root's parent folder.
 +     *
 +     * If root is 'Desktop', then root's parent is also 'Desktop'.
 +     */
 +
 +    pidlParent = ILClone(root);
 +    ILRemoveLastID(pidlParent);
 +    pidlChild = ILClone(ILFindLastID(root));
 +
 +    if (_ILIsDesktop(pidlParent))
 +    {
 +        hr = SHGetDesktopFolder(&lpsfParent);
 +    } else {
 +        CComPtr<IShellFolder> lpsfDesktop;
 +        hr = SHGetDesktopFolder(&lpsfDesktop);
 +        if (FAILED(hr)) {
 +            WARN("SHGetDesktopFolder failed! hr = %08x\n", hr);
 +            ILFree(pidlChild);
 +            ILFree(pidlParent);
 +            return;
 +        }
 +        hr = lpsfDesktop->BindToObject(pidlParent, 0, IID_PPV_ARG(IShellFolder, &lpsfParent));
 +    }
 +
 +    if (FAILED(hr)) {
 +        WARN("Could not bind to parent shell folder! hr = %08x\n", hr);
 +        ILFree(pidlChild);
 +        ILFree(pidlParent);
 +        return;
 +    }
 +
 +    if (pidlChild && pidlChild->mkid.cb) {
 +        hr = lpsfParent->BindToObject(pidlChild, 0, IID_PPV_ARG(IShellFolder, &lpsfRoot));
 +    } else {
 +        lpsfRoot = lpsfParent;
 +    }
 +
 +    if (FAILED(hr)) {
 +        WARN("Could not bind to root shell folder! hr = %08x\n", hr);
 +        ILFree(pidlChild);
 +        ILFree(pidlParent);
 +        return;
 +    }
 +
 +    flags = BrowseFlagsToSHCONTF( info->lpBrowseInfo->ulFlags );
 +    hr = lpsfRoot->EnumObjects(info->hWnd, flags, &pEnumChildren );
 +    if (FAILED(hr)) {
 +        WARN("Could not get child iterator! hr = %08x\n", hr);
 +        ILFree(pidlChild);
 +        ILFree(pidlParent);
 +        return;
 +    }
 +
 +    SendMessageW( info->hwndTreeView, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT );
 +    item = InsertTreeViewItem( info, lpsfParent, pidlChild,
 +                               pidlParent, pEnumChildren, TVI_ROOT );
 +    SendMessageW( info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item );
 +
 +    ILFree(pidlChild);
 +    ILFree(pidlParent);
 +}
 +
 +static int GetIcon(LPCITEMIDLIST lpi, UINT uFlags)
 +{
 +    SHFILEINFOW sfi;
 +    SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), uFlags);
 +    return sfi.iIcon;
 +}
 +
 +static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTVITEMW lpTV_ITEM)
 +{
 +    LPITEMIDLIST pidlDesktop = NULL;
 +    DWORD flags;
 +
 +    TRACE("%p %p\n",lpifq, lpTV_ITEM);
 +
 +    if (!lpifq)
 +    {
 +        pidlDesktop = _ILCreateDesktop();
 +        lpifq = pidlDesktop;
 +    }
 +
 +    flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
 +    lpTV_ITEM->iImage = GetIcon( lpifq, flags );
 +
 +    flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON;
 +    lpTV_ITEM->iSelectedImage = GetIcon( lpifq, flags );
 +
 +    if (pidlDesktop)
 +        ILFree( pidlDesktop );
 +}
 +
 +/******************************************************************************
 + * GetName [Internal]
 + *
 + * Query a shell folder for the display name of one of it's children
 + *
 + * PARAMS
 + *  lpsf           [I] IShellFolder interface of the folder to be queried.
 + *  lpi            [I] ITEMIDLIST of the child, relative to parent
 + *  dwFlags        [I] as in IShellFolder::GetDisplayNameOf
 + *  lpFriendlyName [O] The desired display name in unicode
 + *
 + * RETURNS
 + *  Success: TRUE
 + *  Failure: FALSE
 + */
 +static BOOL GetName(IShellFolder * lpsf, LPCITEMIDLIST lpi, DWORD dwFlags, LPWSTR lpFriendlyName)
 +{
 +    BOOL   bSuccess=TRUE;
 +    STRRET str;
 +
 +    TRACE("%p %p %x %p\n", lpsf, lpi, dwFlags, lpFriendlyName);
 +    if (SUCCEEDED(lpsf->GetDisplayNameOf(lpi, dwFlags, &str)))
 +          bSuccess = StrRetToStrNW(lpFriendlyName, MAX_PATH, &str, lpi);
 +    else
 +      bSuccess = FALSE;
 +
 +    TRACE("-- %s\n", debugstr_w(lpFriendlyName));
 +    return bSuccess;
 +}
 +
 +/******************************************************************************
 + * InsertTreeViewItem [Internal]
 + *
 + * PARAMS
 + *  info       [I] data for the dialog
 + *  lpsf       [I] IShellFolder interface of the item's parent shell folder
 + *  pidl       [I] ITEMIDLIST of the child to insert, relative to parent
 + *  pidlParent [I] ITEMIDLIST of the parent shell folder
 + *  pEnumIL    [I] Iterator for the children of the item to be inserted
 + *  hParent    [I] The treeview-item that represents the parent shell folder
 + *
 + * RETURNS
 + *  Success: Handle to the created and inserted treeview-item
 + *  Failure: NULL
 + */
 +static HTREEITEM InsertTreeViewItem( browse_info *info, IShellFolder * lpsf,
 +    LPCITEMIDLIST pidl, LPCITEMIDLIST pidlParent, IEnumIDList* pEnumIL,
 +    HTREEITEM hParent)
 +{
 +    TVITEMW     tvi;
 +    TVINSERTSTRUCTW    tvins;
 +    WCHAR        szBuff[MAX_PATH];
 +    LPTV_ITEMDATA    lptvid=0;
 +
 +    tvi.mask  = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
 +
 +    tvi.cChildren= pEnumIL ? 1 : 0;
 +    tvi.mask |= TVIF_CHILDREN;
 +
-     if (!GetName(lpsf, pidl, SHGDN_NORMAL, szBuff))
++    if (!GetName(lpsf, pidl, SHGDN_NORMAL, szBuff))
 +        return NULL;
 +
++    lptvid = (TV_ITEMDATA *)SHAlloc( sizeof(TV_ITEMDATA) );
++    if (!lptvid)
 +        return NULL;
 +
 +    tvi.pszText    = szBuff;
 +    tvi.cchTextMax = MAX_PATH;
 +    tvi.lParam = (LPARAM)lptvid;
 +
 +    lpsf->AddRef();
 +    pEnumIL->AddRef();
 +    lptvid->lpsfParent = lpsf;
 +    lptvid->lpi    = ILClone(pidl);
 +    lptvid->lpifq    = pidlParent ? ILCombine(pidlParent, pidl) : ILClone(pidl);
 +    lptvid->pEnumIL = pEnumIL;
 +    GetNormalAndSelectedIcons(lptvid->lpifq, &tvi);
 +
 +    tvins.item         = tvi;
 +    tvins.hInsertAfter = NULL;
 +    tvins.hParent      = hParent;
 +
 +    return TreeView_InsertItem( info->hwndTreeView, &tvins );
 +}
 +
 +/******************************************************************************
 + * FillTreeView [Internal]
 + *
 + * For each child (given by lpe) of the parent shell folder, which is given by
 + * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent
 + *
 + * PARAMS
 + *  info    [I] data for the dialog
 + *  lpsf    [I] IShellFolder interface of the parent shell folder
 + *  pidl    [I] ITEMIDLIST of the parent shell folder
 + *  hParent [I] The treeview item that represents the parent shell folder
 + *  lpe     [I] An iterator for the children of the parent shell folder
 + */
 +static void FillTreeView( browse_info *info, IShellFolder * lpsf,
 +                 LPITEMIDLIST  pidl, HTREEITEM hParent, IEnumIDList* lpe)
 +{
 +    LPITEMIDLIST    pidlTemp = 0;
 +    ULONG        ulFetched;
 +    HRESULT        hr;
 +    HWND        hwnd = GetParent( info->hwndTreeView );
 +
 +    TRACE("%p %p %p %p\n",lpsf, pidl, hParent, lpe);
 +
 +    /* No IEnumIDList -> No children */
 +    if (!lpe) return;
 +
 +    SetCapture( hwnd );
 +    SetCursor( LoadCursorA( 0, (LPSTR)IDC_WAIT ) );
 +
 +    while (S_OK == lpe->Next(1,&pidlTemp,&ulFetched))
 +    {
 +        ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER;
 +        CComPtr<IEnumIDList> pEnumIL;
 +        CComPtr<IShellFolder> pSFChild;
 +        lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &ulAttrs);
 +        if (ulAttrs & SFGAO_FOLDER)
 +        {
 +            hr = lpsf->BindToObject(pidlTemp, NULL, IID_PPV_ARG(IShellFolder, &pSFChild));
 +            if (SUCCEEDED(hr))
 +                {
 +                DWORD flags = BrowseFlagsToSHCONTF(info->lpBrowseInfo->ulFlags);
 +                hr = pSFChild->EnumObjects(hwnd, flags, &pEnumIL);
 +                    if (hr == S_OK)
 +                    {
 +                        if ((pEnumIL->Skip(1) != S_OK) ||
 +                             FAILED(pEnumIL->Reset()))
 +                        {
 +                            pEnumIL = NULL;
 +                        }
 +                    }
 +                }
 +        }
 +
 +        if (!InsertTreeViewItem(info, lpsf, pidlTemp, pidl, pEnumIL, hParent))
 +            goto done;
 +        SHFree(pidlTemp);  /* Finally, free the pidl that the shell gave us... */
 +        pidlTemp=NULL;
 +    }
 +
 +done:
 +    ReleaseCapture();
 +    SetCursor(LoadCursorW(0, (LPWSTR)IDC_ARROW));
 +    SHFree(pidlTemp);
 +}
 +
 +static BOOL __inline PIDLIsType(LPCITEMIDLIST pidl, PIDLTYPE type)
 +{
 +    LPPIDLDATA data = _ILGetDataPointer(pidl);
 +    if (!data)
 +        return FALSE;
 +    return (data->type == type);
 +}
 +
 +static void BrsFolder_CheckValidSelection( browse_info *info, LPTV_ITEMDATA lptvid )
 +{
 +    LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo;
 +    LPCITEMIDLIST pidl = lptvid->lpi;
 +    BOOL bEnabled = TRUE;
 +    DWORD dwAttributes;
 +    HRESULT r;
 +
 +    if ((lpBrowseInfo->ulFlags & BIF_BROWSEFORCOMPUTER) &&
 +        !PIDLIsType(pidl, PT_COMP))
 +        bEnabled = FALSE;
 +    if (lpBrowseInfo->ulFlags & BIF_RETURNFSANCESTORS)
 +    {
 +        dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
 +        r = lptvid->lpsfParent->GetAttributesOf(1,
 +                                (LPCITEMIDLIST*)&lptvid->lpi, &dwAttributes);
 +        if (FAILED(r) || !(dwAttributes & (SFGAO_FILESYSANCESTOR|SFGAO_FILESYSTEM)))
 +            bEnabled = FALSE;
 +    }
 +
 +    dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSTEM;
 +    r = lptvid->lpsfParent->GetAttributesOf(1,
 +                                            (LPCITEMIDLIST*)&lptvid->lpi,
 +                                            &dwAttributes);
 +    if (FAILED(r) ||
 +        ((dwAttributes & (SFGAO_FOLDER|SFGAO_FILESYSTEM)) != (SFGAO_FOLDER|SFGAO_FILESYSTEM)))
 +    {
 +        if (lpBrowseInfo->ulFlags & BIF_RETURNONLYFSDIRS)
 +            bEnabled = FALSE;
 +        EnableWindow(GetDlgItem(info->hWnd, IDC_BROWSE_FOR_FOLDER_NEW_FOLDER), FALSE);
 +    }
 +    else
 +        EnableWindow(GetDlgItem(info->hWnd, IDC_BROWSE_FOR_FOLDER_NEW_FOLDER), TRUE);
 +
 +    SendMessageW(info->hWnd, BFFM_ENABLEOK, 0, bEnabled);
 +}
 +
 +static LRESULT BrsFolder_Treeview_Delete( browse_info *info, NMTREEVIEWW *pnmtv )
 +{
 +    LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA)pnmtv->itemOld.lParam;
 +
 +    TRACE("TVN_DELETEITEMA/W %p\n", lptvid);
 +
 +    lptvid->lpsfParent->Release();
 +    if (lptvid->pEnumIL)
 +        lptvid->pEnumIL->Release();
 +    SHFree(lptvid->lpi);
 +    SHFree(lptvid->lpifq);
 +    SHFree(lptvid);
 +    return 0;
 +}
 +
 +static LRESULT BrsFolder_Treeview_Expand( browse_info *info, NMTREEVIEWW *pnmtv )
 +{
 +    CComPtr<IShellFolder> lpsf2;
 +    LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam;
 +    HRESULT r;
 +
 +    TRACE("TVN_ITEMEXPANDINGA/W\n");
 +
 +    if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
 +        return 0;
 +
 +    if (lptvid->lpi && lptvid->lpi->mkid.cb) {
 +        r = lptvid->lpsfParent->BindToObject(lptvid->lpi, 0, IID_PPV_ARG(IShellFolder, &lpsf2));
 +    } else {
 +        lpsf2 = lptvid->lpsfParent;
 +        r = lpsf2->AddRef();
 +    }
 +
 +    if (SUCCEEDED(r))
 +    {
 +        FillTreeView( info, lpsf2, lptvid->lpifq, pnmtv->itemNew.hItem, lptvid->pEnumIL);
 +        lpsf2->Release();
 +    }
 +
 +    /* My Computer is already sorted and trying to do a simple text
 +     * sort will only mess things up */
 +    if (!_ILIsMyComputer(lptvid->lpi))
 +        SendMessageW( info->hwndTreeView, TVM_SORTCHILDREN,
 +                      FALSE, (LPARAM)pnmtv->itemNew.hItem );
 +
 +    return 0;
 +}
 +
 +static HRESULT BrsFolder_Treeview_Changed( browse_info *info, NMTREEVIEWW *pnmtv )
 +{
 +    LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam;
 +    WCHAR name[MAX_PATH];
 +
 +    ILFree(info->pidlRet);
 +    info->pidlRet = ILClone(lptvid->lpifq);
 +
 +    if (GetName(lptvid->lpsfParent, lptvid->lpi, SHGDN_NORMAL, name))
 +            SetWindowTextW( GetDlgItem(info->hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT), name );
 +
 +    browsefolder_callback( info->lpBrowseInfo, info->hWnd, BFFM_SELCHANGED,
 +                           (LPARAM)info->pidlRet );
 +    BrsFolder_CheckValidSelection( info, lptvid );
 +    return 0;
 +}
 +
 +static LRESULT BrsFolder_Treeview_Rename(browse_info *info, NMTVDISPINFOW *pnmtv)
 +{
 +    LPTV_ITEMDATA item_data;
 +    WCHAR old_path[MAX_PATH], new_path[MAX_PATH], *p;
 +    NMTREEVIEWW nmtv;
 +    TVITEMW item;
 +
 +    if(!pnmtv->item.pszText)
 +        return 0;
 +
 +    item.mask = TVIF_HANDLE|TVIF_PARAM;
 +    item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CARET, 0);
 +    SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
 +    item_data = (LPTV_ITEMDATA)item.lParam;
 +
 +    SHGetPathFromIDListW(item_data->lpifq, old_path);
 +    if(!(p = strrchrW(old_path, '\\')))
 +        return 0;
 +    p = new_path+(p-old_path+1);
 +    memcpy(new_path, old_path, (p-new_path)*sizeof(WCHAR));
 +    strcpyW(p, pnmtv->item.pszText);
 +
 +    if(!MoveFileW(old_path, new_path))
 +        return 0;
 +
 +    SHFree(item_data->lpifq);
 +    SHFree(item_data->lpi);
 +    item_data->lpifq = SHSimpleIDListFromPathW(new_path);
 +    item_data->lpsfParent->ParseDisplayName(NULL, NULL, pnmtv->item.pszText,
 +                                            NULL, &item_data->lpi, NULL);
 +
 +    item.mask = TVIF_HANDLE|TVIF_TEXT;
 +    item.pszText = pnmtv->item.pszText;
 +    SendMessageW(info->hwndTreeView, TVM_SETITEMW, 0, (LPARAM)&item);
 +
 +    nmtv.itemNew.lParam = item.lParam;
 +    BrsFolder_Treeview_Changed(info, &nmtv);
 +    return 0;
 +}
 +
 +static LRESULT BrsFolder_OnNotify( browse_info *info, UINT CtlID, LPNMHDR lpnmh )
 +{
 +    NMTREEVIEWW *pnmtv = (NMTREEVIEWW *)lpnmh;
 +
 +    TRACE("%p %x %p msg=%x\n", info, CtlID, lpnmh, pnmtv->hdr.code);
 +
 +    if (pnmtv->hdr.idFrom != IDC_BROWSE_FOR_FOLDER_TREEVIEW)
 +        return 0;
 +
 +    switch (pnmtv->hdr.code)
 +    {
 +    case TVN_DELETEITEMA:
 +    case TVN_DELETEITEMW:
 +        return BrsFolder_Treeview_Delete( info, pnmtv );
 +
 +    case TVN_ITEMEXPANDINGA:
 +    case TVN_ITEMEXPANDINGW:
 +        return BrsFolder_Treeview_Expand( info, pnmtv );
 +
 +    case TVN_SELCHANGEDA:
 +    case TVN_SELCHANGEDW:
 +        return BrsFolder_Treeview_Changed( info, pnmtv );
 +
 +    case TVN_ENDLABELEDITA:
 +    case TVN_ENDLABELEDITW:
 +        return BrsFolder_Treeview_Rename( info, (LPNMTVDISPINFOW)pnmtv );
 +
 +    default:
 +        WARN("unhandled (%d)\n", pnmtv->hdr.code);
 +        break;
 +    }
 +
 +    return 0;
 +}
 +
 +
 +static BOOL BrsFolder_OnCreate( HWND hWnd, browse_info *info )
 +{
 +    LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo;
 +
 +    info->hWnd = hWnd;
 +    SetPropW( hWnd, szBrowseFolderInfo, info );
 +
 +    if (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)
 +        FIXME("flags BIF_NEWDIALOGSTYLE partially implemented\n");
 +    if (lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS)
 +    FIXME("flags %x not implemented\n", lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS);
 +
 +    if (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)
 +    {
 +        RECT rcWnd;
 +
 +        info->layout = LayoutInit(hWnd, g_layout_info, LAYOUT_INFO_COUNT);
 +
 +        /* TODO: Windows allows shrinking the windows a bit */
 +        GetWindowRect(hWnd, &rcWnd);
 +        info->szMin.cx = rcWnd.right - rcWnd.left;
 +        info->szMin.cy = rcWnd.bottom - rcWnd.top;
 +    }
 +    else
 +    {
 +        info->layout = NULL;
 +    }
 +
 +    if (lpBrowseInfo->lpszTitle)
 +        SetWindowTextW( GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_TITLE), lpBrowseInfo->lpszTitle );
 +    else
 +        ShowWindow( GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_TITLE), SW_HIDE );
 +
 +    if (!(lpBrowseInfo->ulFlags & BIF_STATUSTEXT)
 +        || (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE))
 +        ShowWindow( GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_STATUS), SW_HIDE );
 +
 +    /* Hide "Make New Folder" Button? */
 +    if ((lpBrowseInfo->ulFlags & BIF_NONEWFOLDERBUTTON)
 +        || !(lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE))
 +        ShowWindow( GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_NEW_FOLDER), SW_HIDE );
 +
 +    /* Hide the editbox? */
 +    if (!(lpBrowseInfo->ulFlags & BIF_EDITBOX))
 +    {
 +        ShowWindow( GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER), SW_HIDE );
 +        ShowWindow( GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT), SW_HIDE );
 +    }
 +
 +    info->hwndTreeView = GetDlgItem( hWnd, IDC_BROWSE_FOR_FOLDER_TREEVIEW );
 +    if (info->hwndTreeView)
 +    {
 +        InitializeTreeView( info );
 +
 +        /* Resize the treeview if there's not editbox */
 +        if ((lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)
 +            && !(lpBrowseInfo->ulFlags & BIF_EDITBOX))
 +        {
 +            RECT rc;
 +            GetClientRect(info->hwndTreeView, &rc);
 +            SetWindowPos(info->hwndTreeView, HWND_TOP, 0, 0,
 +                         rc.right, rc.bottom + 40, SWP_NOMOVE);
 +        }
 +    }
 +    else
 +        ERR("treeview control missing!\n");
 +
 +    browsefolder_callback( info->lpBrowseInfo, hWnd, BFFM_INITIALIZED, 0 );
 +
 +    return TRUE;
 +}
 +
 +static HRESULT BrsFolder_Rename(browse_info *info, HTREEITEM rename)
 +{
 +    SendMessageW(info->hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM)rename);
 +    SendMessageW(info->hwndTreeView, TVM_EDITLABELW, 0, (LPARAM)rename);
 +    return S_OK;
 +}
 +
 +static HRESULT BrsFolder_NewFolder(browse_info *info)
 +{
 +    DWORD flags = BrowseFlagsToSHCONTF(info->lpBrowseInfo->ulFlags);
 +    CComPtr<IShellFolder> desktop;
 +    CComPtr<IShellFolder> cur;
 +    CComPtr<ISFHelper> sfhelper;
 +    WCHAR name[MAX_PATH];
 +    HTREEITEM parent, added;
 +    LPTV_ITEMDATA item_data;
 +    LPITEMIDLIST new_item;
 +    TVITEMW item;
 +    HRESULT hr;
 +    int len;
 +
 +    if(!info->pidlRet) {
 +        ERR("Make new folder button should be disabled\n");
 +        return E_FAIL;
 +    }
 +
 +    /* Create new directory */
 +    hr = SHGetDesktopFolder(&desktop);
 +    if(FAILED(hr))
 +        return hr;
 +    hr = desktop->BindToObject(info->pidlRet, 0, IID_PPV_ARG(IShellFolder, &cur));
 +    if(FAILED(hr))
 +        return hr;
 +
 +    hr = cur->QueryInterface(IID_PPV_ARG(ISFHelper, &sfhelper));
 +    if(FAILED(hr))
 +        return hr;
 +
 +    hr = SHGetPathFromIDListW(info->pidlRet, name);
 +    if(FAILED(hr))
 +        goto cleanup;
 +
 +    len = strlenW(name);
 +    if(len<MAX_PATH)
 +        name[len++] = '\\';
 +    hr = sfhelper->GetUniqueName(&name[len], MAX_PATH-len);
 +    if(FAILED(hr))
 +        goto cleanup;
 +
 +    hr = E_FAIL;
 +    if(!CreateDirectoryW(name, NULL))
 +        goto cleanup;
 +
 +    /* Update parent of newly created directory */
 +    parent = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CARET, 0);
 +    if(!parent)
 +        goto cleanup;
 +
 +    SendMessageW(info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)parent);
 +
 +    memset(&item, 0, sizeof(TVITEMW));
 +    item.mask = TVIF_PARAM|TVIF_STATE;
 +    item.hItem = parent;
 +    SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
 +    item_data = (LPTV_ITEMDATA)item.lParam;
 +    if(!item_data)
 +        goto cleanup;
 +
 +    if(item_data->pEnumIL)
 +        item_data->pEnumIL->Release();
 +    hr = cur->EnumObjects(info->hwndTreeView, flags, &item_data->pEnumIL);
 +    if(FAILED(hr))
 +        goto cleanup;
 +
 +    /* Update treeview */
 +    if(!(item.state&TVIS_EXPANDEDONCE)) {
 +        item.mask = TVIF_STATE;
 +        item.state = TVIS_EXPANDEDONCE;
 +        item.stateMask = TVIS_EXPANDEDONCE;
 +        SendMessageW(info->hwndTreeView, TVM_SETITEMW, 0, (LPARAM)&item);
 +    }
 +
 +    hr = cur->ParseDisplayName(NULL, NULL, name+len, NULL, &new_item, NULL);
 +    if(FAILED(hr))
 +        goto cleanup;
 +
 +    added = InsertTreeViewItem(info, cur, new_item, item_data->lpifq, NULL, parent);
 +    SHFree(new_item);
 +
 +    SendMessageW(info->hwndTreeView, TVM_SORTCHILDREN, FALSE, (LPARAM)parent);
 +    return BrsFolder_Rename(info, added);
 +
 +cleanup:
 +    return hr;
 +}
 +
 +static BOOL BrsFolder_OnCommand( browse_info *info, UINT id )
 +{
 +    LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo;
 +
 +    switch (id)
 +    {
 +    case IDOK:
 +        /* The original pidl is owned by the treeview and will be free'd. */
 +        info->pidlRet = ILClone(info->pidlRet);
 +        if (info->pidlRet == NULL) /* A null pidl would mean a cancel */
 +            info->pidlRet = _ILCreateDesktop();
 +        pdump( info->pidlRet );
 +        if (lpBrowseInfo->pszDisplayName)
 +            SHGetPathFromIDListW( info->pidlRet, lpBrowseInfo->pszDisplayName );
 +        EndDialog( info->hWnd, 1 );
 +        return TRUE;
 +
 +    case IDCANCEL:
 +        EndDialog( info->hWnd, 0 );
 +        return TRUE;
 +
 +    case IDC_BROWSE_FOR_FOLDER_NEW_FOLDER:
 +        BrsFolder_NewFolder(info);
 +        return TRUE;
 +    }
 +    return FALSE;
 +}
 +
 +static BOOL BrsFolder_OnSetExpanded(browse_info *info, LPVOID selection,
 +    BOOL is_str, HTREEITEM *pItem)
 +{
 +    LPITEMIDLIST pidlSelection = (LPITEMIDLIST)selection;
 +    LPCITEMIDLIST pidlCurrent, pidlRoot;
 +    TVITEMEXW item;
 +    BOOL bResult = FALSE;
 +
 +    memset(&item, 0, sizeof(item));
 +
 +    /* If 'selection' is a string, convert to a Shell ID List. */ 
 +    if (is_str) {
 +        CComPtr<IShellFolder> psfDesktop;
 +        HRESULT hr;
 +
 +        hr = SHGetDesktopFolder(&psfDesktop);
 +        if (FAILED(hr))
 +            goto done;
 +
 +        hr = psfDesktop->ParseDisplayName(NULL, NULL, (LPOLESTR)selection,
 +                                          NULL, &pidlSelection, NULL);
 +        if (FAILED(hr))
 +            goto done;
 +    }
 +
 +    /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of
 +     * the sub-tree currently displayed. */
 +    pidlRoot = info->lpBrowseInfo->pidlRoot;
 +    pidlCurrent = pidlSelection;
 +    while (!_ILIsEmpty(pidlRoot) && _ILIsEqualSimple(pidlRoot, pidlCurrent)) {
 +        pidlRoot = ILGetNext(pidlRoot);
 +        pidlCurrent = ILGetNext(pidlCurrent);
 +    }
 +
 +    /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */
 +    if (!_ILIsEmpty(pidlRoot))
 +        goto done;
 +
 +    /* Initialize item to point to the first child of the root folder. */
 +    item.mask = TVIF_PARAM;
 +    item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_ROOT, 0);
 +
 +    if (item.hItem)
 +        item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CHILD,
 +                                             (LPARAM)item.hItem);
 +
 +    /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */
 +    while (item.hItem && !_ILIsEmpty(pidlCurrent)) {
 +        LPTV_ITEMDATA pItemData;
 +
 +        SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item);
 +        pItemData = (LPTV_ITEMDATA)item.lParam;
 +
 +        if (_ILIsEqualSimple(pItemData->lpi, pidlCurrent)) {
 +            pidlCurrent = ILGetNext(pidlCurrent);
 +            if (!_ILIsEmpty(pidlCurrent)) {
 +                /* Only expand current node and move on to it's first child,
 +                 * if we didn't already reach the last SHITEMID */
 +                SendMessageW(info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item.hItem);
 +                item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_CHILD,
 +                                                     (LPARAM)item.hItem);
 +            }
 +        } else {
 +            item.hItem = (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_GETNEXTITEM, TVGN_NEXT,
 +                                                 (LPARAM)item.hItem);
 +        }
 +    }
 +
 +    if (_ILIsEmpty(pidlCurrent) && item.hItem)
 +        bResult = TRUE;
 +
 +done:
 +    if (pidlSelection && pidlSelection != (LPITEMIDLIST)selection)
 +        ILFree(pidlSelection);
 +
 +    if (pItem)
 +        *pItem = item.hItem;
 +
 +    return bResult;
 +}
 +
 +static BOOL BrsFolder_OnSetSelectionW(browse_info *info, LPVOID selection, BOOL is_str) {
 +    HTREEITEM hItem;
 +    BOOL bResult;
 +
 +    if (!selection) return FALSE;
 +
 +    bResult = BrsFolder_OnSetExpanded(info, selection, is_str, &hItem);
 +    if (bResult)
 +        SendMessageW(info->hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem );
 +    return bResult;
 +}
 +
 +static BOOL BrsFolder_OnSetSelectionA(browse_info *info, LPVOID selection, BOOL is_str) {
 +    LPWSTR selectionW = NULL;
 +    BOOL result = FALSE;
 +    int length;
 +
 +    if (!is_str)
 +        return BrsFolder_OnSetSelectionW(info, selection, is_str);
 +
 +    if ((length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)selection, -1, NULL, 0)) &&
 +        (selectionW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR))) &&
 +        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)selection, -1, selectionW, length))
 +    {
 +        result = BrsFolder_OnSetSelectionW(info, selectionW, is_str);
 +    }
 +
 +    HeapFree(GetProcessHeap(), 0, selectionW);
 +    return result;
 +}
 +
 +static BOOL BrsFolder_OnWindowPosChanging(browse_info *info, WINDOWPOS *pos)
 +{
 +    if ((info->lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE) && !(pos->flags & SWP_NOSIZE))
 +    {
 +        if (pos->cx < info->szMin.cx)
 +            pos->cx = info->szMin.cx;
 +        if (pos->cy < info->szMin.cy)
 +            pos->cy = info->szMin.cy;
 +    }
 +    return 0;
 +}
 +
 +static INT BrsFolder_OnDestroy(browse_info *info)
 +{
 +    if (info->layout)
 +    {
 +        SHFree(info->layout);
 +        info->layout = NULL;
 +    }
 +
 +    return 0;
 +}
 +
 +/*************************************************************************
 + *             BrsFolderDlgProc32  (not an exported API function)
 + */
 +static INT_PTR CALLBACK BrsFolderDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
 +                                          LPARAM lParam )
 +{
 +    browse_info *info;
 +
 +    TRACE("hwnd=%p msg=%04x 0x%08lx 0x%08lx\n", hWnd, msg, wParam, lParam );
 +
 +    if (msg == WM_INITDIALOG)
 +        return BrsFolder_OnCreate( hWnd, (browse_info*) lParam );
 +
 +    info = (browse_info*) GetPropW( hWnd, szBrowseFolderInfo );
 +
 +    switch (msg)
 +    {
 +    case WM_NOTIFY:
 +        return BrsFolder_OnNotify( info, (UINT)wParam, (LPNMHDR)lParam);
 +
 +    case WM_COMMAND:
 +        return BrsFolder_OnCommand( info, wParam );
 +
 +    case WM_WINDOWPOSCHANGING:
 +        return BrsFolder_OnWindowPosChanging( info, (WINDOWPOS *)lParam);
 +
 +    case WM_SIZE:
 +        if (info->layout)  /* new style dialogs */
 +            LayoutUpdate(hWnd, info->layout, g_layout_info, LAYOUT_INFO_COUNT);
 +        return 0;
 +
 +    case BFFM_SETSTATUSTEXTA:
 +        TRACE("Set status %s\n", debugstr_a((LPSTR)lParam));
 +        SetWindowTextA(GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_STATUS), (LPSTR)lParam);
 +        break;
 +
 +    case BFFM_SETSTATUSTEXTW:
 +        TRACE("Set status %s\n", debugstr_w((LPWSTR)lParam));
 +        SetWindowTextW(GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_STATUS), (LPWSTR)lParam);
 +        break;
 +
 +    case BFFM_ENABLEOK:
 +        TRACE("Enable %ld\n", lParam);
 +        EnableWindow(GetDlgItem(hWnd, 1), (lParam)?TRUE:FALSE);
 +        break;
 +
 +    case BFFM_SETOKTEXT: /* unicode only */
 +        TRACE("Set OK text %s\n", debugstr_w((LPWSTR)wParam));
 +        SetWindowTextW(GetDlgItem(hWnd, 1), (LPWSTR)wParam);
 +        break;
 +
 +    case BFFM_SETSELECTIONA:
 +        return BrsFolder_OnSetSelectionA(info, (LPVOID)lParam, (BOOL)wParam);
 +
 +    case BFFM_SETSELECTIONW:
 +        return BrsFolder_OnSetSelectionW(info, (LPVOID)lParam, (BOOL)wParam);
 +
 +    case BFFM_SETEXPANDED: /* unicode only */
 +        return BrsFolder_OnSetExpanded(info, (LPVOID)lParam, (BOOL)wParam, NULL);
 +
 +    case WM_DESTROY:
 +        return BrsFolder_OnDestroy(info);
 +    }
 +    return FALSE;
 +}
 +
 +
 +
 +
 +/*************************************************************************
 + * SHBrowseForFolderA [SHELL32.@]
 + * SHBrowseForFolder  [SHELL32.@]
 + */
 +LPITEMIDLIST WINAPI SHBrowseForFolderA (LPBROWSEINFOA lpbi)
 +{
 +    BROWSEINFOW bi;
 +    LPITEMIDLIST lpid;
 +    INT len;
 +    LPWSTR title;
 +
 +    TRACE("%p\n", lpbi);
 +
 +    bi.hwndOwner = lpbi->hwndOwner;
 +    bi.pidlRoot = lpbi->pidlRoot;
 +    if (lpbi->pszDisplayName)
 +    {
 +        bi.pszDisplayName = (WCHAR *)HeapAlloc( GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) );
 +        MultiByteToWideChar( CP_ACP, 0, lpbi->pszDisplayName, -1, bi.pszDisplayName, MAX_PATH );
 +    }
 +    else
 +        bi.pszDisplayName = NULL;
 +
 +    if (lpbi->lpszTitle)
 +    {
 +        len = MultiByteToWideChar( CP_ACP, 0, lpbi->lpszTitle, -1, NULL, 0 );
 +        title = (WCHAR *)HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
 +        MultiByteToWideChar( CP_ACP, 0, lpbi->lpszTitle, -1, title, len );
 +    }
 +    else
 +        title = NULL;
 +
 +    bi.lpszTitle = title;
 +    bi.ulFlags = lpbi->ulFlags;
 +    bi.lpfn = lpbi->lpfn;
 +    bi.lParam = lpbi->lParam;
 +    bi.iImage = lpbi->iImage;
 +    lpid = SHBrowseForFolderW( &bi );
 +    if (bi.pszDisplayName)
 +    {
 +        WideCharToMultiByte( CP_ACP, 0, bi.pszDisplayName, -1,
 +                             lpbi->pszDisplayName, MAX_PATH, 0, NULL);
 +        HeapFree( GetProcessHeap(), 0, bi.pszDisplayName );
 +    }
 +    HeapFree(GetProcessHeap(), 0, title);
 +    lpbi->iImage = bi.iImage;
 +    return lpid;
 +}
 +
 +
 +/*************************************************************************
 + * SHBrowseForFolderW [SHELL32.@]
 + *
 + * NOTES
 + *  crashes when passed a null pointer
 + */
 +LPITEMIDLIST WINAPI SHBrowseForFolderW (LPBROWSEINFOW lpbi)
 +{
 +    browse_info info;
 +    DWORD r;
 +    HRESULT hr;
 +    WORD wDlgId;
 +
 +    info.hWnd = 0;
 +    info.pidlRet = NULL;
 +    info.lpBrowseInfo = lpbi;
 +    info.hwndTreeView = NULL;
 +
 +    hr = OleInitialize(NULL);
 +
 +    if (lpbi->ulFlags & BIF_NEWDIALOGSTYLE)
 +        wDlgId = IDD_BROWSE_FOR_FOLDER_NEW;
 +    else
 +        wDlgId = IDD_BROWSE_FOR_FOLDER;
 +    r = DialogBoxParamW( shell32_hInstance, MAKEINTRESOURCEW(wDlgId), lpbi->hwndOwner,
 +                         BrsFolderDlgProc, (LPARAM)&info );
 +    if (SUCCEEDED(hr))
 +        OleUninitialize();
 +    if (!r)
 +    {
 +        ILFree(info.pidlRet);
 +        return NULL;
 +    }
 +
 +    return info.pidlRet;
 +}
@@@ -25,6 -25,9 +25,9 @@@
  DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter);
  HRESULT WINAPI DoDeleteDataObject(IDataObject *pda);
  
+ BOOL TRASH_CanTrashFile(LPCWSTR wszPath);
+ BOOL TRASH_TrashFile(LPCWSTR wszPath);
  class CRecycleBin :
      public CComCoClass<CRecycleBin, &CLSID_RecycleBin>,
      public CComObjectRootEx<CComMultiThreadModelNoCS>,
@@@ -30,7 -30,7 +30,7 @@@ extern HINSTANCE shell32_hInstance
  extern HIMAGELIST     ShellSmallIconList;
  extern HIMAGELIST     ShellBigIconList;
  
extern "C" BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList);
+ BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList);
  
  /* Iconcache */
  #define INVALID_INDEX -1
@@@ -128,7 -128,7 +128,7 @@@ BOOL SHELL_ConfirmYesNoW(HWND hWnd, in
  void WINAPI _InsertMenuItemW (HMENU hmenu, UINT indexMenu, BOOL fByPosition,
                        UINT wID, UINT fType, LPCWSTR dwTypeData, UINT fState);
  
- static BOOL __inline SHELL_OsIsUnicode(void)
+ static __inline BOOL SHELL_OsIsUnicode(void)
  {
      /* if high-bit of version is 0, we are emulating NT */
      return !(GetVersion() & 0x80000000);
          SHFree(*ptr); \
          *ptr = NULL; \
        };
- static void __inline __SHCloneStrA(char **target, const char *source)
+ static __inline void __SHCloneStrA(char **target, const char *source)
  {
        *target = (char *)SHAlloc(strlen(source) + 1);
        strcpy(*target, source);
  }
  
- static void __inline __SHCloneStrWtoA(char **target, const WCHAR *source)
+ static __inline void __SHCloneStrWtoA(char **target, const WCHAR *source)
  {
        int len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL);
        *target = (char *)SHAlloc(len);
        WideCharToMultiByte(CP_ACP, 0, source, -1, *target, len, NULL, NULL);
  }
  
- static void __inline __SHCloneStrW(WCHAR **target, const WCHAR *source)
+ static __inline void __SHCloneStrW(WCHAR **target, const WCHAR *source)
  {
        *target = (WCHAR *)SHAlloc((lstrlenW(source) + 1) * sizeof(WCHAR) );
        lstrcpyW(*target, source);
  }
  
- static LPWSTR __inline __SHCloneStrAtoW(WCHAR **target, const char *source)
+ static __inline LPWSTR __SHCloneStrAtoW(WCHAR **target, const char *source)
  {
        int len = MultiByteToWideChar(CP_ACP, 0, source, -1, NULL, 0);
        *target = (WCHAR *)SHAlloc(len * sizeof(WCHAR));
index 0000000,8bccd1c..8bccd1c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,279 +1,279 @@@
+ /*
+  * Copyright 2000 Juergen Schmied
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2.1 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+  */
+ #define WIN32_NO_STATUS
+ #define _INC_WINDOWS
+ #define NONAMELESSUNION
+ #define NONAMELESSSTRUCT
+ #include <windef.h>
+ #include <winbase.h>
+ #include <shlobj.h>
+ #include <shlwapi.h>
+ #include <wine/unicode.h>
+ #include <wine/debug.h>
+ #include "shell32_main.h"
+ #include "undocshell.h"
+ WINE_DEFAULT_DEBUG_CHANNEL(shell);
+ /************************* STRRET functions ****************************/
+ static const char *debugstr_strret(STRRET *s)
+ {
+     switch (s->uType)
+     {
+         case STRRET_WSTR:
+             return "STRRET_WSTR";
+         case STRRET_CSTR:
+             return "STRRET_CSTR";
+         case STRRET_OFFSET:
+             return "STRRET_OFFSET";
+         default:
+             return "STRRET_???";
+     }
+ }
+ BOOL WINAPI StrRetToStrNA(LPSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
+ {
+     TRACE("dest=%p len=0x%x strret=%p(%s) pidl=%p\n", dest, len, src, debugstr_strret(src), pidl);
+     if (!dest)
+         return FALSE;
+     switch (src->uType)
+     {
+         case STRRET_WSTR:
+             WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
+             CoTaskMemFree(src->u.pOleStr);
+             break;
+         case STRRET_CSTR:
+             lstrcpynA(dest, src->u.cStr, len);
+             break;
+         case STRRET_OFFSET:
+             lstrcpynA(dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
+             break;
+         default:
+             FIXME("unknown type %u!\n", src->uType);
+             if (len)
+                 *dest = '\0';
+             return FALSE;
+     }
+     TRACE("-- %s\n", debugstr_a(dest) );
+     return TRUE;
+ }
+ /************************************************************************/
+ BOOL WINAPI StrRetToStrNW(LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
+ {
+     TRACE("dest=%p len=0x%x strret=%p(%s) pidl=%p\n", dest, len, src, debugstr_strret(src), pidl);
+     if (!dest)
+         return FALSE;
+     switch (src->uType)
+     {
+         case STRRET_WSTR:
+             lstrcpynW(dest, src->u.pOleStr, len);
+             CoTaskMemFree(src->u.pOleStr);
+             break;
+         case STRRET_CSTR:
+             if (!MultiByteToWideChar(CP_ACP, 0, src->u.cStr, -1, dest, len) && len)
+                 dest[len-1] = 0;
+             break;
+         case STRRET_OFFSET:
+             if (!MultiByteToWideChar(CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, dest, len)
+                     && len)
+                 dest[len-1] = 0;
+             break;
+         default:
+             FIXME("unknown type %u!\n", src->uType);
+             if (len)
+                 *dest = '\0';
+             return FALSE;
+     }
+     return TRUE;
+ }
+ /*************************************************************************
+  * StrRetToStrN    [SHELL32.96]
+  *
+  * converts a STRRET to a normal string
+  *
+  * NOTES
+  *  the pidl is for STRRET OFFSET
+  */
+ BOOL WINAPI StrRetToStrNAW(LPVOID dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl)
+ {
+     if(SHELL_OsIsUnicode())
+         return StrRetToStrNW(dest, len, src, pidl);
+     else
+         return StrRetToStrNA(dest, len, src, pidl);
+ }
+ /************************* OLESTR functions ****************************/
+ /************************************************************************
+  *    StrToOleStr                     [SHELL32.163]
+  *
+  */
+ static int StrToOleStrA (LPWSTR lpWideCharStr, LPCSTR lpMultiByteString)
+ {
+       TRACE("(%p, %p %s)\n",
+       lpWideCharStr, lpMultiByteString, debugstr_a(lpMultiByteString));
+       return MultiByteToWideChar(CP_ACP, 0, lpMultiByteString, -1, lpWideCharStr, MAX_PATH);
+ }
+ static int StrToOleStrW (LPWSTR lpWideCharStr, LPCWSTR lpWString)
+ {
+       TRACE("(%p, %p %s)\n",
+       lpWideCharStr, lpWString, debugstr_w(lpWString));
+       strcpyW (lpWideCharStr, lpWString );
+       return strlenW(lpWideCharStr);
+ }
+ BOOL WINAPI StrToOleStrAW (LPWSTR lpWideCharStr, LPCVOID lpString)
+ {
+       if (SHELL_OsIsUnicode())
+         return StrToOleStrW (lpWideCharStr, lpString);
+       return StrToOleStrA (lpWideCharStr, lpString);
+ }
+ /*************************************************************************
+  * StrToOleStrN                                       [SHELL32.79]
+  *  lpMulti, nMulti, nWide [IN]
+  *  lpWide [OUT]
+  */
+ static BOOL StrToOleStrNA (LPWSTR lpWide, INT nWide, LPCSTR lpStrA, INT nStr)
+ {
+       TRACE("(%p, %x, %s, %x)\n", lpWide, nWide, debugstr_an(lpStrA,nStr), nStr);
+       return MultiByteToWideChar (CP_ACP, 0, lpStrA, nStr, lpWide, nWide);
+ }
+ static BOOL StrToOleStrNW (LPWSTR lpWide, INT nWide, LPCWSTR lpStrW, INT nStr)
+ {
+       TRACE("(%p, %x, %s, %x)\n", lpWide, nWide, debugstr_wn(lpStrW, nStr), nStr);
+       if (lstrcpynW (lpWide, lpStrW, nWide))
+       { return lstrlenW (lpWide);
+       }
+       return FALSE;
+ }
+ BOOL WINAPI StrToOleStrNAW (LPWSTR lpWide, INT nWide, LPCVOID lpStr, INT nStr)
+ {
+       if (SHELL_OsIsUnicode())
+         return StrToOleStrNW (lpWide, nWide, lpStr, nStr);
+       return StrToOleStrNA (lpWide, nWide, lpStr, nStr);
+ }
+ /*************************************************************************
+  * OleStrToStrN                                       [SHELL32.78]
+  */
+ static BOOL OleStrToStrNA (LPSTR lpStr, INT nStr, LPCWSTR lpOle, INT nOle)
+ {
+       TRACE("(%p, %x, %s, %x)\n", lpStr, nStr, debugstr_wn(lpOle,nOle), nOle);
+       return WideCharToMultiByte (CP_ACP, 0, lpOle, nOle, lpStr, nStr, NULL, NULL);
+ }
+ static BOOL OleStrToStrNW (LPWSTR lpwStr, INT nwStr, LPCWSTR lpOle, INT nOle)
+ {
+       TRACE("(%p, %x, %s, %x)\n", lpwStr, nwStr, debugstr_wn(lpOle,nOle), nOle);
+       if (lstrcpynW ( lpwStr, lpOle, nwStr))
+       { return lstrlenW (lpwStr);
+       }
+         return FALSE;
+ }
+ BOOL WINAPI OleStrToStrNAW (LPVOID lpOut, INT nOut, LPCVOID lpIn, INT nIn)
+ {
+       if (SHELL_OsIsUnicode())
+         return OleStrToStrNW (lpOut, nOut, lpIn, nIn);
+       return OleStrToStrNA (lpOut, nOut, lpIn, nIn);
+ }
+ /*************************************************************************
+  * CheckEscapesA             [SHELL32.@]
+  *
+  * Checks a string for special characters which are not allowed in a path
+  * and encloses it in quotes if that is the case.
+  *
+  * PARAMS
+  *  string     [I/O] string to check and on return eventually quoted
+  *  len        [I]   length of string
+  *
+  * RETURNS
+  *  length of actual string
+  *
+  * NOTES
+  *  Not really sure if this function returns actually a value at all. 
+  */
+ DWORD WINAPI CheckEscapesA(
+       LPSTR   string,         /* [I/O]   string to check ??*/
+       DWORD   len)            /* [I]      is 0 */
+ {
+       LPWSTR wString;
+       DWORD ret = 0;
+       TRACE("(%s %d)\n", debugstr_a(string), len);
+       wString = LocalAlloc(LPTR, len * sizeof(WCHAR));
+       if (wString)
+       {
+         MultiByteToWideChar(CP_ACP, 0, string, len, wString, len);
+         ret = CheckEscapesW(wString, len);
+         WideCharToMultiByte(CP_ACP, 0, wString, len, string, len, NULL, NULL);
+         LocalFree(wString);
+       }
+       return ret;
+ }
+ static const WCHAR strEscapedChars[] = {' ','"',',',';','^',0};
+ /*************************************************************************
+  * CheckEscapesW             [SHELL32.@]
+  *
+  * See CheckEscapesA.
+  */
+ DWORD WINAPI CheckEscapesW(
+       LPWSTR  string,
+       DWORD   len)
+ {
+       DWORD size = lstrlenW(string);
+       LPWSTR s, d;
+       TRACE("(%s %d) stub\n", debugstr_w(string), len);
+       if (StrPBrkW(string, strEscapedChars) && size + 2 <= len)
+       {
+         s = &string[size - 1];
+         d = &string[size + 2];
+         *d-- = 0;
+         *d-- = '"';
+         for (;d > string;)
+           *d-- = *s--;
+         *d = '"';
+         return size + 2;
+       }
+       return size;
+ }
index 22a03b1,0000000..e8dddf1
mode 100644,000000..100644
--- /dev/null
@@@ -1,1969 -1,0 +1,1967 @@@
- #include "xdg.h"
 +/*
 + * SHFileOperation
 + *
 + * Copyright 2000 Juergen Schmied
 + * Copyright 2002 Andriy Palamarchuk
 + * Copyright 2004 Dietrich Teickner (from Odin)
 + * Copyright 2004 Rolf Kalbermatter
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + */
 +
 +#include "precomp.h"
 +
 +WINE_DEFAULT_DEBUG_CHANNEL(shell);
 +
 +#define IsAttrib(x, y)  ((INVALID_FILE_ATTRIBUTES != (x)) && ((x) & (y)))
 +#define IsAttribFile(x) (!((x) & FILE_ATTRIBUTE_DIRECTORY))
 +#define IsAttribDir(x)  IsAttrib(x, FILE_ATTRIBUTE_DIRECTORY)
 +#define IsDotDir(x)     ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
 +
 +#define FO_MASK         0xF
 +#define WM_FILE       (WM_USER + 1)
 +#define TIMER_ID      (100)
 +
 +static const WCHAR wWildcardFile[] = {'*',0};
 +static const WCHAR wWildcardChars[] = {'*','?',0};
 +
 +static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec);
 +static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path);
 +static DWORD SHNotifyDeleteFileW(LPCWSTR path);
 +static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest, BOOL isdir);
 +static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists);
 +static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly);
 +
 +typedef struct
 +{
 +    SHFILEOPSTRUCTW *req;
 +    DWORD dwYesToAllMask;
 +    BOOL bManyItems;
 +    BOOL bCancelled;
 +} FILE_OPERATION;
 +
 +#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026
 +
 +typedef struct
 +{
 +    DWORD attributes;
 +    LPWSTR szDirectory;
 +    LPWSTR szFilename;
 +    LPWSTR szFullPath;
 +    BOOL bFromWildcard;
 +    BOOL bFromRelative;
 +    BOOL bExists;
 +} FILE_ENTRY;
 +
 +typedef struct
 +{
 +    FILE_ENTRY *feFiles;
 +    DWORD num_alloc;
 +    DWORD dwNumFiles;
 +    BOOL bAnyFromWildcard;
 +    BOOL bAnyDirectories;
 +    BOOL bAnyDontExist;
 +} FILE_LIST;
 +
 +typedef struct
 +{
 +    FILE_LIST * from;
 +    FILE_LIST * to;
 +    FILE_OPERATION * op;
 +    DWORD Index;
 +    HWND hDlgCtrl;
 +    HWND hwndDlg;
 +}FILE_OPERATION_CONTEXT;
 +
 +
 +/* Confirm dialogs with an optional "Yes To All" as used in file operations confirmations
 + */
 +static const WCHAR CONFIRM_MSG_PROP[] = {'W','I','N','E','_','C','O','N','F','I','R','M',0};
 +
 +struct confirm_msg_info
 +{
 +    LPWSTR lpszText;
 +    LPWSTR lpszCaption;
 +    HICON hIcon;
 +    BOOL bYesToAll;
 +};
 +
 +/* as some buttons may be hidden and the dialog height may change we may need
 + * to move the controls */
 +static void confirm_msg_move_button(HWND hDlg, INT iId, INT *xPos, INT yOffset, BOOL bShow)
 +{
 +    HWND hButton = GetDlgItem(hDlg, iId);
 +    RECT r;
 +
 +    if (bShow)
 +    {
 +        POINT pt;
 +        int width;
 +
 +        GetWindowRect(hButton, &r);
 +        width = r.right - r.left;
 +        pt.x = r.left;
 +        pt.y = r.top;
 +        ScreenToClient(hDlg, &pt);
 +        MoveWindow(hButton, *xPos - width, pt.y - yOffset, width, r.bottom - r.top, FALSE);
 +        *xPos -= width + 5;
 +    }
 +    else
 +        ShowWindow(hButton, SW_HIDE);
 +}
 +
 +/* Note: we paint the text manually and don't use the static control to make
 + * sure the text has the same height as the one computed in WM_INITDIALOG
 + */
 +static INT_PTR ConfirmMsgBox_Paint(HWND hDlg)
 +{
 +    PAINTSTRUCT ps;
 +    HFONT hOldFont;
 +    RECT r;
 +    HDC hdc;
 +
 +    BeginPaint(hDlg, &ps);
 +    hdc = ps.hdc;
 +
 +    GetClientRect(GetDlgItem(hDlg, IDC_YESTOALL_MESSAGE), &r);
 +    /* this will remap the rect to dialog coords */
 +    MapWindowPoints(GetDlgItem(hDlg, IDC_YESTOALL_MESSAGE), hDlg, (LPPOINT)&r, 2);
 +    hOldFont = (HFONT)SelectObject(hdc, (HFONT)SendDlgItemMessageW(hDlg, IDC_YESTOALL_MESSAGE, WM_GETFONT, 0, 0));
 +    DrawTextW(hdc, (LPWSTR)GetPropW(hDlg, CONFIRM_MSG_PROP), -1, &r, DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_WORDBREAK);
 +    SelectObject(hdc, hOldFont);
 +    EndPaint(hDlg, &ps);
 +
 +    return TRUE;
 +}
 +
 +static INT_PTR ConfirmMsgBox_Init(HWND hDlg, LPARAM lParam)
 +{
 +    struct confirm_msg_info *info = (struct confirm_msg_info *)lParam;
 +    INT xPos, yOffset;
 +    int width, height;
 +    HFONT hOldFont;
 +    HDC hdc;
 +    RECT r;
 +
 +    SetWindowTextW(hDlg, info->lpszCaption);
 +    ShowWindow(GetDlgItem(hDlg, IDC_YESTOALL_MESSAGE), SW_HIDE);
 +    SetPropW(hDlg, CONFIRM_MSG_PROP, info->lpszText);
 +    SendDlgItemMessageW(hDlg, IDC_YESTOALL_ICON, STM_SETICON, (WPARAM)info->hIcon, 0);
 +
 +    /* compute the text height and resize the dialog */
 +    GetClientRect(GetDlgItem(hDlg, IDC_YESTOALL_MESSAGE), &r);
 +    hdc = GetDC(hDlg);
 +    yOffset = r.bottom;
 +    hOldFont = (HFONT)SelectObject(hdc, (HFONT)SendDlgItemMessageW(hDlg, IDC_YESTOALL_MESSAGE, WM_GETFONT, 0, 0));
 +    DrawTextW(hdc, info->lpszText, -1, &r, DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_WORDBREAK | DT_CALCRECT);
 +    SelectObject(hdc, hOldFont);
 +    yOffset -= r.bottom;
 +    yOffset = min(yOffset, 35);  /* don't make the dialog too small */
 +    ReleaseDC(hDlg, hdc);
 +
 +    GetClientRect(hDlg, &r);
 +    xPos = r.right - 7;
 +    GetWindowRect(hDlg, &r);
 +    width = r.right - r.left;
 +    height = r.bottom - r.top - yOffset;
 +    MoveWindow(hDlg, (GetSystemMetrics(SM_CXSCREEN) - width)/2,
 +        (GetSystemMetrics(SM_CYSCREEN) - height)/2, width, height, FALSE);
 +
 +    confirm_msg_move_button(hDlg, IDCANCEL,     &xPos, yOffset, info->bYesToAll);
 +    confirm_msg_move_button(hDlg, IDNO,         &xPos, yOffset, TRUE);
 +    confirm_msg_move_button(hDlg, IDC_YESTOALL, &xPos, yOffset, info->bYesToAll);
 +    confirm_msg_move_button(hDlg, IDYES,        &xPos, yOffset, TRUE);
 +
 +    return TRUE;
 +}
 +
 +static INT_PTR CALLBACK ConfirmMsgBoxProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 +{
 +    switch (uMsg)
 +    {
 +        case WM_INITDIALOG:
 +            return ConfirmMsgBox_Init(hDlg, lParam);
 +        case WM_PAINT:
 +            return ConfirmMsgBox_Paint(hDlg);
 +        case WM_COMMAND:
 +            EndDialog(hDlg, wParam);
 +            break;
 +        case WM_CLOSE:
 +            EndDialog(hDlg, IDCANCEL);
 +            break;
 +    }
 +    return FALSE;
 +}
 +
 +int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll)
 +{
 +    struct confirm_msg_info info;
 +
 +    info.lpszText = lpszText;
 +    info.lpszCaption = lpszCaption;
 +    info.hIcon = hIcon;
 +    info.bYesToAll = bYesToAll;
 +    return DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_YESTOALL_MSGBOX), hWnd, ConfirmMsgBoxProc, (LPARAM)&info);
 +}
 +
 +/* confirmation dialogs content */
 +typedef struct
 +{
 +    HINSTANCE hIconInstance;
 +    UINT icon_resource_id;
 +    UINT caption_resource_id, text_resource_id;
 +} SHELL_ConfirmIDstruc;
 +
 +static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids)
 +{
 +    ids->hIconInstance = shell32_hInstance;
 +    switch (nKindOfDialog)
 +    {
 +        case ASK_DELETE_FILE:
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_DELETEITEM_CAPTION;
 +            ids->text_resource_id  = IDS_DELETEITEM_TEXT;
 +            return TRUE;
 +
 +        case ASK_DELETE_FOLDER:
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_DELETEFOLDER_CAPTION;
 +            ids->text_resource_id  = IDS_DELETEITEM_TEXT;
 +            return TRUE;
 +
 +        case ASK_DELETE_MULTIPLE_ITEM:
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_DELETEITEM_CAPTION;
 +            ids->text_resource_id  = IDS_DELETEMULTIPLE_TEXT;
 +            return TRUE;
 +
 +        case ASK_TRASH_FILE:
 +            ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
 +            ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
 +            ids->text_resource_id = IDS_TRASHITEM_TEXT;
 +            return TRUE;
 +
 +        case ASK_TRASH_FOLDER:
 +            ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
 +            ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION;
 +            ids->text_resource_id = IDS_TRASHFOLDER_TEXT;
 +            return TRUE;
 +
 +        case ASK_TRASH_MULTIPLE_ITEM:
 +            ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
 +            ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
 +            ids->text_resource_id = IDS_TRASHMULTIPLE_TEXT;
 +            return TRUE;
 +
 +        case ASK_CANT_TRASH_ITEM:
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_DELETEITEM_CAPTION;
 +            ids->text_resource_id  = IDS_CANTTRASH_TEXT;
 +            return TRUE;
 +
 +        case ASK_DELETE_SELECTED:
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_DELETEITEM_CAPTION;
 +            ids->text_resource_id  = IDS_DELETESELECTED_TEXT;
 +            return TRUE;
 +
 +      case ASK_OVERWRITE_FILE:
 +            ids->hIconInstance = NULL;
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_OVERWRITEFILE_CAPTION;
 +            ids->text_resource_id  = IDS_OVERWRITEFILE_TEXT;
 +            return TRUE;
 +
 +      case ASK_OVERWRITE_FOLDER:
 +            ids->hIconInstance = NULL;
 +            ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
 +            ids->caption_resource_id  = IDS_OVERWRITEFILE_CAPTION;
 +            ids->text_resource_id  = IDS_OVERWRITEFOLDER_TEXT;
 +            return TRUE;
 +
 +        default:
 +            FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
 +    }
 +    return FALSE;
 +}
 +
 +static BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir, FILE_OPERATION *op)
 +{
 +    WCHAR szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
 +    SHELL_ConfirmIDstruc ids;
 +    DWORD_PTR args[1];
 +    HICON hIcon;
 +    int ret;
 +
 +    assert(nKindOfDialog >= 0 && nKindOfDialog < 32);
 +    if (op && (op->dwYesToAllMask & (1 << nKindOfDialog)))
 +        return TRUE;
 +
 +    if (!SHELL_ConfirmIDs(nKindOfDialog, &ids)) return FALSE;
 +
 +    LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption)/sizeof(WCHAR));
 +    LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText)/sizeof(WCHAR));
 +
 +    args[0] = (DWORD_PTR)szDir;
 +    FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
 +                   szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)args);
 +    hIcon = LoadIconW(ids.hIconInstance, (LPWSTR)MAKEINTRESOURCE(ids.icon_resource_id));
 +
 +    ret = SHELL_ConfirmMsgBox(hWnd, szBuffer, szCaption, hIcon, op && op->bManyItems);
 +    if (op)
 +    {
 +        if (ret == IDC_YESTOALL)
 +        {
 +            op->dwYesToAllMask |= (1 << nKindOfDialog);
 +            ret = IDYES;
 +        }
 +        if (ret == IDCANCEL)
 +            op->bCancelled = TRUE;
 +        if (ret != IDYES)
 +            op->req->fAnyOperationsAborted = TRUE;
 +    }
 +    return ret == IDYES;
 +}
 +
 +BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
 +{
 +    return SHELL_ConfirmDialogW(hWnd, nKindOfDialog, szDir, NULL);
 +}
 +
 +static DWORD SHELL32_AnsiToUnicodeBuf(LPCSTR aPath, LPWSTR *wPath, DWORD minChars)
 +{
 +    DWORD len = MultiByteToWideChar(CP_ACP, 0, aPath, -1, NULL, 0);
 +
 +    if (len < minChars)
 +      len = minChars;
 +
 +    *wPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +    if (*wPath)
 +    {
 +      MultiByteToWideChar(CP_ACP, 0, aPath, -1, *wPath, len);
 +      return NO_ERROR;
 +    }
 +    return E_OUTOFMEMORY;
 +}
 +
 +static void SHELL32_FreeUnicodeBuf(LPWSTR wPath)
 +{
 +    HeapFree(GetProcessHeap(), 0, wPath);
 +}
 +
 +EXTERN_C HRESULT WINAPI SHIsFileAvailableOffline(LPCWSTR path, LPDWORD status)
 +{
 +    FIXME("(%s, %p) stub\n", debugstr_w(path), status);
 +    return E_FAIL;
 +}
 +
 +/**************************************************************************
 + * SHELL_DeleteDirectory()  [internal]
 + *
 + * Asks for confirmation when bShowUI is true and deletes the directory and
 + * all its subdirectories and files if necessary.
 + */
 +BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI)
 +{
 +    BOOL    ret = TRUE;
 +    HANDLE  hFind;
 +    WIN32_FIND_DATAW wfd;
 +    WCHAR   szTemp[MAX_PATH];
 +
 +    /* Make sure the directory exists before eventually prompting the user */
 +    PathCombineW(szTemp, pszDir, wWildcardFile);
 +    hFind = FindFirstFileW(szTemp, &wfd);
 +    if (hFind == INVALID_HANDLE_VALUE)
 +      return FALSE;
 +
 +    if (!bShowUI || (ret = SHELL_ConfirmDialogW(hwnd, ASK_DELETE_FOLDER, pszDir, NULL)))
 +    {
 +        do
 +        {
 +            if (IsDotDir(wfd.cFileName))
 +                continue;
 +            PathCombineW(szTemp, pszDir, wfd.cFileName);
 +            if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
 +                ret = SHELL_DeleteDirectoryW(hwnd, szTemp, FALSE);
 +            else
 +                ret = (SHNotifyDeleteFileW(szTemp) == ERROR_SUCCESS);
 +        } while (ret && FindNextFileW(hFind, &wfd));
 +    }
 +    FindClose(hFind);
 +    if (ret)
 +        ret = (SHNotifyRemoveDirectoryW(pszDir) == ERROR_SUCCESS);
 +    return ret;
 +}
 +
 +/**************************************************************************
 + * Win32CreateDirectory      [SHELL32.93]
 + *
 + * Creates a directory. Also triggers a change notify if one exists.
 + *
 + * PARAMS
 + *  path       [I]   path to directory to create
 + *
 + * RETURNS
 + *  TRUE if successful, FALSE otherwise
 + */
 +
 +static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
 +{
 +    TRACE("(%s, %p)\n", debugstr_w(path), sec);
 +
 +    if (CreateDirectoryW(path, sec))
 +    {
 +      SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, path, NULL);
 +      return ERROR_SUCCESS;
 +    }
 +    return GetLastError();
 +}
 +
 +/**********************************************************************/
 +
 +EXTERN_C BOOL WINAPI Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
 +{
 +    return (SHNotifyCreateDirectoryW(path, sec) == ERROR_SUCCESS);
 +}
 +
 +/************************************************************************
 + * Win32RemoveDirectory      [SHELL32.94]
 + *
 + * Deletes a directory. Also triggers a change notify if one exists.
 + *
 + * PARAMS
 + *  path       [I]   path to directory to delete
 + *
 + * RETURNS
 + *  TRUE if successful, FALSE otherwise
 + */
 +static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path)
 +{
 +    BOOL ret;
 +    TRACE("(%s)\n", debugstr_w(path));
 +
 +    ret = RemoveDirectoryW(path);
 +    if (!ret)
 +    {
 +      /* Directory may be write protected */
 +      DWORD dwAttr = GetFileAttributesW(path);
 +      if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY))
 +        if (SetFileAttributesW(path, dwAttr & ~FILE_ATTRIBUTE_READONLY))
 +          ret = RemoveDirectoryW(path);
 +    }
 +    if (ret)
 +    {
 +      SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, path, NULL);
 +      return ERROR_SUCCESS;
 +    }
 +    return GetLastError();
 +}
 +
 +/***********************************************************************/
 +
 +EXTERN_C BOOL WINAPI Win32RemoveDirectoryW(LPCWSTR path)
 +{
 +    return (SHNotifyRemoveDirectoryW(path) == ERROR_SUCCESS);
 +}
 +
 +/************************************************************************
 + * Win32DeleteFile           [SHELL32.164]
 + *
 + * Deletes a file. Also triggers a change notify if one exists.
 + *
 + * PARAMS
 + *  path       [I]   path to file to delete
 + *
 + * RETURNS
 + *  TRUE if successful, FALSE otherwise
 + */
 +static DWORD SHNotifyDeleteFileW(LPCWSTR path)
 +{
 +    BOOL ret;
 +
 +    TRACE("(%s)\n", debugstr_w(path));
 +
 +    ret = DeleteFileW(path);
 +    if (!ret)
 +    {
 +      /* File may be write protected or a system file */
 +      DWORD dwAttr = GetFileAttributesW(path);
 +      if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
 +        if (SetFileAttributesW(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
 +            ret = DeleteFileW(path);
 +    }
 +    if (ret)
 +    {
 +        SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, path, NULL);
 +        return ERROR_SUCCESS;
 +    }
 +    return GetLastError();
 +}
 +
 +/***********************************************************************/
 +
 +EXTERN_C DWORD WINAPI Win32DeleteFileW(LPCWSTR path)
 +{
 +    return (SHNotifyDeleteFileW(path) == ERROR_SUCCESS);
 +}
 +
 +/************************************************************************
 + * SHNotifyMoveFile          [internal]
 + *
 + * Moves a file. Also triggers a change notify if one exists.
 + *
 + * PARAMS
 + *  src        [I]   path to source file to move
 + *  dest       [I]   path to target file to move to
 + *
 + * RETURNS
 + *  ERORR_SUCCESS if successful
 + */
 +static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest, BOOL isdir)
 +{
 +    BOOL ret;
 +
 +    TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest));
 +
 +        ret = MoveFileExW(src, dest, MOVEFILE_REPLACE_EXISTING);
 +
 +        /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */
 +        if (!ret)
 +            ret = MoveFileW(src, dest);
 +
 +    if (!ret)
 +    {
 +      DWORD dwAttr;
 +
 +      dwAttr = SHFindAttrW(dest, FALSE);
 +      if (INVALID_FILE_ATTRIBUTES == dwAttr)
 +      {
 +        /* Source file may be write protected or a system file */
 +        dwAttr = GetFileAttributesW(src);
 +        if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
 +            if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
 +                ret = MoveFileW(src, dest);
 +      }
 +    }
 +    if (ret)
 +    {
 +        SHChangeNotify(isdir ? SHCNE_MKDIR : SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
 +        SHChangeNotify(isdir ? SHCNE_RMDIR : SHCNE_DELETE, SHCNF_PATHW, src, NULL);
 +        return ERROR_SUCCESS;
 +    }
 +    return GetLastError();
 +}
 +
 +static DWORD WINAPI SHOperationProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
 +{
 +    FILE_OPERATION_CONTEXT * Context;
 +    LARGE_INTEGER Progress;
 +
 +    /* get context */
 +    Context = (FILE_OPERATION_CONTEXT*)lpData;
 +
 +    if (TotalBytesTransferred.QuadPart)
 +    {
 +        Progress.QuadPart = (TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart;
 +    }
 +    else
 +    {
 +        Progress.QuadPart = 1;
 +    }
 +
 +    /* update progress bar */
 +    SendMessageW(Context->hDlgCtrl, PBM_SETPOS, (WPARAM)Progress.u.LowPart, 0);
 +
 +    if (TotalBytesTransferred.QuadPart == TotalFileSize.QuadPart)
 +    {
 +        /* file was copied */
 +        Context->Index++;
 +        PostMessageW(Context->hwndDlg, WM_FILE, 0, 0);
 +    }
 +
 +    return PROGRESS_CONTINUE;
 +}
 +
 +BOOL
 +QueueFile(
 +    FILE_OPERATION_CONTEXT * Context)
 +{
 +    FILE_ENTRY * from, *to = NULL;
 +    BOOL bRet = FALSE;
 +
 +    if (Context->Index >= Context->from->dwNumFiles)
 +        return FALSE;
 +
 +    /* get current file */
 +    from = &Context->from->feFiles[Context->Index];
 +
 +    if (Context->op->req->wFunc != FO_DELETE)
 +        to = &Context->to->feFiles[Context->Index];
 +
 +    /* update status */
 +    SetDlgItemTextW(Context->hwndDlg, 14001, from->szFullPath);
 +
 +    if (Context->op->req->wFunc == FO_COPY)
 +    {
 +        bRet = CopyFileExW(from->szFullPath, to->szFullPath, SHOperationProgressRoutine, (LPVOID)Context, &Context->op->bCancelled, 0);
 +    }
 +    else if (Context->op->req->wFunc == FO_MOVE)
 +    {
 +        //bRet = MoveFileWithProgressW(from->szFullPath, to->szFullPath, SHOperationProgressRoutine, (LPVOID)Context, MOVEFILE_COPY_ALLOWED);
 +    }
 +    else if (Context->op->req->wFunc == FO_DELETE)
 +    {
 +        bRet = DeleteFile(from->szFullPath);
 +    }
 +
 +    return bRet;
 +}
 +
 +static INT_PTR CALLBACK SHOperationDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 +{
 +    FILE_OPERATION_CONTEXT * Context;
 +
 +    Context = (FILE_OPERATION_CONTEXT*) GetWindowLongPtr(hwndDlg, DWLP_USER);
 +
 +    switch(uMsg)
 +    {
 +        case WM_INITDIALOG:
 +            SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)lParam);
 +
 +            /* get context */
 +            Context = (FILE_OPERATION_CONTEXT*)lParam;
 +
 +            /* store progress bar handle */
 +            Context->hDlgCtrl = GetDlgItem(hwndDlg, 14000);
 +
 +            /* store window handle */
 +            Context->hwndDlg = hwndDlg;
 +
 +            /* set progress bar range */
 +            (void)SendMessageW(Context->hDlgCtrl, (UINT) PBM_SETRANGE, 0, MAKELPARAM(0, 100));
 +
 +            /* start file queueing */
 +            SetTimer(hwndDlg, TIMER_ID, 1000, NULL);
 +            //QueueFile(Context);
 +
 +            return TRUE;
 +
 +        case WM_CLOSE:
 +            Context->op->bCancelled = TRUE;
 +            EndDialog(hwndDlg, Context->op->bCancelled);
 +            return TRUE;
 +
 +        case WM_COMMAND:
 +            if (LOWORD(wParam) == 14002)
 +            {
 +                Context->op->bCancelled = TRUE;
 +                EndDialog(hwndDlg, Context->op->bCancelled);
 +                return TRUE;
 +            }; break;
 +
 +        case WM_TIMER:
 +            if (wParam == TIMER_ID)
 +            {
 +                QueueFile(Context);
 +                KillTimer(hwndDlg, TIMER_ID);
 +            }; break;
 +
 +        case WM_FILE:
 +            if (!QueueFile(Context))
 +                EndDialog(hwndDlg, Context->op->bCancelled);
 +        default:
 +            break;
 +    }
 +    return FALSE;
 +}
 +
 +HRESULT
 +SHShowFileOperationDialog(FILE_OPERATION *op, FILE_LIST *flFrom, FILE_LIST *flTo)
 +{
 +    HWND hwnd;
 +    BOOL bRet;
 +    MSG msg;
 +    FILE_OPERATION_CONTEXT Context;
 +
 +    Context.from = flFrom;
 +    Context.to = flTo;
 +    Context.op = op;
 +    Context.Index = 0;
 +    Context.op->bCancelled = FALSE;
 +
 +    hwnd = CreateDialogParam(shell32_hInstance, MAKEINTRESOURCE(IDD_FILE_COPY), NULL, SHOperationDialog, (LPARAM)&Context);
 +    if (hwnd == NULL)
 +    {
 +        ERR("Failed to create dialog\n");
 +        return E_FAIL;
 +    }
 +    ShowWindow(hwnd, SW_SHOWNORMAL);
 +
 +    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
 +    {
 +        if (!IsWindow(hwnd) || !IsDialogMessage(hwnd, &msg))
 +        {
 +            TranslateMessage(&msg);
 +            DispatchMessage(&msg);
 +        }
 +    }
 +
 +    return NOERROR;
 +}
 +
 +
 +/************************************************************************
 + * SHNotifyCopyFile          [internal]
 + *
 + * Copies a file. Also triggers a change notify if one exists.
 + *
 + * PARAMS
 + *  src           [I]   path to source file to move
 + *  dest          [I]   path to target file to move to
 + *  bFailIfExists [I]   if TRUE, the target file will not be overwritten if
 + *                      a file with this name already exists
 + *
 + * RETURNS
 + *  ERROR_SUCCESS if successful
 + */
 +static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists)
 +{
 +    BOOL ret;
 +    DWORD attribs;
 +
 +    TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : "");
 +
 +    /* Destination file may already exist with read only attribute */
 +    attribs = GetFileAttributesW(dest);
 +    if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY))
 +        SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY);
 +
 +    if (GetFileAttributesW(dest) & FILE_ATTRIBUTE_READONLY)
 +    {
 +        SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY);
 +        if (GetFileAttributesW(dest) & FILE_ATTRIBUTE_READONLY)
 +        {
 +            TRACE("[shell32, SHNotifyCopyFileW] STILL SHIT\n");
 +        }
 +    }
 +
 +    ret = CopyFileW(src, dest, bFailIfExists);
 +    if (ret)
 +    {
 +        SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
 +        return ERROR_SUCCESS;
 +    }
 +
 +    return GetLastError();
 +}
 +
 +/*************************************************************************
 + * SHCreateDirectory         [SHELL32.165]
 + *
 + * This function creates a file system folder whose fully qualified path is
 + * given by path. If one or more of the intermediate folders do not exist,
 + * they will be created as well.
 + *
 + * PARAMS
 + *  hWnd       [I]
 + *  path       [I]   path of directory to create
 + *
 + * RETURNS
 + *  ERROR_SUCCESS or one of the following values:
 + *  ERROR_BAD_PATHNAME if the path is relative
 + *  ERROR_FILE_EXISTS when a file with that name exists
 + *  ERROR_PATH_NOT_FOUND can't find the path, probably invalid
 + *  ERROR_INVALID_NAME if the path contains invalid chars
 + *  ERROR_ALREADY_EXISTS when the directory already exists
 + *  ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
 + *
 + * NOTES
 + *  exported by ordinal
 + *  Win9x exports ANSI
 + *  WinNT/2000 exports Unicode
 + */
 +int WINAPI SHCreateDirectory(HWND hWnd, LPCWSTR path)
 +{
 +     return SHCreateDirectoryExW(hWnd, path, NULL);
 +}
 +
 +/*************************************************************************
 + * SHCreateDirectoryExA      [SHELL32.@]
 + *
 + * This function creates a file system folder whose fully qualified path is
 + * given by path. If one or more of the intermediate folders do not exist,
 + * they will be created as well.
 + *
 + * PARAMS
 + *  hWnd       [I]
 + *  path       [I]   path of directory to create
 + *  sec        [I]   security attributes to use or NULL
 + *
 + * RETURNS
 + *  ERROR_SUCCESS or one of the following values:
 + *  ERROR_BAD_PATHNAME or ERROR_PATH_NOT_FOUND if the path is relative
 + *  ERROR_INVALID_NAME if the path contains invalid chars
 + *  ERROR_FILE_EXISTS when a file with that name exists
 + *  ERROR_ALREADY_EXISTS when the directory already exists
 + *  ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
 + *
 + *  FIXME: Not implemented yet;
 + *  SHCreateDirectoryEx also verifies that the files in the directory will be visible
 + *  if the path is a network path to deal with network drivers which might have a limited
 + *  but unknown maximum path length. If not:
 + *
 + *  If hWnd is set to a valid window handle, a message box is displayed warning
 + *  the user that the files may not be accessible. If the user chooses not to
 + *  proceed, the function returns ERROR_CANCELLED.
 + *
 + *  If hWnd is set to NULL, no user interface is displayed and the function
 + *  returns ERROR_CANCELLED.
 + */
 +int WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec)
 +{
 +    LPWSTR wPath;
 +    DWORD retCode;
 +
 +    TRACE("(%s, %p)\n", debugstr_a(path), sec);
 +
 +    retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0);
 +    if (!retCode)
 +    {
 +        retCode = SHCreateDirectoryExW(hWnd, wPath, sec);
 +        SHELL32_FreeUnicodeBuf(wPath);
 +    }
 +    return retCode;
 +}
 +
 +/*************************************************************************
 + * SHCreateDirectoryExW      [SHELL32.@]
 + *
 + * See SHCreateDirectoryExA.
 + */
 +int WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
 +{
 +    int ret = ERROR_BAD_PATHNAME;
 +    TRACE("(%p, %s, %p)\n", hWnd, debugstr_w(path), sec);
 +
 +    if (PathIsRelativeW(path))
 +    {
 +      SetLastError(ret);
 +    }
 +    else
 +    {
 +        ret = SHNotifyCreateDirectoryW(path, sec);
 +        /* Refuse to work on certain error codes before trying to create directories recursively */
 +        if (ret != ERROR_SUCCESS &&
 +          ret != ERROR_FILE_EXISTS &&
 +          ret != ERROR_ALREADY_EXISTS &&
 +          ret != ERROR_FILENAME_EXCED_RANGE)
 +        {
 +            WCHAR *pEnd, *pSlash, szTemp[MAX_PATH + 1];  /* extra for PathAddBackslash() */
 +
 +            lstrcpynW(szTemp, path, MAX_PATH);
 +            pEnd = PathAddBackslashW(szTemp);
 +            pSlash = szTemp + 3;
 +
 +            while (*pSlash)
 +            {
 +                while (*pSlash && *pSlash != '\\') pSlash++;
 +                if (*pSlash)
 +                {
 +                    *pSlash = 0;    /* terminate path at separator */
 +
 +                    ret = SHNotifyCreateDirectoryW(szTemp, pSlash + 1 == pEnd ? sec : NULL);
 +                }
 +                *pSlash++ = '\\'; /* put the separator back */
 +            }
 +        }
 +
 +        if (ret && hWnd && (ERROR_CANCELLED != ret))
 +        {
 +            /* We failed and should show a dialog box */
 +            FIXME("Show system error message, creating path %s, failed with error %d\n", debugstr_w(path), ret);
 +            ret = ERROR_CANCELLED; /* Error has been already presented to user (not really yet!) */
 +        }
 +    }
 +
 +    return ret;
 +}
 +
 +/*************************************************************************
 + * SHFindAttrW      [internal]
 + *
 + * Get the Attributes for a file or directory. The difference to GetAttributes()
 + * is that this function will also work for paths containing wildcard characters
 + * in its filename.
 +
 + * PARAMS
 + *  path       [I]   path of directory or file to check
 + *  fileOnly   [I]   TRUE if only files should be found
 + *
 + * RETURNS
 + *  INVALID_FILE_ATTRIBUTES if the path does not exist, the actual attributes of
 + *  the first file or directory found otherwise
 + */
 +static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly)
 +{
 +    WIN32_FIND_DATAW wfd;
 +    BOOL b_FileMask = fileOnly && (NULL != StrPBrkW(pName, wWildcardChars));
 +    DWORD dwAttr = INVALID_FILE_ATTRIBUTES;
 +    HANDLE hFind = FindFirstFileW(pName, &wfd);
 +
 +    TRACE("%s %d\n", debugstr_w(pName), fileOnly);
 +    if (INVALID_HANDLE_VALUE != hFind)
 +    {
 +        do
 +        {
 +            if (b_FileMask && IsAttribDir(wfd.dwFileAttributes))
 +               continue;
 +            dwAttr = wfd.dwFileAttributes;
 +            break;
 +        } while (FindNextFileW(hFind, &wfd));
 +
 +      FindClose(hFind);
 +    }
 +    return dwAttr;
 +}
 +
 +/*************************************************************************
 + *
 + * _ConvertAtoW  helper function for SHFileOperationA
 + *
 + * Converts a string or string-list to unicode.
 + */
 +static DWORD _ConvertAtoW(PCSTR strSrc, PCWSTR* pStrDest, BOOL isList)
 +{
 +    *pStrDest = NULL;
 +
 +    // If the input is null, nothing to convert.
 +    if (!strSrc)
 +        return 0;
 +
 +    // Measure the total size, depending on if it's a zero-terminated list.
 +    int sizeA = 0;
 +    if (isList)
 +    {
 +        PCSTR tmpSrc = strSrc;
 +        int size;
 +        do
 +        {
 +            size = lstrlenA(tmpSrc) + 1;
 +            sizeA += size;
 +            tmpSrc += size;
 +        } while (size != 1);
 +    }
 +    else
 +    {
 +        sizeA = lstrlenA(strSrc) + 1;
 +    }
 +
 +    // Measure the needed allocation size.
 +    int sizeW = MultiByteToWideChar(CP_ACP, 0, strSrc, sizeA, NULL, 0);
 +    if (!sizeW)
 +        return GetLastError();
 +
 +    PWSTR strDest = (PWSTR) HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
 +    if (!strDest)
 +        return ERROR_OUTOFMEMORY;
 +
 +    int err = MultiByteToWideChar(CP_ACP, 0, strSrc, sizeA, strDest, sizeW);
 +    if (!err)
 +    {
 +        HeapFree(GetProcessHeap(), 0, strDest);
 +        return GetLastError();
 +    }
 +
 +    *pStrDest = strDest;
 +    return 0;
 +}
 +
 +/*************************************************************************
 + * SHFileOperationA          [SHELL32.@]
 + *
 + * Function to copy, move, delete and create one or more files with optional
 + * user prompts.
 + *
 + * PARAMS
 + *  lpFileOp   [I/O] pointer to a structure containing all the necessary information
 + *
 + * RETURNS
 + *  Success: ERROR_SUCCESS.
 + *  Failure: ERROR_CANCELLED.
 + *
 + * NOTES
 + *  exported by name
 + */
 +int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
 +{
 +    int errCode, retCode;
 +    SHFILEOPSTRUCTW nFileOp = { 0 };
 +
 +    // Convert A information to W
 +    nFileOp.hwnd = lpFileOp->hwnd;
 +    nFileOp.wFunc = lpFileOp->wFunc;
 +    nFileOp.fFlags = lpFileOp->fFlags;
 +
 +    errCode = _ConvertAtoW(lpFileOp->pFrom, &nFileOp.pFrom, TRUE);
 +    if (errCode != 0)
 +        goto cleanup;
 +
 +    if (FO_DELETE != (nFileOp.wFunc & FO_MASK))
 +    {
 +        errCode = _ConvertAtoW(lpFileOp->pTo, &nFileOp.pTo, TRUE);
 +        if (errCode != 0)
 +            goto cleanup;
 +    }
 +
 +    if (nFileOp.fFlags & FOF_SIMPLEPROGRESS)
 +    {
 +        errCode = _ConvertAtoW(lpFileOp->lpszProgressTitle, &nFileOp.lpszProgressTitle, FALSE);
 +        if (errCode != 0)
 +            goto cleanup;
 +    }
 +
 +    // Call the actual function
 +    retCode = SHFileOperationW(&nFileOp);
 +
 +    // Cleanup
 +cleanup:
 +    if (nFileOp.pFrom)
 +        HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.pFrom);
 +    if (nFileOp.pTo)
 +        HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.pTo);
 +    if (nFileOp.lpszProgressTitle)
 +        HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.lpszProgressTitle);
 +
 +    if (errCode != 0)
 +    {
 +        lpFileOp->fAnyOperationsAborted = TRUE;
 +        SetLastError(errCode);
 +
 +        return errCode;
 +    }
 +
 +    // Thankfully, starting with NT4 the name mappings are always unicode, so no need to convert.
 +    lpFileOp->hNameMappings = nFileOp.hNameMappings;
 +    lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
 +    return retCode;
 +}
 +
 +static void __inline grow_list(FILE_LIST *list)
 +{
 +    FILE_ENTRY *newx = (FILE_ENTRY *)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list->feFiles,
 +                                  list->num_alloc * 2 * sizeof(*newx) );
 +    list->feFiles = newx;
 +    list->num_alloc *= 2;
 +}
 +
 +/* adds a file to the FILE_ENTRY struct
 + */
 +static void add_file_to_entry(FILE_ENTRY *feFile, LPCWSTR szFile)
 +{
 +    DWORD dwLen = lstrlenW(szFile) + 1;
 +    LPCWSTR ptr;
 +
 +    feFile->szFullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
 +    lstrcpyW(feFile->szFullPath, szFile);
 +
 +    ptr = StrRChrW(szFile, NULL, '\\');
 +    if (ptr)
 +    {
 +        dwLen = ptr - szFile + 1;
 +        feFile->szDirectory = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
 +        lstrcpynW(feFile->szDirectory, szFile, dwLen);
 +
 +        dwLen = lstrlenW(feFile->szFullPath) - dwLen + 1;
 +        feFile->szFilename = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
 +        lstrcpyW(feFile->szFilename, ptr + 1); /* skip over backslash */
 +    }
 +    feFile->bFromWildcard = FALSE;
 +}
 +
 +static LPWSTR wildcard_to_file(LPCWSTR szWildCard, LPCWSTR szFileName)
 +{
 +    LPCWSTR ptr;
 +    LPWSTR szFullPath;
 +    DWORD dwDirLen, dwFullLen;
 +
 +    ptr = StrRChrW(szWildCard, NULL, '\\');
 +    dwDirLen = ptr - szWildCard + 1;
 +
 +    dwFullLen = dwDirLen + lstrlenW(szFileName) + 1;
 +    szFullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwFullLen * sizeof(WCHAR));
 +
 +    lstrcpynW(szFullPath, szWildCard, dwDirLen + 1);
 +    lstrcatW(szFullPath, szFileName);
 +
 +    return szFullPath;
 +}
 +
 +static void parse_wildcard_files(FILE_LIST *flList, LPCWSTR szFile, LPDWORD pdwListIndex)
 +{
 +    WIN32_FIND_DATAW wfd;
 +    HANDLE hFile = FindFirstFileW(szFile, &wfd);
 +    FILE_ENTRY *file;
 +    LPWSTR szFullPath;
 +    BOOL res;
 +
 +    if (hFile == INVALID_HANDLE_VALUE) return;
 +
 +    for (res = TRUE; res; res = FindNextFileW(hFile, &wfd))
 +    {
 +        if (IsDotDir(wfd.cFileName))
 +            continue;
 +
 +        if (*pdwListIndex >= flList->num_alloc)
 +            grow_list( flList );
 +
 +        szFullPath = wildcard_to_file(szFile, wfd.cFileName);
 +        file = &flList->feFiles[(*pdwListIndex)++];
 +        add_file_to_entry(file, szFullPath);
 +        file->bFromWildcard = TRUE;
 +        file->attributes = wfd.dwFileAttributes;
 +
 +        if (IsAttribDir(file->attributes))
 +            flList->bAnyDirectories = TRUE;
 +
 +        HeapFree(GetProcessHeap(), 0, szFullPath);
 +    }
 +
 +    FindClose(hFile);
 +}
 +
 +/* takes the null-separated file list and fills out the FILE_LIST */
 +static HRESULT parse_file_list(FILE_LIST *flList, LPCWSTR szFiles)
 +{
 +    LPCWSTR ptr = szFiles;
 +    WCHAR szCurFile[MAX_PATH];
 +    DWORD i = 0;
 +
 +    if (!szFiles)
 +        return ERROR_INVALID_PARAMETER;
 +
 +    flList->bAnyFromWildcard = FALSE;
 +    flList->bAnyDirectories = FALSE;
 +    flList->bAnyDontExist = FALSE;
 +    flList->num_alloc = 32;
 +    flList->dwNumFiles = 0;
 +
 +    /* empty list */
 +    if (!szFiles[0])
 +        return ERROR_ACCESS_DENIED;
 +
 +    flList->feFiles = (FILE_ENTRY *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
 +                                flList->num_alloc * sizeof(FILE_ENTRY));
 +
 +    while (*ptr)
 +    {
 +        if (i >= flList->num_alloc) grow_list( flList );
 +
 +        /* change relative to absolute path */
 +        if (PathIsRelativeW(ptr))
 +        {
 +            GetCurrentDirectoryW(MAX_PATH, szCurFile);
 +            PathCombineW(szCurFile, szCurFile, ptr);
 +            flList->feFiles[i].bFromRelative = TRUE;
 +        }
 +        else
 +        {
 +            lstrcpyW(szCurFile, ptr);
 +            flList->feFiles[i].bFromRelative = FALSE;
 +        }
 +
 +        /* parse wildcard files if they are in the filename */
 +        if (StrPBrkW(szCurFile, wWildcardChars))
 +        {
 +            parse_wildcard_files(flList, szCurFile, &i);
 +            flList->bAnyFromWildcard = TRUE;
 +            i--;
 +        }
 +        else
 +        {
 +            FILE_ENTRY *file = &flList->feFiles[i];
 +            add_file_to_entry(file, szCurFile);
 +            file->attributes = GetFileAttributesW( file->szFullPath );
 +            file->bExists = (file->attributes != INVALID_FILE_ATTRIBUTES);
 +
 +            if (!file->bExists)
 +                flList->bAnyDontExist = TRUE;
 +
 +            if (IsAttribDir(file->attributes))
 +                flList->bAnyDirectories = TRUE;
 +        }
 +
 +        /* advance to the next string */
 +        ptr += lstrlenW(ptr) + 1;
 +        i++;
 +    }
 +    flList->dwNumFiles = i;
 +
 +    return S_OK;
 +}
 +
 +/* free the FILE_LIST */
 +static void destroy_file_list(FILE_LIST *flList)
 +{
 +    DWORD i;
 +
 +    if (!flList || !flList->feFiles)
 +        return;
 +
 +    for (i = 0; i < flList->dwNumFiles; i++)
 +    {
 +        HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szDirectory);
 +        HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szFilename);
 +        HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szFullPath);
 +    }
 +
 +    HeapFree(GetProcessHeap(), 0, flList->feFiles);
 +}
 +
 +static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
 +{
 +    WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
 +    SHFILEOPSTRUCTW fileOp;
 +
 +    static const WCHAR wildCardFiles[] = {'*','.','*',0};
 +
 +    if (IsDotDir(feFrom->szFilename))
 +        return;
 +
 +    if (PathFileExistsW(szDestPath))
 +        PathCombineW(szTo, szDestPath, feFrom->szFilename);
 +    else
 +        lstrcpyW(szTo, szDestPath);
 +
 +    if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
 +    {
 +        if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FOLDER, feFrom->szFilename, op))
 +        {
 +            /* Vista returns an ERROR_CANCELLED even if user pressed "No" */
 +            if (!op->bManyItems)
 +                op->bCancelled = TRUE;
 +            return;
 +        }
 +    }
 +
 +    szTo[lstrlenW(szTo) + 1] = '\0';
 +    SHNotifyCreateDirectoryW(szTo, NULL);
 +
 +    PathCombineW(szFrom, feFrom->szFullPath, wildCardFiles);
 +    szFrom[lstrlenW(szFrom) + 1] = '\0';
 +
 +    fileOp = *op->req;
 +    fileOp.pFrom = szFrom;
 +    fileOp.pTo = szTo;
 +    fileOp.fFlags &= ~FOF_MULTIDESTFILES; /* we know we're copying to one dir */
 +
 +    /* Don't ask the user about overwriting files when he accepted to overwrite the
 +       folder. FIXME: this is not exactly what Windows does - e.g. there would be
 +       an additional confirmation for a nested folder */
 +    fileOp.fFlags |= FOF_NOCONFIRMATION;
 +
 +    SHFileOperationW(&fileOp);
 +}
 +
 +static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCHAR *szTo)
 +{
 +    if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
 +    {
 +        if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
 +            return 0;
 +    }
 +
 +    return SHNotifyCopyFileW(szFrom, szTo, FALSE) == 0;
 +}
 +
 +/* copy a file or directory to another directory */
 +static void copy_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
 +{
 +    if (!PathFileExistsW(feTo->szFullPath))
 +        SHNotifyCreateDirectoryW(feTo->szFullPath, NULL);
 +
 +    if (IsAttribFile(feFrom->attributes))
 +    {
 +        WCHAR szDestPath[MAX_PATH];
 +
 +        PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
 +        copy_file_to_file(op, feFrom->szFullPath, szDestPath);
 +    }
 +    else if (!(op->req->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
 +        copy_dir_to_dir(op, feFrom, feTo->szFullPath);
 +}
 +
 +static void create_dest_dirs(LPCWSTR szDestDir)
 +{
 +    WCHAR dir[MAX_PATH];
 +    LPCWSTR ptr = StrChrW(szDestDir, '\\');
 +
 +    /* make sure all directories up to last one are created */
 +    while (ptr && (ptr = StrChrW(ptr + 1, '\\')))
 +    {
 +        lstrcpynW(dir, szDestDir, ptr - szDestDir + 1);
 +
 +        if (!PathFileExistsW(dir))
 +            SHNotifyCreateDirectoryW(dir, NULL);
 +    }
 +
 +    /* create last directory */
 +    if (!PathFileExistsW(szDestDir))
 +        SHNotifyCreateDirectoryW(szDestDir, NULL);
 +}
 +
 +/* the FO_COPY operation */
 +static HRESULT copy_files(FILE_OPERATION *op, const FILE_LIST *flFrom, FILE_LIST *flTo)
 +{
 +    DWORD i;
 +    const FILE_ENTRY *entryToCopy;
 +    const FILE_ENTRY *fileDest = &flTo->feFiles[0];
 +
 +    if (flFrom->bAnyDontExist)
 +        return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
 +
 +    if (flTo->dwNumFiles == 0)
 +    {
 +        /* If the destination is empty, SHFileOperation should use the current directory */
 +        WCHAR curdir[MAX_PATH+1];
 +
 +        GetCurrentDirectoryW(MAX_PATH, curdir);
 +        curdir[lstrlenW(curdir)+1] = 0;
 +
 +        destroy_file_list(flTo);
 +        ZeroMemory(flTo, sizeof(FILE_LIST));
 +        parse_file_list(flTo, curdir);
 +        fileDest = &flTo->feFiles[0];
 +    }
 +
 +    if (op->req->fFlags & FOF_MULTIDESTFILES)
 +    {
 +        if (flFrom->bAnyFromWildcard)
 +            return ERROR_CANCELLED;
 +
 +        if (flFrom->dwNumFiles != flTo->dwNumFiles)
 +        {
 +            if (flFrom->dwNumFiles != 1 && !IsAttribDir(fileDest->attributes))
 +                return ERROR_CANCELLED;
 +
 +            /* Free all but the first entry. */
 +            for (i = 1; i < flTo->dwNumFiles; i++)
 +            {
 +                HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szDirectory);
 +                HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szFilename);
 +                HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szFullPath);
 +            }
 +
 +            flTo->dwNumFiles = 1;
 +        }
 +        else if (IsAttribDir(fileDest->attributes))
 +        {
 +            for (i = 1; i < flTo->dwNumFiles; i++)
 +                if (!IsAttribDir(flTo->feFiles[i].attributes) ||
 +                    !IsAttribDir(flFrom->feFiles[i].attributes))
 +                {
 +                    return ERROR_CANCELLED;
 +                }
 +        }
 +    }
 +    else if (flFrom->dwNumFiles != 1)
 +    {
 +        if (flTo->dwNumFiles != 1 && !IsAttribDir(fileDest->attributes))
 +            return ERROR_CANCELLED;
 +
 +        if (PathFileExistsW(fileDest->szFullPath) &&
 +            IsAttribFile(fileDest->attributes))
 +        {
 +            return ERROR_CANCELLED;
 +        }
 +
 +        if (flTo->dwNumFiles == 1 && fileDest->bFromRelative &&
 +            !PathFileExistsW(fileDest->szFullPath))
 +        {
 +            return ERROR_CANCELLED;
 +        }
 +    }
 +
 +    for (i = 0; i < flFrom->dwNumFiles; i++)
 +    {
 +        entryToCopy = &flFrom->feFiles[i];
 +
 +        if ((op->req->fFlags & FOF_MULTIDESTFILES) &&
 +            flTo->dwNumFiles > 1)
 +        {
 +            fileDest = &flTo->feFiles[i];
 +        }
 +
 +        if (IsAttribDir(entryToCopy->attributes) &&
 +            !lstrcmpiW(entryToCopy->szFullPath, fileDest->szDirectory))
 +        {
 +            return ERROR_SUCCESS;
 +        }
 +
 +        create_dest_dirs(fileDest->szDirectory);
 +
 +        if (!lstrcmpiW(entryToCopy->szFullPath, fileDest->szFullPath))
 +        {
 +            if (IsAttribFile(entryToCopy->attributes))
 +                return ERROR_NO_MORE_SEARCH_HANDLES;
 +            else
 +                return ERROR_SUCCESS;
 +        }
 +
 +        if ((flFrom->dwNumFiles > 1 && flTo->dwNumFiles == 1) ||
 +            IsAttribDir(fileDest->attributes))
 +        {
 +            copy_to_dir(op, entryToCopy, fileDest);
 +        }
 +        else if (IsAttribDir(entryToCopy->attributes))
 +        {
 +            copy_dir_to_dir(op, entryToCopy, fileDest->szFullPath);
 +        }
 +        else
 +        {
 +            if (!copy_file_to_file(op, entryToCopy->szFullPath, fileDest->szFullPath))
 +            {
 +                op->req->fAnyOperationsAborted = TRUE;
 +                return ERROR_CANCELLED;
 +            }
 +        }
 +
 +        /* Vista return code. XP would return e.g. ERROR_FILE_NOT_FOUND, ERROR_ALREADY_EXISTS */
 +        if (op->bCancelled)
 +            return ERROR_CANCELLED;
 +    }
 +
 +    /* Vista return code. On XP if the used pressed "No" for the last item,
 +     * ERROR_ARENA_TRASHED would be returned */
 +    return ERROR_SUCCESS;
 +}
 +
 +static BOOL confirm_delete_list(HWND hWnd, DWORD fFlags, BOOL fTrash, const FILE_LIST *flFrom)
 +{
 +    if (flFrom->dwNumFiles > 1)
 +    {
 +        WCHAR tmp[8];
 +        const WCHAR format[] = {'%','d',0};
 +
 +        wnsprintfW(tmp, sizeof(tmp)/sizeof(tmp[0]), format, flFrom->dwNumFiles);
 +        return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_MULTIPLE_ITEM:ASK_DELETE_MULTIPLE_ITEM), tmp, NULL);
 +    }
 +    else
 +    {
 +        const FILE_ENTRY *fileEntry = &flFrom->feFiles[0];
 +
 +        if (IsAttribFile(fileEntry->attributes))
 +            return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FILE:ASK_DELETE_FILE), fileEntry->szFullPath, NULL);
 +        else if (!(fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
 +            return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FOLDER:ASK_DELETE_FOLDER), fileEntry->szFullPath, NULL);
 +    }
 +    return TRUE;
 +}
 +
 +/* the FO_DELETE operation */
 +static HRESULT delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom)
 +{
 +    const FILE_ENTRY *fileEntry;
 +    DWORD i;
 +    BOOL bPathExists;
 +    BOOL bTrash;
 +
 +    if (!flFrom->dwNumFiles)
 +        return ERROR_SUCCESS;
 +
 +    /* Windows also checks only the first item */
 +    bTrash = (lpFileOp->fFlags & FOF_ALLOWUNDO)
 +        && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath);
 +
 +    if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (!bTrash && lpFileOp->fFlags & FOF_WANTNUKEWARNING))
 +        if (!confirm_delete_list(lpFileOp->hwnd, lpFileOp->fFlags, bTrash, flFrom))
 +        {
 +            lpFileOp->fAnyOperationsAborted = TRUE;
 +            return 0;
 +        }
 +
 +    for (i = 0; i < flFrom->dwNumFiles; i++)
 +    {
 +        bPathExists = TRUE;
 +        fileEntry = &flFrom->feFiles[i];
 +
 +        if (!IsAttribFile(fileEntry->attributes) &&
 +            (lpFileOp->fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
 +            continue;
 +
 +        if (bTrash)
 +        {
 +            BOOL bDelete;
 +            if (TRASH_TrashFile(fileEntry->szFullPath))
 +            {
 +                SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, fileEntry->szFullPath, NULL);
 +                continue;
 +            }
 +
 +            /* Note: Windows silently deletes the file in such a situation, we show a dialog */
 +            if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (lpFileOp->fFlags & FOF_WANTNUKEWARNING))
 +                bDelete = SHELL_ConfirmDialogW(lpFileOp->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL);
 +            else
 +                bDelete = TRUE;
 +
 +            if (!bDelete)
 +            {
 +                lpFileOp->fAnyOperationsAborted = TRUE;
 +                break;
 +            }
 +        }
 +
 +        /* delete the file or directory */
 +        if (IsAttribFile(fileEntry->attributes))
 +        {
 +            bPathExists = DeleteFileW(fileEntry->szFullPath);
 +            SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, fileEntry->szFullPath, NULL);
 +        }
 +        else
 +            bPathExists = SHELL_DeleteDirectoryW(lpFileOp->hwnd, fileEntry->szFullPath, FALSE);
 +
 +        if (!bPathExists)
 +        {
 +            DWORD err = GetLastError();
 +
 +            if (ERROR_FILE_NOT_FOUND == err)
 +            {
 +                // This is a windows 2003 server specific value which ahs been removed.
 +                // Later versions of windows return ERROR_FILE_NOT_FOUND.
 +                return 1026;
 +            }
 +            else
 +            {
 +                return err;
 +            }
 +        }
 +    }
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +static void move_dir_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
 +{
 +    WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
 +    SHFILEOPSTRUCTW fileOp;
 +
 +    static const WCHAR wildCardFiles[] = {'*','.','*',0};
 +
 +    if (IsDotDir(feFrom->szFilename))
 +        return;
 +
 +    SHNotifyCreateDirectoryW(szDestPath, NULL);
 +
 +    PathCombineW(szFrom, feFrom->szFullPath, wildCardFiles);
 +    szFrom[lstrlenW(szFrom) + 1] = '\0';
 +
 +    lstrcpyW(szTo, szDestPath);
 +    szTo[lstrlenW(szDestPath) + 1] = '\0';
 +
 +    fileOp = *lpFileOp;
 +    fileOp.pFrom = szFrom;
 +    fileOp.pTo = szTo;
 +
 +    SHFileOperationW(&fileOp);
 +}
 +
 +/* moves a file or directory to another directory */
 +static void move_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
 +{
 +    WCHAR szDestPath[MAX_PATH];
 +
 +    PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
 +
 +    if (IsAttribFile(feFrom->attributes))
 +        SHNotifyMoveFileW(feFrom->szFullPath, szDestPath, FALSE);
 +    else if (!(lpFileOp->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
 +        move_dir_to_dir(lpFileOp, feFrom, szDestPath);
 +}
 +
 +/* the FO_MOVE operation */
 +static HRESULT move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, const FILE_LIST *flTo)
 +{
 +    DWORD i;
 +    const FILE_ENTRY *entryToMove;
 +    const FILE_ENTRY *fileDest;
 +
 +    if (!flFrom->dwNumFiles || !flTo->dwNumFiles)
 +        return ERROR_CANCELLED;
 +
 +    if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
 +        flTo->dwNumFiles > 1 && flFrom->dwNumFiles > 1)
 +    {
 +        return ERROR_CANCELLED;
 +    }
 +
 +    if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
 +        !flFrom->bAnyDirectories &&
 +        flFrom->dwNumFiles > flTo->dwNumFiles)
 +    {
 +        return ERROR_CANCELLED;
 +    }
 +
 +    if (!PathFileExistsW(flTo->feFiles[0].szDirectory))
 +        return ERROR_CANCELLED;
 +
 +    if ((lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
 +        flFrom->dwNumFiles != flTo->dwNumFiles)
 +    {
 +        return ERROR_CANCELLED;
 +    }
 +
 +    fileDest = &flTo->feFiles[0];
 +    for (i = 0; i < flFrom->dwNumFiles; i++)
 +    {
 +        entryToMove = &flFrom->feFiles[i];
 +
 +        if (lpFileOp->fFlags & FOF_MULTIDESTFILES)
 +            fileDest = &flTo->feFiles[i];
 +
 +        if (!PathFileExistsW(fileDest->szDirectory))
 +            return ERROR_CANCELLED;
 +
 +        if (fileDest->bExists && IsAttribDir(fileDest->attributes))
 +            move_to_dir(lpFileOp, entryToMove, fileDest);
 +        else
 +            SHNotifyMoveFileW(entryToMove->szFullPath, fileDest->szFullPath, IsAttribDir(entryToMove->attributes));
 +    }
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +/* the FO_RENAME files */
 +static HRESULT rename_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, const FILE_LIST *flTo)
 +{
 +    const FILE_ENTRY *feFrom;
 +    const FILE_ENTRY *feTo;
 +
 +    if (flFrom->dwNumFiles != 1)
 +        return ERROR_GEN_FAILURE;
 +
 +    if (flTo->dwNumFiles != 1)
 +        return ERROR_CANCELLED;
 +
 +    feFrom = &flFrom->feFiles[0];
 +    feTo= &flTo->feFiles[0];
 +
 +    /* fail if destination doesn't exist */
 +    if (!feFrom->bExists)
 +        return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
 +
 +    /* fail if destination already exists */
 +    if (feTo->bExists)
 +        return ERROR_ALREADY_EXISTS;
 +
 +    return SHNotifyMoveFileW(feFrom->szFullPath, feTo->szFullPath, IsAttribDir(feFrom->attributes));
 +}
 +
 +/* alert the user if an unsupported flag is used */
 +static void check_flags(FILEOP_FLAGS fFlags)
 +{
 +    WORD wUnsupportedFlags = FOF_NO_CONNECTED_ELEMENTS |
 +        FOF_NOCOPYSECURITYATTRIBS | FOF_NORECURSEREPARSE |
 +        FOF_RENAMEONCOLLISION | FOF_WANTMAPPINGHANDLE;
 +
 +    if (fFlags & wUnsupportedFlags)
 +        FIXME("Unsupported flags: %04x\n", fFlags);
 +}
 +
 +/*************************************************************************
 + * SHFileOperationW          [SHELL32.@]
 + *
 + * See SHFileOperationA
 + */
 +int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
 +{
 +    FILE_OPERATION op;
 +    FILE_LIST flFrom, flTo;
 +    int ret = 0;
 +
 +    if (!lpFileOp)
 +        return ERROR_INVALID_PARAMETER;
 +
 +    check_flags(lpFileOp->fFlags);
 +
 +    ZeroMemory(&flFrom, sizeof(FILE_LIST));
 +    ZeroMemory(&flTo, sizeof(FILE_LIST));
 +
 +    if ((ret = parse_file_list(&flFrom, lpFileOp->pFrom)))
 +        return ret;
 +
 +    if (lpFileOp->wFunc != FO_DELETE)
 +        parse_file_list(&flTo, lpFileOp->pTo);
 +
 +    ZeroMemory(&op, sizeof(op));
 +    op.req = lpFileOp;
 +    op.bManyItems = (flFrom.dwNumFiles > 1);
 +
 +    switch (lpFileOp->wFunc)
 +    {
 +        case FO_COPY:
 +            ret = copy_files(&op, &flFrom, &flTo);
 +            break;
 +        case FO_DELETE:
 +            ret = delete_files(lpFileOp, &flFrom);
 +            break;
 +        case FO_MOVE:
 +            ret = move_files(lpFileOp, &flFrom, &flTo);
 +            break;
 +        case FO_RENAME:
 +            ret = rename_files(lpFileOp, &flFrom, &flTo);
 +            break;
 +        default:
 +            ret = ERROR_INVALID_PARAMETER;
 +            break;
 +    }
 +
 +    destroy_file_list(&flFrom);
 +
 +    if (lpFileOp->wFunc != FO_DELETE)
 +        destroy_file_list(&flTo);
 +
 +    if (ret == ERROR_CANCELLED)
 +        lpFileOp->fAnyOperationsAborted = TRUE;
 +
 +    return ret;
 +}
 +
 +// Used by SHFreeNameMappings
 +static int CALLBACK _DestroyCallback(void *p, void *pData)
 +{
 +    LPSHNAMEMAPPINGW lp = (SHNAMEMAPPINGW *)p;
 +
 +    SHFree(lp->pszOldPath);
 +    SHFree(lp->pszNewPath);
 +
 +    return TRUE;
 +}
 +
 +/*************************************************************************
 + * SHFreeNameMappings      [shell32.246]
 + *
 + * Free the mapping handle returned by SHFileOperation if FOF_WANTSMAPPINGHANDLE
 + * was specified.
 + *
 + * PARAMS
 + *  hNameMapping [I] handle to the name mappings used during renaming of files
 + *
 + * RETURNS
 + *  Nothing
 + */
 +void WINAPI SHFreeNameMappings(HANDLE hNameMapping)
 +{
 +    if (hNameMapping)
 +    {
 +        DSA_DestroyCallback((HDSA) hNameMapping, _DestroyCallback, NULL);
 +    }
 +}
 +
 +/*************************************************************************
 + * SheGetDirA [SHELL32.@]
 + *
 + * drive = 0: returns the current directory path
 + * drive > 0: returns the current directory path of the specified drive
 + *            drive=1 -> A:  drive=2 -> B:  ...
 + * returns 0 if successful
 +*/
 +EXTERN_C DWORD WINAPI SheGetDirA(DWORD drive, LPSTR buffer)
 +{
 +    WCHAR org_path[MAX_PATH];
 +    DWORD ret;
 +    char drv_path[3];
 +
 +    /* change current directory to the specified drive */
 +    if (drive) {
 +        strcpy(drv_path, "A:");
 +        drv_path[0] += (char)drive-1;
 +
 +        GetCurrentDirectoryW(MAX_PATH, org_path);
 +
 +        SetCurrentDirectoryA(drv_path);
 +    }
 +
 +    /* query current directory path of the specified drive */
 +    ret = GetCurrentDirectoryA(MAX_PATH, buffer);
 +
 +    /* back to the original drive */
 +    if (drive)
 +        SetCurrentDirectoryW(org_path);
 +
 +    if (!ret)
 +        return GetLastError();
 +
 +    return 0;
 +}
 +
 +/*************************************************************************
 + * SheGetDirW [SHELL32.@]
 + *
 + * drive = 0: returns the current directory path
 + * drive > 0: returns the current directory path of the specified drive
 + *            drive=1 -> A:  drive=2 -> B:  ...
 + * returns 0 if successful
 + */
 +EXTERN_C DWORD WINAPI SheGetDirW(DWORD drive, LPWSTR buffer)
 +{
 +    WCHAR org_path[MAX_PATH];
 +    DWORD ret;
 +    char drv_path[3];
 +
 +    /* change current directory to the specified drive */
 +    if (drive)
 +    {
 +        strcpy(drv_path, "A:");
 +        drv_path[0] += (char)drive-1;
 +
 +        GetCurrentDirectoryW(MAX_PATH, org_path);
 +
 +        SetCurrentDirectoryA(drv_path);
 +    }
 +
 +    /* query current directory path of the specified drive */
 +    ret = GetCurrentDirectoryW(MAX_PATH, buffer);
 +
 +    /* back to the original drive */
 +    if (drive)
 +        SetCurrentDirectoryW(org_path);
 +
 +    if (!ret)
 +        return GetLastError();
 +
 +    return 0;
 +}
 +
 +/*************************************************************************
 + * SheChangeDirA [SHELL32.@]
 + *
 + * changes the current directory to the specified path
 + * and returns 0 if successful
 + */
 +EXTERN_C DWORD WINAPI SheChangeDirA(LPSTR path)
 +{
 +    if (SetCurrentDirectoryA(path))
 +        return 0;
 +    else
 +        return GetLastError();
 +}
 +
 +/*************************************************************************
 + * SheChangeDirW [SHELL32.@]
 + *
 + * changes the current directory to the specified path
 + * and returns 0 if successful
 + */
 +EXTERN_C DWORD WINAPI SheChangeDirW(LPWSTR path)
 +{
 +    if (SetCurrentDirectoryW(path))
 +        return 0;
 +    else
 +        return GetLastError();
 +}
 +
 +/*************************************************************************
 + * IsNetDrive            [SHELL32.66]
 + */
 +EXTERN_C int WINAPI IsNetDrive(int drive)
 +{
 +    char root[4];
 +    strcpy(root, "A:\\");
 +    root[0] += (char)drive;
 +    return (GetDriveTypeA(root) == DRIVE_REMOTE);
 +}
 +
 +
 +/*************************************************************************
 + * RealDriveType                [SHELL32.524]
 + */
 +EXTERN_C INT WINAPI RealDriveType(INT drive, BOOL bQueryNet)
 +{
 +    char root[] = "A:\\";
 +    root[0] += (char)drive;
 +    return GetDriveTypeA(root);
 +}
 +
 +/***********************************************************************
 + *              SHPathPrepareForWriteW (SHELL32.@)
 + */
 +EXTERN_C HRESULT WINAPI SHPathPrepareForWriteW(HWND hwnd, IUnknown *modless, LPCWSTR path, DWORD flags)
 +{
 +    DWORD res;
 +    DWORD err;
 +    LPCWSTR realpath;
 +    int len;
 +    WCHAR* last_slash;
 +    WCHAR* temppath=NULL;
 +
 +    TRACE("%p %p %s 0x%80x\n", hwnd, modless, debugstr_w(path), flags);
 +
 +    if (flags & ~(SHPPFW_DIRCREATE|SHPPFW_ASKDIRCREATE|SHPPFW_IGNOREFILENAME))
 +        FIXME("unimplemented flags 0x%08x\n", flags);
 +
 +    /* cut off filename if necessary */
 +    if (flags & SHPPFW_IGNOREFILENAME)
 +    {
 +        last_slash = StrRChrW(path, NULL, '\\');
 +        if (last_slash == NULL)
 +            len = 1;
 +        else
 +            len = last_slash - path + 1;
 +        temppath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        if (!temppath)
 +            return E_OUTOFMEMORY;
 +        StrCpyNW(temppath, path, len);
 +        realpath = temppath;
 +    }
 +    else
 +    {
 +        realpath = path;
 +    }
 +
 +    /* try to create the directory if asked to */
 +    if (flags & (SHPPFW_DIRCREATE|SHPPFW_ASKDIRCREATE))
 +    {
 +        if (flags & SHPPFW_ASKDIRCREATE)
 +            FIXME("treating SHPPFW_ASKDIRCREATE as SHPPFW_DIRCREATE\n");
 +
 +        SHCreateDirectoryExW(0, realpath, NULL);
 +    }
 +
 +    /* check if we can access the directory */
 +    res = GetFileAttributesW(realpath);
 +
 +    HeapFree(GetProcessHeap(), 0, temppath);
 +
 +    if (res == INVALID_FILE_ATTRIBUTES)
 +    {
 +        err = GetLastError();
 +        if (err == ERROR_FILE_NOT_FOUND)
 +            return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
 +        return HRESULT_FROM_WIN32(err);
 +    }
 +    else if (res & FILE_ATTRIBUTE_DIRECTORY)
 +        return S_OK;
 +    else
 +        return HRESULT_FROM_WIN32(ERROR_DIRECTORY);
 +}
 +
 +/***********************************************************************
 + *              SHPathPrepareForWriteA (SHELL32.@)
 + */
 +EXTERN_C HRESULT WINAPI SHPathPrepareForWriteA(HWND hwnd, IUnknown *modless, LPCSTR path, DWORD flags)
 +{
 +    WCHAR wpath[MAX_PATH];
 +    MultiByteToWideChar( CP_ACP, 0, path, -1, wpath, MAX_PATH);
 +    return SHPathPrepareForWriteW(hwnd, modless, wpath, flags);
 +}
@@@ -8,7 -8,7 +8,7 @@@
  
  #include "precomp.h"
  
- #define NDEBUG
//#define NDEBUG
  #include <debug.h>
  
  /*
@@@ -1984,7 -1984,7 +1984,7 @@@ FinishDlgProc(HWND hwndDlg
              PSETUPDATA SetupData = (PSETUPDATA)((LPPROPSHEETPAGE)lParam)->lParam;
  
              /* Run the Wine Gecko prompt */
-             Control_RunDLLW(GetDesktopWindow(), 0, L"appwiz.cpl install_gecko", SW_SHOW);
+             Control_RunDLLW(hwndDlg, 0, L"appwiz.cpl install_gecko", SW_SHOW);
  
              /* Set title font */
              SendDlgItemMessage(hwndDlg,
@@@ -24,6 -24,7 +24,7 @@@ VfatCleanupFile
      PVFAT_IRP_CONTEXT IrpContext)
  {
      PVFATFCB pFcb;
+     PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
      PFILE_OBJECT FileObject = IrpContext->FileObject;
  
      DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
@@@ -37,6 -38,7 +38,7 @@@
      if (pFcb->Flags & FCB_IS_VOLUME)
      {
          pFcb->OpenHandleCount--;
+         DeviceExt->OpenHandleCount--;
  
          if (pFcb->OpenHandleCount != 0)
          {
@@@ -63,6 -65,7 +65,7 @@@
                             FileObject->FsContext2);
  
          pFcb->OpenHandleCount--;
+         DeviceExt->OpenHandleCount--;
  
          if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
              FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
@@@ -89,6 -92,7 +92,7 @@@
                  pFcb->FileObject = NULL;
                  CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
                  ObDereferenceObject(tmpFileObject);
+                 vfatReleaseFCB(IrpContext->DeviceExt, pFcb);
              }
  
              CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, FALSE);
@@@ -365,7 -365,6 +365,6 @@@ VfatOpenFile
          DPRINT("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
  
          *ParentFcb = FileObject->RelatedFileObject->FsContext;
-         vfatGrabFCB(DeviceExt, *ParentFcb);
      }
      else
      {
@@@ -473,10 -472,18 +472,18 @@@ VfatCreateFile
          return STATUS_INVALID_PARAMETER;
      }
  
+     /* Deny create if the volume is locked */
+     if (DeviceExt->Flags & VCB_VOLUME_LOCKED)
+     {
+         return STATUS_ACCESS_DENIED;
+     }
      /* This a open operation for the volume itself */
      if (FileObject->FileName.Length == 0 &&
          (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
      {
+         DPRINT1("Volume opening\n");
          if (RequestedDisposition != FILE_OPEN &&
              RequestedDisposition != FILE_OPEN_IF)
          {
  
          pFcb = DeviceExt->VolumeFcb;
          vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject);
+         DeviceExt->OpenHandleCount++;
  
          Irp->IoStatus.Information = FILE_OPENED;
          return STATUS_SUCCESS;
              }
  
              pFcb->OpenHandleCount++;
+             DeviceExt->OpenHandleCount++;
          }
          else if (ParentFcb != NULL)
          {
      }
  
      pFcb->OpenHandleCount++;
+     DeviceExt->OpenHandleCount++;
  
      /* FIXME : test write access if requested */
  
@@@ -396,30 -396,41 +396,41 @@@ vfatPrepareTargetForRename
      /* If it exists */
      if (NT_SUCCESS(Status))
      {
+         DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName, TargetFcb->Flags);
          /* Check whether we are allowed to replace */
          if (ReplaceIfExists)
          {
              /* If that's a directory or a read-only file, we're not allowed */
-             if (vfatFCBIsDirectory(TargetFcb) || ((*TargetFcb->Attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY));
+             if (vfatFCBIsDirectory(TargetFcb) || ((*TargetFcb->Attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY))
              {
+                 DPRINT("And this is a readonly file!\n");
                  vfatReleaseFCB(DeviceExt, *ParentFCB);
                  *ParentFCB = NULL;
                  vfatReleaseFCB(DeviceExt, TargetFcb);
                  return STATUS_OBJECT_NAME_COLLISION;
              }
  
-             /* Attempt to flush (might close the file) */
-             if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
+             /* If we still have a file object, close it. */
+             if (TargetFcb->FileObject)
              {
-                 vfatReleaseFCB(DeviceExt, *ParentFCB);
-                 *ParentFCB = NULL;
-                 vfatReleaseFCB(DeviceExt, TargetFcb);
-                 return STATUS_ACCESS_DENIED;
+                 if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
+                 {
+                     DPRINT("MmFlushImageSection failed.\n");
+                     vfatReleaseFCB(DeviceExt, *ParentFCB);
+                     *ParentFCB = NULL;
+                     vfatReleaseFCB(DeviceExt, TargetFcb);
+                     return STATUS_ACCESS_DENIED;
+                 }
+                 TargetFcb->FileObject->DeletePending = TRUE;
+                 VfatCloseFile(DeviceExt, TargetFcb->FileObject);
              }
  
-             /* If we are, ensure the file isn't open by anyone! */
+             /* If we are here, ensure the file isn't open by anyone! */
              if (TargetFcb->OpenHandleCount != 0)
              {
+                 DPRINT("There are still open handles for this file.\n");
                  vfatReleaseFCB(DeviceExt, *ParentFCB);
                  *ParentFCB = NULL;
                  vfatReleaseFCB(DeviceExt, TargetFcb);
              }
  
              /* Effectively delete old file to allow renaming */
+             DPRINT("Effectively deleting the file.\n");
              VfatDelEntry(DeviceExt, TargetFcb, NULL);
-             vfatGrabFCB(DeviceExt, *ParentFCB);
              vfatReleaseFCB(DeviceExt, TargetFcb);
              *Deleted = TRUE;
+             return STATUS_SUCCESS;
          }
          else
          {
@@@ -612,6 -612,8 +612,8 @@@ VfatMount
      FsRtlNotifyInitializeSync(&DeviceExt->NotifySync);
      InitializeListHead(&DeviceExt->NotifyList);
  
+     DPRINT1("Mount success\n");
      Status = STATUS_SUCCESS;
  
  ByeBye:
@@@ -855,6 -857,72 +857,72 @@@ VfatMarkVolumeDirty
      return Status;
  }
  
+ static
+ NTSTATUS
+ VfatLockOrUnlockVolume(
+     PVFAT_IRP_CONTEXT IrpContext,
+     BOOLEAN Lock)
+ {
+     PFILE_OBJECT FileObject;
+     PDEVICE_EXTENSION DeviceExt;
+     DPRINT1("VfatLockOrUnlockVolume(%p, %d)\n", IrpContext, Lock);
+     DeviceExt = IrpContext->DeviceExt;
+     FileObject = IrpContext->FileObject;
+     /* Only allow locking with the volume open */
+     if (FileObject->FsContext != DeviceExt->VolumeFcb)
+     {
+         return STATUS_ACCESS_DENIED;
+     }
+     /* Bail out if it's already in the demanded state */
+     if (((DeviceExt->Flags & VCB_VOLUME_LOCKED) && Lock) ||
+         (!(DeviceExt->Flags & VCB_VOLUME_LOCKED) && !Lock))
+     {
+         return STATUS_ACCESS_DENIED;
+     }
+     /* Deny locking if we're not alone */
+     if (Lock && DeviceExt->OpenHandleCount != 1)
+     {
+         return STATUS_ACCESS_DENIED;
+     }
+     /* Finally, proceed */
+     if (Lock)
+     {
+         DeviceExt->Flags |= VCB_VOLUME_LOCKED;
+     }
+     else
+     {
+         DeviceExt->Flags &= ~VCB_VOLUME_LOCKED;
+     }
+     return STATUS_SUCCESS;
+ }
+ static
+ NTSTATUS
+ VfatDismountVolume(
+     PVFAT_IRP_CONTEXT IrpContext)
+ {
+     PDEVICE_EXTENSION DeviceExt;
+     DPRINT1("VfatDismountVolume(%p)\n", IrpContext);
+     DeviceExt = IrpContext->DeviceExt;
+     if (!(DeviceExt->Flags & VCB_VOLUME_LOCKED))
+     {
+         return STATUS_ACCESS_DENIED;
+     }
+     UNIMPLEMENTED;
+     return STATUS_NOT_IMPLEMENTED;
+ }
  /*
   * FUNCTION: File system control
   */
@@@ -898,6 -966,18 +966,18 @@@ VfatFileSystemControl
                      Status = VfatMarkVolumeDirty(IrpContext);
                      break;
  
+                 case FSCTL_LOCK_VOLUME:
+                     Status = VfatLockOrUnlockVolume(IrpContext, TRUE);
+                     break;
+                 case FSCTL_UNLOCK_VOLUME:
+                     Status = VfatLockOrUnlockVolume(IrpContext, FALSE);
+                     break;
+                 case FSCTL_DISMOUNT_VOLUME:
+                     Status = VfatDismountVolume(IrpContext);
+                     break;
                  default:
                      Status = STATUS_INVALID_DEVICE_REQUEST;
              }
@@@ -296,6 -296,9 +296,9 @@@ typedef struct DEVICE_EXTENSIO
      /* Notifications */
      LIST_ENTRY NotifyList;
      PNOTIFY_SYNC NotifySync;
+     /* Incremented on IRP_MJ_CREATE, decremented on IRP_MJ_CLEANUP */
+     ULONG OpenHandleCount;
  } DEVICE_EXTENSION, VCB, *PVCB;
  
  typedef struct
@@@ -526,6 -526,132 +526,132 @@@ NtfsVerifyVolume(PDEVICE_OBJECT DeviceO
  }
  
  
+ static
+ NTSTATUS
+ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
+                  PIRP Irp)
+ {
+     PIO_STACK_LOCATION Stack;
+     PNTFS_VOLUME_DATA_BUFFER DataBuffer;
+     PNTFS_ATTR_RECORD Attribute;
+     DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->UserBuffer;
+     Stack = IoGetCurrentIrpStackLocation(Irp);
+     if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(NTFS_VOLUME_DATA_BUFFER) ||
+         Irp->UserBuffer == NULL)
+     {
+         DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->UserBuffer);
+         return STATUS_INVALID_PARAMETER;
+     }
+     DataBuffer->VolumeSerialNumber.QuadPart = DeviceExt->NtfsInfo.SerialNumber;
+     DataBuffer->NumberSectors.QuadPart = DeviceExt->NtfsInfo.SectorCount;
+     DataBuffer->TotalClusters.QuadPart = DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster;
+     DataBuffer->FreeClusters.QuadPart = NtfsGetFreeClusters(DeviceExt);
+     DataBuffer->TotalReserved.QuadPart = 0LL; // FIXME
+     DataBuffer->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
+     DataBuffer->BytesPerCluster = DeviceExt->NtfsInfo.BytesPerCluster;
+     DataBuffer->BytesPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord;
+     DataBuffer->ClustersPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord / DeviceExt->NtfsInfo.BytesPerCluster;
+     DataBuffer->MftStartLcn.QuadPart = DeviceExt->NtfsInfo.MftStart.QuadPart;
+     DataBuffer->Mft2StartLcn.QuadPart = DeviceExt->NtfsInfo.MftMirrStart.QuadPart;
+     DataBuffer->MftZoneStart.QuadPart = 0; // FIXME
+     DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME
+     Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->AttributeOffset);
+     while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->BytesInUse) &&
+            Attribute->Type != AttributeEnd)
+     {
+         if (Attribute->Type == AttributeData)
+         {
+             ASSERT(Attribute->IsNonResident);
+             DataBuffer->MftValidDataLength.QuadPart = Attribute->NonResident.DataSize;
+             break;
+         }
+         Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+     }
+     if (Stack->Parameters.FileSystemControl.OutputBufferLength >= sizeof(NTFS_EXTENDED_VOLUME_DATA) + sizeof(NTFS_VOLUME_DATA_BUFFER))
+     {
+         PNTFS_EXTENDED_VOLUME_DATA ExtendedData = (PNTFS_EXTENDED_VOLUME_DATA)((ULONG_PTR)Irp->UserBuffer + sizeof(NTFS_VOLUME_DATA_BUFFER));
+         ExtendedData->ByteCount = sizeof(NTFS_EXTENDED_VOLUME_DATA);
+         ExtendedData->MajorVersion = DeviceExt->NtfsInfo.MajorVersion;
+         ExtendedData->MinorVersion = DeviceExt->NtfsInfo.MinorVersion;
+     }
+     return STATUS_SUCCESS;
+ }
+ static
+ NTSTATUS
+ GetNtfsFileRecord(PDEVICE_EXTENSION DeviceExt,
+                   PIRP Irp)
+ {
+     NTSTATUS Status;
+     PIO_STACK_LOCATION Stack;
+     PNTFS_FILE_RECORD_INPUT_BUFFER InputBuffer;
+     PFILE_RECORD_HEADER FileRecord;
+     PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer;
+     ULONGLONG MFTRecord;
+     Stack = IoGetCurrentIrpStackLocation(Irp);
+     if (Stack->Parameters.FileSystemControl.InputBufferLength < sizeof(NTFS_FILE_RECORD_INPUT_BUFFER) ||
+         Irp->AssociatedIrp.SystemBuffer == NULL)
+     {
+         DPRINT1("Invalid input! %d %p\n", Stack->Parameters.FileSystemControl.InputBufferLength, Irp->AssociatedIrp.SystemBuffer);
+         return STATUS_INVALID_PARAMETER;
+     }
+     if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER) ||
+         Irp->AssociatedIrp.SystemBuffer == NULL)
+     {
+         DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->AssociatedIrp.SystemBuffer);
+         return STATUS_BUFFER_TOO_SMALL;
+     }
+     FileRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                        DeviceExt->NtfsInfo.BytesPerFileRecord,
+                                        TAG_NTFS);
+     if (FileRecord == NULL)
+     {
+         return STATUS_INSUFFICIENT_RESOURCES;
+     }
+     InputBuffer = (PNTFS_FILE_RECORD_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+     MFTRecord = InputBuffer->FileReferenceNumber.QuadPart;
+     Status = ReadFileRecord(DeviceExt, MFTRecord, FileRecord);
+     if (!NT_SUCCESS(Status))
+     {
+         DPRINT1("Failed reading record: %I64x\n", MFTRecord);
+         ExFreePoolWithTag(FileRecord, TAG_NTFS);
+         return Status;
+     }
+     if (Stack->Parameters.FileSystemControl.OutputBufferLength < (FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer) + FileRecord->BytesInUse))
+     {
+         DPRINT1("Buffer too small: %lu vs %lu\n", Stack->Parameters.FileSystemControl.OutputBufferLength, FileRecord->BytesInUse);
+         ExFreePoolWithTag(FileRecord, TAG_NTFS);
+         return STATUS_BUFFER_TOO_SMALL;
+     }
+     OutputBuffer = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+     OutputBuffer->FileReferenceNumber.QuadPart = MFTRecord;
+     OutputBuffer->FileRecordLength = FileRecord->BytesInUse;
+     RtlCopyMemory(OutputBuffer->FileRecordBuffer, FileRecord, FileRecord->BytesInUse);
+     ExFreePoolWithTag(FileRecord, TAG_NTFS);
+     return STATUS_SUCCESS;
+ }
  static
  NTSTATUS
  NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject,
      NTSTATUS Status;
      PIO_STACK_LOCATION Stack;
      PDEVICE_EXTENSION DeviceExt;
-     PNTFS_VOLUME_DATA_BUFFER DataBuffer;
-     PNTFS_ATTR_RECORD Attribute;
  
      DPRINT1("NtfsUserFsRequest(%p, %p)\n", DeviceObject, Irp);
  
      Stack = IoGetCurrentIrpStackLocation(Irp);
+     DeviceExt = DeviceObject->DeviceExtension;
      switch (Stack->Parameters.FileSystemControl.FsControlCode)
      {
          case FSCTL_GET_NTFS_VOLUME_DATA:
-             DeviceExt = DeviceObject->DeviceExtension;
-             DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->UserBuffer;
-             if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(NTFS_VOLUME_DATA_BUFFER) ||
-                 Irp->UserBuffer == NULL)
-             {
-                 DPRINT1("Invalid output! %d %p\n", Stack->Parameters.FileSystemControl.OutputBufferLength, Irp->UserBuffer);
-                 Status = STATUS_INVALID_PARAMETER;
-                 break;
-             }
-             DataBuffer->VolumeSerialNumber.QuadPart = DeviceExt->NtfsInfo.SerialNumber;
-             DataBuffer->NumberSectors.QuadPart = DeviceExt->NtfsInfo.SectorCount;
-             DataBuffer->TotalClusters.QuadPart = DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster;
-             DataBuffer->FreeClusters.QuadPart = NtfsGetFreeClusters(DeviceExt);
-             DataBuffer->TotalReserved.QuadPart = 0LL; // FIXME
-             DataBuffer->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
-             DataBuffer->BytesPerCluster = DeviceExt->NtfsInfo.BytesPerCluster;
-             DataBuffer->BytesPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord;
-             DataBuffer->ClustersPerFileRecordSegment = DeviceExt->NtfsInfo.BytesPerFileRecord / DeviceExt->NtfsInfo.BytesPerCluster;
-             DataBuffer->MftStartLcn.QuadPart = DeviceExt->NtfsInfo.MftStart.QuadPart;
-             DataBuffer->Mft2StartLcn.QuadPart = DeviceExt->NtfsInfo.MftMirrStart.QuadPart;
-             DataBuffer->MftZoneStart.QuadPart = 0; // FIXME
-             DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME
-             Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->AttributeOffset);
-             while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->BytesInUse) &&
-                    Attribute->Type != AttributeEnd)
-             {
-                 if (Attribute->Type == AttributeData)
-                 {
-                     ASSERT(Attribute->IsNonResident);
-                     DataBuffer->MftValidDataLength.QuadPart = Attribute->NonResident.DataSize;
-                     break;
-                 }
-                 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
-             }
-             if (Stack->Parameters.FileSystemControl.OutputBufferLength >= sizeof(NTFS_EXTENDED_VOLUME_DATA) + sizeof(NTFS_VOLUME_DATA_BUFFER))
-             {
-                 PNTFS_EXTENDED_VOLUME_DATA ExtendedData = (PNTFS_EXTENDED_VOLUME_DATA)((ULONG_PTR)Irp->UserBuffer + sizeof(NTFS_VOLUME_DATA_BUFFER));
-                 ExtendedData->ByteCount = sizeof(NTFS_EXTENDED_VOLUME_DATA);
-                 ExtendedData->MajorVersion = DeviceExt->NtfsInfo.MajorVersion;
-                 ExtendedData->MinorVersion = DeviceExt->NtfsInfo.MinorVersion;
-             }
-             Status = STATUS_SUCCESS;
+             Status = GetNfsVolumeData(DeviceExt, Irp);
+             break;
+         case FSCTL_GET_NTFS_FILE_RECORD:
+             Status = GetNtfsFileRecord(DeviceExt, Irp);
              break;
  
          default:
@@@ -251,6 -251,23 +251,23 @@@ VfatFormat(IN PUNICODE_STRING DriveRoot
          Status = STATUS_INVALID_PARAMETER;
      }
  
+     /* Attempt to dismount formatted volume */
+     LockStatus = NtFsControlFile(FileHandle,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  &Iosb,
+                                  FSCTL_DISMOUNT_VOLUME,
+                                  NULL,
+                                  0,
+                                  NULL,
+                                  0);
+     if (!NT_SUCCESS(LockStatus))
+     {
+         DPRINT1("Failed to umount volume (Status: 0x%x)\n", LockStatus);
+     }
      LockStatus = NtFsControlFile(FileHandle,
                                   NULL,
                                   NULL,
diff --combined ntoskrnl/io/iomgr/file.c
@@@ -419,28 -419,6 +419,6 @@@ IopParseDevice(IN PVOID ParseObject
          DirectOpen = TRUE;
      }
  
- #if 1
-     /* FIXME: Small hack still exists, have to check why...
-      * This is triggered multiple times by usetup and then once per boot.
-      */
-     if (!(DirectOpen) &&
-         !(RemainingName->Length) &&
-         !(OpenPacket->RelatedFileObject) &&
-         ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
-          (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
-         !(UseDummyFile))
-     {
-         DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
-         DesiredAccess & ~(SYNCHRONIZE |
-                           FILE_READ_ATTRIBUTES |
-                           READ_CONTROL |
-                           ACCESS_SYSTEM_SECURITY |
-                           WRITE_OWNER |
-                           WRITE_DAC));
-         DirectOpen = TRUE;
-     }
- #endif
      /* Check if we have a related FO that wasn't a direct open */
      if ((OpenPacket->RelatedFileObject) &&
          !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
@@@ -20,6 -20,7 +20,7 @@@ typedef struct _VC
      USHORT NodeByteSize;
      PDEVICE_OBJECT TargetDeviceObject;
      PVPB Vpb;
+     PVPB LocalVpb;
      ULONG VcbState;
      KMUTEX Mutex;
      CLONG OpenCount;
@@@ -34,20 -35,27 +35,27 @@@ typedef struct _VOLUME_DEVICE_OBJEC
      VCB Vcb;
  } VOLUME_DEVICE_OBJECT, *PVOLUME_DEVICE_OBJECT;
  
+ #define VCB_STATE_LOCKED     0x00000001
+ #define VCB_STATE_DISMOUNTED 0x00000002
  /* GLOBALS *******************************************************************/
  
  PDEVICE_OBJECT RawDiskDeviceObject, RawCdromDeviceObject, RawTapeDeviceObject;
  
  /* FUNCTIONS *****************************************************************/
  
- VOID
+ NTSTATUS
  NTAPI
  RawInitializeVcb(IN OUT PVCB Vcb,
                   IN PDEVICE_OBJECT TargetDeviceObject,
                   IN PVPB Vpb)
  {
+     NTSTATUS Status = STATUS_SUCCESS;
      PAGED_CODE();
  
+     DPRINT("RawInitializeVcb(%p, %p, %p)\n", Vcb, TargetDeviceObject, Vpb);
      /* Clear it */
      RtlZeroMemory(Vcb, sizeof(VCB));
  
  
      /* Initialize the lock */
      KeInitializeMutex(&Vcb->Mutex, 0);
+     Vcb->LocalVpb = ExAllocatePoolWithTag(NonPagedPool, sizeof(VPB), ' waR');
+     if (Vcb->LocalVpb == NULL)
+     {
+         Status = STATUS_INSUFFICIENT_RESOURCES;
+     }
+     return Status;
  }
  
  BOOLEAN
@@@ -68,6 -84,10 +84,10 @@@ RawCheckForDismount(IN PVCB Vcb
      PVPB Vpb;
      BOOLEAN Delete;
  
+     DPRINT("RawCheckForDismount(%p, %lu)\n", Vcb, CreateOperation);
+     ASSERT(KeReadStateMutant(&Vcb->Mutex) == 0);
      /* Lock VPB */
      IoAcquireVpbSpinLock(&OldIrql);
  
      Vpb = Vcb->Vpb;
      if (Vcb->Vpb->ReferenceCount != CreateOperation)
      {
+         /* Copy the VPB to our local own to prepare later dismount */
+         if (Vcb->LocalVpb != NULL)
+         {
+             RtlZeroMemory(Vcb->LocalVpb, sizeof(VPB));
+             Vcb->LocalVpb->Type = IO_TYPE_VPB;
+             Vcb->LocalVpb->Size = sizeof(VPB);
+             Vcb->LocalVpb->RealDevice = Vcb->Vpb->RealDevice;
+             Vcb->LocalVpb->DeviceObject = NULL;
+             Vcb->LocalVpb->Flags = Vcb->Vpb->Flags & VPB_REMOVE_PENDING;
+             Vcb->Vpb->RealDevice->Vpb = Vcb->LocalVpb;
+             Vcb->LocalVpb = NULL;
+             Vcb->Vpb->Flags |= VPB_PERSISTENT;
+         }
          /* Don't do anything */
          Delete = FALSE;
      }
  
      /* Release lock and return status */
      IoReleaseVpbSpinLock(OldIrql);
+     /* If we were to delete, delete volume */
+     if (Delete)
+     {
+         PVPB DelVpb;
+         /* Release our Vcb lock to be able delete us */
+         KeReleaseMutex(&Vcb->Mutex, 0);
+         /* If we have a local VPB, we'll have to delete it
+          * but we won't dismount us - something went bad before
+          */
+         if (Vcb->LocalVpb)
+         {
+             DelVpb = Vcb->LocalVpb;
+         }
+         /* Otherwise, dismount our device if possible */
+         else
+         {
+             if (Vcb->Vpb->ReferenceCount)
+             {
+                 ObfDereferenceObject(Vcb->TargetDeviceObject);
+                 IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
+                                                                  VOLUME_DEVICE_OBJECT,
+                                                                  Vcb));
+                 return Delete;
+             }
+             DelVpb = Vcb->Vpb;
+         }
+         /* Delete any of the available VPB and dismount */
+         ExFreePool(DelVpb);
+         ObfDereferenceObject(Vcb->TargetDeviceObject);
+         IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
+                                                          VOLUME_DEVICE_OBJECT,
+                                                          Vcb));
+         return Delete;
+     }
      return Delete;
  }
  
@@@ -104,6 -178,8 +178,8 @@@ RawCompletionRoutine(IN PDEVICE_OBJECT 
  {
      PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
  
+     DPRINT("RawCompletionRoutine(%p, %p, %p)\n", DeviceObject, Irp, Context);
      /* Check if this was a valid sync R/W request */
      if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
           (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
@@@ -128,9 -204,18 +204,18 @@@ RawClose(IN PVCB Vcb
           IN PIO_STACK_LOCATION IoStackLocation)
  {
      NTSTATUS Status;
-     BOOLEAN Deleted = FALSE;
      PAGED_CODE();
  
+     DPRINT("RawClose(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
+     /* If its a stream, not much to do */
+     if (IoStackLocation->FileObject->Flags & FO_STREAM_FILE)
+     {
+         Irp->IoStatus.Status = STATUS_SUCCESS;
+         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+         return STATUS_SUCCESS;
+     }
      /* Make sure we can clean up */
      Status = KeWaitForSingleObject(&Vcb->Mutex,
                                     Executive,
  
      /* Decrease the open count and check if this is a dismount */
      Vcb->OpenCount--;
-     if (!Vcb->OpenCount) Deleted = RawCheckForDismount(Vcb, FALSE);
-     /* Check if we should delete the device */
-     KeReleaseMutex(&Vcb->Mutex, FALSE);
-     if (Deleted)
+     if (!Vcb->OpenCount || !RawCheckForDismount(Vcb, FALSE))
      {
-         /* Delete it */
-         IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
-                                                          VOLUME_DEVICE_OBJECT,
-                                                          Vcb));
+         KeReleaseMutex(&Vcb->Mutex, FALSE);
      }
  
      /* Complete the request */
@@@ -166,11 -244,13 +244,13 @@@ RawCreate(IN PVCB Vcb
            IN PIO_STACK_LOCATION IoStackLocation)
  {
      NTSTATUS Status;
-     BOOLEAN Deleted = FALSE;
      USHORT ShareAccess;
      ACCESS_MASK DesiredAccess;
+     BOOLEAN Deleted = FALSE;
      PAGED_CODE();
  
+     DPRINT("RawCreate(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Make sure we can clean up */
      Status = KeWaitForSingleObject(&Vcb->Mutex,
                                     Executive,
           (!(IoStackLocation->Parameters.Create.Options & FILE_DIRECTORY_FILE)))
      {
          /* Make sure the VCB isn't locked */
-         if (Vcb->VcbState & 1)
+         if (Vcb->VcbState & VCB_STATE_LOCKED)
          {
              /* Refuse the operation */
              Status = STATUS_ACCESS_DENIED;
              Irp->IoStatus.Information = 0;
          }
+         else if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
+         {
+             /* Refuse the operation */
+             Status = STATUS_VOLUME_DISMOUNTED;
+             Irp->IoStatus.Information = 0;
+         }
          else
          {
              /* Setup share access */
      if (!(NT_SUCCESS(Status)) && !(Vcb->OpenCount))
      {
          /* Check if we can dismount the device */
-         Deleted = RawCheckForDismount(Vcb, FALSE);
+         Deleted = RawCheckForDismount(Vcb, TRUE);   
      }
  
-     /* Check if we should delete the device */
-     KeReleaseMutex(&Vcb->Mutex, FALSE);
-     if (Deleted)
+     /* In case of deletion, the mutex is already released */
+     if (!Deleted)
      {
-         /* Delete it */
-         IoDeleteDevice((PDEVICE_OBJECT)CONTAINING_RECORD(Vcb,
-                                                          VOLUME_DEVICE_OBJECT,
-                                                          Vcb));
+         KeReleaseMutex(&Vcb->Mutex, FALSE);
      }
  
      /* Complete the request */
-     Irp->IoStatus.Status = STATUS_SUCCESS;
+     Irp->IoStatus.Status = Status;
      IoCompleteRequest(Irp, IO_DISK_INCREMENT);
-     return STATUS_SUCCESS;
+     return Status;
  }
  
  NTSTATUS
@@@ -275,6 -357,8 +357,8 @@@ RawReadWriteDeviceControl(IN PVCB Vcb
      NTSTATUS Status;
      PAGED_CODE();
  
+     DPRINT("RawReadWriteDeviceControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Don't do anything if the request was 0 bytes */
      if (((IoStackLocation->MajorFunction == IRP_MJ_READ) ||
           (IoStackLocation->MajorFunction == IRP_MJ_WRITE)) &&
@@@ -315,6 -399,8 +399,8 @@@ RawMountVolume(IN PIO_STACK_LOCATION Io
      PFILE_OBJECT FileObject = NULL;
      PAGED_CODE();
  
+     DPRINT("RawMountVolume(%p)\n", IoStackLocation);
      /* Remember our owner */
      DeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject;
  
                                                      AlignmentRequirement);
  
      /* Setup the VCB */
-     RawInitializeVcb(&Volume->Vcb,
-                      IoStackLocation->Parameters.MountVolume.DeviceObject,
-                      IoStackLocation->Parameters.MountVolume.Vpb);
+     Status = RawInitializeVcb(&Volume->Vcb,
+                               IoStackLocation->Parameters.MountVolume.DeviceObject,
+                               IoStackLocation->Parameters.MountVolume.Vpb);
+     if (!NT_SUCCESS(Status))
+     {
+         IoDeleteDevice((PDEVICE_OBJECT)Volume);
+         return Status;
+     }
  
      /* Set dummy label and serial number */
      Volume->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
@@@ -391,6 -482,8 +482,8 @@@ RawUserFsCtrl(IN PIO_STACK_LOCATION IoS
      NTSTATUS Status;
      PAGED_CODE();
  
+     DPRINT("RawUserFsCtrl(%p, %p)\n", IoStackLocation, Vcb);
      /* Lock the device */
      Status = KeWaitForSingleObject(&Vcb->Mutex,
                                     Executive,
@@@ -502,6 -595,8 +595,8 @@@ RawFileSystemControl(IN PVCB Vcb
      NTSTATUS Status;
      PAGED_CODE();
  
+     DPRINT("RawFileSystemControl(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Check the kinds of FSCTLs that we support */
      switch (IoStackLocation->MinorFunction)
      {
@@@ -563,6 -658,8 +658,8 @@@ RawQueryInformation(IN PVCB Vcb
      PFILE_POSITION_INFORMATION Buffer;
      PAGED_CODE();
  
+     DPRINT("RawQueryInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Get information from the IRP */
      Length = &IoStackLocation->Parameters.QueryFile.Length;
      Buffer = Irp->AssociatedIrp.SystemBuffer;
@@@ -608,6 -705,8 +705,8 @@@ RawSetInformation(IN PVCB Vcb
      PDEVICE_OBJECT DeviceObject;
      PAGED_CODE();
  
+     DPRINT("RawSetInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Get information from the IRP */
      Buffer = Irp->AssociatedIrp.SystemBuffer;
  
@@@ -650,6 -749,8 +749,8 @@@ RawQueryFsVolumeInfo(IN PVCB Vcb
  {
      PAGED_CODE();
  
+     DPRINT("RawQueryFsVolumeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
      /* Clear the buffer and stub it out */
      RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION));
      Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
@@@ -677,6 -778,8 +778,8 @@@ RawQueryFsSizeInfo(IN PVCB Vcb
      BOOLEAN DiskHasPartitions;
      PAGED_CODE();
  
+     DPRINT("RawQueryFsSizeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
      /* Validate the buffer */
      if (*Length < sizeof(FILE_FS_SIZE_INFORMATION))
      {
@@@ -806,6 -909,8 +909,8 @@@ RawQueryFsDeviceInfo(IN PVCB Vcb
  {
      PAGED_CODE();
  
+     DPRINT("RawQueryFsDeviceInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
      /* Validate buffer */
      if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION))
      {
@@@ -833,6 -938,8 +938,8 @@@ RawQueryFsAttributeInfo(IN PVCB Vcb
      ULONG ReturnLength;
      PAGED_CODE();
  
+     DPRINT("RawQueryFsAttributeInfo(%p, %p, %p)\n", Vcb, Buffer, Length);
      /* Check if the buffer is large enough for our name ("RAW") */
      ReturnLength = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION,
                                  FileSystemName[sizeof(szRawFSName) / sizeof(szRawFSName[0])]);
@@@ -860,6 -967,8 +967,8 @@@ RawQueryVolumeInformation(IN PVCB Vcb
      PVOID Buffer;
      PAGED_CODE();
  
+     DPRINT("RawQueryVolumeInformation(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Get IRP Data */
      Length = IoStackLocation->Parameters.QueryVolume.Length;
      Buffer = Irp->AssociatedIrp.SystemBuffer;
@@@ -916,6 -1025,8 +1025,8 @@@ RawCleanup(IN PVCB Vcb
      NTSTATUS Status;
      PAGED_CODE();
  
+     DPRINT("RawCleanup(%p, %p, %p)\n", Vcb, Irp, IoStackLocation);
      /* Make sure we can clean up */
      Status = KeWaitForSingleObject(&Vcb->Mutex,
                                     Executive,
                                     NULL);
      ASSERT(NT_SUCCESS(Status));
  
-     /* Remove shared access and complete the request */
+     /* Remove shared access */
      IoRemoveShareAccess(IoStackLocation->FileObject, &Vcb->ShareAccess);
+     /* Check if we're to dismount */
+     if (Vcb->VcbState & VCB_STATE_DISMOUNTED)
+     {
+         ASSERT(Vcb->OpenCount == 1);
+         RawCheckForDismount(Vcb, FALSE);
+     }
      KeReleaseMutex(&Vcb->Mutex, FALSE);
      Irp->IoStatus.Status = STATUS_SUCCESS;
      IoCompleteRequest(Irp, IO_DISK_INCREMENT);
@@@ -942,6 -1061,8 +1061,8 @@@ RawDispatch(IN PVOLUME_DEVICE_OBJECT De
      PVCB Vcb;
      PAGED_CODE();
  
+     DPRINT("RawDispatch(%p, %p)\n", DeviceObject, Irp);
      /* Get the stack location */
      IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
  
diff --combined ntoskrnl/se/token.c
@@@ -1909,8 -1909,20 +1909,20 @@@ NtSetInformationToken(IN HANDLE TokenHa
                                  ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
                              }
  
-                             /* Set the new dacl */
-                             Token->DefaultDacl = CapturedAcl;
+                             Token->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
+                                                                        CapturedAcl->AclSize,
+                                                                        TAG_TOKEN_ACL);
+                             if (!Token->DefaultDacl)
+                             {
+                                 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
+                                 Status = STATUS_NO_MEMORY;
+                             }
+                             else
+                             {
+                                 /* Set the new dacl */
+                                 RtlCopyMemory(Token->DefaultDacl, CapturedAcl, CapturedAcl->AclSize);
+                                 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
+                             }
                          }
                      }
                      else
@@@ -3365,6 -3365,11 +3365,11 @@@ GreExtTextOutW
      BrushOrigin.x = 0;
      BrushOrigin.y = 0;
  
+     psurf = dc->dclevel.pSurface ;
+     if(!psurf) 
+         psurf = psurfDefaultBitmap;
      if ((fuOptions & ETO_OPAQUE) && lprc)
      {
          DestRect.left   = lprc->left;
              DC_vUpdateBackgroundBrush(dc);
  
          IntEngBitBlt(
-             &dc->dclevel.pSurface->SurfObj,
+             &psurf->SurfObj,
              NULL,
              NULL,
              &dc->co.ClipObj,
      /* Lock blit with a dummy rect */
      DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
  
-     psurf = dc->dclevel.pSurface ;
-     if(!psurf) psurf = psurfDefaultBitmap;
      SurfObj = &psurf->SurfObj ;
  
      EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);