windows-nt/Source/XPSP1/NT/shell/browseui/searchext.cpp
2020-09-26 16:20:57 +08:00

397 lines
13 KiB
C++

#include "priv.h"
#include "varutil.h"
// static context menu for the start.search menu. note, this gets invoked directly
// by a number of clients (in shell32 for example)
class CShellSearchExt : public IContextMenu, public IObjectWithSite
{
public:
CShellSearchExt();
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IContextMenu
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT wFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
// IObjectWithSite
STDMETHODIMP SetSite(IUnknown *pUnkSite);
STDMETHODIMP GetSite(REFIID riid, void **ppvSite);
protected:
virtual ~CShellSearchExt(); // for a derived class
private:
virtual BOOL _GetSearchUrls(GUID *pguid, LPTSTR psz, DWORD cch,
LPTSTR pszUrlNavNew, DWORD cchNavNew, BOOL *pfRunInProcess);
HRESULT _IsShellSearchBand(REFGUID guidSearch);
HRESULT _ShowShellSearchResults(IWebBrowser2* pwb2, BOOL fNewFrame, REFGUID guidSearch);
LONG _cRef;
IUnknown *_pSite;
};
STDAPI CShellSearchExt_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CShellSearchExt* psse = new CShellSearchExt();
if (psse)
{
*ppunk = SAFECAST(psse, IContextMenu*);
return S_OK;
}
else
{
*ppunk = NULL;
return E_OUTOFMEMORY;
}
}
STDMETHODIMP CShellSearchExt::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(CShellSearchExt, IContextMenu),
QITABENT(CShellSearchExt, IObjectWithSite),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
STDMETHODIMP_(ULONG) CShellSearchExt::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CShellSearchExt::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
STDMETHODIMP CShellSearchExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
return E_NOTIMPL;
}
#define SZ_SHELL_SEARCH TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FindExtensions\\Static\\ShellSearch")
BOOL CShellSearchExt::_GetSearchUrls(GUID *pguidSearch, LPTSTR pszUrl, DWORD cch,
LPTSTR pszUrlNavNew, DWORD cchNavNew, BOOL *pfRunInProcess)
{
BOOL bRet = FALSE;
*pfRunInProcess = FALSE; // Assume that we are not forcing it to run in process.
if (pszUrl == NULL || IsEqualGUID(*pguidSearch, GUID_NULL) || pszUrlNavNew == NULL)
return bRet;
*pszUrlNavNew = 0;
HKEY hkey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_SHELL_SEARCH, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
{
TCHAR szSubKey[32];
HKEY hkeySub;
for (int i = 0; wnsprintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%d"), i),
RegOpenKey(hkey, szSubKey, &hkeySub) == ERROR_SUCCESS;
i++)
{
TCHAR szSearchGuid[MAX_PATH];
DWORD dwType, cb = sizeof(szSearchGuid);
if (SHGetValue(hkeySub, TEXT("SearchGUID"), NULL, &dwType, (BYTE*)szSearchGuid, &cb) == ERROR_SUCCESS)
{
GUID guid;
if (GUIDFromString(szSearchGuid, &guid) &&
IsEqualGUID(guid, *pguidSearch))
{
cb = cch * sizeof(TCHAR);
bRet = (SHGetValue(hkeySub, TEXT("SearchGUID\\Url"), NULL, &dwType, (BYTE*)pszUrl, &cb) == ERROR_SUCCESS);
if (bRet || IsEqualGUID(*pguidSearch, SRCID_SFileSearch))
{
if (!bRet)
{
*pszUrl = 0;
// in file search case we don't need url but we still succeed
bRet = TRUE;
}
// See if there is a URL that we should navigate to if we
// are navigating to a new
cb = cchNavNew * sizeof(TCHAR);
SHGetValue(hkeySub, TEXT("SearchGUID\\UrlNavNew"), NULL, &dwType, (BYTE*)pszUrlNavNew, &cb);
// likewise try to grab the RunInProcess flag, if not there or zero then off, else on
// reuse szSearchGuid for now...
*pfRunInProcess = (BOOL)SHRegGetIntW(hkeySub, L"RunInProcess", 0);
}
RegCloseKey(hkeySub);
break;
}
}
RegCloseKey(hkeySub);
}
RegCloseKey(hkey);
}
if (!bRet)
pszUrl[0] = 0;
return bRet;
}
STDMETHODIMP CShellSearchExt::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
TCHAR szUrl[MAX_URL_STRING], szUrlNavNew[MAX_URL_STRING];
BOOL bNewFrame = FALSE;
// First get the Urls such that we can see which class we should create...
GUID guidSearch = GUID_NULL;
BOOL fRunInProcess = FALSE;
CLSID clsidBand; // deskband object for search
// Retrieve search ID from invoke params
if (pici->lpParameters)
GUIDFromStringA(pici->lpParameters, &guidSearch);
HRESULT hr = S_OK;
BOOL fShellSearchBand = (S_OK == _IsShellSearchBand(guidSearch));
if (fShellSearchBand)
{
clsidBand = CLSID_FileSearchBand;
if (SHRestricted(REST_NOFIND) && IsEqualGUID(guidSearch, SRCID_SFileSearch))
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // user saw the error
}
else
{
clsidBand = CLSID_SearchBand;
// retrieve search URLs from registry
if (!_GetSearchUrls(&guidSearch, szUrl, ARRAYSIZE(szUrl), szUrlNavNew, ARRAYSIZE(szUrlNavNew), &fRunInProcess))
hr = E_FAIL;
}
if (SUCCEEDED(hr))
{
// if invoked from within a browser reuse it, else open a new browser
IWebBrowser2 *pwb2;
hr = IUnknown_QueryServiceForWebBrowserApp(_pSite, IID_PPV_ARG(IWebBrowser2, &pwb2));
if (FAILED(hr))
{
// Note: we want the frame to display shell characteristics (CLSID_ShellBrowserWindow),
// including persistence behavior, if we're loading shell search (CLSID_FileSearchBand).
if (fRunInProcess || IsEqualGUID(clsidBand, CLSID_FileSearchBand))
hr = CoCreateInstance(CLSID_ShellBrowserWindow, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IWebBrowser2, &pwb2));
else
hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IWebBrowser2, &pwb2));
bNewFrame = TRUE;
}
if (SUCCEEDED(hr))
{
// show html-hosting band
VARIANT var, varEmpty = {0};
hr = InitBSTRVariantFromGUID(&var, clsidBand);
if (SUCCEEDED(hr))
{
hr = pwb2->ShowBrowserBar(&var, &varEmpty, &varEmpty);
VariantClear(&var);
}
if (SUCCEEDED(hr))
{
if (fShellSearchBand)
{
hr = _ShowShellSearchResults(pwb2, bNewFrame, guidSearch);
}
else
{
LBSTR::CString strUrl;
VARIANT varFlags;
varFlags.vt = VT_I4;
varFlags.lVal = navBrowserBar;
LPTSTR pstrUrl = strUrl.GetBuffer( MAX_URL_STRING );
if ( strUrl.GetAllocLength() < MAX_URL_STRING )
{
TraceMsg( TF_WARNING, "CShellSearchExt::InvokeCommand() - strUrl Allocation Failed!" );
strUrl.Empty();
}
else
{
SHTCharToUnicode( szUrl, pstrUrl, MAX_URL_STRING );
// Let CString class own the buffer again.
strUrl.ReleaseBuffer();
}
var.vt = VT_BSTR;
var.bstrVal = strUrl;
// if we opened a new window, navigate the right side to about.blank
if (bNewFrame)
{
LBSTR::CString strNavNew;
if ( szUrlNavNew[0] )
{
LPTSTR pstrNavNew = strNavNew.GetBuffer( MAX_URL_STRING );
if ( strNavNew.GetAllocLength() < MAX_URL_STRING )
{
TraceMsg( TF_WARNING, "CShellSearchExt::InvokeCommand() - strNavNew Allocation Failed!" );
strNavNew.Empty();
}
else
{
SHTCharToUnicode( szUrlNavNew, pstrNavNew, MAX_URL_STRING );
// Let CString class own the buffer again.
strNavNew.ReleaseBuffer();
}
}
else
{
strNavNew = L"about:blank";
}
// we don't care about the error here
pwb2->Navigate( strNavNew, &varEmpty, &varEmpty, &varEmpty, &varEmpty );
}
// navigate the search bar to the correct url
hr = pwb2->Navigate2( &var, &varFlags, &varEmpty, &varEmpty, &varEmpty );
}
}
if (SUCCEEDED(hr) && bNewFrame)
hr = pwb2->put_Visible(TRUE);
pwb2->Release();
}
}
return hr;
}
HRESULT CShellSearchExt::_IsShellSearchBand(REFGUID guidSearch)
{
if (IsEqualGUID(guidSearch, SRCID_SFileSearch) ||
IsEqualGUID(guidSearch, SRCID_SFindComputer) ||
IsEqualGUID(guidSearch, SRCID_SFindPrinter))
return S_OK;
return S_FALSE;
}
HRESULT CShellSearchExt::_ShowShellSearchResults(IWebBrowser2* pwb2, BOOL bNewFrame, REFGUID guidSearch)
{
VARIANT varBand;
HRESULT hr = InitBSTRVariantFromGUID(&varBand, CLSID_FileSearchBand);
if (SUCCEEDED(hr))
{
// Retrieve the FileSearchBand's unknown from the browser frame as a VT_UNKNOWN property;
// (FileSearchBand initialized and this when he was created and hosted.)
VARIANT varFsb;
hr = pwb2->GetProperty(varBand.bstrVal, &varFsb);
if (SUCCEEDED(hr))
{
IFileSearchBand* pfsb;
if (SUCCEEDED(QueryInterfaceVariant(varFsb, IID_PPV_ARG(IFileSearchBand, &pfsb))))
{
// Assign the correct search type to the band
VARIANT varSearchID;
if (SUCCEEDED(InitBSTRVariantFromGUID(&varSearchID, guidSearch)))
{
VARIANT varNil = {0};
VARIANT_BOOL bNavToResults = bNewFrame ? VARIANT_TRUE : VARIANT_FALSE ;
pfsb->SetSearchParameters(&varSearchID.bstrVal, bNavToResults, &varNil, &varNil);
VariantClear(&varSearchID);
}
pfsb->Release();
}
VariantClear(&varFsb);
}
VariantClear(&varBand);
}
return hr;
}
STDMETHODIMP CShellSearchExt::GetCommandString(UINT_PTR idCmd, UINT wFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
return E_NOTIMPL;
}
STDMETHODIMP CShellSearchExt::SetSite(IUnknown *pUnkSite)
{
IUnknown_Set(&_pSite, pUnkSite);
return S_OK;
}
STDMETHODIMP CShellSearchExt::GetSite(REFIID riid, void **ppvSite)
{
if (_pSite)
return _pSite->QueryInterface(riid, ppvSite);
*ppvSite = NULL;
return E_NOINTERFACE;
}
CShellSearchExt::CShellSearchExt() : _cRef(1), _pSite(NULL)
{
}
CShellSearchExt::~CShellSearchExt()
{
ATOMICRELEASE(_pSite);
}
class CWebSearchExt : public CShellSearchExt
{
public:
CWebSearchExt();
private:
virtual BOOL _GetSearchUrls(GUID *pguidSearch, LPTSTR pszUrl, DWORD cch,
LPTSTR pszUrlNavNew, DWORD cchNavNew, BOOL *pfRunInProcess);
};
STDAPI CWebSearchExt_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CWebSearchExt* pwse;
pwse = new CWebSearchExt();
if (pwse)
{
*ppunk = SAFECAST(pwse, IContextMenu*);
return S_OK;
}
else
{
*ppunk = NULL;
return E_OUTOFMEMORY;
}
}
CWebSearchExt::CWebSearchExt() : CShellSearchExt()
{
}
BOOL CWebSearchExt::_GetSearchUrls(GUID *pguidSearch, LPTSTR pszUrl, DWORD cch,
LPTSTR pszUrlNavNew, DWORD cchNavNew, BOOL *pfRunInProcess)
{
// Currently does not support NavNew, can be extended later if desired, likewise for RunInProcess...
*pfRunInProcess = FALSE;
if (pszUrlNavNew && cchNavNew)
*pszUrlNavNew = 0;
return GetDefaultInternetSearchUrl(pszUrl, cch, TRUE);
}