1ccf9ce32SBrock Mammen #include "CFindFolder.h"
241d7b370SBrock Mammen #include <exdispid.h>
3ccf9ce32SBrock Mammen 
4ccf9ce32SBrock Mammen WINE_DEFAULT_DEBUG_CHANNEL(shellfind);
5ccf9ce32SBrock Mammen 
62fdaa386SBrock Mammen // FIXME: Remove this declaration after the function has been fully implemented
72fdaa386SBrock Mammen EXTERN_C HRESULT
82fdaa386SBrock Mammen WINAPI
92fdaa386SBrock Mammen SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder,
102fdaa386SBrock Mammen                            UINT cidl,
112fdaa386SBrock Mammen                            PCUITEMID_CHILD_ARRAY apidl,
122fdaa386SBrock Mammen                            DWORD dwFlags);
132fdaa386SBrock Mammen 
14ccf9ce32SBrock Mammen struct FolderViewColumns
15ccf9ce32SBrock Mammen {
16ccf9ce32SBrock Mammen     LPCWSTR wzColumnName;
17ccf9ce32SBrock Mammen     DWORD dwDefaultState;
18ccf9ce32SBrock Mammen     int fmt;
19ccf9ce32SBrock Mammen     int cxChar;
20ccf9ce32SBrock Mammen };
21ccf9ce32SBrock Mammen 
22ccf9ce32SBrock Mammen static FolderViewColumns g_ColumnDefs[] =
23ccf9ce32SBrock Mammen {
24ccf9ce32SBrock Mammen     {L"Name",      SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
25ccf9ce32SBrock Mammen     {L"In Folder", SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
26ccf9ce32SBrock Mammen     {L"Relevance", SHCOLSTATE_TYPE_STR,                          LVCFMT_LEFT, 0}
27ccf9ce32SBrock Mammen };
28ccf9ce32SBrock Mammen 
296d6bc885SBrock Mammen CFindFolder::CFindFolder() :
306d6bc885SBrock Mammen     m_hStopEvent(NULL)
316d6bc885SBrock Mammen {
326d6bc885SBrock Mammen }
336d6bc885SBrock Mammen 
342f3db8d9SBrock Mammen static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath)
35666bf346SBrock Mammen {
362f3db8d9SBrock Mammen     CComHeapPtr<ITEMIDLIST> lpFSPidl(ILCreateFromPathW(lpszPath));
372f3db8d9SBrock Mammen     if (!(LPITEMIDLIST)lpFSPidl)
382f3db8d9SBrock Mammen     {
392f3db8d9SBrock Mammen         ERR("Failed to create pidl from path\n");
402f3db8d9SBrock Mammen         return 0;
412f3db8d9SBrock Mammen     }
422f3db8d9SBrock Mammen     LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
432f3db8d9SBrock Mammen 
44666bf346SBrock Mammen     int pathLen = (wcslen(lpszPath) + 1) * sizeof(WCHAR);
452f3db8d9SBrock Mammen     int cbData = sizeof(WORD) + pathLen + lpLastFSPidl->mkid.cb;
46666bf346SBrock Mammen     LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(cbData + sizeof(WORD));
47666bf346SBrock Mammen     if (!pidl)
48666bf346SBrock Mammen         return NULL;
49666bf346SBrock Mammen 
50666bf346SBrock Mammen     LPBYTE p = (LPBYTE) pidl;
51666bf346SBrock Mammen     *((WORD *) p) = cbData;
52666bf346SBrock Mammen     p += sizeof(WORD);
53666bf346SBrock Mammen 
54666bf346SBrock Mammen     memcpy(p, lpszPath, pathLen);
55666bf346SBrock Mammen     p += pathLen;
56666bf346SBrock Mammen 
572f3db8d9SBrock Mammen     memcpy(p, lpLastFSPidl, lpLastFSPidl->mkid.cb);
582f3db8d9SBrock Mammen     p += lpLastFSPidl->mkid.cb;
59666bf346SBrock Mammen 
60666bf346SBrock Mammen     *((WORD *) p) = 0;
61666bf346SBrock Mammen 
62666bf346SBrock Mammen     return pidl;
63666bf346SBrock Mammen }
64666bf346SBrock Mammen 
65666bf346SBrock Mammen static LPCWSTR _ILGetPath(LPCITEMIDLIST pidl)
66666bf346SBrock Mammen {
67666bf346SBrock Mammen     if (!pidl || !pidl->mkid.cb)
68666bf346SBrock Mammen         return NULL;
69666bf346SBrock Mammen     return (LPCWSTR) pidl->mkid.abID;
70666bf346SBrock Mammen }
71666bf346SBrock Mammen 
72666bf346SBrock Mammen static LPCITEMIDLIST _ILGetFSPidl(LPCITEMIDLIST pidl)
73666bf346SBrock Mammen {
74666bf346SBrock Mammen     if (!pidl || !pidl->mkid.cb)
75666bf346SBrock Mammen         return pidl;
76666bf346SBrock Mammen     return (LPCITEMIDLIST) ((LPBYTE) pidl->mkid.abID
77666bf346SBrock Mammen                             + ((wcslen((LPCWSTR) pidl->mkid.abID) + 1) * sizeof(WCHAR)));
78666bf346SBrock Mammen }
79666bf346SBrock Mammen 
802f3db8d9SBrock Mammen struct _SearchData
812f3db8d9SBrock Mammen {
822f3db8d9SBrock Mammen     HWND hwnd;
832f3db8d9SBrock Mammen     HANDLE hStopEvent;
848246cd4eSBrock Mammen     CStringW szPath;
858246cd4eSBrock Mammen     CStringW szFileName;
868246cd4eSBrock Mammen     CStringA szQueryA;
878246cd4eSBrock Mammen     CStringW szQueryW;
888246cd4eSBrock Mammen     CComPtr<CFindFolder> pFindFolder;
892f3db8d9SBrock Mammen };
902f3db8d9SBrock Mammen 
918246cd4eSBrock Mammen template<typename TChar, typename TString, int (&StrNCmp)(const TChar *, const TChar *, size_t)>
928246cd4eSBrock Mammen static const TChar* StrStrN(const TChar *lpFirst, const TString &lpSrch, UINT cchMax)
932f3db8d9SBrock Mammen {
948246cd4eSBrock Mammen     if (!lpFirst || lpSrch.IsEmpty() || !cchMax)
952f3db8d9SBrock Mammen         return NULL;
962f3db8d9SBrock Mammen 
978246cd4eSBrock Mammen     for (UINT i = cchMax; i > 0 && *lpFirst; i--, lpFirst++)
982f3db8d9SBrock Mammen     {
998246cd4eSBrock Mammen         if (!StrNCmp(lpFirst, lpSrch, lpSrch.GetLength()))
1008246cd4eSBrock Mammen             return (const TChar*)lpFirst;
1012f3db8d9SBrock Mammen     }
1022f3db8d9SBrock Mammen 
1032f3db8d9SBrock Mammen     return NULL;
1042f3db8d9SBrock Mammen }
1052f3db8d9SBrock Mammen 
1068246cd4eSBrock Mammen template<typename TChar, typename TString, int (&StrNCmp)(const TChar *, const TChar *, size_t)>
1078246cd4eSBrock Mammen static UINT StrStrNCount(const TChar *lpFirst, const TString &lpSrch, UINT cchMax)
1088246cd4eSBrock Mammen {
1098246cd4eSBrock Mammen     const TChar *lpSearchEnd = lpFirst + cchMax;
1108246cd4eSBrock Mammen     UINT uCount = 0;
1118246cd4eSBrock Mammen     while (lpFirst < lpSearchEnd && (lpFirst = StrStrN<TChar, TString, StrNCmp>(lpFirst, lpSrch, cchMax)))
1128246cd4eSBrock Mammen     {
1138246cd4eSBrock Mammen         uCount++;
1148246cd4eSBrock Mammen         lpFirst += lpSrch.GetLength();
1158246cd4eSBrock Mammen         cchMax = lpSearchEnd - lpFirst;
1168246cd4eSBrock Mammen     }
1178246cd4eSBrock Mammen     return uCount;
1188246cd4eSBrock Mammen }
1198246cd4eSBrock Mammen 
1208246cd4eSBrock Mammen static UINT StrStrCountA(const CHAR *lpFirst, const CStringA &lpSrch, UINT cchMax)
1218246cd4eSBrock Mammen {
1228246cd4eSBrock Mammen     return StrStrNCount<CHAR, CStringA, strncmp>(lpFirst, lpSrch, cchMax);
1238246cd4eSBrock Mammen }
1248246cd4eSBrock Mammen 
1258246cd4eSBrock Mammen static UINT StrStrCountW(const WCHAR *lpFirst, const CStringW &lpSrch, UINT cchMax)
1268246cd4eSBrock Mammen {
1278246cd4eSBrock Mammen     return StrStrNCount<WCHAR, CStringW, wcsncmp>(lpFirst, lpSrch, cchMax);
1288246cd4eSBrock Mammen }
1298246cd4eSBrock Mammen 
1302f3db8d9SBrock Mammen static UINT SearchFile(LPCWSTR lpFilePath, _SearchData *pSearchData)
1312f3db8d9SBrock Mammen {
1322f3db8d9SBrock Mammen     HANDLE hFile = CreateFileW(lpFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
1332f3db8d9SBrock Mammen     if (hFile == INVALID_HANDLE_VALUE)
1342f3db8d9SBrock Mammen         return 0;
1352f3db8d9SBrock Mammen 
1362f3db8d9SBrock Mammen     DWORD size = GetFileSize(hFile, NULL);
1372f3db8d9SBrock Mammen     HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
1382f3db8d9SBrock Mammen     CloseHandle(hFile);
1392f3db8d9SBrock Mammen     if (hFileMap == INVALID_HANDLE_VALUE)
1402f3db8d9SBrock Mammen         return 0;
1412f3db8d9SBrock Mammen 
1422f3db8d9SBrock Mammen     LPBYTE lpFileContent = (LPBYTE) MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
1432f3db8d9SBrock Mammen     CloseHandle(hFileMap);
1442f3db8d9SBrock Mammen     if (!lpFileContent)
1452f3db8d9SBrock Mammen         return 0;
1462f3db8d9SBrock Mammen 
1472f3db8d9SBrock Mammen     UINT uMatches = 0;
1488246cd4eSBrock Mammen     // Check for UTF-16 BOM
1498246cd4eSBrock Mammen     if (size >= 2 && lpFileContent[0] == 0xFF && lpFileContent[1] == 0xFE)
1502f3db8d9SBrock Mammen     {
1518246cd4eSBrock Mammen         uMatches = StrStrCountW((LPCWSTR) lpFileContent, pSearchData->szQueryW, size / sizeof(WCHAR));
1522f3db8d9SBrock Mammen     }
1532f3db8d9SBrock Mammen     else
1542f3db8d9SBrock Mammen     {
1558246cd4eSBrock Mammen         uMatches = StrStrCountA((LPCSTR) lpFileContent, pSearchData->szQueryA, size / sizeof(CHAR));
1562f3db8d9SBrock Mammen     }
1572f3db8d9SBrock Mammen 
1582f3db8d9SBrock Mammen     UnmapViewOfFile(lpFileContent);
1592f3db8d9SBrock Mammen 
1602f3db8d9SBrock Mammen     return uMatches;
1612f3db8d9SBrock Mammen }
1622f3db8d9SBrock Mammen 
163*c46d6036SBrock Mammen static UINT RecursiveFind(LPCWSTR lpPath, _SearchData *pSearchData)
1642f3db8d9SBrock Mammen {
1652f3db8d9SBrock Mammen     if (WaitForSingleObject(pSearchData->hStopEvent, 0) != WAIT_TIMEOUT)
166*c46d6036SBrock Mammen         return 0;
1672f3db8d9SBrock Mammen 
1682f3db8d9SBrock Mammen     WCHAR szPath[MAX_PATH];
1692f3db8d9SBrock Mammen     WIN32_FIND_DATAW FindData;
1702f3db8d9SBrock Mammen     HANDLE hFindFile;
1712f3db8d9SBrock Mammen     BOOL bMoreFiles = TRUE;
172*c46d6036SBrock Mammen     UINT uTotalFound = 0;
1732f3db8d9SBrock Mammen 
1742f3db8d9SBrock Mammen     PathCombineW(szPath, lpPath, L"*.*");
1752f3db8d9SBrock Mammen 
1762f3db8d9SBrock Mammen     for (hFindFile = FindFirstFileW(szPath, &FindData);
1772f3db8d9SBrock Mammen         bMoreFiles && hFindFile != INVALID_HANDLE_VALUE;
1782f3db8d9SBrock Mammen         bMoreFiles = FindNextFileW(hFindFile, &FindData))
1792f3db8d9SBrock Mammen     {
1802f3db8d9SBrock Mammen         if (!wcscmp(FindData.cFileName, L".") || !wcscmp(FindData.cFileName, L".."))
1812f3db8d9SBrock Mammen             continue;
1822f3db8d9SBrock Mammen 
1832f3db8d9SBrock Mammen         PathCombineW(szPath, lpPath, FindData.cFileName);
1842f3db8d9SBrock Mammen 
1852f3db8d9SBrock Mammen         if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1862f3db8d9SBrock Mammen         {
187*c46d6036SBrock Mammen             CStringW status;
188*c46d6036SBrock Mammen             status.Format(IDS_SEARCH_FOLDER, FindData.cFileName);
189*c46d6036SBrock Mammen             PostMessageW(pSearchData->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) StrDupW(status.GetBuffer()));
1902f3db8d9SBrock Mammen 
191*c46d6036SBrock Mammen             uTotalFound += RecursiveFind(szPath, pSearchData);
1922f3db8d9SBrock Mammen         }
1938246cd4eSBrock Mammen         else if ((pSearchData->szFileName.IsEmpty() || PathMatchSpecW(FindData.cFileName, pSearchData->szFileName))
1948246cd4eSBrock Mammen                 && (pSearchData->szQueryA.IsEmpty() || SearchFile(szPath, pSearchData)))
1952f3db8d9SBrock Mammen         {
1968246cd4eSBrock Mammen             uTotalFound++;
1978246cd4eSBrock Mammen             PostMessageW(pSearchData->hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM) StrDupW(szPath));
1982f3db8d9SBrock Mammen         }
1992f3db8d9SBrock Mammen     }
2002f3db8d9SBrock Mammen 
2012f3db8d9SBrock Mammen     if (hFindFile != INVALID_HANDLE_VALUE)
2022f3db8d9SBrock Mammen         FindClose(hFindFile);
203*c46d6036SBrock Mammen 
204*c46d6036SBrock Mammen     return uTotalFound;
2052f3db8d9SBrock Mammen }
2062f3db8d9SBrock Mammen 
2078246cd4eSBrock Mammen DWORD WINAPI CFindFolder::SearchThreadProc(LPVOID lpParameter)
2082f3db8d9SBrock Mammen {
2092f3db8d9SBrock Mammen     _SearchData *data = static_cast<_SearchData*>(lpParameter);
2102f3db8d9SBrock Mammen 
21141d7b370SBrock Mammen     data->pFindFolder->NotifyConnections(DISPID_SEARCHSTART);
21241d7b370SBrock Mammen 
213*c46d6036SBrock Mammen     UINT uTotalFound = RecursiveFind(data->szPath, data);
2142f3db8d9SBrock Mammen 
21541d7b370SBrock Mammen     data->pFindFolder->NotifyConnections(DISPID_SEARCHCOMPLETE);
21641d7b370SBrock Mammen 
217*c46d6036SBrock Mammen     CStringW status;
218*c46d6036SBrock Mammen     status.Format(IDS_SEARCH_FILES_FOUND, uTotalFound);
219*c46d6036SBrock Mammen     ::PostMessageW(data->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) StrDupW(status.GetBuffer()));
220*c46d6036SBrock Mammen 
221*c46d6036SBrock Mammen     delete data;
2222f3db8d9SBrock Mammen 
2232f3db8d9SBrock Mammen     return 0;
2242f3db8d9SBrock Mammen }
2252f3db8d9SBrock Mammen 
22641d7b370SBrock Mammen void CFindFolder::NotifyConnections(DISPID id)
22741d7b370SBrock Mammen {
22841d7b370SBrock Mammen     DISPPARAMS dispatchParams = {0};
22941d7b370SBrock Mammen     CComDynamicUnkArray &subscribers =
23041d7b370SBrock Mammen         IConnectionPointImpl<CFindFolder, &DIID_DSearchCommandEvents>::m_vec;
23141d7b370SBrock Mammen     for (IUnknown** pSubscriber = subscribers.begin(); pSubscriber < subscribers.end(); pSubscriber++)
23241d7b370SBrock Mammen     {
23341d7b370SBrock Mammen         if (!*pSubscriber)
23441d7b370SBrock Mammen             continue;
23541d7b370SBrock Mammen 
23641d7b370SBrock Mammen         CComPtr<IDispatch> pDispatch;
23741d7b370SBrock Mammen         HRESULT hResult = (*pSubscriber)->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch));
23841d7b370SBrock Mammen         if (!FAILED_UNEXPECTEDLY(hResult))
23941d7b370SBrock Mammen             pDispatch->Invoke(id, GUID_NULL, 0, DISPATCH_METHOD, &dispatchParams, NULL, NULL, NULL);
24041d7b370SBrock Mammen     }
24141d7b370SBrock Mammen }
24241d7b370SBrock Mammen 
2432f3db8d9SBrock Mammen LRESULT CFindFolder::StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
244666bf346SBrock Mammen {
245666bf346SBrock Mammen     if (!lParam)
246666bf346SBrock Mammen         return 0;
247666bf346SBrock Mammen 
2482f3db8d9SBrock Mammen     // Clear all previous search results
249666bf346SBrock Mammen     UINT uItemIndex;
2502f3db8d9SBrock Mammen     m_shellFolderView->RemoveObject(NULL, &uItemIndex);
251666bf346SBrock Mammen 
2522f3db8d9SBrock Mammen     _SearchData* pSearchData = new _SearchData();
2532f3db8d9SBrock Mammen     pSearchData->pFindFolder = this;
2542f3db8d9SBrock Mammen     pSearchData->hwnd = m_hWnd;
2558246cd4eSBrock Mammen 
2568246cd4eSBrock Mammen     SearchStart *pSearchParams = (SearchStart *) lParam;
2578246cd4eSBrock Mammen     pSearchData->szPath = pSearchParams->szPath;
2588246cd4eSBrock Mammen     pSearchData->szFileName = pSearchParams->szFileName;
2598246cd4eSBrock Mammen     pSearchData->szQueryA = pSearchParams->szQuery;
2608246cd4eSBrock Mammen     pSearchData->szQueryW = pSearchParams->szQuery;
2618246cd4eSBrock Mammen     SHFree(pSearchParams);
2628246cd4eSBrock Mammen 
2632f3db8d9SBrock Mammen     if (m_hStopEvent)
2642f3db8d9SBrock Mammen         SetEvent(m_hStopEvent);
2652f3db8d9SBrock Mammen     pSearchData->hStopEvent = m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
2662f3db8d9SBrock Mammen 
2678246cd4eSBrock Mammen     if (!SHCreateThread(SearchThreadProc, pSearchData, NULL, NULL))
2682f3db8d9SBrock Mammen     {
2692f3db8d9SBrock Mammen         SHFree(pSearchData);
2702f3db8d9SBrock Mammen         return HRESULT_FROM_WIN32(GetLastError());
2712f3db8d9SBrock Mammen     }
2722f3db8d9SBrock Mammen 
2732f3db8d9SBrock Mammen     return S_OK;
2742f3db8d9SBrock Mammen }
2752f3db8d9SBrock Mammen 
27641f9ad12SBrock Mammen LRESULT CFindFolder::StopSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
27741f9ad12SBrock Mammen {
27841f9ad12SBrock Mammen     if (m_hStopEvent)
27941f9ad12SBrock Mammen     {
28041f9ad12SBrock Mammen         SetEvent(m_hStopEvent);
28141f9ad12SBrock Mammen         m_hStopEvent = NULL;
28241f9ad12SBrock Mammen     }
28341f9ad12SBrock Mammen     return 0;
28441f9ad12SBrock Mammen }
28541f9ad12SBrock Mammen 
2862f3db8d9SBrock Mammen LRESULT CFindFolder::AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2872f3db8d9SBrock Mammen {
2882f3db8d9SBrock Mammen     if (!lParam)
2892f3db8d9SBrock Mammen         return 0;
2902f3db8d9SBrock Mammen 
2912f3db8d9SBrock Mammen     CComHeapPtr<WCHAR> lpPath((LPWSTR) lParam);
2922f3db8d9SBrock Mammen 
2932f3db8d9SBrock Mammen     CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(lpPath));
2942f3db8d9SBrock Mammen     if (lpSearchPidl)
2952f3db8d9SBrock Mammen     {
2962f3db8d9SBrock Mammen         UINT uItemIndex;
2972f3db8d9SBrock Mammen         m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
2982f3db8d9SBrock Mammen     }
2992f3db8d9SBrock Mammen 
3002f3db8d9SBrock Mammen     return 0;
301666bf346SBrock Mammen }
302666bf346SBrock Mammen 
30304fcbe32SBrock Mammen LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
30404fcbe32SBrock Mammen {
305*c46d6036SBrock Mammen     CComHeapPtr<WCHAR> status((LPWSTR) lParam);
30604fcbe32SBrock Mammen     if (m_shellBrowser)
30704fcbe32SBrock Mammen     {
308*c46d6036SBrock Mammen         m_shellBrowser->SetStatusTextSB(status);
30904fcbe32SBrock Mammen     }
31004fcbe32SBrock Mammen 
31104fcbe32SBrock Mammen     return S_OK;
31204fcbe32SBrock Mammen }
31304fcbe32SBrock Mammen 
314ccf9ce32SBrock Mammen // *** IShellFolder2 methods ***
315ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetDefaultSearchGUID(GUID *pguid)
316ccf9ce32SBrock Mammen {
317ccf9ce32SBrock Mammen     UNIMPLEMENTED;
318ccf9ce32SBrock Mammen     return E_NOTIMPL;
319ccf9ce32SBrock Mammen }
320ccf9ce32SBrock Mammen 
321ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::EnumSearches(IEnumExtraSearch **ppenum)
322ccf9ce32SBrock Mammen {
323ccf9ce32SBrock Mammen     UNIMPLEMENTED;
324ccf9ce32SBrock Mammen     return E_NOTIMPL;
325ccf9ce32SBrock Mammen }
326ccf9ce32SBrock Mammen 
327ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetDefaultColumn(DWORD, ULONG *pSort, ULONG *pDisplay)
328ccf9ce32SBrock Mammen {
329ccf9ce32SBrock Mammen     if (pSort)
330ccf9ce32SBrock Mammen         *pSort = 0;
331ccf9ce32SBrock Mammen     if (pDisplay)
332ccf9ce32SBrock Mammen         *pDisplay = 0;
333ccf9ce32SBrock Mammen     return S_OK;
334ccf9ce32SBrock Mammen }
335ccf9ce32SBrock Mammen 
336ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
337ccf9ce32SBrock Mammen {
338c0799cd2SBrock Mammen     if (!pcsFlags)
339ccf9ce32SBrock Mammen         return E_INVALIDARG;
340c0799cd2SBrock Mammen     if (iColumn >= _countof(g_ColumnDefs))
341c0799cd2SBrock Mammen         return m_pisfInner->GetDefaultColumnState(iColumn - _countof(g_ColumnDefs) + 1, pcsFlags);
342ccf9ce32SBrock Mammen     *pcsFlags = g_ColumnDefs[iColumn].dwDefaultState;
343ccf9ce32SBrock Mammen     return S_OK;
344ccf9ce32SBrock Mammen }
345ccf9ce32SBrock Mammen 
346ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
347ccf9ce32SBrock Mammen {
348c0799cd2SBrock Mammen     return m_pisfInner->GetDetailsEx(pidl, pscid, pv);
349ccf9ce32SBrock Mammen }
350ccf9ce32SBrock Mammen 
351ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *pDetails)
352ccf9ce32SBrock Mammen {
353ccf9ce32SBrock Mammen     if (iColumn >= _countof(g_ColumnDefs))
354666bf346SBrock Mammen         return m_pisfInner->GetDetailsOf(_ILGetFSPidl(pidl), iColumn - _countof(g_ColumnDefs) + 1, pDetails);
355ccf9ce32SBrock Mammen 
356ccf9ce32SBrock Mammen     pDetails->cxChar = g_ColumnDefs[iColumn].cxChar;
357ccf9ce32SBrock Mammen     pDetails->fmt = g_ColumnDefs[iColumn].fmt;
358ccf9ce32SBrock Mammen 
359ccf9ce32SBrock Mammen     if (!pidl)
360ccf9ce32SBrock Mammen         return SHSetStrRet(&pDetails->str, g_ColumnDefs[iColumn].wzColumnName);
361ccf9ce32SBrock Mammen 
362666bf346SBrock Mammen     if (iColumn == 1)
363666bf346SBrock Mammen     {
364666bf346SBrock Mammen         WCHAR path[MAX_PATH];
365666bf346SBrock Mammen         wcscpy(path, _ILGetPath(pidl));
366666bf346SBrock Mammen         PathRemoveFileSpecW(path);
367666bf346SBrock Mammen         return SHSetStrRet(&pDetails->str, path);
368666bf346SBrock Mammen     }
369666bf346SBrock Mammen 
370ccf9ce32SBrock Mammen     return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
371ccf9ce32SBrock Mammen }
372ccf9ce32SBrock Mammen 
373ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
374ccf9ce32SBrock Mammen {
375ccf9ce32SBrock Mammen     UNIMPLEMENTED;
376ccf9ce32SBrock Mammen     return E_NOTIMPL;
377ccf9ce32SBrock Mammen }
378ccf9ce32SBrock Mammen 
379ccf9ce32SBrock Mammen // *** IShellFolder methods ***
380ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten,
381ccf9ce32SBrock Mammen                                            PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
382ccf9ce32SBrock Mammen {
383ccf9ce32SBrock Mammen     UNIMPLEMENTED;
384ccf9ce32SBrock Mammen     return E_NOTIMPL;
385ccf9ce32SBrock Mammen }
386ccf9ce32SBrock Mammen 
387ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
388ccf9ce32SBrock Mammen {
389ccf9ce32SBrock Mammen     *ppEnumIDList = NULL;
390ccf9ce32SBrock Mammen     return S_FALSE;
391ccf9ce32SBrock Mammen }
392ccf9ce32SBrock Mammen 
393ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
394ccf9ce32SBrock Mammen {
395ccf9ce32SBrock Mammen     UNIMPLEMENTED;
396ccf9ce32SBrock Mammen     return E_NOTIMPL;
397ccf9ce32SBrock Mammen }
398ccf9ce32SBrock Mammen 
399ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
400ccf9ce32SBrock Mammen {
401ccf9ce32SBrock Mammen     UNIMPLEMENTED;
402ccf9ce32SBrock Mammen     return E_NOTIMPL;
403ccf9ce32SBrock Mammen }
404ccf9ce32SBrock Mammen 
405ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
406ccf9ce32SBrock Mammen {
407666bf346SBrock Mammen     return m_pisfInner->CompareIDs(lParam, _ILGetFSPidl(pidl1), _ILGetFSPidl(pidl2));
408ccf9ce32SBrock Mammen }
409ccf9ce32SBrock Mammen 
410ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
411ccf9ce32SBrock Mammen {
412ccf9ce32SBrock Mammen     if (riid == IID_IShellView)
413ccf9ce32SBrock Mammen     {
414ccf9ce32SBrock Mammen         SFV_CREATE sfvparams = {};
415ccf9ce32SBrock Mammen         sfvparams.cbSize = sizeof(SFV_CREATE);
416ccf9ce32SBrock Mammen         sfvparams.pshf = this;
4179c290040SBrock Mammen         sfvparams.psfvcb = this;
418666bf346SBrock Mammen         HRESULT hr = SHCreateShellFolderView(&sfvparams, (IShellView **) ppvOut);
419666bf346SBrock Mammen         if (FAILED_UNEXPECTEDLY(hr))
420666bf346SBrock Mammen         {
421666bf346SBrock Mammen             return hr;
422666bf346SBrock Mammen         }
423666bf346SBrock Mammen 
424666bf346SBrock Mammen         return ((IShellView * ) * ppvOut)->QueryInterface(IID_PPV_ARG(IShellFolderView, &m_shellFolderView));
425ccf9ce32SBrock Mammen     }
426ccf9ce32SBrock Mammen     return E_NOINTERFACE;
427ccf9ce32SBrock Mammen }
428ccf9ce32SBrock Mammen 
429ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
430ccf9ce32SBrock Mammen {
431666bf346SBrock Mammen     CComHeapPtr<PCITEMID_CHILD> aFSPidl;
432666bf346SBrock Mammen     aFSPidl.Allocate(cidl);
433666bf346SBrock Mammen     for (UINT i = 0; i < cidl; i++)
434666bf346SBrock Mammen     {
435666bf346SBrock Mammen         aFSPidl[i] = _ILGetFSPidl(apidl[i]);
436666bf346SBrock Mammen     }
437666bf346SBrock Mammen 
438666bf346SBrock Mammen     return m_pisfInner->GetAttributesOf(cidl, aFSPidl, rgfInOut);
439ccf9ce32SBrock Mammen }
440ccf9ce32SBrock Mammen 
441ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
442ccf9ce32SBrock Mammen                                         UINT *prgfInOut, LPVOID *ppvOut)
443ccf9ce32SBrock Mammen {
4442fdaa386SBrock Mammen     if (riid == IID_IDataObject && cidl == 1)
4452fdaa386SBrock Mammen     {
4462fdaa386SBrock Mammen         WCHAR path[MAX_PATH];
4472fdaa386SBrock Mammen         wcscpy(path, (LPCWSTR) apidl[0]->mkid.abID);
4482fdaa386SBrock Mammen         PathRemoveFileSpecW(path);
4496d6bc885SBrock Mammen         CComHeapPtr<ITEMIDLIST> rootPidl(ILCreateFromPathW(path));
4502fdaa386SBrock Mammen         if (!rootPidl)
4512fdaa386SBrock Mammen             return E_OUTOFMEMORY;
4522fdaa386SBrock Mammen         PCITEMID_CHILD aFSPidl[1];
4532fdaa386SBrock Mammen         aFSPidl[0] = _ILGetFSPidl(apidl[0]);
4542fdaa386SBrock Mammen         return IDataObject_Constructor(hwndOwner, rootPidl, aFSPidl, cidl, (IDataObject **) ppvOut);
4552fdaa386SBrock Mammen     }
4562fdaa386SBrock Mammen 
457666bf346SBrock Mammen     if (cidl <= 0)
458666bf346SBrock Mammen     {
459c0799cd2SBrock Mammen         return m_pisfInner->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
460ccf9ce32SBrock Mammen     }
461ccf9ce32SBrock Mammen 
462666bf346SBrock Mammen     PCITEMID_CHILD *aFSPidl = new PCITEMID_CHILD[cidl];
463666bf346SBrock Mammen     for (UINT i = 0; i < cidl; i++)
464666bf346SBrock Mammen     {
465666bf346SBrock Mammen         aFSPidl[i] = _ILGetFSPidl(apidl[i]);
466666bf346SBrock Mammen     }
467666bf346SBrock Mammen 
4682fdaa386SBrock Mammen     if (riid == IID_IContextMenu)
4692fdaa386SBrock Mammen     {
4702fdaa386SBrock Mammen         HKEY hKeys[16];
4712fdaa386SBrock Mammen         UINT cKeys = 0;
4722fdaa386SBrock Mammen         AddFSClassKeysToArray(aFSPidl[0], hKeys, &cKeys);
4732fdaa386SBrock Mammen 
4742fdaa386SBrock Mammen         DEFCONTEXTMENU dcm;
4752fdaa386SBrock Mammen         dcm.hwnd = hwndOwner;
4762fdaa386SBrock Mammen         dcm.pcmcb = this;
4772fdaa386SBrock Mammen         dcm.pidlFolder = m_pidl;
4782fdaa386SBrock Mammen         dcm.psf = this;
4792fdaa386SBrock Mammen         dcm.cidl = cidl;
4802fdaa386SBrock Mammen         dcm.apidl = apidl;
4812fdaa386SBrock Mammen         dcm.cKeys = cKeys;
4822fdaa386SBrock Mammen         dcm.aKeys = hKeys;
4832fdaa386SBrock Mammen         dcm.punkAssociationInfo = NULL;
4842fdaa386SBrock Mammen         HRESULT hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
4852fdaa386SBrock Mammen         delete[] aFSPidl;
4862fdaa386SBrock Mammen 
4872fdaa386SBrock Mammen         return hr;
4882fdaa386SBrock Mammen     }
4892fdaa386SBrock Mammen 
490666bf346SBrock Mammen     HRESULT hr = m_pisfInner->GetUIObjectOf(hwndOwner, cidl, aFSPidl, riid, prgfInOut, ppvOut);
491666bf346SBrock Mammen     delete[] aFSPidl;
492666bf346SBrock Mammen 
493666bf346SBrock Mammen     return hr;
494666bf346SBrock Mammen }
495666bf346SBrock Mammen 
496ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET pName)
497ccf9ce32SBrock Mammen {
498666bf346SBrock Mammen     return m_pisfInner->GetDisplayNameOf(_ILGetFSPidl(pidl), dwFlags, pName);
499ccf9ce32SBrock Mammen }
500ccf9ce32SBrock Mammen 
501ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags,
502ccf9ce32SBrock Mammen                                     PITEMID_CHILD *pPidlOut)
503ccf9ce32SBrock Mammen {
504ccf9ce32SBrock Mammen     UNIMPLEMENTED;
505ccf9ce32SBrock Mammen     return E_NOTIMPL;
506ccf9ce32SBrock Mammen }
5079c290040SBrock Mammen 
5089c290040SBrock Mammen //// *** IShellFolderViewCB method ***
5099c290040SBrock Mammen STDMETHODIMP CFindFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
5109c290040SBrock Mammen {
5119c290040SBrock Mammen     switch (uMsg)
5129c290040SBrock Mammen     {
5139c290040SBrock Mammen         case SFVM_DEFVIEWMODE:
5149c290040SBrock Mammen         {
5159c290040SBrock Mammen             FOLDERVIEWMODE *pViewMode = (FOLDERVIEWMODE *) lParam;
5169c290040SBrock Mammen             *pViewMode = FVM_DETAILS;
5179c290040SBrock Mammen             return S_OK;
5189c290040SBrock Mammen         }
51906fd04d7SBrock Mammen         case SFVM_WINDOWCREATED:
52006fd04d7SBrock Mammen         {
52106fd04d7SBrock Mammen             SubclassWindow((HWND) wParam);
52204fcbe32SBrock Mammen 
52304fcbe32SBrock Mammen             CComPtr<IServiceProvider> pServiceProvider;
52404fcbe32SBrock Mammen             HRESULT hr = m_shellFolderView->QueryInterface(IID_PPV_ARG(IServiceProvider, &pServiceProvider));
52504fcbe32SBrock Mammen             if (FAILED_UNEXPECTEDLY(hr))
52604fcbe32SBrock Mammen             {
52704fcbe32SBrock Mammen                 return hr;
52804fcbe32SBrock Mammen             }
52904fcbe32SBrock Mammen             return pServiceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARG(IShellBrowser, &m_shellBrowser));
53006fd04d7SBrock Mammen         }
5319c290040SBrock Mammen     }
5329c290040SBrock Mammen     return E_NOTIMPL;
5339c290040SBrock Mammen }
5349c290040SBrock Mammen 
5352fdaa386SBrock Mammen //// *** IContextMenuCB method ***
5362fdaa386SBrock Mammen STDMETHODIMP CFindFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
5372fdaa386SBrock Mammen {
5382fdaa386SBrock Mammen     switch (uMsg)
5392fdaa386SBrock Mammen     {
5402fdaa386SBrock Mammen         case DFM_MERGECONTEXTMENU:
5412fdaa386SBrock Mammen         {
5422fdaa386SBrock Mammen             QCMINFO *pqcminfo = (QCMINFO *) lParam;
5432fdaa386SBrock Mammen             _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
5442fdaa386SBrock Mammen             _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_STRING, L"Open Containing Folder", MFS_ENABLED);
5452fdaa386SBrock Mammen             _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_SEPARATOR, NULL, 0);
5462fdaa386SBrock Mammen             return S_OK;
5472fdaa386SBrock Mammen         }
5482fdaa386SBrock Mammen         case DFM_INVOKECOMMAND:
5492fdaa386SBrock Mammen         case DFM_INVOKECOMMANDEX:
5502fdaa386SBrock Mammen         {
5512fdaa386SBrock Mammen             if (wParam != 1)
5522fdaa386SBrock Mammen                 break;
5532fdaa386SBrock Mammen 
5542fdaa386SBrock Mammen             PCUITEMID_CHILD *apidl;
5552fdaa386SBrock Mammen             UINT cidl;
5562fdaa386SBrock Mammen             HRESULT hr = m_shellFolderView->GetSelectedObjects(&apidl, &cidl);
5572fdaa386SBrock Mammen             if (FAILED_UNEXPECTEDLY(hr))
5582fdaa386SBrock Mammen                 return hr;
5592fdaa386SBrock Mammen 
5602fdaa386SBrock Mammen             for (UINT i = 0; i < cidl; i++)
5612fdaa386SBrock Mammen             {
5626d6bc885SBrock Mammen                 CComHeapPtr<ITEMIDLIST> pidl;
5632fdaa386SBrock Mammen                 DWORD attrs = 0;
5642fdaa386SBrock Mammen                 hr = SHILCreateFromPathW((LPCWSTR) apidl[i]->mkid.abID, &pidl, &attrs);
5652fdaa386SBrock Mammen                 if (SUCCEEDED(hr))
5662fdaa386SBrock Mammen                 {
5672fdaa386SBrock Mammen                     SHOpenFolderAndSelectItems(NULL, 1, &pidl, 0);
5682fdaa386SBrock Mammen                 }
5692fdaa386SBrock Mammen             }
5702fdaa386SBrock Mammen 
5712fdaa386SBrock Mammen             return S_OK;
5722fdaa386SBrock Mammen         }
5732fdaa386SBrock Mammen         case DFM_GETDEFSTATICID:
5742fdaa386SBrock Mammen             return S_FALSE;
5752fdaa386SBrock Mammen     }
5762fdaa386SBrock Mammen     return Shell_DefaultContextMenuCallBack(m_pisfInner, pdtobj);
5772fdaa386SBrock Mammen }
5782fdaa386SBrock Mammen 
579ccf9ce32SBrock Mammen //// *** IPersistFolder2 methods ***
580ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetCurFolder(LPITEMIDLIST *pidl)
581ccf9ce32SBrock Mammen {
582ccf9ce32SBrock Mammen     *pidl = ILClone(m_pidl);
583ccf9ce32SBrock Mammen     return S_OK;
584ccf9ce32SBrock Mammen }
585ccf9ce32SBrock Mammen 
586ccf9ce32SBrock Mammen // *** IPersistFolder methods ***
587ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::Initialize(LPCITEMIDLIST pidl)
588ccf9ce32SBrock Mammen {
589ccf9ce32SBrock Mammen     m_pidl = ILClone(pidl);
590ccf9ce32SBrock Mammen     if (!m_pidl)
591ccf9ce32SBrock Mammen         return E_OUTOFMEMORY;
592ccf9ce32SBrock Mammen 
593c0799cd2SBrock Mammen     return SHELL32_CoCreateInitSF(m_pidl,
594c0799cd2SBrock Mammen                                   NULL,
595c0799cd2SBrock Mammen                                   NULL,
596c0799cd2SBrock Mammen                                   &CLSID_ShellFSFolder,
597c0799cd2SBrock Mammen                                   IID_PPV_ARG(IShellFolder2, &m_pisfInner));
598ccf9ce32SBrock Mammen }
599ccf9ce32SBrock Mammen 
600ccf9ce32SBrock Mammen // *** IPersist methods ***
601ccf9ce32SBrock Mammen STDMETHODIMP CFindFolder::GetClassID(CLSID *pClassId)
602ccf9ce32SBrock Mammen {
603ccf9ce32SBrock Mammen     if (pClassId == NULL)
604ccf9ce32SBrock Mammen         return E_INVALIDARG;
605ccf9ce32SBrock Mammen     memcpy(pClassId, &CLSID_FindFolder, sizeof(CLSID));
606ccf9ce32SBrock Mammen     return S_OK;
607ccf9ce32SBrock Mammen }
608