[SHELLFIND] Add search functionality
authorBrock Mammen <brockmammen@gmail.com>
Sat, 3 Aug 2019 17:07:59 +0000 (12:07 -0500)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Sun, 15 Sep 2019 16:46:36 +0000 (19:46 +0300)
dll/win32/browseui/shellfind/CFindFolder.cpp
dll/win32/browseui/shellfind/CFindFolder.h
dll/win32/browseui/shellfind/CSearchBar.cpp
dll/win32/browseui/shellfind/CSearchBar.h

index 4e986be..535c1af 100644 (file)
@@ -37,10 +37,18 @@ CFindFolder::CFindFolder() :
 {
 }
 
 {
 }
 
-static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath, LPCITEMIDLIST lpcFindDataPidl)
+static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath)
 {
 {
+    CComHeapPtr<ITEMIDLIST> lpFSPidl(ILCreateFromPathW(lpszPath));
+    if (!(LPITEMIDLIST)lpFSPidl)
+    {
+        ERR("Failed to create pidl from path\n");
+        return 0;
+    }
+    LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
+
     int pathLen = (wcslen(lpszPath) + 1) * sizeof(WCHAR);
     int pathLen = (wcslen(lpszPath) + 1) * sizeof(WCHAR);
-    int cbData = sizeof(WORD) + pathLen + lpcFindDataPidl->mkid.cb;
+    int cbData = sizeof(WORD) + pathLen + lpLastFSPidl->mkid.cb;
     LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(cbData + sizeof(WORD));
     if (!pidl)
         return NULL;
     LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(cbData + sizeof(WORD));
     if (!pidl)
         return NULL;
@@ -52,8 +60,8 @@ static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath, LPCITEMIDLIST lpcFindDataPidl)
     memcpy(p, lpszPath, pathLen);
     p += pathLen;
 
     memcpy(p, lpszPath, pathLen);
     p += pathLen;
 
-    memcpy(p, lpcFindDataPidl, lpcFindDataPidl->mkid.cb);
-    p += lpcFindDataPidl->mkid.cb;
+    memcpy(p, lpLastFSPidl, lpLastFSPidl->mkid.cb);
+    p += lpLastFSPidl->mkid.cb;
 
     *((WORD *) p) = 0;
 
 
     *((WORD *) p) = 0;
 
@@ -75,53 +83,199 @@ static LPCITEMIDLIST _ILGetFSPidl(LPCITEMIDLIST pidl)
                             + ((wcslen((LPCWSTR) pidl->mkid.abID) + 1) * sizeof(WCHAR)));
 }
 
                             + ((wcslen((LPCWSTR) pidl->mkid.abID) + 1) * sizeof(WCHAR)));
 }
 
