[SHELL] IPersistFolder::Initialize takes a PCIDLIST_ABSOLUTE. CORE-16385
[reactos.git] / dll / win32 / browseui / shellfind / CFindFolder.cpp
index 4e986be..0a2aec8 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "CFindFolder.h"
+#include <exdispid.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
 
@@ -17,9 +18,75 @@ SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder,
                            PCUITEMID_CHILD_ARRAY apidl,
                            DWORD dwFlags);
 
+static HRESULT SHELL32_CoCreateInitSF(LPCITEMIDLIST pidlRoot, PERSIST_FOLDER_TARGET_INFO* ppfti,
+                                LPCITEMIDLIST pidlChild, const GUID* clsid, REFIID riid, LPVOID *ppvOut)
+{
+    HRESULT hr;
+    CComPtr<IShellFolder> pShellFolder;
+
+    hr = SHCoCreateInstance(NULL, clsid, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
+    if (FAILED(hr))
+        return hr;
+
+    LPITEMIDLIST pidlAbsolute = ILCombine (pidlRoot, pidlChild);
+    CComPtr<IPersistFolder> ppf;
+    CComPtr<IPersistFolder3> ppf3;
+
+    if (ppfti && SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3))))
+    {
+        ppf3->InitializeEx(NULL, pidlAbsolute, ppfti);
+    }
+    else if (SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf))))
+    {
+        ppf->Initialize(pidlAbsolute);
+    }
+    ILFree (pidlAbsolute);
+
+    return pShellFolder->QueryInterface(riid, ppvOut);
+}
+
+static void WINAPI _InsertMenuItemW(
+        HMENU hMenu,
+        UINT indexMenu,
+        BOOL fByPosition,
+        UINT wID,
+        UINT fType,
+        LPCWSTR dwTypeData,
+        UINT fState)
+{
+    MENUITEMINFOW mii;
+    WCHAR wszText[100];
+
+    ZeroMemory(&mii, sizeof(mii));
+    mii.cbSize = sizeof(mii);
+    if (fType == MFT_SEPARATOR)
+        mii.fMask = MIIM_ID | MIIM_TYPE;
+    else if (fType == MFT_STRING)
+    {
+        mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
+        if (IS_INTRESOURCE(dwTypeData))
+        {
+            if (LoadStringW(_AtlBaseModule.GetResourceInstance(), LOWORD((ULONG_PTR)dwTypeData), wszText, _countof(wszText)))
+                mii.dwTypeData = wszText;
+            else
+            {
+                ERR("failed to load string %p\n", dwTypeData);
+                return;
+            }
+        }
+        else
+            mii.dwTypeData = (LPWSTR)dwTypeData;
+        mii.fState = fState;
+    }
+
+    mii.wID = wID;
+    mii.fType = fType;
+    InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
+}
+
 struct FolderViewColumns
 {
-    LPCWSTR wzColumnName;
+    int iResource;
     DWORD dwDefaultState;
     int fmt;
     int cxChar;
@@ -27,9 +94,9 @@ struct FolderViewColumns
 
 static FolderViewColumns g_ColumnDefs[] =
 {
-    {L"Name",      SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
-    {L"In Folder", SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
-    {L"Relevance", SHCOLSTATE_TYPE_STR,                          LVCFMT_LEFT, 0}
+    {IDS_COL_NAME,      SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
+    {IDS_COL_LOCATION,  SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
+    {IDS_COL_RELEVANCE, SHCOLSTATE_TYPE_STR,                          LVCFMT_LEFT, 0}
 };
 
 CFindFolder::CFindFolder() :
@@ -37,10 +104,18 @@ CFindFolder::CFindFolder() :
 {
 }
 
-static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath, LPCITEMIDLIST lpcFindDataPidl)
+static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath)
 {
-    int pathLen = (wcslen(lpszPath) + 1) * sizeof(WCHAR);
-    int cbData = sizeof(WORD) + pathLen + lpcFindDataPidl->mkid.cb;
+    CComHeapPtr<ITEMIDLIST> lpFSPidl(ILCreateFromPathW(lpszPath));
+    if (!lpFSPidl)
+    {
+        ERR("Failed to create pidl from path\n");
+        return NULL;
+    }
+    LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
+
+    int pathLen = (PathFindFileNameW(lpszPath) - lpszPath) * sizeof(WCHAR);
+    int cbData = sizeof(WORD) + pathLen + lpLastFSPidl->mkid.cb;
     LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(cbData + sizeof(WORD));
     if (!pidl)
         return NULL;
@@ -50,10 +125,12 @@ static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath, LPCITEMIDLIST lpcFindDataPidl)
     p += sizeof(WORD);
 
     memcpy(p, lpszPath, pathLen);
-    p += pathLen;
+    p += pathLen - sizeof(WCHAR);
+    *((WCHAR *) p) = '\0';
+    p += sizeof(WCHAR);
 
-    memcpy(p, lpcFindDataPidl, lpcFindDataPidl->mkid.cb);
-    p += lpcFindDataPidl->mkid.cb;
+    memcpy(p, lpLastFSPidl, lpLastFSPidl->mkid.cb);
+    p += lpLastFSPidl->mkid.cb;
 
     *((WORD *) p) = 0;
 
@@ -75,55 +152,240 @@ static LPCITEMIDLIST _ILGetFSPidl(LPCITEMIDLIST pidl)
                             + ((wcslen((LPCWSTR) pidl->mkid.abID) + 1) * sizeof(WCHAR)));
 }
 
-LRESULT CFindFolder::AddItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+struct _SearchData
 {
-    if (!lParam)
+    HWND hwnd;
+    HANDLE hStopEvent;
+    CStringW szPath;
+    CStringW szFileName;
+    CStringA szQueryA;
+    CStringW szQueryW;
+    CComPtr<CFindFolder> pFindFolder;
+};
+
+template<typename TChar, typename TString, int (&StrNCmp)(const TChar *, const TChar *, size_t)>
+static const TChar* StrStrN(const TChar *lpFirst, const TString &lpSrch, UINT cchMax)
+{
+    if (!lpFirst || lpSrch.IsEmpty() || !cchMax)
+        return NULL;
+
+    for (UINT i = cchMax; i > 0 && *lpFirst; i--, lpFirst++)
+    {
+        if (!StrNCmp(lpFirst, lpSrch, lpSrch.GetLength()))
+            return (const TChar*)lpFirst;
+    }
+
+    return NULL;
+}
+
+template<typename TChar, typename TString, int (&StrNCmp)(const TChar *, const TChar *, size_t)>
+static UINT StrStrNCount(const TChar *lpFirst, const TString &lpSrch, UINT cchMax)
+{
+    const TChar *lpSearchEnd = lpFirst + cchMax;
+    UINT uCount = 0;
+    while (lpFirst < lpSearchEnd && (lpFirst = StrStrN<TChar, TString, StrNCmp>(lpFirst, lpSrch, cchMax)))
+    {
+        uCount++;
+        lpFirst += lpSrch.GetLength();
+        cchMax = lpSearchEnd - lpFirst;
+    }
+    return uCount;
+}
+
+static UINT StrStrCountNIA(const CHAR *lpFirst, const CStringA &lpSrch, UINT cchMax)
+{
+    return StrStrNCount<CHAR, CStringA, _strnicmp>(lpFirst, lpSrch, cchMax);
+}
+
+static UINT StrStrCountNIW(const WCHAR *lpFirst, const CStringW &lpSrch, UINT cchMax)
+{
+    return StrStrNCount<WCHAR, CStringW, _wcsnicmp>(lpFirst, lpSrch, cchMax);
+}
+
+static UINT SearchFile(LPCWSTR lpFilePath, _SearchData *pSearchData)
+{
+    HANDLE hFile = CreateFileW(lpFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
         return 0;
 
-    HRESULT hr;
-    LPWSTR path = (LPWSTR) lParam;
+    DWORD size = GetFileSize(hFile, NULL);
+    HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+    CloseHandle(hFile);
+    if (hFileMap == INVALID_HANDLE_VALUE)
+        return 0;
 
-    CComPtr<IShellFolder> pShellFolder;
-    hr = SHGetDesktopFolder(&pShellFolder);
-    if (FAILED_UNEXPECTEDLY(hr))
+    LPBYTE lpFileContent = (LPBYTE) MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
+    CloseHandle(hFileMap);
+    if (!lpFileContent)
+        return 0;
+
+    UINT uMatches = 0;
+    // Check for UTF-16 BOM
+    if (size >= 2 && lpFileContent[0] == 0xFF && lpFileContent[1] == 0xFE)
     {
-        LocalFree(path);
-        return hr;
+        uMatches = StrStrCountNIW((LPCWSTR) lpFileContent, pSearchData->szQueryW, size / sizeof(WCHAR));
     }
+    else
+    {
+        uMatches = StrStrCountNIA((LPCSTR) lpFileContent, pSearchData->szQueryA, size / sizeof(CHAR));
+    }
+
+    UnmapViewOfFile(lpFileContent);
 
-    CComHeapPtr<ITEMIDLIST> lpFSPidl;
-    DWORD pchEaten;
-    hr = pShellFolder->ParseDisplayName(NULL, NULL, path, &pchEaten, &lpFSPidl, NULL);
-    if (FAILED_UNEXPECTEDLY(hr))
+    return uMatches;
+}
+
+static UINT RecursiveFind(LPCWSTR lpPath, _SearchData *pSearchData)
+{
+    if (WaitForSingleObject(pSearchData->hStopEvent, 0) != WAIT_TIMEOUT)
+        return 0;
+
+    WCHAR szPath[MAX_PATH];
+    WIN32_FIND_DATAW FindData;
+    HANDLE hFindFile;
+    BOOL bMoreFiles = TRUE;
+    UINT uTotalFound = 0;
+
+    PathCombineW(szPath, lpPath, L"*.*");
+
+    for (hFindFile = FindFirstFileW(szPath, &FindData);
+        bMoreFiles && hFindFile != INVALID_HANDLE_VALUE;
+        bMoreFiles = FindNextFileW(hFindFile, &FindData))
     {
-        LocalFree(path);
-        return hr;
+        if (!wcscmp(FindData.cFileName, L".") || !wcscmp(FindData.cFileName, L".."))
+            continue;
+
+        PathCombineW(szPath, lpPath, FindData.cFileName);
+
+        if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        {
+            CStringW status;
+            status.Format(IDS_SEARCH_FOLDER, FindData.cFileName);
+            PostMessageW(pSearchData->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) StrDupW(status.GetBuffer()));
+
+            uTotalFound += RecursiveFind(szPath, pSearchData);
+        }
+        else if ((pSearchData->szFileName.IsEmpty() || PathMatchSpecW(FindData.cFileName, pSearchData->szFileName))
+                && (pSearchData->szQueryA.IsEmpty() || SearchFile(szPath, pSearchData)))
+        {
+            uTotalFound++;
+            PostMessageW(pSearchData->hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM) StrDupW(szPath));
+        }
     }
 
-    LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
-    CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(path, lpLastFSPidl));
-    LocalFree(path);
-    if (!lpSearchPidl)
+    if (hFindFile != INVALID_HANDLE_VALUE)
+        FindClose(hFindFile);
+
+    return uTotalFound;
+}
+
+DWORD WINAPI CFindFolder::SearchThreadProc(LPVOID lpParameter)
+{
+    _SearchData *data = static_cast<_SearchData*>(lpParameter);
+
+    data->pFindFolder->NotifyConnections(DISPID_SEARCHSTART);
+
+    UINT uTotalFound = RecursiveFind(data->szPath, data);
+
+    data->pFindFolder->NotifyConnections(DISPID_SEARCHCOMPLETE);
+
+    CStringW status;
+    status.Format(IDS_SEARCH_FILES_FOUND, uTotalFound);
+    ::PostMessageW(data->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) StrDupW(status.GetBuffer()));
+    ::SendMessageW(data->hwnd, WM_SEARCH_STOP, 0, 0);
+
+    CloseHandle(data->hStopEvent);
+    delete data;
+
+    return 0;
+}
+
+void CFindFolder::NotifyConnections(DISPID id)
+{
+    DISPPARAMS dispatchParams = {0};
+    CComDynamicUnkArray &subscribers =
+        IConnectionPointImpl<CFindFolder, &DIID_DSearchCommandEvents>::m_vec;
+    for (IUnknown** pSubscriber = subscribers.begin(); pSubscriber < subscribers.end(); pSubscriber++)
     {
-        return E_OUTOFMEMORY;
+        if (!*pSubscriber)
+            continue;
+
+        CComPtr<IDispatch> pDispatch;
+        HRESULT hResult = (*pSubscriber)->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
+        if (!FAILED_UNEXPECTEDLY(hResult))
+            pDispatch->Invoke(id, GUID_NULL, 0, DISPATCH_METHOD, &dispatchParams, NULL, NULL, NULL);
     }
+}
+
+LRESULT CFindFolder::StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+    if (!lParam)
+        return 0;
 
