Leaked source code of windows server 2003
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

/*
* 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);
}