/* * 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 */