/* * extricon.cpp - IExtractIcon implementation for CFusionShortcut class. */ /* Headers **********/ #include "project.hpp" #include // for _snwprintf /* Global Constants *******************/ const WCHAR g_cwzDefaultIconKey[] = L"manifestfile\\DefaultIcon"; const HKEY g_hkeySettings = HKEY_CLASSES_ROOT; /* Module Constants *******************/ const WCHAR s_cwzGenericIconFile[] = L"adfshell.dll"; const int s_ciGenericIconFileIndex = 0; void TrimString(PWSTR pwzTrimMe, PCWSTR pwzTrimChars) { PWSTR pwz = pwzTrimMe;; PWSTR pwzStartMeat = NULL; if ( !pwzTrimMe || !pwzTrimChars ) goto exit; // Trim leading characters. while (*pwz && wcschr(pwzTrimChars, *pwz)) { //CharNext(pwz); if (*pwz != L'\0') // this really will not be false... pwz++; } pwzStartMeat = pwz; // Trim trailing characters. if (*pwz) { pwz += wcslen(pwz); //CharPrev(pwzStartMeat, pwz); if (pwz != pwzStartMeat) // this check is not really necessary... pwz--; if (pwz > pwzStartMeat) { while (wcschr(pwzTrimChars, *pwz)) { //CharPrev(pwzStartMeat, pwz); if (pwz != pwzStartMeat) // this really will not be false... pwz--; } //CharNext(pwz); if (*pwz != L'\0') // this check is not really necessary... pwz++; ASSERT(pwz > pwzStartMeat); *pwz = L'\0'; } } // Relocate stripped string. if (*pwzStartMeat && pwzStartMeat > pwzTrimMe) // (+ 1) for null terminator. // BUGBUG?: is this going to bite us later? MoveMemory(pwzTrimMe, pwzStartMeat, (wcslen(pwzStartMeat)+1) * sizeof(WCHAR)); else if (!*pwzStartMeat) pwzTrimMe[0] = L'\0'; else ASSERT(pwzStartMeat == pwzTrimMe); exit: return; } /* ** TrimWhiteSpace() ** ** Trims leading and trailing white space from a string in place. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ void TrimWhiteSpace(PWSTR pwzTrimMe) { TrimString(pwzTrimMe, g_cwzWhiteSpace); // TrimString() validates pwzTrimMe on output. return; } /* ** GetRegKeyValue() ** ** Retrieves the data from a registry key's value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ LONG GetRegKeyValue(HKEY hkeyParent, PCWSTR pcwzSubKey, PCWSTR pcwzValue, PDWORD pdwValueType, PBYTE pbyteBuf, PDWORD pdwcbBufLen) { LONG lResult; HKEY hkeySubKey; ASSERT(IS_VALID_HANDLE(hkeyParent, KEY)); ASSERT(! pcwzSubKey || ! pcwzValue || ! pdwValueType || ! pbyteBuf); lResult = RegOpenKeyEx(hkeyParent, pcwzSubKey, 0, KEY_QUERY_VALUE, &hkeySubKey); if (lResult == ERROR_SUCCESS) { LONG lResultClose; lResult = RegQueryValueEx(hkeySubKey, pcwzValue, NULL, pdwValueType, pbyteBuf, pdwcbBufLen); lResultClose = RegCloseKey(hkeySubKey); if (lResult == ERROR_SUCCESS) lResult = lResultClose; } return(lResult); } /* ** GetRegKeyStringValue() ** ** Retrieves the data from a registry key's string value. ** ** Arguments: ** ** Returns: ERROR_CANTREAD if not string ** ** Side Effects: none */ LONG GetRegKeyStringValue(HKEY hkeyParent, PCWSTR pcwzSubKey, PCWSTR pcwzValue, PWSTR pwzBuf, PDWORD pdwcbBufLen) { LONG lResult; DWORD dwValueType; // GetRegKeyValue() will verify the parameters. lResult = GetRegKeyValue(hkeyParent, pcwzSubKey, pcwzValue, &dwValueType, (PBYTE)pwzBuf, pdwcbBufLen); if (lResult == ERROR_SUCCESS && dwValueType != REG_SZ) lResult = ERROR_CANTREAD; return(lResult); } /* ** GetDefaultRegKeyValue() ** ** Retrieves the data from a registry key's default string value. ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ LONG GetDefaultRegKeyValue(HKEY hkeyParent, PCWSTR pcwzSubKey, PWSTR pwzBuf, PDWORD pdwcbBufLen) { // GetRegKeyStringValue() will verify the parameters. return(GetRegKeyStringValue(hkeyParent, pcwzSubKey, NULL, pwzBuf, pdwcbBufLen)); } /***************************** Private Functions *****************************/ /* ** ParseIconEntry() ** ** ** Arguments: ** ** Returns: S_OK if icon entry parsed successfully. ** S_FALSE if not (empty string). ** (get 0 if icon index empty, or ** if icon index parsing fails) ** ** Side Effects: The contents of pwzIconEntry are modified. ** */ HRESULT ParseIconEntry(LPWSTR pwzIconEntry, PINT pniIcon) { HRESULT hr = S_OK; LPWSTR pwzComma; // caller GetGenericIcon() will verify the parameters. pwzComma = wcschr(pwzIconEntry, L','); if (pwzComma) { *pwzComma++ = L'\0'; LPWSTR pwzStopString=NULL; *pniIcon = (int) wcstol(pwzComma, &pwzStopString, 10); } else { *pniIcon = 0; } TrimWhiteSpace(pwzIconEntry); if (pwzIconEntry[0] == L'\0') { hr = S_FALSE; } ASSERT(IsValidIconIndex(hr, pwzIconEntry, MAX_PATH, *pniIcon)); return(hr); } /* ** GetFallBackGenericIcon() ** ** ** Arguments: ** ** Returns: S_OK if fallback generic icon information retrieved ** successfully. ** E_FAIL if not. ** ** Side Effects: none */ HRESULT GetFallBackGenericIcon(LPWSTR pwzIconFile, UINT ucbIconFileBufLen, PINT pniIcon) { HRESULT hr = S_OK; // Fall back to first icon in this module. // caller GetGenericIcon() will verify the parameters. if (ucbIconFileBufLen >= ( sizeof(s_cwzGenericIconFile) / sizeof(WCHAR) )) { wcscpy(pwzIconFile, s_cwzGenericIconFile); *pniIcon = s_ciGenericIconFileIndex; } else { hr = E_FAIL; } ASSERT(IsValidIconIndex(hr, pwzIconFile, ucbIconFileBufLen, *pniIcon)); return(hr); } /* ** GetGenericIcon() ** ** ** Arguments: ** ** Returns: S_OK if generic icon information retrieved successfully. ** Otherwise error (E_FAIL). ** ** Side Effects: none */ // assumptions: always structure the reg key value and fallback path so that the iconfile // can be found by the shell!! // should also consider making it a fully qualify path // finally the iconfile must exist HRESULT GetGenericIcon(LPWSTR pwzIconFile, UINT ucbIconFileBufLen, PINT pniIcon) { HRESULT hr = S_OK; DWORD dwcbLen = ucbIconFileBufLen; // caller GetIconLocation() will verify parameters ASSERT(IS_VALID_HANDLE(g_hkeySettings, KEY)); if (GetDefaultRegKeyValue(g_hkeySettings, g_cwzDefaultIconKey, pwzIconFile, &dwcbLen) == ERROR_SUCCESS) hr = ParseIconEntry(pwzIconFile, pniIcon); else { // no icon entry hr = S_FALSE; } if (hr == S_FALSE) hr = GetFallBackGenericIcon(pwzIconFile, ucbIconFileBufLen, pniIcon); ASSERT(IsValidIconIndex(hr, pwzIconFile, ucbIconFileBufLen, *pniIcon)); return(hr); } /********************************** Methods **********************************/ HRESULT STDMETHODCALLTYPE CFusionShortcut::GetIconLocation(UINT uInFlags, LPWSTR pwzIconFile, UINT ucbIconFileBufLen, PINT pniIcon, PUINT puOutFlags) { // is there any pref hit by doing this logic/probing here? // maybe this can be done in IPersistFile::Load instead? // always attempt to return S_OK or S_FALSE // only exception is that one case of E_INVALIDARG right below HRESULT hr=S_OK; if (!pwzIconFile || !pniIcon || ucbIconFileBufLen <= 0) { // should this return S_FALSE anyway so that the default shell icon is used? hr = E_INVALIDARG; goto exit; } if (IS_FLAG_CLEAR(uInFlags, GIL_OPENICON)) { // .. this get the path ... hr = GetIconLocation(pwzIconFile, ucbIconFileBufLen, pniIcon); if (hr == S_OK && GetFileAttributes(pwzIconFile) == (DWORD)-1) { // if the file specified by iconfile does not exist, try again in working dir // it can be a relative path... // see note in shlink.cpp for string array size LPWSTR pwzWorkingDir = new WCHAR[ucbIconFileBufLen]; hr = GetWorkingDirectory(pwzWorkingDir, ucbIconFileBufLen); if (hr != S_OK) hr = S_FALSE; else { LPWSTR pwzPath = new WCHAR[ucbIconFileBufLen]; // working dir does not end w/ '\' _snwprintf(pwzPath, ucbIconFileBufLen, L"%s\\%s", pwzWorkingDir, pwzIconFile); if (GetFileAttributes(pwzPath) == (DWORD)-1) hr = S_FALSE; else wcscpy(pwzIconFile, pwzPath); delete [] pwzPath; } delete [] pwzWorkingDir; } // BUGBUG?: change to '!= S_OK'? // no need because GetIconLocation(,,) only returns S_OK/S_FALSE here if (hr == S_FALSE) { if (m_pwzPath) { // no icon file, use the entry point... // BUGBUG?: passing NULL as PWIN32_FIND_DATA will assert.. hr = GetPath(pwzIconFile, ucbIconFileBufLen, NULL, SLGP_SHORTPATH); //?????? 0); if (hr != S_OK || GetFileAttributes(pwzIconFile) == (DWORD)-1) hr = S_FALSE; *pniIcon = 0; } /*else hr = S_FALSE;*/ if (hr == S_FALSE) { // ... there's nothing? // Use generic URL icon. // see assumptions on GetGenericIcon() hr = GetGenericIcon(pwzIconFile, ucbIconFileBufLen, pniIcon); if (FAILED(hr)) // worst case: ask shell to use its generic icon hr = S_FALSE; } } } else // No "open look" icon. hr = S_FALSE; if (hr != S_OK) { // see shelllink? if (ucbIconFileBufLen > 0) *pwzIconFile = L'\0'; *pniIcon = 0; } exit: if (puOutFlags) *puOutFlags = 0; // ignore puOutFlags == NULL case ASSERT(IsValidIconIndex(hr, pwzIconFile, ucbIconFileBufLen, *pniIcon))// && return(hr); } HRESULT STDMETHODCALLTYPE CFusionShortcut::Extract(LPCWSTR pcwzIconFile, UINT uiIcon, HICON* phiconLarge, HICON* phiconSmall, UINT ucIconSize) { HRESULT hr; ASSERT(IsValidIconIndex(S_OK, pcwzIconFile, MAX_PATH, uiIcon)); // FEATURE: Validate ucIconSize here. if (phiconLarge) *phiconLarge = NULL; if (phiconSmall) *phiconSmall = NULL; // Use caller's default implementation of ExtractIcon(). // GetIconLocation() should return good path and index hr = S_FALSE; ASSERT((hr == S_OK && IS_VALID_HANDLE(*phiconLarge, ICON) && IS_VALID_HANDLE(*phiconSmall, ICON)) || (hr != S_OK && ! *phiconLarge && ! *phiconSmall)); return(hr); }