[SHELL] IPersistFolder2::GetCurFolder takes a PIDLIST_ABSOLUTE*. CORE-16385
[reactos.git] / dll / win32 / shell32 / folders / CFSFolder.cpp
index 980636a..c475c2c 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Copyright 1997             Marcus Meissner
  * Copyright 1998, 1999, 2002 Juergen Schmied
+ * Copyright 2019             Katayama Hirofumi MZ
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 WINE_DEFAULT_DEBUG_CHANNEL (shell);
 
+HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName)
+{
+    HKEY hkey;
+
+    if (!_ILIsValue(pidl))
+    {
+        ERR("Invalid pidl!\n");
+        return NULL;
+    }
+
+    FileStructW* pDataW = _ILGetFileStructW(pidl);
+    if (!pDataW)
+    {
+        ERR("Invalid pidl!\n");
+        return NULL;
+    }
+
+    LPWSTR pExtension = PathFindExtensionW(pDataW->wszName);
+    if (!pExtension || *pExtension == NULL)
+    {
+        WARN("No extension for %S!\n", pDataW->wszName);
+        return NULL;
+    }
+
+    WCHAR FullName[MAX_PATH];
+    DWORD dwSize = sizeof(FullName);
+    wsprintf(FullName, L"%s\\%s", pExtension, KeyName);
+
+    LONG res = RegOpenKeyExW(HKEY_CLASSES_ROOT, FullName, 0, KEY_READ, &hkey);
+    if (!res)
+        return hkey;
+
+    res = RegGetValueW(HKEY_CLASSES_ROOT, pExtension, NULL, RRF_RT_REG_SZ, NULL, FullName, &dwSize);
+    if (res)
+    {
+        WARN("Failed to get progid for file %S, extension %S (%x), address %x, pidl: %x, error %d\n", pDataW->wszName, pExtension, pExtension, &dwSize, pidl, res);
+        return NULL;
+    }
+
+    wcscat(FullName, L"\\");
+    wcscat(FullName, KeyName);
+
+    hkey = NULL;
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, FullName, 0, KEY_READ, &hkey);
+    if (res)
+        WARN("Could not open key %S for extension %S\n", KeyName, pExtension);
+
+    return hkey;
+}
+
+HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
+{
+    HKEY hkeyProgId = OpenKeyFromFileType(pidl, KeyName);
+    if (!hkeyProgId)
+    {
+        WARN("OpenKeyFromFileType failed for key %S\n", KeyName);
+        return S_FALSE;
+    }
+
+    WCHAR wszCLSIDValue[CHARS_IN_GUID];
+    DWORD dwSize = sizeof(wszCLSIDValue);
+    LONG res = RegGetValueW(hkeyProgId, NULL, NULL, RRF_RT_REG_SZ, NULL, wszCLSIDValue, &dwSize);
+    RegCloseKey(hkeyProgId);
+    if (res)
+    {
+        ERR("OpenKeyFromFileType succeeded but RegGetValueW failed\n");
+        return S_FALSE;
+    }
+
+#if 0
+    {
+        res = RegGetValueW(HKEY_LOCAL_MACHINE,
+                           L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
+                           wszCLSIDValue,
+                           RRF_RT_REG_SZ,
+                           NULL,
+                           NULL,
+                           NULL);
+        if (res != ERROR_SUCCESS)
+        {
+            ERR("DropHandler extension %S not approved\n", wszName);
+            return E_ACCESSDENIED;
+        }
+    }
+#endif
+
+    if (RegGetValueW(HKEY_LOCAL_MACHINE,
+                     L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked",
+                     wszCLSIDValue,
+                     RRF_RT_REG_SZ,
+                     NULL,
+                     NULL,
+                     NULL) == ERROR_SUCCESS)
+    {
+        ERR("Extension %S  not approved\n", wszCLSIDValue);
+        return E_ACCESSDENIED;
+    }
+
+    HRESULT hres = CLSIDFromString (wszCLSIDValue, pclsid);
+    if (FAILED_UNEXPECTEDLY(hres))
+        return hres;
+
+    return S_OK;
+}
+
+static HRESULT
+getDefaultIconLocation(LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT uFlags)
+{
+    static const WCHAR folder[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
+
+    if (!HCR_GetIconW(folder, szIconFile, NULL, cchMax, piIndex))
+    {
+        lstrcpynW(szIconFile, swShell32Name, cchMax);
+        *piIndex = -IDI_SHELL_FOLDER;
+    }
+
+    if (uFlags & GIL_OPENICON)
+    {
+        // next icon
+        if (*piIndex < 0)
+            (*piIndex)--;
+        else
+            (*piIndex)++;
+    }
+
+    return S_OK;
+}
+
+static const WCHAR s_shellClassInfo[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 };
+
+static BOOL
+getShellClassInfo(LPCWSTR Entry, LPWSTR pszValue, DWORD cchValueLen, LPCWSTR IniFile)
+{
+    return GetPrivateProfileStringW(s_shellClassInfo, Entry, NULL, pszValue, cchValueLen, IniFile);
+}
+
+static HRESULT
+getIconLocationForFolder(IShellFolder * psf, PCITEMID_CHILD pidl, UINT uFlags,
+                         LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
+{
+    DWORD dwFileAttrs;
+    WCHAR wszPath[MAX_PATH];
+    WCHAR wszIniFullPath[MAX_PATH];
+    static const WCHAR iconFile[] = { 'I', 'c', 'o', 'n', 'F', 'i', 'l', 'e', 0 };
+    static const WCHAR clsid[] = { 'C', 'L', 'S', 'I', 'D', 0 };
+    static const WCHAR clsid2[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 };
+    static const WCHAR iconIndex[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 };
+    static const WCHAR iconResource[] = { 'I', 'c', 'o', 'n', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 0 };
+    static const WCHAR wszDesktopIni[] = { 'd','e','s','k','t','o','p','.','i','n','i',0 };
+
+    if (uFlags & GIL_DEFAULTICON)
+        goto Quit;
+
+    // get path
+    if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0))
+        goto Quit;
+    if (!PathIsDirectoryW(wszPath))
+        goto Quit;
+
+    // read-only or system folder?
+    dwFileAttrs = _ILGetFileAttributes(ILFindLastID(pidl), NULL, 0);
+    if ((dwFileAttrs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) == 0)
+        goto Quit;
+
+    // build the full path of ini file
+    StringCchCopyW(wszIniFullPath, _countof(wszIniFullPath), wszPath);
+    PathAppendW(wszIniFullPath, wszDesktopIni);
+
+    WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH];
+    if (getShellClassInfo(iconFile, wszValue, _countof(wszValue), wszIniFullPath))
+    {
+        // wszValue --> wszTemp
+        ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp));
+
+        // wszPath + wszTemp --> wszPath
+        if (PathIsRelativeW(wszTemp))
+            PathAppendW(wszPath, wszTemp);
+        else
+            StringCchCopyW(wszPath, _countof(wszPath), wszTemp);
+
+        // wszPath --> szIconFile
+        GetFullPathNameW(wszPath, cchMax, szIconFile, NULL);
+
+        *piIndex = GetPrivateProfileIntW(s_shellClassInfo, iconIndex, 0, wszIniFullPath);
+        return S_OK;
+    }
+    else if (getShellClassInfo(clsid, wszValue, _countof(wszValue), wszIniFullPath) &&
+             HCR_GetIconW(wszValue, szIconFile, NULL, cchMax, piIndex))
+    {
+        return S_OK;
+    }
+    else if (getShellClassInfo(clsid2, wszValue, _countof(wszValue), wszIniFullPath) &&
+             HCR_GetIconW(wszValue, szIconFile, NULL, cchMax, piIndex))
+    {
+        return S_OK;
+    }
+    else if (getShellClassInfo(iconResource, wszValue, _countof(wszValue), wszIniFullPath))
+    {
+        // wszValue --> wszTemp
+        ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp));
+
+        // parse the icon location
+        *piIndex = PathParseIconLocationW(wszTemp);
+
+        // wszPath + wszTemp --> wszPath
+        if (PathIsRelativeW(wszTemp))
+            PathAppendW(wszPath, wszTemp);
+        else
+            StringCchCopyW(wszPath, _countof(wszPath), wszTemp);
+
+        // wszPath --> szIconFile
+        GetFullPathNameW(wszPath, cchMax, szIconFile, NULL);
+        return S_OK;
+    }
+
+Quit:
+    return getDefaultIconLocation(szIconFile, cchMax, piIndex, uFlags);
+}
+
+HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut)
+{
+    CComPtr<IDefaultExtractIconInit> initIcon;
+    HRESULT hr;
+    int icon_idx = 0;
+    UINT flags = 0; // FIXME: Use it!
+    WCHAR wTemp[MAX_PATH] = L"";
+
+    hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
+    if (FAILED(hr))
+        return hr;
+
+    if (_ILIsFolder (pidl))
+    {
+        if (SUCCEEDED(getIconLocationForFolder(psf, 
+                          pidl, 0, wTemp, _countof(wTemp),
+                          &icon_idx,
+                          &flags)))
+        {
+            initIcon->SetNormalIcon(wTemp, icon_idx);
+            // FIXME: if/when getIconLocationForFolder does something for 
+            //        GIL_FORSHORTCUT, code below should be uncommented. and
+            //        the following line removed.
+            initIcon->SetShortcutIcon(wTemp, icon_idx);
+        }
+        if (SUCCEEDED(getIconLocationForFolder(psf, 
+                          pidl, GIL_DEFAULTICON, wTemp, _countof(wTemp),
+                          &icon_idx,
+                          &flags)))
+        {
+            initIcon->SetDefaultIcon(wTemp, icon_idx);
+        }
+        // if (SUCCEEDED(getIconLocationForFolder(psf, 
+        //                   pidl, GIL_FORSHORTCUT, wTemp, _countof(wTemp),
+        //                   &icon_idx,
+        //                   &flags)))
+        // {
+        //     initIcon->SetShortcutIcon(wTemp, icon_idx);
+        // }
+        if (SUCCEEDED(getIconLocationForFolder(psf, 
+                          pidl, GIL_OPENICON, wTemp, _countof(wTemp),
+                          &icon_idx,
+                          &flags)))
+        {
+            initIcon->SetOpenIcon(wTemp, icon_idx);
+        }
+    }
+    else
+    {
+        HKEY hkey = OpenKeyFromFileType(pidl, L"DefaultIcon");
+        if (!hkey)
+            WARN("Could not open DefaultIcon key!\n");
+
+        DWORD dwSize = sizeof(wTemp);
+        if (hkey && !SHQueryValueExW(hkey, NULL, NULL, NULL, wTemp, &dwSize))
+        {
+            WCHAR sNum[5];
+            if (ParseFieldW (wTemp, 2, sNum, 5))
+                icon_idx = _wtoi(sNum);
+            else
+                icon_idx = 0; /* sometimes the icon number is missing */
+            ParseFieldW (wTemp, 1, wTemp, MAX_PATH);
+            PathUnquoteSpacesW(wTemp);
+
+            if (!wcscmp(L"%1", wTemp)) /* icon is in the file */
+            {
+                ILGetDisplayNameExW(psf, pidl, wTemp, 0);
+                icon_idx = 0;
+            }
+
+            initIcon->SetNormalIcon(wTemp, icon_idx);
+        }
+        else
+        {
+            initIcon->SetNormalIcon(swShell32Name, 0);
+        }
+
+        if (hkey)
+            RegCloseKey(hkey);
+    }
+
+    return initIcon->QueryInterface(iid, ppvOut);
+}
+
 /*
 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
 returned by Next. When the enumerator is created, it can do numerous additional operations
@@ -57,20 +361,65 @@ CFileSysEnum::~CFileSysEnum()
 {
 }
 
-HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR sPathTarget, DWORD dwFlags)
+HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR lpszPath, DWORD dwFlags)
 {
-    return CreateFolderEnumList(sPathTarget, dwFlags);
-}
+    WIN32_FIND_DATAW stffile;
+    HANDLE hFile;
+    WCHAR  szPath[MAX_PATH];
+    BOOL succeeded = TRUE;
+    static const WCHAR stars[] = { '*','.','*',0 };
+    static const WCHAR dot[] = { '.',0 };
+    static const WCHAR dotdot[] = { '.','.',0 };
 
-/**************************************************************************
-* registers clipboardformat once
-*/
-void CFSFolder::SF_RegisterClipFmt()
-{
-    TRACE ("(%p)\n", this);
+    TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags);
+
+    if(!lpszPath || !lpszPath[0]) return FALSE;
+
+    wcscpy(szPath, lpszPath);
+    PathAddBackslashW(szPath);
+    wcscat(szPath,stars);
+
+    hFile = FindFirstFileW(szPath,&stffile);
+    if ( hFile != INVALID_HANDLE_VALUE )
+    {
+        BOOL findFinished = FALSE;
+
+        do
+        {
+            if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
+             || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
+            {
+                LPITEMIDLIST pidl = NULL;
+
+                if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+                 dwFlags & SHCONTF_FOLDERS &&
+                 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
+                {
+                    pidl = _ILCreateFromFindDataW(&stffile);
+                    succeeded = succeeded && AddToEnumList(pidl);
+                }
+                else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                 && dwFlags & SHCONTF_NONFOLDERS)
+                {
+                    pidl = _ILCreateFromFindDataW(&stffile);
+                    succeeded = succeeded && AddToEnumList(pidl);
+                }
+            }
+            if (succeeded)
+            {
+                if (!FindNextFileW(hFile, &stffile))
+                {
+                    if (GetLastError() == ERROR_NO_MORE_FILES)
+                        findFinished = TRUE;
+                    else
+                        succeeded = FALSE;
+                }
+            }
+        } while (succeeded && !findFinished);
+        FindClose(hFile);
+    }
 