-LRESULT CFindFolder::AddItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+struct _SearchData
 {
 {
-    if (!lParam)
-        return 0;
+    HWND hwnd;
+    HANDLE hStopEvent;
+    SearchStart *pSearchParams;
+};
 
 
-    HRESULT hr;
-    LPWSTR path = (LPWSTR) lParam;
+static LPCSTR WINAPI StrStrNA(LPCSTR lpFirst, LPCSTR lpSrch, UINT cchMax)
+{
+    UINT i;
+    int len;
 
 
-    CComPtr<IShellFolder> pShellFolder;
-    hr = SHGetDesktopFolder(&pShellFolder);
-    if (FAILED_UNEXPECTEDLY(hr))
+    if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
+        return NULL;
+
+    len = strlen(lpSrch);
+
+    for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
     {
     {
-        LocalFree(path);
-        return hr;
+        if (!strncmp(lpFirst, lpSrch, len))
+            return (LPCSTR)lpFirst;
     }
 
     }
 
-    CComHeapPtr<ITEMIDLIST> lpFSPidl;
-    DWORD pchEaten;
-    hr = pShellFolder->ParseDisplayName(NULL, NULL, path, &pchEaten, &lpFSPidl, NULL);
-    if (FAILED_UNEXPECTEDLY(hr))
+    return NULL;
+}
+
+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;
+
+    DWORD size = GetFileSize(hFile, NULL);
+    HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+    CloseHandle(hFile);
+    if (hFileMap == INVALID_HANDLE_VALUE)
+        return 0;
+
+    LPBYTE lpFileContent = (LPBYTE) MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
+    CloseHandle(hFileMap);
+    if (!lpFileContent)
+        return 0;
+
+    UINT uMatches = 0;
+    if ((size >= 2) && (lpFileContent[0] == 0xFF) && (lpFileContent[1] == 0xFE))
     {
     {
-        LocalFree(path);
-        return hr;
+        // UTF16 LE
+        LPCWSTR lpSearchPos = (LPCWSTR) lpFileContent;
+        DWORD dwCharsRemaining = size / sizeof(WCHAR);
+        const LPCWSTR lpSearchEnd = (LPCWSTR) lpFileContent + dwCharsRemaining;
+        const LPCWSTR lpszQuery = pSearchData->pSearchParams->szQuery;
+        const size_t queryLen = wcslen(lpszQuery);
+        while ((lpSearchPos = StrStrNW(lpSearchPos, lpszQuery, dwCharsRemaining))
+                && lpSearchPos < lpSearchEnd)
+        {
+            uMatches++;
+            lpSearchPos += queryLen;
+            dwCharsRemaining -= queryLen;
+        }
+    }
+    else
+    {
+        DWORD len = WideCharToMultiByte(CP_ACP, 0, pSearchData->pSearchParams->szQuery, -1, NULL, 0, NULL, NULL);
+        const LPSTR lpszQuery = new CHAR[len];
+        WideCharToMultiByte(CP_ACP, 0, pSearchData->pSearchParams->szQuery, -1, lpszQuery, len, NULL, NULL);
+        LPCSTR lpSearchPos = (LPCSTR) lpFileContent;
+        DWORD dwCharsRemaining = size;
+        const LPCSTR lpSearchEnd = (LPCSTR) lpFileContent + dwCharsRemaining;
+        const size_t queryLen = len;
+        while ((lpSearchPos = StrStrNA(lpSearchPos, lpszQuery, dwCharsRemaining))
+                && lpSearchPos < lpSearchEnd)
+        {
+            uMatches++;
+            lpSearchPos += queryLen;
+            dwCharsRemaining -= queryLen;
+        }
     }
 
     }
 
-    LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
-    CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(path, lpLastFSPidl));
-    LocalFree(path);
-    if (!lpSearchPidl)
+    UnmapViewOfFile(lpFileContent);
+
+    return uMatches;
+}
+
+static VOID RecursiveFind(LPCWSTR lpPath, _SearchData *pSearchData)
+{
+    if (WaitForSingleObject(pSearchData->hStopEvent, 0) != WAIT_TIMEOUT)
+        return;
+
+    WCHAR szPath[MAX_PATH];
+    WIN32_FIND_DATAW FindData;
+    HANDLE hFindFile;
+    BOOL bMoreFiles = TRUE;
+
+    PathCombineW(szPath, lpPath, L"*.*");
+
+    for (hFindFile = FindFirstFileW(szPath, &FindData);
+        bMoreFiles && hFindFile != INVALID_HANDLE_VALUE;
+        bMoreFiles = FindNextFileW(hFindFile, &FindData))
     {
     {
-        return E_OUTOFMEMORY;
+        if (!wcscmp(FindData.cFileName, L".") || !wcscmp(FindData.cFileName, L".."))
+            continue;
+
+        PathCombineW(szPath, lpPath, FindData.cFileName);
+
+        if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        {
+            CStringW* status = new CStringW();
+            status->Format(L"Searching '%s'", FindData.cFileName);
+            PostMessageW(pSearchData->hwnd, WM_SEARCH_UPDATE_STATUS, 0, (LPARAM) status);
+
+            RecursiveFind(szPath, pSearchData);
+        }
+        else if (pSearchData->szFileName.IsEmpty() || PathMatchSpecW(FindData.cFileName, pSearchData->szFileName))
+        {
+            DbgPrint("Searching file: '%S'\n", szPath);
+            UINT uMatches = SearchFile(szPath, pSearchData);
+            if (uMatches)
+            {
+                ::PostMessageW(pSearchData->hwnd, WM_SEARCH_ADD_RESULT, 0, (LPARAM) StrDupW(szPath));
+            }
+        }
     }
 
     }
 
+    if (hFindFile != INVALID_HANDLE_VALUE)
+        FindClose(hFindFile);
+}
+
+static DWORD WINAPI _SearchThreadProc(LPVOID lpParameter)
+{
+    _SearchData *data = static_cast<_SearchData*>(lpParameter);
+
+    SearchStart* params = (SearchStart *) data->pSearchParams;
+
+    RecursiveFind(params->szPath, data);
+
+    SHFree(params);
+    SHFree(lpParameter);
+
+    return 0;
+}
+
+LRESULT CFindFolder::StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+    if (!lParam)
+        return 0;
+
+    // Clear all previous search results
     UINT uItemIndex;
     UINT uItemIndex;