+    // Clear all previous search results
     UINT uItemIndex;
-    hr = m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
+    m_shellFolderView->RemoveObject(NULL, &uItemIndex);
+
+    _SearchData* pSearchData = new _SearchData();
+    pSearchData->pFindFolder = this;
+    pSearchData->hwnd = m_hWnd;
+
+    SearchStart *pSearchParams = (SearchStart *) lParam;
+    pSearchData->szPath = pSearchParams->szPath;
+    pSearchData->szFileName = pSearchParams->szFileName;
+    pSearchData->szQueryA = pSearchParams->szQuery;
+    pSearchData->szQueryW = pSearchParams->szQuery;
+    SHFree(pSearchParams);
+
+    if (m_hStopEvent)
+        SetEvent(m_hStopEvent);
+    pSearchData->hStopEvent = m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+    if (!SHCreateThread(SearchThreadProc, pSearchData, NULL, NULL))
+    {
+        SHFree(pSearchData);
+        return 0;
+    }
+
+    return 0;
+}
+
+LRESULT CFindFolder::StopSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+    if (m_hStopEvent)
+    {
+        SetEvent(m_hStopEvent);
+        m_hStopEvent = NULL;
+    }
+    return 0;
+}
+
+LRESULT CFindFolder::AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+    if (!lParam)
+        return 0;
+
+    CComHeapPtr<WCHAR> lpPath((LPWSTR) lParam);
+
+    CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(lpPath));
+    if (lpSearchPidl)
+    {
+        UINT uItemIndex;
+        m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
+    }
 