-    if (!cfShellIDList)
-        cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
+    return succeeded;
 }
 
 CFSFolder::CFSFolder()
@@ -78,9 +427,6 @@ CFSFolder::CFSFolder()
     pclsid = (CLSID *)&CLSID_ShellFSFolder;
     sPathTarget = NULL;
     pidlRoot = NULL;
-    cfShellIDList = 0;
-    SF_RegisterClipFmt();
-    fAcceptFmt = FALSE;
     m_bGroupPolicyActive = 0;
 }
 
@@ -94,14 +440,15 @@ CFSFolder::~CFSFolder()
 
 
 static const shvheader GenericSFHeader[] = {
-    {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
-    {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
-    {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
-    {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
-    {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
+    {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
+    {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 0},
+    {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
+    {IDS_SHV_COLUMN_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+    {IDS_SHV_COLUMN_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12},
+    {IDS_SHV_COLUMN_ATTRIBUTES, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}
 };
 
-#define GENERICSHELLVIEWCOLUMNS 5
+#define GENERICSHELLVIEWCOLUMNS 6
 
 /**************************************************************************
  *  SHELL32_CreatePidlFromBindCtx  [internal]
@@ -143,6 +490,80 @@ LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
     return pidl;
 }
 
+void SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, CLSID* pclsidFolder)
+{
+    WCHAR wszCLSIDValue[CHARS_IN_GUID];
+    WCHAR wszDesktopIni[MAX_PATH];
+    StringCchCopyW(wszDesktopIni, MAX_PATH, pwszDir);
+    StringCchCatW(wszDesktopIni, MAX_PATH, L"\\desktop.ini");
+
+    if (GetPrivateProfileStringW(L".ShellClassInfo", 
+                                 L"CLSID", 
+                                 L"",
+                                 wszCLSIDValue, 
+                                 CHARS_IN_GUID, 
+                                 wszDesktopIni))
+    {
+        CLSIDFromString (wszCLSIDValue, pclsidFolder);
+    }
+}
+
+HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
+{
+    DWORD dwFileAttributes, dwShellAttributes;
+
+    if (!_ILIsFolder(pidl) && !_ILIsValue(pidl))
+    {
+        ERR("Got wrong type of pidl!\n");
+        *pdwAttributes &= SFGAO_CANLINK;
+        return S_OK;
+    }
+
+    dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
+
+    /* Set common attributes */
+    dwShellAttributes = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK | SFGAO_CANRENAME | SFGAO_CANDELETE |
+                        SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSTEM;
+
+    if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        dwShellAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STORAGE);
+    else
+        dwShellAttributes |= SFGAO_STREAM;
+
+    if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
+        dwShellAttributes |=  SFGAO_HIDDEN;
+
+    if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+        dwShellAttributes |=  SFGAO_READONLY;
+
+    if (SFGAO_LINK & *pdwAttributes)
+    {
+        char ext[MAX_PATH];
+
+        if (_ILGetExtension(pidl, ext, MAX_PATH) && !lstrcmpiA(ext, "lnk"))
+            dwShellAttributes |= SFGAO_LINK;
+    }
+
+    if (SFGAO_HASSUBFOLDER & *pdwAttributes)
+    {
+        CComPtr<IShellFolder> psf2;
+        if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_PPV_ARG(IShellFolder, &psf2))))
+        {
+            CComPtr<IEnumIDList> pEnumIL;
+            if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL)))
+            {
+                if (pEnumIL->Skip(1) == S_OK)
+                    dwShellAttributes |= SFGAO_HASSUBFOLDER;
+            }
+        }
+    }
+
+    *pdwAttributes = dwShellAttributes;
+
+    TRACE ("-- 0x%08x\n", *pdwAttributes);
+    return S_OK;
+}
+
 /**************************************************************************
 * CFSFolder::ParseDisplayName {SHELL32}
 *
@@ -207,6 +628,13 @@ HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner,
         pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, szElement);
         if (pidlTemp != NULL)
         {
+            /* We are creating an id list without ensuring that the items exist.
+               If we have a remaining path, this must be a folder. 
+               We have to do it now because it is set as a file by default */
+            if (szNext)
+            {
+                pidlTemp->mkid.abID[0] = PT_FOLDER;
+            }
             hr = S_OK;
         }
         else