-    hr = m_shellFolderView->AddObject(lpSearchPidl, &uItemIndex);
+    m_shellFolderView->RemoveObject(NULL, &uItemIndex);
 
 
-    return hr;
+    _SearchData* pSearchData = new _SearchData();
+    pSearchData->pFindFolder = this;
+    pSearchData->hwnd = m_hWnd;
+    if (m_hStopEvent)
+        SetEvent(m_hStopEvent);
+    pSearchData->hStopEvent = m_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    pSearchData->pSearchParams = (SearchStart *) lParam;
+
+    if (!SHCreateThread(_SearchThreadProc, pSearchData, NULL, NULL))
+    {
+        SHFree(pSearchData->pSearchParams);
+        SHFree(pSearchData);
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    return S_OK;
+}
+
+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 0;
 }
 
 LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
 {
 }
 
 LRESULT CFindFolder::UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
 {
-    LPWSTR status = (LPWSTR) lParam;
+    CStringW *status = (CStringW *) lParam;
     if (m_shellBrowser)
     {
     if (m_shellBrowser)
     {
-        m_shellBrowser->SetStatusTextSB(status);
+        m_shellBrowser->SetStatusTextSB(status->GetBuffer());
     }
     }
-    LocalFree(status);
+    delete status;
 
     return S_OK;
 }
 
     return S_OK;
 }
index 236d353..1768d47 100644 (file)
@@ -66,6 +66,7 @@ private:
     CComPtr<IShellFolder2> m_pisfInner;
     CComPtr<IShellFolderView> m_shellFolderView;
     CComPtr<IShellBrowser> m_shellBrowser;
     CComPtr<IShellFolder2> m_pisfInner;
     CComPtr<IShellFolderView> m_shellFolderView;
     CComPtr<IShellBrowser> m_shellBrowser;
+    HANDLE m_hStopEvent;
 
     //// *** IPersistFolder2 methods ***
     STDMETHODIMP GetCurFolder(LPITEMIDLIST *pidl);
 
     //// *** IPersistFolder2 methods ***
     STDMETHODIMP GetCurFolder(LPITEMIDLIST *pidl);
@@ -78,11 +79,16 @@ private:
     // *** IPersist methods ***
     STDMETHODIMP GetClassID(CLSID *pClassId);
 
     // *** IPersist methods ***
     STDMETHODIMP GetClassID(CLSID *pClassId);
 