-    return hr;
+    return 0;
 }
 
 LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
 {
-    LPWSTR status = (LPWSTR) lParam;
+    CComHeapPtr<WCHAR> status((LPWSTR) lParam);
     if (m_shellBrowser)
     {
         m_shellBrowser->SetStatusTextSB(status);
     }
-    LocalFree(status);
 
-    return S_OK;
+    return 0;
 }
 
 // *** IShellFolder2 methods ***
@@ -172,14 +434,11 @@ STDMETHODIMP CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELL
     pDetails->fmt = g_ColumnDefs[iColumn].fmt;
 
     if (!pidl)
-        return SHSetStrRet(&pDetails->str, g_ColumnDefs[iColumn].wzColumnName);
+        return SHSetStrRet(&pDetails->str, _AtlBaseModule.GetResourceInstance(), g_ColumnDefs[iColumn].iResource);
 
     if (iColumn == 1)
     {
-        WCHAR path[MAX_PATH];
-        wcscpy(path, _ILGetPath(pidl));
-        PathRemoveFileSpecW(path);
-        return SHSetStrRet(&pDetails->str, path);
+        return SHSetStrRet(&pDetails->str, _ILGetPath(pidl));
     }
 
     return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
@@ -253,28 +512,88 @@ STDMETHODIMP CFindFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl
     return m_pisfInner->GetAttributesOf(cidl, aFSPidl, rgfInOut);
 }
 
-STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
-                                        UINT *prgfInOut, LPVOID *ppvOut)
+class CFindFolderContextMenu :
+        public IContextMenu,
+        public CComObjectRootEx<CComMultiThreadModelNoCS>
 {
-    if (riid == IID_IDataObject && cidl == 1)
+    CComPtr<IContextMenu> m_pInner;
+    CComPtr<IShellFolderView> m_shellFolderView;
+    UINT m_firstCmdId;
+    static const UINT ADDITIONAL_MENU_ITEMS = 2;
+
+    //// *** IContextMenu methods ***
+    STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
     {
-        WCHAR path[MAX_PATH];
-        wcscpy(path, (LPCWSTR) apidl[0]->mkid.abID);
-        PathRemoveFileSpecW(path);
-        CComHeapPtr<ITEMIDLIST> rootPidl(ILCreateFromPathW(path));
-        if (!rootPidl)
-            return E_OUTOFMEMORY;
-        PCITEMID_CHILD aFSPidl[1];
-        aFSPidl[0] = _ILGetFSPidl(apidl[0]);
-        return IDataObject_Constructor(hwndOwner, rootPidl, aFSPidl, cidl, (IDataObject **) ppvOut);
+        m_firstCmdId = indexMenu;
+        _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst++, MFT_STRING, MAKEINTRESOURCEW(IDS_SEARCH_OPEN_FOLDER), MFS_ENABLED);
+        _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst++, MFT_SEPARATOR, NULL, 0);
+        return m_pInner->QueryContextMenu(hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
     }
 