@@ -233,7 +661,7 @@ HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner,
             {
                 /* it's the last element */
                 if (pdwAttributes && *pdwAttributes)
-                    hr = SHELL32_GetItemAttributes(this, pidlTemp, pdwAttributes);
+                    hr = SHELL32_GetFSItemAttributes(this, pidlTemp, pdwAttributes);
             }
         }
     }
@@ -260,7 +688,7 @@ HRESULT WINAPI CFSFolder::EnumObjects(
     DWORD dwFlags,
     LPENUMIDLIST *ppEnumIDList)
 {
-    return ShellObjectCreatorInit<CFileSysEnum>(sPathTarget, dwFlags, IID_IEnumIDList, ppEnumIDList);
+    return ShellObjectCreatorInit<CFileSysEnum>(sPathTarget, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
 }
 
 /**************************************************************************
@@ -280,7 +708,59 @@ HRESULT WINAPI CFSFolder::BindToObject(
     TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc,
           shdebugstr_guid(&riid), ppvOut);
 
-    return SHELL32_BindToChild(pidlRoot, sPathTarget, pidl, riid, ppvOut);
+    CComPtr<IShellFolder> pSF;
+    HRESULT hr;
+
+    if (!pidlRoot || !ppvOut || !pidl || !pidl->mkid.cb)
+    {
+        ERR("CFSFolder::BindToObject: Invalid parameters\n");
+        return E_INVALIDARG;
+    }
+
+    /* Get the pidl data */
+    FileStruct* pData = &_ILGetDataPointer(pidl)->u.file;
+    FileStructW* pDataW = _ILGetFileStructW(pidl);
+
+    if (!pDataW)
+    {
+        ERR("CFSFolder::BindToObject: Invalid pidl!\n");
+        return E_INVALIDARG;
+    }
+
+    *ppvOut = NULL;
+
+    /* Create the target folder info */
+    PERSIST_FOLDER_TARGET_INFO pfti = {0};
+    pfti.dwAttributes = -1;
+    pfti.csidl = -1;
+    PathCombineW(pfti.szTargetParsingName, sPathTarget, pDataW->wszName);
+
+    /* Get the CLSID to bind to */
+    CLSID clsidFolder;
+    if (_ILIsFolder(pidl))
+    {
+        clsidFolder = CLSID_ShellFSFolder;
+
+        if ((pData->uFileAttribs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0)
+            SHELL32_GetCLSIDForDirectory(pfti.szTargetParsingName, &clsidFolder);
+    }
+    else
+    {
+        hr = GetCLSIDForFileType(pidl, L"CLSID", &clsidFolder);
+        if (hr == S_FALSE)
+            return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+        if (hr != S_OK)
+            return hr;
+    }
+
+    hr = SHELL32_BindToSF(pidlRoot, &pfti, pidl, &clsidFolder, riid, ppvOut);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    TRACE ("-- returning (%p) %08x\n", *ppvOut, hr);
+
+    return S_OK;
+
 }
 
 /**************************************************************************
@@ -312,12 +792,53 @@ HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
                                      PCUIDLIST_RELATIVE pidl1,
                                      PCUIDLIST_RELATIVE pidl2)
 {
-    int nReturn;
+    LPPIDLDATA pData1 = _ILGetDataPointer(pidl1);
+    LPPIDLDATA pData2 = _ILGetDataPointer(pidl2);
+    FileStructW* pDataW1 = _ILGetFileStructW(pidl1);
+    FileStructW* pDataW2 = _ILGetFileStructW(pidl2);
+    BOOL bIsFolder1 = _ILIsFolder(pidl1);
+    BOOL bIsFolder2 = _ILIsFolder(pidl2);
+    LPWSTR pExtension1, pExtension2;
+
+    if (!pDataW1 || !pDataW2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS)
+        return E_INVALIDARG;
+
+    /* When sorting between a File and a Folder, the Folder gets sorted first */
+    if (bIsFolder1 != bIsFolder2)
+    {
+        return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1);
+    }
+
+    int result;
+    switch (LOWORD(lParam))
+    {
+        case 0: /* Name */
+            result = wcsicmp(pDataW1->wszName, pDataW2->wszName);
+            break;
+        case 1: /* Comments */
+            result = 0;
+            break;
+        case 2: /* Type */
+            pExtension1 = PathFindExtensionW(pDataW1->wszName);
+            pExtension2 = PathFindExtensionW(pDataW2->wszName);
+            result = wcsicmp(pExtension1, pExtension2); 
+            break;
+        case 3: /* Size */
+            result = pData1->u.file.dwFileSize - pData2->u.file.dwFileSize;
+            break;
+        case 4: /* Modified */
+            result = pData1->u.file.uFileDate - pData2->u.file.uFileDate;
+            if (result == 0)
+                result = pData1->u.file.uFileTime - pData2->u.file.uFileTime;
+            break;
+        case 5: /* Attributes */
+            return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
+    }
+
+    if (result == 0)
+        return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
 