-    LRESULT AddItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+    // *** Message handlers ***
+    LRESULT StartSearch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+
+    LRESULT AddResult(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
 
     LRESULT UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
 
 public:
 
     LRESULT UpdateStatus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
 
 public:
+    CFindFolder();
+
     DECLARE_REGISTRY_RESOURCEID(IDR_FINDFOLDER)
 
     DECLARE_NOT_AGGREGATABLE(CFindFolder)
     DECLARE_REGISTRY_RESOURCEID(IDR_FINDFOLDER)
 
     DECLARE_NOT_AGGREGATABLE(CFindFolder)
@@ -90,8 +96,9 @@ public:
     DECLARE_PROTECT_FINAL_CONSTRUCT()
 
     BEGIN_MSG_MAP(CFindFolder)
     DECLARE_PROTECT_FINAL_CONSTRUCT()
 
     BEGIN_MSG_MAP(CFindFolder)
-        MESSAGE_HANDLER(SWM_ADD_ITEM, AddItem)
-        MESSAGE_HANDLER(SWM_UPDATE_STATUS, UpdateStatus)
+        MESSAGE_HANDLER(WM_SEARCH_START, StartSearch)
+        MESSAGE_HANDLER(WM_SEARCH_ADD_RESULT, AddResult)
+        MESSAGE_HANDLER(WM_SEARCH_UPDATE_STATUS, UpdateStatus)
     END_MSG_MAP()
 
     BEGIN_COM_MAP(CFindFolder)
     END_MSG_MAP()
 
     BEGIN_COM_MAP(CFindFolder)
index 49d6f87..d09c478 100644 (file)
@@ -46,34 +46,35 @@ void CSearchBar::InitializeSearchBar()
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
 
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
 
-    CreateWindowExW(0, WC_STATIC, L"A &word or phrase in the file:",
+    CreateWindowExW(0, WC_STATIC, L"All or part &of the file name:",
         WS_CHILD | WS_VISIBLE,
         10, 50, 500, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
         WS_CHILD | WS_VISIBLE,
         10, 50, 500, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
-    CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
+    m_fileName = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
         WS_BORDER | WS_CHILD | WS_VISIBLE,
         10, 70, 100, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
 
         WS_BORDER | WS_CHILD | WS_VISIBLE,
         10, 70, 100, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
 
-    CreateWindowExW(0, WC_STATIC, L"&Look in:",
+    CreateWindowExW(0, WC_STATIC, L"A &word or phrase in the file:",
         WS_CHILD | WS_VISIBLE,
         10, 100, 500, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
         WS_CHILD | WS_VISIBLE,
         10, 100, 500, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
-    CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
+    m_query = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
         WS_BORDER | WS_CHILD | WS_VISIBLE,
         10, 120, 100, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
         WS_BORDER | WS_CHILD | WS_VISIBLE,
         10, 120, 100, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
+    Edit_LimitText(m_query, MAX_PATH);
 
     CreateWindowExW(0, WC_STATIC, L"&Look in:",
         WS_CHILD | WS_VISIBLE,
         10, 150, 500, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
 
     CreateWindowExW(0, WC_STATIC, L"&Look in:",
         WS_CHILD | WS_VISIBLE,
         10, 150, 500, 20,
         m_hWnd, NULL,
         _AtlBaseModule.GetModuleInstance(), NULL);
-    CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
+    m_path = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL,
         WS_BORDER | WS_CHILD | WS_VISIBLE,
         10, 180, 100, 20,
         m_hWnd, NULL,
         WS_BORDER | WS_CHILD | WS_VISIBLE,
         10, 180, 100, 20,
         m_hWnd, NULL,
@@ -198,8 +199,10 @@ LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndC
             return hr;
     }
 
             return hr;
     }
 
-    GetSearchResultsFolder(&pShellBrowser, &hwnd, NULL);
-    if (hwnd)
+    hr = GetSearchResultsFolder(*pShellBrowser, &hwnd, NULL);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
     ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) StrDupW(L"Starting search..."));
 
     return S_OK;
     ::PostMessageW(hwnd, WM_SEARCH_START, 0, (LPARAM) StrDupW(L"Starting search..."));
 
     return S_OK;
index fd84b0c..0613a31 100644 (file)
@@ -41,6 +41,9 @@ private:
     CComPtr<IUnknown> pSite;
     BOOL fVisible;
     BOOL bFocused;
     CComPtr<IUnknown> pSite;
     BOOL fVisible;
     BOOL bFocused;
+    HWND m_fileName;
+    HWND m_query;
+    HWND m_path;
 
     void InitializeSearchBar();
     HRESULT GetSearchResultsFolder(IShellBrowser **ppShellBrowser, HWND *pHwnd, IShellFolder **ppShellFolder);
 
     void InitializeSearchBar();
     HRESULT GetSearchResultsFolder(IShellBrowser **ppShellBrowser, HWND *pHwnd, IShellFolder **ppShellFolder);