+    STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+    {
+        if (!IS_INTRESOURCE(lpcmi->lpVerb))
+        {
+            return m_pInner->InvokeCommand(lpcmi);
+        }
+
+        if (LOWORD(lpcmi->lpVerb) < m_firstCmdId + ADDITIONAL_MENU_ITEMS)
+        {
+            PCUITEMID_CHILD *apidl;
+            UINT cidl;
+            HRESULT hResult = m_shellFolderView->GetSelectedObjects(&apidl, &cidl);
+            if (FAILED_UNEXPECTEDLY(hResult))
+                return hResult;
+
+            for (UINT i = 0; i < cidl; i++)
+            {
+                CComHeapPtr<ITEMIDLIST> folderPidl(ILCreateFromPathW(_ILGetPath(apidl[i])));
+                if (!folderPidl)
+                    return E_OUTOFMEMORY;
+                LPCITEMIDLIST pidl = _ILGetFSPidl(apidl[i]);
+                SHOpenFolderAndSelectItems(folderPidl, 1, &pidl, 0);
+            }
+            return S_OK;
+        }
+
+        CMINVOKECOMMANDINFOEX actualCmdInfo;
+        memcpy(&actualCmdInfo, lpcmi, lpcmi->cbSize);
+        actualCmdInfo.lpVerb -= ADDITIONAL_MENU_ITEMS;
+        return m_pInner->InvokeCommand((CMINVOKECOMMANDINFO *)&actualCmdInfo);
+    }
+
+    STDMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
+    {
+        return m_pInner->GetCommandString(idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+    }
+
+public:
+    static HRESULT Create(IShellFolderView *pShellFolderView, IContextMenu *pInnerContextMenu, IContextMenu **pContextMenu)
+    {
+        CComObject<CFindFolderContextMenu> *pObj;
+        HRESULT hResult = CComObject<CFindFolderContextMenu>::CreateInstance(&pObj);
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        pObj->m_shellFolderView = pShellFolderView;
+        pObj->m_pInner = pInnerContextMenu;
+        return pObj->QueryInterface(IID_PPV_ARG(IContextMenu, pContextMenu));
+    }
+
+    BEGIN_COM_MAP(CFindFolderContextMenu)
+        COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
+    END_COM_MAP()
+};
+
+STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
+                                        UINT *prgfInOut, LPVOID *ppvOut)
+{
     if (cidl <= 0)
     {
         return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
     }
 
-    PCITEMID_CHILD *aFSPidl = new PCITEMID_CHILD[cidl];
+    CComHeapPtr<PCITEMID_CHILD> aFSPidl;
+    aFSPidl.Allocate(cidl);
     for (UINT i = 0; i < cidl; i++)
     {
         aFSPidl[i] = _ILGetFSPidl(apidl[i]);
@@ -282,30 +601,25 @@ STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHI
 
     if (riid == IID_IContextMenu)
     {
-        HKEY hKeys[16];
-        UINT cKeys = 0;
-        AddFSClassKeysToArray(aFSPidl[0], hKeys, &cKeys);
-
-        DEFCONTEXTMENU dcm;
-        dcm.hwnd = hwndOwner;
-        dcm.pcmcb = this;
-        dcm.pidlFolder = m_pidl;
-        dcm.psf = this;
-        dcm.cidl = cidl;
-        dcm.apidl = apidl;
-        dcm.cKeys = cKeys;
-        dcm.aKeys = hKeys;
-        dcm.punkAssociationInfo = NULL;
-        HRESULT hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
-        delete[] aFSPidl;
-
-        return hr;
+        CComHeapPtr<ITEMIDLIST> folderPidl(ILCreateFromPathW(_ILGetPath(apidl[0])));
+        if (!folderPidl)
+            return E_OUTOFMEMORY;
+        CComPtr<IShellFolder> pDesktopFolder;
+        HRESULT hResult = SHGetDesktopFolder(&pDesktopFolder);
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        CComPtr<IShellFolder> pShellFolder;
+        hResult = pDesktopFolder->BindToObject(folderPidl, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        CComPtr<IContextMenu> pContextMenu;
+        hResult = pShellFolder->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, (LPVOID *)&pContextMenu);
+        if (FAILED_UNEXPECTEDLY(hResult))
+            return hResult;
+        return CFindFolderContextMenu::Create(m_shellFolderView, pContextMenu, (IContextMenu **)ppvOut);
     }
 
-    HRESULT hr = m_pisfInner->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, ppvOut);
-    delete[] aFSPidl;
-
-    return hr;
+    return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, ppvOut);
 }
 
 STDMETHODIMP CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET pName)
