[SHELLFIND] Add search functionality

This commit is contained in:
Brock Mammen 2019-08-03 12:07:59 -05:00 committed by Giannis Adamopoulos
parent 3583900b17
commit 2f3db8d9a3
4 changed files with 215 additions and 48 deletions

View 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 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;
@ -52,8 +60,8 @@ static LPITEMIDLIST _ILCreate(LPCWSTR lpszPath, LPCITEMIDLIST lpcFindDataPidl)
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;
@ -75,53 +83,199 @@ 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
{
HWND hwnd;
HANDLE hStopEvent;
SearchStart *pSearchParams;
};
static LPCSTR WINAPI StrStrNA(LPCSTR lpFirst, LPCSTR lpSrch, UINT cchMax)
{
UINT i;
int len;
if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
return NULL;
len = strlen(lpSrch);
for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
{
if (!strncmp(lpFirst, lpSrch, len))
return (LPCSTR)lpFirst;
}
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))
{
// 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;
}
}
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))
{
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;
HRESULT hr;
LPWSTR path = (LPWSTR) lParam;
CComPtr<IShellFolder> pShellFolder;
hr = SHGetDesktopFolder(&pShellFolder);
if (FAILED_UNEXPECTEDLY(hr))
{
LocalFree(path);
return hr;
}
CComHeapPtr<ITEMIDLIST> lpFSPidl;
DWORD pchEaten;
hr = pShellFolder->ParseDisplayName(NULL, NULL, path, &pchEaten, &lpFSPidl, NULL);
if (FAILED_UNEXPECTEDLY(hr))
{
LocalFree(path);
return hr;
}
LPITEMIDLIST lpLastFSPidl = ILFindLastID(lpFSPidl);
CComHeapPtr<ITEMIDLIST> lpSearchPidl(_ILCreate(path, lpLastFSPidl));
LocalFree(path);
if (!lpSearchPidl)
{
return E_OUTOFMEMORY;
}
// Clear all previous search results
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)
{
LPWSTR status = (LPWSTR) lParam;
CStringW *status = (CStringW *) lParam;
if (m_shellBrowser)
{
m_shellBrowser->SetStatusTextSB(status);
m_shellBrowser->SetStatusTextSB(status->GetBuffer());
}
LocalFree(status);
delete status;
return S_OK;
}

View file

@ -66,6 +66,7 @@ private:
CComPtr<IShellFolder2> m_pisfInner;
CComPtr<IShellFolderView> m_shellFolderView;
CComPtr<IShellBrowser> m_shellBrowser;
HANDLE m_hStopEvent;
//// *** IPersistFolder2 methods ***
STDMETHODIMP GetCurFolder(LPITEMIDLIST *pidl);
@ -78,11 +79,16 @@ private:
// *** 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:
CFindFolder();
DECLARE_REGISTRY_RESOURCEID(IDR_FINDFOLDER)
DECLARE_NOT_AGGREGATABLE(CFindFolder)
@ -90,8 +96,9 @@ public:
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)

View file

@ -46,34 +46,35 @@ void CSearchBar::InitializeSearchBar()
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);
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);
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);
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);
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(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,
@ -198,8 +199,10 @@ LRESULT CSearchBar::OnSearchButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndC
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;

View file

@ -41,6 +41,9 @@ private:
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);