You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
11 KiB
473 lines
11 KiB
/*
|
|
* extricon.cpp - IExtractIcon implementation for CFusionShortcut class.
|
|
*/
|
|
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.hpp"
|
|
#include <stdio.h> // 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);
|
|
}
|
|
|