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

596 lines
14 KiB
C++

/*
* extricon.cpp - IExtractIcon implementation for URL class.
*/
/* Headers
**********/
#include "project.hpp"
#pragma hdrstop
#include "assoc.h"
/* Global Constants
*******************/
#pragma data_seg(DATA_SEG_READ_ONLY)
extern const char g_cszURLDefaultIconKey[] = "InternetShortcut\\DefaultIcon";
extern const HKEY g_hkeyURLSettings = HKEY_LOCAL_MACHINE;
#pragma data_seg()
/* Module Constants
*******************/
#pragma data_seg(DATA_SEG_READ_ONLY)
PRIVATE_DATA const char s_cszDefaultIconSubKey[] = "DefaultIcon";
PRIVATE_DATA const char s_cszGenericURLIconFile[] = "url.dll";
PRIVATE_DATA const int s_ciGenericURLIcon = 0;
// IExtractIcon::GetIconLocation() flag combinations
PRIVATE_DATA const int ALL_GIL_IN_FLAGS = (GIL_OPENICON |
GIL_FORSHELL);
PRIVATE_DATA const int ALL_GIL_OUT_FLAGS = (GIL_SIMULATEDOC |
GIL_PERINSTANCE |
GIL_PERCLASS |
GIL_NOTFILENAME |
GIL_DONTCACHE);
#pragma data_seg()
/***************************** Private Functions *****************************/
/*
** ParseIconEntry()
**
**
**
** Arguments:
**
** Returns: S_OK if icon entry parsed successfully.
** E_FAIL if not.
**
** Side Effects: The contents of pszIconEntry are destroyed.
**
** pszIconEntry and pszIconFile may be the same.
*/
PRIVATE_CODE HRESULT ParseIconEntry(PSTR pszIconEntry, PSTR pszIconFile,
UINT ucbIconFileBufLen, PINT pniIcon)
{
HRESULT hr;
PSTR pszComma;
ASSERT(IS_VALID_STRING_PTR(pszIconEntry, STR));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
pszComma = StrChr(pszIconEntry, ',');
if (pszComma)
{
*pszComma++ = '\0';
TrimWhiteSpace(pszComma);
*pniIcon = StringToInt(pszComma);
}
else
{
*pniIcon = 0;
WARNING_OUT(("ParseIconEntry(): No icon index in entry %s. Using icon index 0.",
pszIconEntry));
}
TrimWhiteSpace(pszIconEntry);
if ((UINT)lstrlen(pszIconEntry) < ucbIconFileBufLen)
{
lstrcpy(pszIconFile, pszIconEntry);
hr = S_OK;
TRACE_OUT(("ParseIconEntry(): Parsed icon file %s, index %d.",
pszIconFile,
*pniIcon));
}
else
{
hr = S_FALSE;
// (+ 1) for null terminator.
WARNING_OUT(("ParseIconEntry(): Icon file buffer too small for icon file %s (%u bytes supplied, %lu bytes required).",
pszIconEntry,
ucbIconFileBufLen,
lstrlen(pszIconEntry) + 1));
}
ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
return(hr);
}
/*
** GetURLIcon()
**
**
**
** Arguments:
**
** Returns: S_OK if icon information retrieved successfully.
** S_FALSE if no icon entry for this URL.
** Otherwise error.
**
** Side Effects: none
*/
PRIVATE_CODE HRESULT GetURLIcon(HKEY hkey, PCSTR pcszKey, PSTR pszIconFile,
UINT ucbIconFileBufLen, PINT pniIcon)
{
HRESULT hr;
DWORD dwcbLen = ucbIconFileBufLen;
ASSERT(IS_VALID_HANDLE(hkey, KEY));
ASSERT(IS_VALID_STRING_PTR(pcszKey, CSTR));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
if (GetDefaultRegKeyValue(hkey, pcszKey, pszIconFile, &dwcbLen)
== ERROR_SUCCESS)
hr = ParseIconEntry(pszIconFile, pszIconFile, ucbIconFileBufLen,
pniIcon);
else
{
// No protocol handler.
hr = S_FALSE;
TRACE_OUT(("GetURLIcon(): Couldn't get default value for key %s.",
pcszKey));
}
ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
return(hr);
}
/*
** GetFallBackGenericURLIcon()
**
**
**
** Arguments:
**
** Returns: S_OK if fallback generic icon information retrieved
** successfully.
** E_FAIL if not.
**
** Side Effects: none
*/
PRIVATE_CODE HRESULT GetFallBackGenericURLIcon(PSTR pszIconFile,
UINT ucbIconFileBufLen,
PINT pniIcon)
{
HRESULT hr;
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
// Fall back to first icon in this module.
if (ucbIconFileBufLen >= sizeof(s_cszGenericURLIconFile))
{
lstrcpy(pszIconFile, s_cszGenericURLIconFile);
*pniIcon = s_ciGenericURLIcon;
hr = S_OK;
TRACE_OUT(("GetFallBackGenericURLIcon(): Using generic URL icon file %s, index %d.",
s_cszGenericURLIconFile,
s_ciGenericURLIcon));
}
else
{
hr = E_FAIL;
WARNING_OUT(("GetFallBackGenericURLIcon(): Icon file buffer too small for generic icon file %s (%u bytes supplied, %lu bytes required).",
s_cszGenericURLIconFile,
ucbIconFileBufLen,
sizeof(s_cszGenericURLIconFile)));
}
ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
return(hr);
}
/*
** GetGenericURLIcon()
**
**
**
** Arguments:
**
** Returns: S_OK if generic icon information retrieved successfully.
** Otherwise error.
**
** Side Effects: none
*/
PRIVATE_CODE HRESULT GetGenericURLIcon(PSTR pszIconFile,
UINT ucbIconFileBufLen, PINT pniIcon)
{
HRESULT hr;
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
hr = GetURLIcon(g_hkeyURLProtocols, g_cszURLDefaultIconKey, pszIconFile,
ucbIconFileBufLen, pniIcon);
if (hr == S_FALSE)
hr = GetFallBackGenericURLIcon(pszIconFile, ucbIconFileBufLen, pniIcon);
ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
return(hr);
}
/****************************** Public Functions *****************************/
/*
** StringToInt()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
**
** Stops at first non-digit character encountered.
*/
PUBLIC_CODE int StringToInt(PCSTR pcsz)
{
int nResult = 0;
BOOL bNegative;
#ifdef DEBUG
PCSTR pcszStart = pcsz;
#endif
ASSERT(IS_VALID_STRING_PTR(pcsz, CSTR));
if (*pcsz == '-')
{
bNegative = TRUE;
pcsz++;
}
else
bNegative = FALSE;
while (IsDigit(*pcsz))
{
ASSERT(nResult <= INT_MAX / 10);
nResult *= 10;
ASSERT(nResult <= INT_MAX - (*pcsz - '0'));
nResult += *pcsz++ - '0';
}
if (*pcsz) {
WARNING_OUT(("StringToInt(): Stopped at non-digit character %c in string %s.",
*pcsz,
pcszStart));
}
// nResult may be any value.
return(bNegative ? - nResult : nResult);
}
PUBLIC_CODE BOOL IsWhiteSpace(char ch)
{
return((ch && StrChr(g_cszWhiteSpace, ch)) ? TRUE : FALSE);
}
PUBLIC_CODE BOOL AnyMeat(PCSTR pcsz)
{
ASSERT(! pcsz ||
IS_VALID_STRING_PTR(pcsz, CSTR));
return(pcsz ? StrSpn(pcsz, g_cszWhiteSpace) < lstrlen(pcsz) : FALSE);
}
PUBLIC_CODE HRESULT CopyURLProtocol(PCSTR pcszURL, PSTR *ppszProtocol)
{
HRESULT hr;
PARSEDURL pu;
ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppszProtocol, PSTR));
*ppszProtocol = NULL;
pu.cbSize = sizeof(pu);
hr = ParseURL(pcszURL, &pu);
if (hr == S_OK)
{
// (+ 1) for null terminator.
*ppszProtocol = new(char[pu.cchProtocol + 1]);
if (*ppszProtocol)
{
// (+ 1) for null terminator.
lstrcpyn(*ppszProtocol, pu.pszProtocol, pu.cchProtocol + 1);
ASSERT((UINT)lstrlen(*ppszProtocol) == pu.cchProtocol);
}
else
hr = E_OUTOFMEMORY;
}
ASSERT(FAILED(hr) ||
(hr == S_OK &&
IS_VALID_STRING_PTR(*ppszProtocol, STR)));
return(hr);
}
PUBLIC_CODE HRESULT CopyURLSuffix(PCSTR pcszURL, PSTR *ppszSuffix)
{
HRESULT hr;
PARSEDURL pu;
ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppszSuffix, PSTR));
*ppszSuffix = NULL;
hr = ParseURL(pcszURL, &pu);
if (hr == S_OK)
{
// (+ 1) for null terminator.
*ppszSuffix = new(char[pu.cchSuffix + 1]);
if (*ppszSuffix)
{
// (+ 1) for null terminator.
lstrcpyn(*ppszSuffix, pu.pszSuffix, pu.cchSuffix + 1);
ASSERT((UINT)lstrlen(*ppszSuffix) == pu.cchSuffix);
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
}
ASSERT(FAILED(hr) ||
IS_VALID_STRING_PTR(*ppszSuffix, STR));
return(hr);
}
PUBLIC_CODE HRESULT GetProtocolKey(PCSTR pcszProtocol, PCSTR pcszSubKey,
PSTR *ppszKey)
{
HRESULT hr;
ULONG ulcbKeyLen;
ASSERT(IS_VALID_STRING_PTR(pcszProtocol, STR));
ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR));
ASSERT(IS_VALID_WRITE_PTR(ppszKey, PSTR));
// (+ 1) for possible separator.
// (+ 1) for null terminator.
ulcbKeyLen = lstrlen(pcszProtocol) + 1 + lstrlen(pcszSubKey) + 1;
*ppszKey = new(char[ulcbKeyLen]);
if (*ppszKey)
{
lstrcpy(*ppszKey, pcszProtocol);
PathAppend(*ppszKey, pcszSubKey);
ASSERT((UINT)lstrlen(*ppszKey) < ulcbKeyLen);
hr = S_OK;
}
else
hr = E_OUTOFMEMORY;
ASSERT((hr == S_OK &&
IS_VALID_STRING_PTR(*ppszKey, STR)) ||
hr == E_OUTOFMEMORY);
return(hr);
}
PUBLIC_CODE HRESULT GetURLKey(PCSTR pcszURL, PCSTR pcszSubKey, PSTR *pszKey)
{
HRESULT hr;
PSTR pszProtocol;
ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR));
ASSERT(IS_VALID_WRITE_PTR(pszKey, PSTR));
*pszKey = NULL;
hr = CopyURLProtocol(pcszURL, &pszProtocol);
if (hr == S_OK)
{
hr = GetProtocolKey(pszProtocol, pcszSubKey, pszKey);
delete pszProtocol;
pszProtocol = NULL;
}
ASSERT((hr == S_OK &&
IS_VALID_STRING_PTR(*pszKey, STR)) ||
FAILED(hr));
return(hr);
}
/********************************** Methods **********************************/
HRESULT STDMETHODCALLTYPE InternetShortcut::GetIconLocation(
UINT uInFlags,
PSTR pszIconFile,
UINT ucbIconFileBufLen,
PINT pniIcon,
PUINT puOutFlags)
{
HRESULT hr;
DebugEntry(InternetShortcut::GetIconLocation);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(FLAGS_ARE_VALID(uInFlags, ALL_GIL_IN_FLAGS));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
ASSERT(IS_VALID_WRITE_PTR(puOutFlags, UINT));
if (IS_FLAG_CLEAR(uInFlags, GIL_OPENICON))
{
hr = GetIconLocation(pszIconFile, ucbIconFileBufLen, pniIcon);
if (hr != S_OK)
{
if (m_pszURL)
{
PSTR pszDefaultIconKey;
// Look up URL icon based on protocol handler.
hr = GetURLKey(m_pszURL, s_cszDefaultIconSubKey,
&pszDefaultIconKey);
if (hr == S_OK)
{
hr = GetURLIcon(g_hkeyURLProtocols, pszDefaultIconKey,
pszIconFile, ucbIconFileBufLen, pniIcon);
delete pszDefaultIconKey;
pszDefaultIconKey = NULL;
}
}
else
hr = S_FALSE;
if (hr == S_FALSE)
{
// Use generic URL icon.
hr = GetGenericURLIcon(pszIconFile, ucbIconFileBufLen, pniIcon);
if (hr == S_OK) {
TRACE_OUT(("InternetShortcut::GetIconLocation(): Using generic URL icon."));
}
}
if (hr == S_OK)
{
char rgchFullPath[MAX_PATH_LEN];
hr = FullyQualifyPath(pszIconFile, rgchFullPath,
sizeof(rgchFullPath));
if (hr == S_OK)
{
if ((UINT)lstrlen(rgchFullPath) < ucbIconFileBufLen)
lstrcpy(pszIconFile, rgchFullPath);
else
hr = E_FAIL;
}
}
}
}
else
// No "open look" icon.
hr = S_FALSE;
if (hr != S_OK)
{
if (ucbIconFileBufLen > 0)
*pszIconFile = '\0';
*pniIcon = 0;
}
*puOutFlags = 0;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon) &&
FLAGS_ARE_VALID(*puOutFlags, ALL_GIL_OUT_FLAGS));
DebugExitHRESULT(InternetShortcut::GetIconLocation, hr);
return(hr);
}
#pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
HRESULT STDMETHODCALLTYPE InternetShortcut::Extract(PCSTR pcszIconFile,
UINT uiIcon,
PHICON phiconLarge,
PHICON phiconSmall,
UINT ucIconSize)
{
HRESULT hr;
DebugEntry(InternetShortcut::Extract);
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT(IS_VALID_STRING_PTR(pcszIconFile, CSTR));
ASSERT(IsValidIconIndex(S_OK, pcszIconFile, MAX_PATH_LEN, uiIcon));
ASSERT(IS_VALID_WRITE_PTR(phiconLarge, HICON));
ASSERT(IS_VALID_WRITE_PTR(phiconSmall, HICON));
// FEATURE: Validate ucIconSize here.
*phiconLarge = NULL;
*phiconSmall = NULL;
// Use caller's default implementation of ExtractIcon().
hr = S_FALSE;
ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
ASSERT((hr == S_OK &&
IS_VALID_HANDLE(*phiconLarge, ICON) &&
IS_VALID_HANDLE(*phiconSmall, ICON)) ||
(hr != S_OK &&
! *phiconLarge &&
! *phiconSmall));
DebugExitHRESULT(InternetShortcut::Extract, hr);
return(hr);
}
#pragma warning(default:4100) /* "unreferenced formal parameter" warning */