-    TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
-    nReturn = SHELL32_CompareIDs(this, lParam, pidl1, pidl2);
-    TRACE("-- %i\n", nReturn);
-    return nReturn;
+    return MAKE_COMPARE_HRESULT(result);
 }
 
 /**************************************************************************
@@ -337,19 +858,29 @@ HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner,
         *ppvOut = NULL;
 
         if (IsEqualIID (riid, IID_IDropTarget))
-            hr = this->QueryInterface (IID_IDropTarget, ppvOut);
+            hr = CFSDropTarget_CreateInstance(sPathTarget, riid, ppvOut);
         else if (IsEqualIID (riid, IID_IContextMenu))
         {
-            FIXME ("IContextMenu not implemented\n");
-            hr = E_NOTIMPL;
+            HKEY hKeys[16];
+            UINT cKeys = 0;
+            AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
+
+            DEFCONTEXTMENU dcm;
+            dcm.hwnd = hwndOwner;
+            dcm.pcmcb = this;
+            dcm.pidlFolder = pidlRoot;
+            dcm.psf = this;
+            dcm.cidl = 0;
+            dcm.apidl = NULL;
+            dcm.cKeys = cKeys;
+            dcm.aKeys = hKeys;
+            dcm.punkAssociationInfo = NULL;
+            hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
         }
         else if (IsEqualIID (riid, IID_IShellView))
         {
-            hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
-            if (pShellView)
-            {
-                hr = pShellView->QueryInterface(riid, ppvOut);
-            }
+            SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this, NULL, this};
+            hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
         }
     }
     TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
@@ -370,9 +901,6 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
 {
     HRESULT hr = S_OK;
 
-    TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this, cidl, apidl,
-          rgfInOut, rgfInOut ? *rgfInOut : 0);
-
     if (!rgfInOut)
         return E_INVALIDARG;
     if (cidl && !apidl)
@@ -383,14 +911,25 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
 
     if(cidl == 0)
     {
-        IShellFolder *psfParent = NULL;
-        LPCITEMIDLIST rpidl = NULL;
+        LPCITEMIDLIST rpidl = ILFindLastID(pidlRoot);
 
-        hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), &rpidl);
-        if(SUCCEEDED(hr))
+        if (_ILIsFolder(rpidl) || _ILIsValue(rpidl))
+        {
+            SHELL32_GetFSItemAttributes(this, rpidl, rgfInOut);
+        }
+        else if (_ILIsDrive(rpidl))
+        {
+            IShellFolder *psfParent = NULL;
+            hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), NULL);
+            if(SUCCEEDED(hr))
+            {
+                hr = psfParent->GetAttributesOf(1, &rpidl, (SFGAOF*)rgfInOut);
+                psfParent->Release();
+            }
+        }
+        else
         {
-            SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
-            psfParent->Release();
+            ERR("Got and unknown pidl!\n");
         }
     }
     else
@@ -398,7 +937,10 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
         while (cidl > 0 && *apidl)
         {
             pdump(*apidl);
-            SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
+            if(_ILIsFolder(*apidl) || _ILIsValue(*apidl))
+                SHELL32_GetFSItemAttributes(this, *apidl, rgfInOut);
+            else
+                ERR("Got an unknown type of pidl!!!\n");
             apidl++;
             cidl--;
         }
@@ -439,8 +981,7 @@ HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
                                         REFIID riid, UINT * prgfInOut,
                                         LPVOID * ppvOut)
 {
-    LPITEMIDLIST pidl;
-    IUnknown *pObj = NULL;
+    LPVOID pObj = NULL;
     HRESULT hr = E_INVALIDARG;
 
     TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
@@ -450,11 +991,30 @@ HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
     {
         *ppvOut = NULL;
 
+        if (cidl == 1 && _ILIsValue(apidl[0]))
+        {
+            hr = _CreateExtensionUIObject(apidl[0], riid, ppvOut);
+            if(hr != S_FALSE)
+                return hr;
+        }
+
         if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
         {
-            IContextMenu  * pCm = NULL;
-            hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
-            pObj = pCm;
+            HKEY hKeys[16];
+            UINT cKeys = 0;
+            AddFSClassKeysToArray(apidl[0], hKeys, &cKeys);
+
+            DEFCONTEXTMENU dcm;
+            dcm.hwnd = hwndOwner;
+            dcm.pcmcb = this;
+            dcm.pidlFolder = pidlRoot;
+            dcm.psf = this;
+            dcm.cidl = cidl;
+            dcm.apidl = apidl;
+            dcm.cKeys = cKeys;
+            dcm.aKeys = hKeys;
+            dcm.punkAssociationInfo = NULL;
+            hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
         }
         else if (IsEqualIID (riid, IID_IDataObject))
         {
@@ -464,40 +1024,24 @@ HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
             }
             else
             {
-                hr = IDataObject_Constructor (hwndOwner, pidlRoot, (LPCITEMIDLIST*)&pidlRoot, 1, (IDataObject **)&pObj);
+                hr = E_INVALIDARG;
             }
         }
-        else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
+        else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
         {
-            pidl = ILCombine (pidlRoot, apidl[0]);
-            pObj = IExtractIconA_Constructor (pidl);
-            SHFree (pidl);
-            hr = S_OK;
-        }
-        else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
-        {
-            pidl = ILCombine (pidlRoot, apidl[0]);
-            pObj = IExtractIconW_Constructor (pidl);
-            SHFree (pidl);
-            hr = S_OK;
+            if (_ILIsValue(apidl[0]))
+                hr = _GetIconHandler(apidl[0], riid, (LPVOID*)&pObj);
+            if (hr != S_OK)
+                hr = CFSExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
         }
         else if (IsEqualIID (riid, IID_IDropTarget))
         {
             /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
             if (cidl != 1 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj)))
             {
-                IDropTarget * pDt = NULL;
-                hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
-                pObj = pDt;
+                hr = CFSDropTarget_CreateInstance(sPathTarget, riid, (LPVOID*) &pObj);
             }
         }
-        else if ((IsEqualIID(riid, IID_IShellLinkW) ||
-            IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
-        {
-            pidl = ILCombine (pidlRoot, apidl[0]);
-            hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
-            SHFree (pidl);
-        }
         else
             hr = E_NOINTERFACE;
 
@@ -584,67 +1128,47 @@ void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
 HRESULT WINAPI CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl,
         DWORD dwFlags, LPSTRRET strRet)
 {
-    LPWSTR pszPath;
-
-    HRESULT hr = S_OK;
-    int len = 0;
-
-    TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
-    pdump(pidl);
-
-    if (!pidl || !strRet)
+    if (!strRet)
         return E_INVALIDARG;
 
-    pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
-    if (!pszPath)
-        return E_OUTOFMEMORY;
-
-    if (_ILIsDesktop(pidl)) /* empty pidl */
+    /* If it is a complex pidl, let the child handle it */
+    if (!_ILIsPidlSimple (pidl)) /* complex pidl */
     {
-        if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
-                (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
-        {
-            if (sPathTarget)
-                lstrcpynW(pszPath, sPathTarget, MAX_PATH);
-        }
-        else
-            hr = E_INVALIDARG; /* pidl has to contain exactly one non null SHITEMID */
+        return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
     }
-    else if (_ILIsPidlSimple(pidl))
+    else if (pidl && !pidl->mkid.cb) /* empty pidl */
     {
-        if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
-                (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
-                sPathTarget)
-        {
-            lstrcpynW(pszPath, sPathTarget, MAX_PATH);
-            PathAddBackslashW(pszPath);
-            len = wcslen(pszPath);
-        }
-        _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
-        if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
-    } else
-        hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
-
-    if (SUCCEEDED(hr)) {
-        /* Win9x always returns ANSI strings, NT always returns Unicode strings */
-        if (GetVersion() & 0x80000000)
-        {
-            strRet->uType = STRRET_CSTR;
-            if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
-                                     NULL, NULL))
-                strRet->cStr[0] = '\0';
-            CoTaskMemFree(pszPath);
-        }
-        else
+        /* If it is an empty pidl return only the path of the folder */
+        if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && 
+            (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
+            sPathTarget)
         {
-            strRet->uType = STRRET_WSTR;
-            strRet->pOleStr = pszPath;
+            return SHSetStrRet(strRet, sPathTarget);
         }
-    } else
-        CoTaskMemFree(pszPath);
+        return E_INVALIDARG;
+    }
+    
+    int len = 0;
+    LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+    if (!pszPath)
+        return E_OUTOFMEMORY;
+
+    if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
+        (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
+        sPathTarget)
+    {
+        lstrcpynW(pszPath, sPathTarget, MAX_PATH);
+        PathAddBackslashW(pszPath);
+        len = wcslen(pszPath);
+    }
+    _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
+    if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
+
+    strRet->uType = STRRET_WSTR;
+    strRet->pOleStr = pszPath;
 
     TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
-    return hr;
+    return S_OK;
 }
 
 /**************************************************************************
@@ -667,25 +1191,25 @@ HRESULT WINAPI CFSFolder::SetNameOf(
     PITEMID_CHILD *pPidlOut)
 {
     WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
-    LPWSTR ptr;
     BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
 
     TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
            debugstr_w (lpName), dwFlags, pPidlOut);
 
-    /* build source path */
-    lstrcpynW(szSrc, sPathTarget, MAX_PATH);
-    ptr = PathAddBackslashW (szSrc);
-    if (ptr)
-        _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
-
+    FileStructW* pDataW = _ILGetFileStructW(pidl);
+    if (!pDataW)
+    {
+        ERR("Got garbage pidl\n");
+        return E_INVALIDARG;
+    }
+
+    /* build source path */
+    PathCombineW(szSrc, sPathTarget, pDataW->wszName);
+
     /* build destination path */
-    if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
-        lstrcpynW(szDest, sPathTarget, MAX_PATH);
-        ptr = PathAddBackslashW (szDest);
-        if (ptr)
-            lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
-    } else
+    if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER)
+        PathCombineW(szDest, sPathTarget, lpName);
+    else
         lstrcpynW(szDest, lpName, MAX_PATH);
 
     if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
@@ -697,7 +1221,7 @@ HRESULT WINAPI CFSFolder::SetNameOf(
     }
 
     TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