@@ -333,73 +647,41 @@ STDMETHODIMP CFindFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
         }
         case SFVM_WINDOWCREATED:
         {
+            // Subclass window to receive window messages
             SubclassWindow((HWND) wParam);
 
+            // Get shell browser for updating status bar text
             CComPtr<IServiceProvider> pServiceProvider;
             HRESULT hr = m_shellFolderView->QueryInterface(IID_PPV_ARG(IServiceProvider, &pServiceProvider));
             if (FAILED_UNEXPECTEDLY(hr))
-            {
                 return hr;
-            }
-            return pServiceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &m_shellBrowser));
-        }
-    }
-    return E_NOTIMPL;
-}
-
-//// *** IContextMenuCB method ***
-STDMETHODIMP CFindFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    switch (uMsg)
-    {
-        case DFM_MERGECONTEXTMENU:
-        {
-            QCMINFO *pqcminfo = (QCMINFO *) lParam;
-            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
-            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_STRING, L"Open Containing Folder", MFS_ENABLED);
-            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
-            return S_OK;
-        }
-        case DFM_INVOKECOMMAND:
-        case DFM_INVOKECOMMANDEX:
-        {
-            if (wParam != 1)
-                break;
-
-            PCUITEMID_CHILD *apidl;
-            UINT cidl;
-            HRESULT hr = m_shellFolderView->GetSelectedObjects(&apidl, &cidl);
+            hr = pServiceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &m_shellBrowser));
             if (FAILED_UNEXPECTEDLY(hr))
                 return hr;
 
-            for (UINT i = 0; i < cidl; i++)
-            {
-                CComHeapPtr<ITEMIDLIST> pidl;
-                DWORD attrs = 0;
-                hr = SHILCreateFromPathW((LPCWSTR) apidl[i]->mkid.abID, &pidl, &attrs);
-                if (SUCCEEDED(hr))
-                {
-                    SHOpenFolderAndSelectItems(NULL, 1, &pidl, 0);
-                }
-            }
-
-            return S_OK;
+            // Open search bar
+            CComPtr<IWebBrowser2> pWebBrowser2;
+            hr = m_shellBrowser->QueryInterface(IID_PPV_ARG(IWebBrowser2, &pWebBrowser2));
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
+            WCHAR pwszGuid[MAX_PATH];
+            StringFromGUID2(CLSID_FileSearchBand, pwszGuid, _countof(pwszGuid));
+            CComVariant searchBar(pwszGuid);
+            return pWebBrowser2->ShowBrowserBar(&searchBar, NULL, NULL);
         }
-        case DFM_GETDEFSTATICID:
-            return S_FALSE;
     }
-    return Shell_DefaultContextMenuCallBack(m_pisfInner, pdtobj);
+    return E_NOTIMPL;
 }
 
 //// *** IPersistFolder2 methods ***
-STDMETHODIMP CFindFolder::GetCurFolder(LPITEMIDLIST *pidl)
+STDMETHODIMP CFindFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl)
 {
     *pidl = ILClone(m_pidl);
     return S_OK;
 }
 
 // *** IPersistFolder methods ***
-STDMETHODIMP CFindFolder::Initialize(LPCITEMIDLIST pidl)
+STDMETHODIMP CFindFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
 {
     m_pidl = ILClone(pidl);
     if (!m_pidl)
@@ -417,6 +699,6 @@ STDMETHODIMP CFindFolder::GetClassID(CLSID *pClassId)
 {
     if (pClassId == NULL)
         return E_INVALIDARG;
-    memcpy(pClassId, &CLSID_FindFolder, sizeof(CLSID));
+    *pClassId = CLSID_FindFolder;
     return S_OK;
 }