|
|
/*
* url.cpp - IUniformResourceLocator implementation for InternetShortcut class. */
/* Headers
**********/
#include "priv.h"
#pragma hdrstop
#define INC_OLE2
#include "intshcut.h"
/* Module Constants
*******************/
const TCHAR c_szURLPrefixesKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes"); const TCHAR c_szDefaultURLPrefixKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix");
// DPA array that holds the IURLSearchHook Pointers
static HDPA g_hdpaHooks = NULL;
// CURRENT_USER
static const TCHAR c_szURLSearchHook[] = TSZIEPATH TEXT("\\URLSearchHooks");
/***************************** Private Functions *****************************/
int DPA_DestroyURLSearchHooksCallback(LPVOID p, LPVOID d) { IURLSearchHook * psuh = (IURLSearchHook *)p; ASSERT(psuh); ATOMICRELEASET(psuh, IURLSearchHook);
return 1; }
extern "C" { void DestroyHdpaHooks() { if (g_hdpaHooks) { ENTERCRITICAL; //---------------------------- Critical Section -------------------------
HDPA hdpa = g_hdpaHooks; g_hdpaHooks = NULL; //-----------------------------------------------------------------------
LEAVECRITICAL; if (hdpa) { DPA_DestroyCallback(hdpa, DPA_DestroyURLSearchHooksCallback, 0); hdpa = NULL; } } }
}
HRESULT InvokeURLSearchHook(IURLSearchHook * pusHook, LPCTSTR pcszQuery, LPTSTR pszResult, ISearchContext * pSC) { HRESULT hr = E_FAIL; ASSERT(pusHook); WCHAR szSearchURL[MAX_URL_STRING];
SHTCharToUnicode(pcszQuery, szSearchURL, ARRAYSIZE(szSearchURL));
// if we can get an IURLSearchHook2, we'll pass in the
// search context, otherwise we'll just do without
IURLSearchHook2 * pUSH2 = NULL; hr = pusHook->QueryInterface(IID_IURLSearchHook2, (void **)&pUSH2); if (SUCCEEDED(hr)) { RIP(pUSH2 != NULL); hr = pUSH2->TranslateWithSearchContext(szSearchURL, ARRAYSIZE(szSearchURL), pSC); pUSH2->Release(); } else { hr = pusHook->Translate(szSearchURL, ARRAYSIZE(szSearchURL)); } // In case the URLSearchHook worked, convert result to TCHAR
// This includes two cases: S_OK and S_FALSE
if (SUCCEEDED(hr)) { //WARNING: (dli) Assuming pszResult size = MAX_URL_STRING
SHUnicodeToTChar(szSearchURL, pszResult, MAX_URL_STRING); }
return hr; }
/*
* Returns: * S_OK Search handled completely, pszResult has the full URL to browse to. * 0x00000000 Stop running any further IURLSearchHooks and pass this URL back to * the browser for browsing. * * S_FALSE Query has been preprocessed, pszResult has the result of the preprocess, * 0x00000001 further search still needed. Go on executing the rest of the IURLSearchHooks * The preprocessing steps can be: 1. replaced certain characters * 2. added more hints * * E_ABORT Search handled completely, stop running any further IURLSearchHooks, * 0x80004004 but NO BROWSING NEEDED as a result, pszResult is a copy of pcszQuery. * FEATURE: This is not fully implemented, yet, making IURLQualify return this * involves too much change. * * E_FAIL This Hook was unsuccessful. Search not handled at all, pcszQueryURL has the * 0x80004005 query string. Please go on running other IURLSearchHooks. * return */
HRESULT TryURLSearchHooks(LPCTSTR pcszQuery, LPTSTR pszResult, ISearchContext * pSC) { HRESULT hr = E_FAIL; TCHAR szNewQuery[MAX_URL_STRING]; StrCpyN(szNewQuery, pcszQuery, ARRAYSIZE(szNewQuery));
int ihdpa; for (ihdpa = 0; ihdpa < (g_hdpaHooks ? DPA_GetPtrCount(g_hdpaHooks) : 0); ihdpa++) { IURLSearchHook * pusHook; pusHook = (IURLSearchHook *) DPA_GetPtr(g_hdpaHooks, ihdpa); if (!pusHook) return E_FAIL; hr = InvokeURLSearchHook(pusHook, szNewQuery, pszResult, pSC); if ((hr == S_OK) || (hr == E_ABORT)) break; else if (hr == S_FALSE) StrCpyN(szNewQuery, pszResult, ARRAYSIZE(szNewQuery)); }
return hr; }
void InitURLSearchHooks() { HDPA hdpa = DPA_Create(4); // We need to look in LOCAL_MACHINE if this registry entry doesn't exist in CURRENT_USER.
// The installer needs to install the values into LOCAL_MACHINE so they are accessable
// to all users. Then anyone wanting to modify the value, will need to determine if they
// want to add it to a specific user's CURRENT_USER or modify the LOCAL_MACHINE value to
// apply the change to all users. (bryanst - #6722)
HUSKEY hkeyHooks; if ((hdpa) && (SHRegOpenUSKey(c_szURLSearchHook, KEY_READ, NULL, &hkeyHooks, FALSE) == ERROR_SUCCESS)) { TCHAR szCLSID[GUIDSTR_MAX]; DWORD dwccCLSIDLen; LONG lEnumReturn; DWORD dwiValue = 0; do { dwccCLSIDLen = ARRAYSIZE(szCLSID); lEnumReturn = SHRegEnumUSValue(hkeyHooks, dwiValue, szCLSID, &dwccCLSIDLen, NULL, NULL, NULL, SHREGENUM_DEFAULT); if (lEnumReturn == ERROR_SUCCESS) { CLSID clsidHook; if (SUCCEEDED(SHCLSIDFromString(szCLSID, &clsidHook))) { IURLSearchHook * pusHook; HRESULT hr = CoCreateInstance(clsidHook, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IURLSearchHook, &pusHook)); if (SUCCEEDED(hr)) DPA_AppendPtr(hdpa, pusHook); } } dwiValue++; } while (lEnumReturn == ERROR_SUCCESS); SHRegCloseUSKey(hkeyHooks); } ENTERCRITICAL; //---------------------------- Critical Section --------------------------
if (!g_hdpaHooks) { g_hdpaHooks = hdpa; hdpa = NULL; } //------------------------------------------------------------------------
LEAVECRITICAL; if (hdpa) { DPA_DestroyCallback(hdpa, DPA_DestroyURLSearchHooksCallback, 0); hdpa = NULL; } }
HRESULT ApplyURLSearch(LPCTSTR pcszQuery, LPTSTR pszTranslatedUrl, ISearchContext * pSC) { if (!g_hdpaHooks) InitURLSearchHooks(); return TryURLSearchHooks(pcszQuery, pszTranslatedUrl, pSC); }
/*----------------------------------------------------------
Purpose: This function qualifies a string as a URL. Strings such as "www.foo.com" would have the scheme guessed if the correct flags are given. Local paths are converted to "file:" URLs.
pszTranslatedURL may point to the same buffer as pcszURL.
If the given string is already a URL (not necessarily canonicalized, though), this function will not touch it, unless UQF_CANONICALIZE is set, in which case the string will be canonicalized.
Returns: S_OK or S_FALSE means we filled in pszTranslatedURL. S_OK means we altered the URL to qualify it too. various failure codes too
Cond: -- */ SHDOCAPI IURLQualifyWithContext( IN LPCWSTR pcszURL, IN DWORD dwFlags, // UQF_*
IN DWORD cchTranslatedURL, OUT LPWSTR pszTranslatedURL, LPBOOL pbWasSearchURL, LPBOOL pbWasCorrected, ISearchContext * pSC) { HRESULT hres = S_FALSE; DWORD cchSize;
SHSTR strOut; BOOL bWasCorrected = FALSE;
ASSERT(IS_VALID_STRING_PTR(pcszURL, -1)); ASSERT(IS_VALID_WRITE_BUFFER(pszTranslatedURL, TCHAR, MAX_URL_STRING));
if (pbWasSearchURL) *pbWasSearchURL = FALSE;
// Special cases: URLs of the form <drive>:<filename>
// URLs of the form \<filename>
// we'll assume that if the second character is a : or |, this is an url of
// that form, and we will guess "file://" for the prefix.
// we'll assume any url that begins with a single \ is a file: url
// NOTE: We do this here because these are cases where the protocol is
// left off, and is likely to be incorrectly guessed, such as a
// relative path \data\ftp\docs, would wrongly be turned
// into "ftp://\data\ftp\docs".
// Note: PathIsURL returns TRUE for non-canonicalized URLs too
if (PathIsURL(pcszURL)) { LPCWSTR pcszTemp = pcszURL; cchSize = MAX_URL_STRING; if (IsFlagSet(dwFlags, UQF_AUTOCORRECT)) { hres = UrlFixup(pcszURL, pszTranslatedURL, cchSize); if (hres == S_OK) { bWasCorrected = TRUE; pcszTemp = pszTranslatedURL; } }
if (dwFlags & UQF_CANONICALIZE) hres = UrlCanonicalize(pcszTemp, pszTranslatedURL, &cchSize, 0); else if (pszTranslatedURL != pcszTemp) StrCpyN(pszTranslatedURL, pcszTemp, cchTranslatedURL);
hres = S_OK; } else { // Look for file paths
if (IsFlagClear(dwFlags, UQF_IGNORE_FILEPATHS) && ( pcszURL[1] == TEXT(':') || pcszURL[1] == TEXT('|') || pcszURL[0] == TEXT('\\'))) { hres = strOut.SetSize(MAX_PATH);
if(SUCCEEDED(hres)) { // SHSTRs have a size granularity, so the size
// will be equal to or greater than what was set.
// this means we need to get it our self.
DWORD cchOut = strOut.GetSize(); TCHAR szCurrentDir[MAX_PATH];
//
// APPCOMPAT - IE30 compatibility - zekel 8-Jan-97
// we need to GetCurrentDirectory() in order to
// put a default drive letter on the path
// if necessary.
//
if(GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir)) PathCombine(strOut.GetInplaceStr(), szCurrentDir, pcszURL); else hres = strOut.SetStr(pcszURL);
if(SUCCEEDED(hres)) { hres = UrlCreateFromPath(strOut, strOut.GetInplaceStr(), &cchOut, 0); if (E_POINTER == hres && SUCCEEDED(hres = strOut.SetSize(cchOut))) { cchOut = strOut.GetSize(); hres = UrlCreateFromPath(strOut, strOut.GetInplaceStr(), &cchOut, 0); } } } } else if (SUCCEEDED(hres = strOut.SetSize(MAX_URL_STRING))) { // all the Apply*() below rely on MAX_URL_STRING
// No; begin processing general-case URLs. Try to guess the
// protocol or resort to the default protocol.
DWORD cchOut = strOut.GetSize(); if (IsFlagSet(dwFlags, UQF_GUESS_PROTOCOL)) hres = UrlApplyScheme(pcszURL, strOut.GetInplaceStr(), &cchOut, URL_APPLY_GUESSSCHEME);
//
// Try to auto-correct the protocol
//
if (hres == S_FALSE && IsFlagSet(dwFlags, UQF_AUTOCORRECT)) { hres = UrlFixup(pcszURL, strOut.GetInplaceStr(), strOut.GetSize()); bWasCorrected = (hres == S_OK); }
if (hres == S_FALSE && IsFlagSet(dwFlags, UQF_USE_DEFAULT_PROTOCOL)) { // run the search with or without the search context
hres = ApplyURLSearch(pcszURL, strOut.GetInplaceStr(), pSC); if (SUCCEEDED(hres) && pbWasSearchURL) { *pbWasSearchURL = TRUE; } // If that fails, then tack on the default protocol
if (FAILED(hres) || hres == S_FALSE) { cchOut = strOut.GetSize(); hres = UrlApplyScheme(pcszURL, strOut.GetInplaceStr(), &cchOut, URL_APPLY_DEFAULT); } }
// Did the above fail?
if (S_FALSE == hres) { // Yes; return the real reason why the URL is bad
hres = URL_E_INVALID_SYNTAX; } else if (dwFlags & UQF_CANONICALIZE) { // No; canonicalize
cchSize = strOut.GetSize(); hres = UrlCanonicalize(strOut, strOut.GetInplaceStr(), &cchSize, 0); } }
if (SUCCEEDED(hres)) { StrCpyN(pszTranslatedURL, strOut, cchTranslatedURL); } }
if (pbWasCorrected) *pbWasCorrected = bWasCorrected;
return hres; }
SHDOCAPI IURLQualify( IN LPCWSTR pcszURL, IN DWORD dwFlags, // UQF_*
OUT LPWSTR pszTranslatedURL, LPBOOL pbWasSearchURL, LPBOOL pbWasCorrected) { // this is exported
return IURLQualifyWithContext(pcszURL, dwFlags, MAX_URL_STRING, pszTranslatedURL, pbWasSearchURL, pbWasCorrected, NULL); }
/***************************** Exported Functions ****************************/
STDAPI URLQualifyA( LPCSTR pszURL, DWORD dwFlags, // UQF_*
LPSTR *ppszOut) { HRESULT hres;
ASSERT(IS_VALID_STRING_PTRA(pszURL, -1)); ASSERT(IS_VALID_WRITE_PTR(ppszOut, LPSTR));
*ppszOut = NULL;
WCHAR szTempTranslatedURL[MAX_URL_STRING]; WCHAR szURL[MAX_URL_STRING];
SHAnsiToUnicode(pszURL, szURL, ARRAYSIZE(szURL));
hres = IURLQualifyWithContext(szURL, dwFlags, ARRAYSIZE(szTempTranslatedURL), szTempTranslatedURL, NULL, NULL, NULL);
if (SUCCEEDED(hres)) { CHAR szOut[MAX_URL_STRING];
SHUnicodeToAnsi(szTempTranslatedURL, szOut, ARRAYSIZE(szOut));
*ppszOut = StrDupA(szOut);
if (!*ppszOut) hres = E_OUTOFMEMORY; }
return hres; }
STDAPI URLQualifyW( LPCWSTR pszURL, DWORD dwFlags, // UQF_*
LPWSTR *ppszOut) { HRESULT hres;
ASSERT(IS_VALID_STRING_PTRW(pszURL, -1)); ASSERT(IS_VALID_WRITE_PTR(ppszOut, LPWSTR));
WCHAR szTempTranslatedURL[MAX_URL_STRING];
hres = IURLQualify(pszURL, dwFlags, szTempTranslatedURL, NULL, NULL);
if (SUCCEEDED(hres)) { *ppszOut = StrDup(szTempTranslatedURL);
if (!*ppszOut) hres = E_OUTOFMEMORY; }
return hres; }
|