-    if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
+    if (!wcscmp(szSrc, szDest))
     {
         /* src and destination is the same */
         HRESULT hr = S_OK;
@@ -707,7 +1231,6 @@ HRESULT WINAPI CFSFolder::SetNameOf(
         return hr;
     }
 
-
     if (MoveFileW (szSrc, szDest))
     {
         HRESULT hr = S_OK;
@@ -785,10 +1308,7 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
         /* the header titles */
         psd->fmt = GenericSFHeader[iColumn].fmt;
         psd->cxChar = GenericSFHeader[iColumn].cxChar;
-        psd->str.uType = STRRET_CSTR;
-        LoadStringA(shell32_hInstance, GenericSFHeader[iColumn].colnameid,
-                    psd->str.cStr, MAX_PATH);
-        return S_OK;
+        return SHSetStrRet(&psd->str, GenericSFHeader[iColumn].colnameid);
     }
     else
     {
@@ -798,19 +1318,21 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
         switch (iColumn)
         {
             case 0:                /* name */
-                hr = GetDisplayNameOf (pidl,
-                    SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+                hr = GetDisplayNameOf (pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
                 break;
-            case 1:                /* size */
-                _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
+            case 1:                /* FIXME: comments */
+                psd->str.cStr[0] = 0;
                 break;
             case 2:                /* type */
                 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
                 break;
-            case 3:                /* date */
+            case 3:                /* size */
+                _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
+                break;
+            case 4:                /* date */
                 _ILGetFileDate(pidl, psd->str.cStr, MAX_PATH);
                 break;
-            case 4:                /* attributes */
+            case 5:                /* attributes */
                 _ILGetFileAttributes(pidl, psd->str.cStr, MAX_PATH);
                 break;
         }
@@ -826,337 +1348,6 @@ HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column,
     return E_NOTIMPL;
 }
 
-/****************************************************************************
- * ISFHelper for IShellFolder implementation
- */
-
-/****************************************************************************
- * CFSFolder::GetUniqueName
- *
- * creates a unique folder name
- */
-
-HRESULT WINAPI CFSFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
-{
-    CComPtr<IEnumIDList> penum;
-    HRESULT hr;
-    WCHAR wszText[MAX_PATH];
-    WCHAR wszNewFolder[25];
-    const WCHAR wszFormat[] = L"%s %d";
-
-    LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder));
-
-    TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
-
-    if (uLen < _countof(wszNewFolder) + 3)
-        return E_POINTER;
-
-    lstrcpynW (pwszName, wszNewFolder, uLen);
-
-    hr = EnumObjects(0, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
-    if (penum)
-    {
-        LPITEMIDLIST pidl;
-        DWORD dwFetched;
-        int i = 1;
-
-next:
-        penum->Reset ();
-        while (S_OK == penum->Next(1, &pidl, &dwFetched) && dwFetched)
-        {
-            _ILSimpleGetTextW(pidl, wszText, MAX_PATH);
-            if (0 == lstrcmpiW(wszText, pwszName))
-            {
-                _snwprintf(pwszName, uLen, wszFormat, wszNewFolder, i++);
-                if (i > 99)
-                {
-                    hr = E_FAIL;
-                    break;
-                }
-                goto next;
-            }
-        }
-    }
-    return hr;
-}
-
-/****************************************************************************
- * CFSFolder::AddFolder
- *
- * adds a new folder.
- */
-
-HRESULT WINAPI CFSFolder::AddFolder(HWND hwnd, LPCWSTR pwszName,
-                                    LPITEMIDLIST * ppidlOut)
-{
-    WCHAR wszNewDir[MAX_PATH];
-    DWORD bRes;
-    HRESULT hres = E_FAIL;
-
-    TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
-
-    wszNewDir[0] = 0;
-    if (sPathTarget)
-        lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
-    PathAppendW(wszNewDir, pwszName);
-
-    bRes = CreateDirectoryW(wszNewDir, NULL);
-    if (bRes)
-    {
-        SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
-
-        hres = S_OK;
-
-        if (ppidlOut)
-            hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
-    }
-    else
-    {
-        WCHAR wszText[128 + MAX_PATH];
-        WCHAR wszTempText[128];
-        WCHAR wszCaption[256];
-
-        /* Cannot Create folder because of permissions */
-        LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
-                    _countof(wszTempText));
-        LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
-                    _countof(wszCaption));
-        swprintf(wszText, wszTempText, wszNewDir);
-        MessageBoxW(hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
-    }
-
-    return hres;
-}
-
-/****************************************************************************
- * BuildPathsList
- *
- * Builds a list of paths like the one used in SHFileOperation from a table of
- * PIDLs relative to the given base folder
- */
-WCHAR *
-BuildPathsList(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls)
-{
-    WCHAR *pwszPathsList;
-    WCHAR *pwszListPos;
-    int iPathLen, i;
-
-    iPathLen = wcslen(wszBasePath);
-    pwszPathsList = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
-    pwszListPos = pwszPathsList;
-
-    for (i = 0; i < cidl; i++)
-    {
-        if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
-            continue;
-
-        wcscpy(pwszListPos, wszBasePath);
-        pwszListPos += iPathLen;
-        /* FIXME: abort if path too long */
-        _ILSimpleGetTextW(pidls[i], pwszListPos, MAX_PATH - iPathLen);
-        pwszListPos += wcslen(pwszListPos) + 1;
-    }
-    *pwszListPos = 0;
-    return pwszPathsList;
-}
-
-/****************************************************************************
- * CFSFolder::DeleteItems
- *
- * deletes items in folder
- */
-HRESULT WINAPI CFSFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
-{
-    UINT i;
-    SHFILEOPSTRUCTW op;
-    WCHAR wszPath[MAX_PATH];
-    WCHAR *wszPathsList;
-    HRESULT ret;
-    WCHAR *wszCurrentPath;
-
-    TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
-    if (cidl == 0) return S_OK;
-
-    if (sPathTarget)
-        lstrcpynW(wszPath, sPathTarget, MAX_PATH);
-    else
-        wszPath[0] = '\0';
-    PathAddBackslashW(wszPath);
-    wszPathsList = BuildPathsList(wszPath, cidl, apidl);
-
-    ZeroMemory(&op, sizeof(op));
-    op.hwnd = GetActiveWindow();
-    op.wFunc = FO_DELETE;
-    op.pFrom = wszPathsList;
-    op.fFlags = FOF_ALLOWUNDO;
-    if (SHFileOperationW(&op))
-    {
-        WARN("SHFileOperation failed\n");
-        ret = E_FAIL;
-    }
-    else
-        ret = S_OK;
-
-    /* we currently need to manually send the notifies */
-    wszCurrentPath = wszPathsList;
-    for (i = 0; i < cidl; i++)
-    {
-        LONG wEventId;
-
-        if (_ILIsFolder(apidl[i]))
-            wEventId = SHCNE_RMDIR;
-        else if (_ILIsValue(apidl[i]))
-            wEventId = SHCNE_DELETE;
-        else
-            continue;
-
-        /* check if file exists */
-        if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
-        {
-            LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
-            SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
-            SHFree(pidl);
-        }
-
-        wszCurrentPath += wcslen(wszCurrentPath) + 1;
-    }
-    HeapFree(GetProcessHeap(), 0, wszPathsList);
-    return ret;
-}
-
-/****************************************************************************
- * CFSFolder::CopyItems
- *
- * copies items to this folder
- */
-HRESULT WINAPI CFSFolder::CopyItems(IShellFolder * pSFFrom, UINT cidl,
-                                    LPCITEMIDLIST * apidl, BOOL bCopy)
-{
-    CComPtr<IPersistFolder2> ppf2 = NULL;
-    WCHAR szSrcPath[MAX_PATH];
-    WCHAR szTargetPath[MAX_PATH];
-    SHFILEOPSTRUCTW op;
-    LPITEMIDLIST pidl;
-    LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
-    int res, length;
-    HRESULT hr;
-    STRRET strRet;
-
-    TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
-
-    hr = pSFFrom->QueryInterface (IID_PPV_ARG(IPersistFolder2, &ppf2));
-    if (SUCCEEDED(hr))
-    {
-        hr = ppf2->GetCurFolder(&pidl);
-        if (FAILED(hr))
-        {
-            return hr;
-        }
-
-        hr = pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet);
-        if (FAILED(hr))
-        {
-            SHFree(pidl);
-            return hr;
-        }
-
-        hr = StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH);
-        if (FAILED(hr))
-        {
-            SHFree(pidl);
-            return hr;
-        }
-        SHFree(pidl);
-
-        pszSrc = PathAddBackslashW(szSrcPath);
-
-        wcscpy(szTargetPath, sPathTarget);
-        pszTarget = PathAddBackslashW(szTargetPath);
-
-        pszSrcList = BuildPathsList(szSrcPath, cidl, apidl);
-        pszTargetList = BuildPathsList(szTargetPath, cidl, apidl);
-
-        if (!pszSrcList || !pszTargetList)
-        {
-            if (pszSrcList)
-                HeapFree(GetProcessHeap(), 0, pszSrcList);
-
-            if (pszTargetList)
-                HeapFree(GetProcessHeap(), 0, pszTargetList);
-
-            SHFree(pidl);
-            return E_OUTOFMEMORY;
-        }
-
-        ZeroMemory(&op, sizeof(op));
-        if (!pszSrcList[0])
-        {
-            /* remove trailing backslash */
-            pszSrc--;
-            pszSrc[0] = L'\0';
-            op.pFrom = szSrcPath;
-        }
-        else
-        {
-            op.pFrom = pszSrcList;
-        }
-
-        if (!pszTargetList[0])
-        {
-            /* remove trailing backslash */
-            if (pszTarget - szTargetPath > 3)
-            {
-                pszTarget--;
-                pszTarget[0] = L'\0';
-            }
-            else
-            {
-                pszTarget[1] = L'\0';
-            }
-
-            op.pTo = szTargetPath;
-            op.fFlags = 0;
-        }
-        else
-        {
-            op.pTo = pszTargetList;
-            op.fFlags = FOF_MULTIDESTFILES;
-        }
-        op.hwnd = GetActiveWindow();
-        op.wFunc = bCopy ? FO_COPY : FO_MOVE;
-        op.fFlags |= FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
-
-        res = SHFileOperationW(&op);
-
-        if (res == DE_SAMEFILE)
-        {
-            length = wcslen(szTargetPath);
-
-            pszFileName = wcsrchr(pszSrcList, '\\');
-            pszFileName++;
-
-            if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
-            {
-                wcscat(szTargetPath, L" ");
-            }
-
-            wcscat(szTargetPath, pszFileName);
-            op.pTo = szTargetPath;
-
-            res = SHFileOperationW(&op);
-        }
-
-        HeapFree(GetProcessHeap(), 0, pszSrcList);
-        HeapFree(GetProcessHeap(), 0, pszTargetList);
-
-        if (res)
-            return E_FAIL;
-        else
-            return S_OK;
-    }
-    return E_FAIL;
-}
-
 /************************************************************************
  * CFSFolder::GetClassID
  */
@@ -1207,7 +1398,7 @@ HRESULT WINAPI CFSFolder::Initialize(LPCITEMIDLIST pidl)
 /**************************************************************************
  * CFSFolder::GetCurFolder
  */
-HRESULT WINAPI CFSFolder::GetCurFolder(LPITEMIDLIST * pidl)
+HRESULT WINAPI CFSFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl)
 {
     TRACE ("(%p)->(%p)\n", this, pidl);
 
@@ -1300,554 +1491,266 @@ HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti
     return E_NOTIMPL;
 }
 
-BOOL
-CFSFolder::GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
+HRESULT CFSFolder::_CreateExtensionUIObject(PCUIDLIST_RELATIVE pidl, REFIID riid, LPVOID *ppvOut)
 {
-    WCHAR wszLink[40];
+    static const WCHAR formatW[] = {'S','h','e','l','l','E','x','\\',
+        '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
+        '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
+        '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
+    WCHAR buf[MAX_PATH];
 
-    if (!bShortcut)
-    {
-        if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
-            wszLink[0] = L'\0';
-    }
+    sprintfW(buf, formatW, riid.Data1, riid.Data2, riid.Data3,
+             riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
+             riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
 
-    if (!bShortcut)
-        swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
-    else
-        swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
+    CLSID clsid;
+    HRESULT hr;
 
-    for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
-    {
-        if (!bShortcut)
-            swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
-        else
-            swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
-    }
+    hr = GetCLSIDForFileType(pidl, buf, &clsid);
+    if (hr != S_OK)
+        return hr;
 
-    return TRUE;
+    hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    return S_OK;
 }
 
-/****************************************************************************
- * IDropTarget implementation
- */
-BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
+HRESULT CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) 
 {
-    /* TODO Windows does different drop effects if dragging across drives. 
-    i.e., it will copy instead of move if the directories are on different disks. */
-
-    DWORD dwEffect = DROPEFFECT_MOVE;
-
-    *pdwEffect = DROPEFFECT_NONE;
+    HRESULT hr;
 
-    if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
-        *pdwEffect = KeyStateToDropEffect (dwKeyState);
+    TRACE("CFSFolder::_GetDropTarget entered\n");
 
-        if (*pdwEffect == DROPEFFECT_NONE)
-            *pdwEffect = dwEffect;
+    if (_ILIsFolder (pidl))
+    {
+        CComPtr<IShellFolder> psfChild;
+        hr = this->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
 
-        /* ... matches the desired effect ? */
-        if (dwEffect & *pdwEffect) {
-            return TRUE;
-        }
+        return psfChild->CreateViewObject(NULL, IID_IDropTarget, ppvOut);
     }
-    return FALSE;
-}
-
-HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
-                                    DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
-{
-    TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
-    FORMATETC fmt;
-    FORMATETC fmt2;
-    fAcceptFmt = FALSE;
 
-    InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
-    InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
+    CLSID clsid;
+    hr = GetCLSIDForFileType(pidl, L"shellex\\DropHandler", &clsid);
+    if (hr != S_OK)
+        return hr;
 
-    if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
-        fAcceptFmt = TRUE;
-    else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
-        fAcceptFmt = TRUE;
+    hr = _CreateShellExtInstance(&clsid, pidl, IID_IDropTarget, ppvOut);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return S_FALSE;
 
-    QueryDrop(dwKeyState, pdwEffect);
     return S_OK;
 }
 
-HRESULT WINAPI CFSFolder::DragOver(DWORD dwKeyState, POINTL pt,
-                                   DWORD *pdwEffect)
+HRESULT CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) 
 {
-    TRACE("(%p)\n", this);
-
-    if (!pdwEffect)
-        return E_INVALIDARG;
-
-    QueryDrop(dwKeyState, pdwEffect);
-
-    return S_OK;
-}
+    CLSID clsid;
+    HRESULT hr;
 
-HRESULT WINAPI CFSFolder::DragLeave()
-{
-    TRACE("(%p)\n", this);
+    hr = GetCLSIDForFileType(pidl, L"shellex\\IconHandler", &clsid);
+    if (hr != S_OK)
+        return hr;
 
-    fAcceptFmt = FALSE;
+    hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return S_FALSE;
 
     return S_OK;
 }
 
-HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
-                               DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+HRESULT CFSFolder::_CreateShellExtInstance(const CLSID *pclsid, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
 {
-    TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
-    
-    BOOL fIsOpAsync = FALSE;
-    CComPtr<IAsyncOperation> pAsyncOperation;
+    HRESULT hr;
+    WCHAR wszPath[MAX_PATH];
 
-    if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
+    FileStructW* pDataW = _ILGetFileStructW(pidl);
+    if (!pDataW)
     {
-        if (SUCCEEDED(pAsyncOperation->GetAsyncMode(&fIsOpAsync)) && fIsOpAsync)
-        {
-            _DoDropData *data = static_cast<_DoDropData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
-            data->This = this;
-            // Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
-            pDataObject->AddRef();
-            pAsyncOperation->StartOperation(NULL);
-            CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &data->pStream);
-            this->AddRef();
-            data->dwKeyState = dwKeyState;
-            data->pt = pt;
-            // Need to dereference as pdweffect gets freed.
-            data->pdwEffect = *pdwEffect;
-            SHCreateThread(CFSFolder::_DoDropThreadProc, data, NULL, NULL);
-            return S_OK;
-        }
+        ERR("Got garbage pidl\n");
+        return E_INVALIDARG;
     }
-    return this->_DoDrop(pDataObject, dwKeyState, pt, pdwEffect);
-}
 
-HRESULT WINAPI CFSFolder::_DoDrop(IDataObject *pDataObject,
-                               DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
-{
-    TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect);
-    FORMATETC fmt;
-    FORMATETC fmt2;
-    STGMEDIUM medium;
+    PathCombineW(wszPath, sPathTarget, pDataW->wszName);
 
-    InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
-    InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
+    CComPtr<IPersistFile> pp;
+    hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-    HRESULT hr;
-    bool bCopy = TRUE;
-    bool bLinking = FALSE;
+    pp->Load(wszPath, 0);
 
-    /* Figure out what drop operation we're doing */
-    if (pdwEffect)
+    hr = pp->QueryInterface(riid, ppvOut);
+    if (hr != S_OK)
     {
-        TRACE("Current drop effect flag %i\n", *pdwEffect);
-        if ((*pdwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
-            bCopy = FALSE;
-        if ((*pdwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK)
-            bLinking = TRUE;
+        ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
+        return hr;
     }
+    return hr;
+}
 
-    if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
-    {
-        hr = pDataObject->GetData(&fmt, &medium);
-        TRACE("CFSTR_SHELLIDLIST.\n");
-
-        /* lock the handle */
-        LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
-        if (!lpcida)
-        {
-            ReleaseStgMedium(&medium);
-            return E_FAIL;
-        }
-
-        /* convert the data into pidl */
-        LPITEMIDLIST pidl;
-        LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
-        if (!apidl)
-        {
-            ReleaseStgMedium(&medium);
-            return E_FAIL;
-        }
-
-        CComPtr<IShellFolder> psfDesktop;
-        CComPtr<IShellFolder> psfFrom = NULL;
-        CComPtr<IShellFolder> psfTarget = NULL;
-
-        hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
-        if (FAILED(hr))
-        {
-            ERR("psfTarget setting failed\n");
-            SHFree(pidl);
-            _ILFreeaPidl(apidl, lpcida->cidl);
-            ReleaseStgMedium(&medium);
-            return E_FAIL;
-        }
-
-        /* Grab the desktop shell folder */
-        hr = SHGetDesktopFolder(&psfDesktop);
-        if (FAILED(hr))
-        {
-            ERR("SHGetDesktopFolder failed\n");
-            SHFree(pidl);
-            _ILFreeaPidl(apidl, lpcida->cidl);
-            ReleaseStgMedium(&medium);
-            return E_FAIL;
-        }
+HRESULT WINAPI CFSFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
+        return S_OK;
 
-        /* Find source folder, this is where the clipboard data was copied from */
-        if (_ILIsDesktop(pidl))
+    /* no data object means no selection */
+    if (!pdtobj)
+    {
+        if (uMsg == DFM_INVOKECOMMAND && wParam == 0)
         {
-            /* use desktop shell folder */
-            psfFrom = psfDesktop;
+            PUITEMID_CHILD pidlChild = ILClone(ILFindLastID(pidlRoot));
+            LPITEMIDLIST pidlParent = ILClone(pidlRoot);
+            ILRemoveLastID(pidlParent);
+            HRESULT hr = SH_ShowPropertiesDialog(sPathTarget, pidlParent, &pidlChild);
+            if (FAILED(hr))
+                ERR("SH_ShowPropertiesDialog failed\n");
+            ILFree(pidlChild);
+            ILFree(pidlParent);
         }
-        else 
+        else if (uMsg == DFM_MERGECONTEXTMENU)
         {
-            hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
-            if (FAILED(hr))
-            {
-                ERR("no IShellFolder\n");
-                SHFree(pidl);
-                _ILFreeaPidl(apidl, lpcida->cidl);
-                ReleaseStgMedium(&medium);
-                return E_FAIL;
-            }
+            QCMINFO *pqcminfo = (QCMINFO *)lParam;
+            HMENU hpopup = CreatePopupMenu();
+            _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
+            Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
+            DestroyMenu(hpopup);
         }
 
-        if (bLinking)
-        {
-            CComPtr<IPersistFolder2> ppf2 = NULL;
-            STRRET strFile;
-            WCHAR wszTargetPath[MAX_PATH];
-            LPITEMIDLIST targetpidl;
-            WCHAR wszPath[MAX_PATH];
-            WCHAR wszTarget[MAX_PATH];
-
-            hr = this->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
-            if (SUCCEEDED(hr))
-            {
-                hr = ppf2->GetCurFolder(&targetpidl);
-                if (SUCCEEDED(hr))
-                {
-                    hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
-                    ILFree(targetpidl);
-                    if (SUCCEEDED(hr)) 
-                    {
-                        hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
-                    }
-                }
-            }
+        return S_OK;
+    }
 
-            if (FAILED(hr)) 
-            {
-                ERR("Error obtaining target path");
-            }
+    if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES)
+        return S_OK;
 
-            TRACE("target path = %s", debugstr_w(wszTargetPath));
+    return Shell_DefaultContextMenuCallBack(this, pdtobj);
+}
 
-            /* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
-            for (UINT i = 0; i < lpcida->cidl; i++)
-            {
-                //Find out which file we're copying
-                STRRET strFile;
-                hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
-                if (FAILED(hr)) 
-                {
-                    ERR("Error source obtaining path");
-                    break;
-                }
+static HBITMAP DoLoadPicture(LPCWSTR pszFileName)
+{
+    // create stream from file
+    HRESULT hr;
+    CComPtr<IStream> pStream;
+    hr = SHCreateStreamOnFileEx(pszFileName, STGM_READ, FILE_ATTRIBUTE_NORMAL,
+                                FALSE, NULL, &pStream);
+    if (FAILED(hr))
+        return NULL;
 
-                hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
-                if (FAILED(hr)) 
-                {
-                    ERR("Error putting source path into buffer");
-                    break;
-                }
-                TRACE("source path = %s", debugstr_w(wszPath));
+    // load the picture
+    HBITMAP hbm = NULL;
+    CComPtr<IPicture> pPicture;
+    OleLoadPicture(pStream, 0, FALSE, IID_IPicture, (LPVOID *)&pPicture);
 
-                // Creating a buffer to hold the combined path
-                WCHAR buffer_1[MAX_PATH] = L"";
-                WCHAR *lpStr1;
-                lpStr1 = buffer_1;
+    // get the bitmap handle
+    if (pPicture)
+    {
+        pPicture->get_Handle((OLE_HANDLE *)&hbm);
 
-                LPWSTR pwszFileName = PathFindFileNameW(wszPath);
-                LPWSTR pwszExt = PathFindExtensionW(wszPath);
-                LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, pwszFileName);
-                CComPtr<IPersistFile> ppf;
+        // copy the bitmap handle
+        hbm = (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+    }
 
-                //Check to see if it's already a link. 
-                if (!wcsicmp(pwszExt, L".lnk"))
-                {
-                    //It's a link so, we create a new one which copies the old.
-                    if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE)) 
-                    {
-                        ERR("Error getting unique file name");
-                        hr = E_FAIL;
-                        break;
-                    }
-                    hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf);
-                    if (FAILED(hr)) {
-                        ERR("Error constructing link from file");
-                        break;
-                    }
-
-                    hr = ppf->Save(wszTarget, FALSE);
-                                       if (FAILED(hr))
-                                               break;
-                                       SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
-                }
-                else
-                {
-                    //It's not a link, so build a new link using the creator class and fill it in.
-                    //Create a file name for the link
-                    if (!GetUniqueFileName(placementPath, L".lnk", wszTarget, TRUE))
-                    {
-                        ERR("Error creating unique file name");
-                        hr = E_FAIL;
-                        break;
-                    }
-
-                    CComPtr<IShellLinkW> pLink;
-                    hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
-                    if (FAILED(hr)) {
-                        ERR("Error instantiating IShellLinkW");
-                        break;
-                    }
-
-                    WCHAR szDirPath[MAX_PATH], *pwszFile;
-                    GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
-                    if (pwszFile) pwszFile[0] = 0;
-
-                    hr = pLink->SetPath(wszPath);
-                    if(FAILED(hr))
-                        break;
-
-                    hr = pLink->SetWorkingDirectory(szDirPath);
-                    if(FAILED(hr))
-                        break;
-
-                    hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
-                    if(FAILED(hr))
-                        break;
-
-                    hr = ppf->Save(wszTarget, TRUE);
-                                       if (FAILED(hr))
-                                               break;
-                                       SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
-                }
-            }
-        }
-        else 
-        {
-            hr = this->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
-        }
+    return hbm;
+}
 
-        SHFree(pidl);
-        _ILFreeaPidl(apidl, lpcida->cidl);
-        ReleaseStgMedium(&medium);
+HRESULT WINAPI CFSFolder::GetCustomViewInfo(ULONG unknown, SFVM_CUSTOMVIEWINFO_DATA *data)
+{
+    if (data == NULL)
+    {
+        return E_POINTER;
     }
-    else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
+    if (data->cbSize != sizeof(*data))
     {
-        FORMATETC fmt2;
-        InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
-        if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
-        {
-            CComPtr<IPersistFolder2> ppf2 = NULL;
-            STRRET strFile;
-            WCHAR wszTargetPath[MAX_PATH + 1];
-            LPWSTR pszSrcList;
-            LPITEMIDLIST targetpidl;
-            CComPtr<IShellFolder> psfDesktop = NULL;
-            hr = SHGetDesktopFolder(&psfDesktop);
-            if (FAILED(hr))
-            {
-                ERR("SHGetDesktopFolder failed\n");
-                return E_FAIL;
-            }
+        // NOTE: You have to set the cbData member before SFVM_GET_CUSTOMVIEWINFO call.
+        return E_INVALIDARG;
+    }
 
-            hr = this->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
-            if (SUCCEEDED(hr))
-            {
-                hr = ppf2->GetCurFolder(&targetpidl);
-                if (SUCCEEDED(hr))
-                {
-                    hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
-                    ILFree(targetpidl);
-                    if (SUCCEEDED(hr)) 
-                    {
-                        hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
-                        //Double NULL terminate.
-                        wszTargetPath[wcslen(wszTargetPath) + 1] = '\0';
-                    }
-                }
-            }
-            if (FAILED(hr)) 
-            {
-                ERR("Error obtaining target path");
-                return E_FAIL;
-            }
+    data->hbmBack = NULL;
+    data->clrText = CLR_INVALID;
+    data->clrTextBack = CLR_INVALID;
 
-            LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
-            if (!lpdf)
-            {
-                ERR("Error locking global\n");
-                return E_FAIL;
-            }
-            pszSrcList = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);
-            TRACE("Source file (just the first) = %s\n", debugstr_w(pszSrcList));
-            TRACE("Target path = %s\n", debugstr_w(wszTargetPath));
-
-            SHFILEOPSTRUCTW op;
-            ZeroMemory(&op, sizeof(op));
-            op.pFrom = pszSrcList;
-            op.pTo = wszTargetPath;
-            op.hwnd = GetActiveWindow();
-            op.wFunc = bCopy ? FO_COPY : FO_MOVE;
-            op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
-            hr = SHFileOperationW(&op);
-            return hr;
-        }
-        ERR("Error calling GetData\n");
-        hr = E_FAIL;
-    }
-    else 
-    {
-        ERR("No viable drop format.\n");
-        hr = E_FAIL;
-    }    
-    return hr;
-}
+    WCHAR szPath[MAX_PATH], szIniFile[MAX_PATH];
 
-DWORD WINAPI CFSFolder::_DoDropThreadProc(LPVOID lpParameter) {
-    CoInitialize(NULL);
-    _DoDropData *data = static_cast<_DoDropData*>(lpParameter);
-    CComPtr<IDataObject> pDataObject;
-    HRESULT hr = CoGetInterfaceAndReleaseStream (data->pStream, IID_PPV_ARG(IDataObject, &pDataObject));
+    // does the folder exists?
+    if (!SHGetPathFromIDListW(pidlRoot, szPath) || !PathIsDirectoryW(szPath))
+    {
+        return E_INVALIDARG;
+    }
 
-    if (SUCCEEDED(hr))
+    // don't use custom view in network path for security
+    if (PathIsNetworkPath(szPath))
     {
-        CComPtr<IAsyncOperation> pAsyncOperation;
-        hr = data->This->_DoDrop(pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
-        if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
-        {
-            pAsyncOperation->EndOperation(hr, NULL, data->pdwEffect);
-        }
+        return E_ACCESSDENIED;
     }
-    //Release the CFSFolder and data object holds in the copying thread.
-    data->This->Release();
-    //Release the parameter from the heap.
-    HeapFree(GetProcessHeap(), 0, data);
-    CoUninitialize();
-    return 0;
-}
 
-HRESULT WINAPI CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) {
-    HKEY hKey;
-    HRESULT hr;
+    // build the ini file path
+    StringCchCopyW(szIniFile, _countof(szIniFile), szPath);
+    PathAppend(szIniFile, L"desktop.ini");
 
-    TRACE("CFSFolder::_GetDropTarget entered\n");
+    static LPCWSTR TheGUID = L"{BE098140-A513-11D0-A3A4-00C04FD706EC}";
+    static LPCWSTR Space = L" \t\n\r\f\v";
 
-    if (_ILGetGUIDPointer (pidl) || _ILIsFolder (pidl))
-        return this->BindToObject(pidl, NULL, IID_IDropTarget, ppvOut);
+    // get info from ini file
+    WCHAR szImage[MAX_PATH], szText[64];
 
-    STRRET strFile;
-    hr = this->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
-    if (hr == S_OK)
+    // load the image
+    szImage[0] = UNICODE_NULL;
+    GetPrivateProfileStringW(TheGUID, L"IconArea_Image", L"", szImage, _countof(szImage), szIniFile);
+    if (szImage[0])
     {
-        WCHAR wszPath[MAX_PATH];
-        hr = StrRetToBufW(&strFile, pidl, wszPath, _countof(wszPath));
-
-        if (hr == S_OK)
+        StrTrimW(szImage, Space);
+        if (PathIsRelativeW(szImage))
         {
-            LPCWSTR pwszExt = PathFindExtensionW(wszPath);
-            if (pwszExt[0])
-            {
-                /* enumerate dynamic/static for a given file class */
-                if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-                {
-                    /* load dynamic extensions from file extension key, for example .jpg */
-                    _LoadDynamicDropTargetHandlerForKey(hKey, wszPath, ppvOut);
-                    RegCloseKey(hKey);
-                }
-
-                WCHAR wszTemp[40];
-                DWORD dwSize = sizeof(wszTemp);
-                if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
-                {
-                    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
-                    {
-                        /* load dynamic extensions from progid key, for example jpegfile */
-                        _LoadDynamicDropTargetHandlerForKey(hKey, wszPath, ppvOut);
-                        RegCloseKey(hKey);
-                    }
-                }
-            }
+            PathAppendW(szPath, szImage);
+            StringCchCopyW(szImage, _countof(szImage), szPath);
         }
+        data->hbmBack = DoLoadPicture(szImage);
     }
-    else
-        ERR("GetDisplayNameOf failed: %x\n", hr);
 
-    return hr;
-}
+    // load the text color
+    szText[0] = UNICODE_NULL;
+    GetPrivateProfileStringW(TheGUID, L"IconArea_Text", L"", szText, _countof(szText), szIniFile);
+    if (szText[0])
+    {
+        StrTrimW(szText, Space);
 
-HRESULT WINAPI CFSFolder::_LoadDynamicDropTargetHandlerForKey(HKEY hRootKey, LPCWSTR pwcsname, LPVOID *ppvOut) 
-{
-    TRACE("CFSFolder::_LoadDynamicDropTargetHandlerForKey entered\n");
+        LPWSTR pchEnd = NULL;
+        COLORREF cr = (wcstol(szText, &pchEnd, 0) & 0xFFFFFF);
 
-    WCHAR wszName[MAX_PATH], *pwszClsid;
-    DWORD dwSize = sizeof(wszName);
-    HRESULT hr;
+        if (pchEnd && !*pchEnd)
+            data->clrText = cr;
+    }
 
-    if (RegGetValueW(hRootKey, L"shellex\\DropHandler", NULL, RRF_RT_REG_SZ, NULL, wszName, &dwSize) == ERROR_SUCCESS)
+    // load the text background color
+    szText[0] = UNICODE_NULL;
+    GetPrivateProfileStringW(TheGUID, L"IconArea_TextBackground", L"", szText, _countof(szText), szIniFile);
+    if (szText[0])
     {
-        CLSID clsid;
-        hr = CLSIDFromString(wszName, &clsid);
-        if (hr == S_OK)
-            pwszClsid = wszName;
+        StrTrimW(szText, Space);
 
-        if (m_bGroupPolicyActive)
-        {
-            if (RegGetValueW(HKEY_LOCAL_MACHINE,
-                L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
-                pwszClsid,
-                RRF_RT_REG_SZ,
-                NULL,
-                NULL,
-                NULL) == ERROR_SUCCESS)
-            {
-                hr = _LoadDynamicDropTargetHandler(&clsid, pwcsname, ppvOut);
-            }
-        }
-        else
-        {
-            hr = _LoadDynamicDropTargetHandler(&clsid, pwcsname, ppvOut);
-        }
+        LPWSTR pchEnd = NULL;
+        COLORREF cr = (wcstol(szText, &pchEnd, 0) & 0xFFFFFF);
+
+        if (pchEnd && !*pchEnd)
+            data->clrTextBack = cr;
     }
-    else
-        return E_FAIL;
-    return hr;
-}
 
-HRESULT WINAPI CFSFolder::_LoadDynamicDropTargetHandler(const CLSID *pclsid, LPCWSTR pwcsname, LPVOID *ppvOut)
-{
-    TRACE("CFSFolder::_LoadDynamicDropTargetHandler entered\n");
-    HRESULT hr;
+    if (data->hbmBack != NULL || data->clrText != CLR_INVALID || data->clrTextBack != CLR_INVALID)
+        return S_OK;
 
-    CComPtr<IPersistFile> pp;
-    hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp));
-    if (hr != S_OK)
-    {
-        ERR("SHCoCreateInstance failed %x\n", GetLastError());
-    }
-    pp->Load(pwcsname, 0);
+    return E_FAIL;
+}
 
-    hr = pp->QueryInterface(IID_PPV_ARG(IDropTarget, (IDropTarget**) ppvOut));
-    if (hr != S_OK)
+HRESULT WINAPI CFSFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    HRESULT hr = E_NOTIMPL;
+    switch (uMsg)
     {
-        ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
-        return hr;
+    case SFVM_GET_CUSTOMVIEWINFO:
+        hr = GetCustomViewInfo((ULONG)wParam, (SFVM_CUSTOMVIEWINFO_DATA *)lParam);
+        break;
     }
     return hr;
-}
\ No newline at end of file
+}