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.
 
 
 
 
 
 

1140 lines
30 KiB

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// cdfidl.cpp
//
// Cdf id list helper functions.
//
// History:
//
// 3/19/97 edwardp Created.
//
////////////////////////////////////////////////////////////////////////////////
//
// Includes
//
#include "stdinc.h"
#include "cdfidl.h"
#include "xmlutil.h"
#include "winineti.h" // for MAX_CACHE_ENTRY_INFO_SIZE
//
// Helper functions
//
LPTSTR CDFIDL_GetUserName()
{
static BOOL gunCalled = FALSE;
static TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH] = TEXT("");
if (!gunCalled)
{
char szUserNameA[INTERNET_MAX_USER_NAME_LENGTH];
szUserNameA[0] = 0;
DWORD size = INTERNET_MAX_USER_NAME_LENGTH;
GetUserNameA(szUserNameA, &size);
SHAnsiToTChar(szUserNameA, szUserName, ARRAYSIZE(szUserName));
gunCalled = TRUE;
}
return szUserName;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_Create ***
//
//
// Description:
// Creates a cdf id list.
//
// Parameters:
// [In] pCdfItem - A pointer to cdf item data.
//
// Return:
// A new cdf id list on success.
// NULL otherwise.
//
// Comments:
// This function builds a variable length cdf item id list. The item id
// consists of a fixed length initial section followed by two or more null
// terminated strings. It has the following form:
//
// USHORT cb - Size in bytes of this cdf item id.
// WORD wVersion; - Version number of this item id structure.
// DWORD dwId; - Used to identify cdf item ids. Set to
// 0x0ed1964ed
// CDFITEMTYPE cdfItemType - CDF_Folder, CDF_FolderLink or CDF_Link.
// LONG nIndex - The object model index for this item.
// TCHAR szName[1]; - Two or more null terminated strings
// beggining with the name of this item.
// USHORT next.cb - The size of the next item in the list.
// Set to zero to terminate the list.
//
// It is the callers responsability to free the item id list. This should
// be done using the IMalloc returned from SHGetMalloc();
//
////////////////////////////////////////////////////////////////////////////////
PCDFITEMIDLIST
CDFIDL_Create(
PCDFITEM pCdfItem
)
{
#ifdef ALIGNMENT_MACHINE
TCHAR *pszTempName;
#endif
ASSERT(pCdfItem);
ASSERT(pCdfItem->bstrName);
ASSERT(pCdfItem->bstrURL);
PCDFITEMIDLIST pcdfidl = NULL;
//
// Get the number of chars of the name of the item including the terminating
// null character.
//
USHORT cchName = StrLenW(pCdfItem->bstrName) + 1;
//
// Get the number of chars of the URL of the item including the terminating
// null character.
//
USHORT cchURL = StrLenW(pCdfItem->bstrURL) + 1;
//
// Calculate the total size of the cdf item id in bytes. When calculating the size
// of a cdf item id one TCHAR should be subtracted to account for the TCHAR
// szName[1] included in the CDFITEMID struct definition.
//
USHORT cbItemId = sizeof(CDFITEMID) + (cchName + cchURL) * sizeof(TCHAR) - sizeof(TCHAR);
#ifdef ALIGNMENT_MACHINE
cbItemId = ALIGN4(cbItemId);
#endif
//
// Item ids must allocated by the shell's IMalloc interface.
//
IMalloc* pIMalloc;
HRESULT hr = SHGetMalloc(&pIMalloc);
if (SUCCEEDED(hr))
{
ASSERT(pIMalloc);
//
// An item id *list* must be NULL terminated so an additional USHORT is
// allocated to hold the terminating NULL.
//
pcdfidl = (PCDFITEMIDLIST)pIMalloc->Alloc(cbItemId + sizeof(USHORT));
if (pcdfidl)
{
//
// NULL terminate the list.
//
*((UNALIGNED USHORT*) ( ((LPBYTE)pcdfidl) + cbItemId )) = 0;
#ifdef ALIGNMENT_MACHINE
USHORT cbActaulItemId = sizeof(CDFITEMID) + (cchName + cchURL) * sizeof(TCHAR) - sizeof(TCHAR);
if(cbActaulItemId < cbItemId)
ZeroMemory((LPBYTE)pcdfidl + cbActaulItemId, cbItemId - cbActaulItemId);
#endif
//
// Fill in the data shared by all cdf item ids.
//
pcdfidl->mkid.cb = cbItemId;
pcdfidl->mkid.wVersion = CDFITEMID_VERSION;
pcdfidl->mkid.dwId = CDFITEMID_ID;
//
// Set the data that is specific to this cdf item id.
//
pcdfidl->mkid.cdfItemType = pCdfItem->cdfItemType;
pcdfidl->mkid.nIndex = pCdfItem->nIndex;
//
// REVIEW: Need WSTR to TSTR conversion.
//
#ifndef ALIGNMENT_MACHINE
SHUnicodeToTChar(pCdfItem->bstrName, pcdfidl->mkid.szName, cchName);
SHUnicodeToTChar(pCdfItem->bstrURL, pcdfidl->mkid.szName + cchName,
cchURL);
#else
pszTempName = (LPTSTR)ALIGN4((ULONG_PTR)(pcdfidl->mkid.szName));
SHUnicodeToTChar(pCdfItem->bstrName, pszTempName, cchName);
pszTempName = (LPTSTR)((ULONG_PTR)(pcdfidl->mkid.szName+cchName));
SHUnicodeToTChar(pCdfItem->bstrURL, pszTempName,
cchURL);
#endif
}
else
{
pcdfidl = NULL;
}
pIMalloc->Release();
}
ASSERT(CDFIDL_IsValid(pcdfidl) || NULL == pcdfidl);
return pcdfidl;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_CreateFromXMLElement ***
//
//
// Description:
// Creates a cdf item id list from a xml element.
//
// Parameters:
// [In] pIXMLElement - A pointer to the xml element.
// [In] nIndex - The index value used to set the cdfidl index field.
//
// Return:
// A poniter to a new cdf item id list if successful.
// NULL otherwise.
//
// Comments:
// The caller is responsible for freeing the returned id list.
//
////////////////////////////////////////////////////////////////////////////////
PCDFITEMIDLIST
CDFIDL_CreateFromXMLElement(
IXMLElement* pIXMLElement,
ULONG nIndex
)
{
ASSERT(pIXMLElement);
PCDFITEMIDLIST pcdfidl = NULL;
CDFITEM cdfItem;
if (cdfItem.bstrName = XML_GetAttribute(pIXMLElement, XML_TITLE))
{
if (cdfItem.bstrURL = XML_GetAttribute(pIXMLElement, XML_HREF))
{
cdfItem.nIndex = nIndex;
if (INDEX_CHANNEL_LINK == nIndex)
{
cdfItem.cdfItemType = CDF_FolderLink;
}
else
{
cdfItem.cdfItemType = XML_IsFolder(pIXMLElement) ? CDF_Folder :
CDF_Link;
}
pcdfidl = CDFIDL_Create(&cdfItem);
SysFreeString(cdfItem.bstrURL);
}
SysFreeString(cdfItem.bstrName);
}
ASSERT(CDFIDL_IsValid(pcdfidl) || NULL == pcdfidl);
return pcdfidl;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_CreateFolderPidl ***
//
//
// Description: creates a special folder pidl
//
//
// Parameters:
// [In] pcdfidl - Pointer to the cdf id list to be created from
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
PCDFITEMIDLIST
CDFIDL_CreateFolderPidl(
PCDFITEMIDLIST pcdfidl
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
PCDFITEMIDLIST pcdfidlRet = (PCDFITEMIDLIST)ILClone((LPITEMIDLIST)pcdfidl);
if (pcdfidlRet)
{
((PCDFITEMID)pcdfidlRet)->nIndex = INDEX_CHANNEL_LINK;
((PCDFITEMID)pcdfidlRet)->cdfItemType = CDF_FolderLink; //CDF_Link instead?
}
ASSERT(CDFIDL_IsValid(pcdfidlRet));
return pcdfidlRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_Free ***
//
//
// Description:
// Free the given cdf item id list.
//
// Parameters:
// [In] pcdfidl - Pointer to the cdf id list to be freed.
//
// Return:
// No return value.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
void
CDFIDL_Free(
PCDFITEMIDLIST pcdfidl
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
IMalloc *pIMalloc;
if (SUCCEEDED(SHGetMalloc(&pIMalloc)))
{
ASSERT(pIMalloc);
ASSERT(pIMalloc->DidAlloc(pcdfidl));
pIMalloc->Free(pcdfidl);
pIMalloc->Release();
}
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_GetDisplayName ***
//
//
// Description:
// Gets the name stored in the given cdf item id list.
//
// Parameters:
// [In] pcdfidl - A pointer to a cdf item id list.
// [Out] pName - A pointer to a STRRET structure. STRRET has the following
// structure:
// UINT uType - STRRET_CSTR, _OFFSET or _WSTR
// union {
// LPWSTR pOleStr;
// UINT uOffset;
// char cStr[MAX_PATH];
// }
//
// Return:
// S_OK on success. E_Fail otherwise.
//
// Comments:
// This function returns the name as an offset of the string from the start
// of the cdf item id list.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CDFIDL_GetDisplayName(
PCDFITEMIDLIST pcdfidl,
LPSTRRET pName
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
ASSERT(pName);
pName->uType = STRRET_CSTR;
LPTSTR pszName = CDFIDL_GetName(pcdfidl);
SHTCharToAnsi(pszName, pName->cStr, ARRAYSIZE(pName->cStr));
return S_OK;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_GetName ***
//
//
// Description:
// Gets a pointer to the URL stored in the given cdf item id list.
//
// Parameters:
// [In] pcdfidl - A pointer to a cdf item id list.
//
// Return:
// A LPTSTR to the Name stored in the pidl.
//
// Comments:
// This function returns a pointer to the Name in the cdf item id list.
// The pointer is valid for the life of the item id list. The caller is
// resposible for maintaining the item id list and for not using the
// the returned pointer after the id list is freed.
//
// The name returned is the name of the last item in the list.
//
////////////////////////////////////////////////////////////////////////////////
LPTSTR
CDFIDL_GetName(
PCDFITEMIDLIST pcdfidl
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
pcdfidl = (PCDFITEMIDLIST)ILFindLastID((LPITEMIDLIST)pcdfidl);
return CDFIDL_GetNameId(&pcdfidl->mkid);
}
LPTSTR
CDFIDL_GetNameId(
PCDFITEMID pcdfid
)
{
ASSERT(pcdfid);
#if defined(ALIGNMENT_MACHINE)
return (LPTSTR)(ALIGN4((ULONG_PTR)pcdfid->szName));
#else
return pcdfid->szName;
#endif
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_GetURL ***
//
//
// Description:
// Gets a pointer to the URL stored in the given cdf item id list.
//
// Parameters:
// [In] pcdfidl - A pointer to a cdf item id list.
//
// Return:
// A LPTSTR to the URL value for the given pcdfidl.
//
// Comments:
// This function returns a pointer to the URL in the cdf item id list. The
// pointer is valid for the life of the item id list. The caller is
// resposible for maintaining the item id list and for not using the
// the returned pointer after the id list is freed.
//
// The URL returned is the URL of the last item in the list.
//
////////////////////////////////////////////////////////////////////////////////
LPTSTR
CDFIDL_GetURL(
PCDFITEMIDLIST pcdfidl
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
//
// Get the first string after the name.
//
LPTSTR szURL = CDFIDL_GetName(pcdfidl);
while (*szURL++);
return szURL;
}
LPTSTR
CDFIDL_GetURLId(
PCDFITEMID pcdfid
)
{
ASSERT(pcdfid);
//
// Get the first string after the name.
//
LPTSTR szURL = CDFIDL_GetNameId(pcdfid);
while (*szURL++);
return szURL;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_GetIndex ***
//
//
// Description:
// Returns the index item of the given cdf id list.
//
// Parameters:
// [In] pcdfidl - Pointer to the cdf item id list.
//
// Return:
// Returns the index item of the given id list.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
ULONG
CDFIDL_GetIndex(
PCDFITEMIDLIST pcdfidl
)
{
pcdfidl = (PCDFITEMIDLIST)ILFindLastID((LPITEMIDLIST)pcdfidl);
return CDFIDL_GetIndexId(&pcdfidl->mkid);
}
ULONG
CDFIDL_GetIndexId(
PCDFITEMID pcdfid
)
{
return pcdfid->nIndex;
}
#define ASTR_HISTORY_PREFIX TEXT("Visited: ")
//
// Looks the URL up in the cache to see if the user has ever read this url
//
// REVIEW
// REVIEW - Should probably use IUrlStorage instead of constructing the
// REVIEW
// history cache URL on the fly
//
BOOL
CDFIDL_IsUnreadURL(
LPTSTR szUrl
)
{
DWORD dwLen;
//
// Canonicalize the input url.
//
TCHAR szCanonicalizedUrl[INTERNET_MAX_URL_LENGTH];
dwLen = INTERNET_MAX_URL_LENGTH;
if (!InternetCanonicalizeUrl(szUrl, szCanonicalizedUrl, &dwLen, 0))
StrCpyN(szCanonicalizedUrl, szUrl, ARRAYSIZE(szCanonicalizedUrl));
//
// Build a string that is the URL prefixed with VISITED: and the UserName
//
TCHAR szVisited[
INTERNET_MAX_USER_NAME_LENGTH+
1+
INTERNET_MAX_URL_LENGTH+
ARRAYSIZE(ASTR_HISTORY_PREFIX)];
StrCpyN(szVisited, ASTR_HISTORY_PREFIX, ARRAYSIZE(szVisited));
StrCatBuff(szVisited, CDFIDL_GetUserName(), ARRAYSIZE(szVisited));
int len = StrLen(szVisited);
StrCpyN(szVisited + len, TEXT("@"), ARRAYSIZE(szVisited) - len);
len++;
StrCpyN(szVisited + len, szCanonicalizedUrl, ARRAYSIZE(szVisited) - len);
len++;
// Check for trailing slash and eliminate, copied from shdocvw\urlhist.cpp
LPTSTR pszT = CharPrev(szVisited, szVisited + lstrlen(szVisited));
if (*pszT == TEXT('/'))
{
ASSERT(lstrlen(pszT) == 1);
*pszT = 0;
}
//
// If the VISITED: entry does not exist in the cache assume url is unread
//
#ifndef ALIGNMENT_MACHINE
BYTE visitedCEI[MAX_CACHE_ENTRY_INFO_SIZE];
LPINTERNET_CACHE_ENTRY_INFO pVisitedCEI = (LPINTERNET_CACHE_ENTRY_INFO)visitedCEI;
#else
union
{
double align8;
BYTE visitedCEI[MAX_CACHE_ENTRY_INFO_SIZE];
} alignedvisitedCEI;
LPINTERNET_CACHE_ENTRY_INFO pVisitedCEI = (LPINTERNET_CACHE_ENTRY_INFO)&alignedvisitedCEI;
#endif /* ALIGNMENT_MACHINE */
dwLen = MAX_CACHE_ENTRY_INFO_SIZE;
if (GetUrlCacheEntryInfo(szVisited, pVisitedCEI, &dwLen) == FALSE)
{
return TRUE;
}
else
{
//
// URL has been visited, but it still may be unread if the page has
// been placed in the cache by the infodelivery mechanism
//
#ifndef ALIGNMENT_MACHINE
BYTE urlCEI[MAX_CACHE_ENTRY_INFO_SIZE];
LPINTERNET_CACHE_ENTRY_INFO pUrlCEI = (LPINTERNET_CACHE_ENTRY_INFO)urlCEI;
#else
union
{
double align8;
BYTE urlCEI[MAX_CACHE_ENTRY_INFO_SIZE];
} alignedurlCEI;
LPINTERNET_CACHE_ENTRY_INFO pUrlCEI = (LPINTERNET_CACHE_ENTRY_INFO)&alignedurlCEI;
#endif /* ALIGNMENT_MACHINE */
dwLen = MAX_CACHE_ENTRY_INFO_SIZE;
if (GetUrlCacheEntryInfo(szCanonicalizedUrl, pUrlCEI, &dwLen) == FALSE)
{
return FALSE; // no url cache entry but url was visited so mark read
}
else
{
//
// If the url has been modified after the time of the visited
// record then url is unread
//
if (CompareFileTime(&pUrlCEI->LastModifiedTime,
&pVisitedCEI->LastModifiedTime) > 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
}
}
//
// Looks the URL up in the cache. TRUE if it is and FALSE otherwise
//
BOOL
CDFIDL_IsCachedURL(
LPWSTR wszUrl
)
{
BOOL fCached;
TCHAR szUrlT[INTERNET_MAX_URL_LENGTH];
//
// Canonicalize the input url.
//
if (SHUnicodeToTChar(wszUrl, szUrlT, ARRAYSIZE(szUrlT)))
{
URL_COMPONENTS uc;
ZeroMemory(&uc, sizeof(uc));
uc.dwStructSize = sizeof(URL_COMPONENTS);
uc.dwSchemeLength = 1;
if (InternetCrackUrl(szUrlT, 0, 0, &uc))
{
// zekel should look at this
TCHAR *pchLoc = StrChr(szUrlT, TEXT('#'));
if (pchLoc)
*pchLoc = TEXT('\0');
fCached = GetUrlCacheEntryInfoEx(szUrlT, NULL, NULL, NULL, NULL, NULL, 0);
if(fCached)
{
return TRUE;
}
else
{
TCHAR szCanonicalizedUrlT[INTERNET_MAX_URL_LENGTH];
DWORD dwLen = INTERNET_MAX_URL_LENGTH;
InternetCanonicalizeUrl(szUrlT, szCanonicalizedUrlT, &dwLen, 0);
fCached = GetUrlCacheEntryInfoEx(szCanonicalizedUrlT, NULL, NULL, NULL, NULL, NULL, 0);
if(fCached)
return TRUE;
}
}
}
return FALSE;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_GetAttributes ***
//
//
// Description:
// Returns the attributes item of the given cdf item id list.
//
// Parameters:
// [In] pIXMLElementCollectionparent - The containing element collection.
// [In] pcdfidl - A pointer to the cdf item id list.
// [In] fAttributesFilter - Determines which flags to bother
// looking at
//
// Return:
// The attributes of the given id list.
// Zero on failure. Note: Zero is a valid attribute value.
//
// Comments:
// The attribute flags returned by this function can be used directly as a
// return value by IShellFolder->GetAttributesOf().
//
////////////////////////////////////////////////////////////////////////////////
ULONG
CDFIDL_GetAttributes(
IXMLElementCollection* pIXMLElementCollectionParent,
PCDFITEMIDLIST pcdfidl,
ULONG fAttributesFilter
)
{
ASSERT(pIXMLElementCollectionParent);
ASSERT(CDFIDL_IsValid(pcdfidl));
ASSERT(ILIsEmpty(_ILNext((LPITEMIDLIST)pcdfidl)));
//
// REVIEW: Need to properly determine shell attributes of cdf items.
//
ULONG uRet;
if (CDFIDL_IsFolderId(&pcdfidl->mkid))
{
uRet = SFGAO_FOLDER | SFGAO_CANLINK;
// If we weren't asked for HASSUBFOLDER don't bother looking for it
// This should be a win in non tree views (ie. std open mode)
if ((SFGAO_HASSUBFOLDER & fAttributesFilter) &&
pIXMLElementCollectionParent &&
XML_ChildContainsFolder(pIXMLElementCollectionParent,
CDFIDL_GetIndex(pcdfidl)))
{
uRet |= SFGAO_HASSUBFOLDER;
}
}
else
{
uRet = SFGAO_CANLINK;
// If we weren't asked for NEWCONTENT don't bother looking for it
// This will be a win in non channel pane views.
// Can't test for SFGAO_NEWCONTENT since shell is never
// expressing interest in it!
if (/*(SFGAO_NEWCONTENT & fAttributeFilter) && */
CDFIDL_IsUnreadURL(CDFIDL_GetURL(pcdfidl)))
{
uRet |= SFGAO_NEWCONTENT;
}
}
return uRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_Compare ***
//
//
// Description:
// Compares two cdf item id lists
//
// Parameters:
// [In] pcdfidl1 - A pointer to the first item id list to compare.
// [In] pcdfidl2 - A pointer to the second item id list to compare.
//
// Return:
// -1 if item 1 comes before item 2.
// 0 if the items are equal.
// 1 if item 2 comes before item 1.
//
// Comments:
// Sort Order:
// 1) Use the CompareId result of the first items in the lists.
// 2) If 1) returns 0. Compare the next two items in the lists.
// 3) If both list are empty. They are equal.
// 4) The shorter id list comes first.
//
////////////////////////////////////////////////////////////////////////////////
SHORT
CDFIDL_Compare(
PCDFITEMIDLIST pcdfidl1,
PCDFITEMIDLIST pcdfidl2
)
{
ASSERT(CDFIDL_IsValid(pcdfidl1));
ASSERT(CDFIDL_IsValid(pcdfidl2));
SHORT sRet;
sRet = CDFIDL_CompareId(&pcdfidl1->mkid, &pcdfidl2->mkid);
if (0 == sRet)
{
if (!ILIsEmpty(_ILNext(pcdfidl1)) && !ILIsEmpty(_ILNext(pcdfidl2)))
{
sRet = CDFIDL_Compare((PCDFITEMIDLIST)_ILNext(pcdfidl1),
(PCDFITEMIDLIST)_ILNext(pcdfidl2));
}
else if(!ILIsEmpty(_ILNext(pcdfidl1)) && ILIsEmpty(_ILNext(pcdfidl2)))
{
sRet = 1;
}
else if (ILIsEmpty(_ILNext(pcdfidl1)) && !ILIsEmpty(_ILNext(pcdfidl2)))
{
sRet = -1;
}
}
return sRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_CompareId ***
//
//
// Description:
// Compares two item cdf item ids.
//
// Parameters:
// [In] pcdfid1 - A pointer to the first item id to compare.
// [In] pcdfid2 - A pointer to the second item id to compare.
//
// Return:
// -1 if item 1 comes before item 2.
// 0 if the items are the same.
// 1 if item 2 comes before item 1.
//
// Comments:
// Sort Order:
// 1) CDF_FolderLink (Essentially an URL for the current folder). These
// have an index of -1.
// 2) Everything else accoring to its order in the CDF. These have
// a zero-based index.
// 3) Non CDF items (should't have any).
//
////////////////////////////////////////////////////////////////////////////////
SHORT
CDFIDL_CompareId(
PCDFITEMID pcdfid1,
PCDFITEMID pcdfid2
)
{
ASSERT(CDFIDL_IsValidId(pcdfid1));
ASSERT(CDFIDL_IsValidId(pcdfid2));
SHORT sRet;
if (pcdfid1->nIndex < pcdfid2->nIndex)
{
sRet = -1;
}
else if (pcdfid1->nIndex > pcdfid2->nIndex)
{
sRet = 1;
}
else
{
sRet = (short) CompareString(LOCALE_USER_DEFAULT, 0, CDFIDL_GetNameId(pcdfid1),
-1, CDFIDL_GetNameId(pcdfid2), -1);
//
// Note: CompareString returns 1 if S1 comes before S2, 2 if S1 is equal
// to S2, 3 if S2 comes before S1 and 0 on error.
//
sRet = sRet ? sRet - 2 : 0;
if (0 == sRet)
{
//
// If the URLs aren't equal just pick one at random.
//
sRet = !StrEql(CDFIDL_GetURLId(pcdfid1), CDFIDL_GetURLId(pcdfid2));
ASSERT((pcdfid1->cb == pcdfid2->cb) || 0 != sRet);
ASSERT((pcdfid1->cdfItemType == pcdfid1->cdfItemType) || 0 != sRet);
}
}
return sRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_IsValid ***
//
//
// Description:
// Determines if the given pcdfidl is valid.
//
// Parameters:
// pcdfid - A pointer to the cdf id to check.
//
// Return:
// TRUE if the id is a cdf id.
// FALSE otherwise.
//
// Comments:
// An empty list is not valid.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
CDFIDL_IsValid(
PCDFITEMIDLIST pcdfidl
)
{
BOOL bRet;
if (pcdfidl && (pcdfidl->mkid.cb > 0))
{
bRet = TRUE;
while (pcdfidl->mkid.cb && bRet)
{
bRet = CDFIDL_IsValidId(&pcdfidl->mkid);
pcdfidl = (PCDFITEMIDLIST)_ILNext((LPITEMIDLIST)pcdfidl);
}
}
else
{
bRet = FALSE;
}
return bRet;
}
//
// Inline helper functions.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_IsValidId ***
//
//
// Description:
// Inline function that returns TRUE if the given id is a pointer to a cdf
// item id.
//
// Parameters:
// pcdfid - A pointer to the cdf id to check.
//
// Return:
// TRUE if the id is a cdf id.
// FALSE otherwise.
//
// Comments:
// This function is not completely safe. If the first word pointed to
// is large but the memory block pointed to is smaller than a 8 bytes an
// access violation will occur. Also, if the first word is large enough and
// the second DWORD is equal to CDFITEM_ID but the item isn't a cdf id a
// false positive will occur.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
CDFIDL_IsValidId(
PCDFITEMID pcdfid
)
{
ASSERT(pcdfid);
return (pcdfid->cb >= (sizeof(CDFITEMID) + sizeof(TCHAR)) &&
pcdfid->dwId == CDFITEMID_ID &&
CDFIDL_IsValidSize(pcdfid) &&
CDFIDL_IsValidType(pcdfid) &&
CDFIDL_IsValidIndex(pcdfid) &&
CDFIDL_IsValidStrings(pcdfid) );
}
inline
BOOL
CDFIDL_IsValidSize(
PCDFITEMID pcdfid
)
{
int cbName = (StrLen(CDFIDL_GetNameId(pcdfid)) + 1) *
sizeof(TCHAR);
int cbURL = (StrLen(CDFIDL_GetURLId(pcdfid)) + 1) *
sizeof(TCHAR);
#ifndef ALIGNMENT_MACHINE
return (sizeof(CDFITEMID) - sizeof(TCHAR) + cbName + cbURL == pcdfid->cb);
#else
return ((ALIGN4(sizeof(CDFITEMID) - sizeof(TCHAR) + cbName + cbURL)) == pcdfid->cb);
#endif
}
inline
BOOL
CDFIDL_IsValidType(
PCDFITEMID pcdfid
)
{
return ((CDF_Folder == (CDFITEMTYPE)pcdfid->cdfItemType) ||
(CDF_Link == (CDFITEMTYPE)pcdfid->cdfItemType) ||
(CDF_FolderLink == (CDFITEMTYPE)pcdfid->cdfItemType) );
}
inline
BOOL
CDFIDL_IsValidIndex(
PCDFITEMID pcdfid
)
{
return ( pcdfid->nIndex >= 0
||
(INDEX_CHANNEL_LINK == pcdfid->nIndex &&
CDF_FolderLink == (CDFITEMTYPE)pcdfid->cdfItemType));
}
inline
BOOL
CDFIDL_IsValidStrings(
PCDFITEMID pcdfid
)
{
//
// REVIEW: Validate pidl strings.
//
return TRUE;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_IsFolder ***
//
//
// Description:
// Inline function that returns TRUE if the given cdfidl is a folder as far
// as the shel is concerned.
//
// Parameters:
// pcdfidl - The cdf item id list to check.
//
// Return:
// TRUE if the cdf item id list is a folder.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
CDFIDL_IsFolder(
PCDFITEMIDLIST pcdfidl
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
pcdfidl = (PCDFITEMIDLIST)ILFindLastID((LPITEMIDLIST)pcdfidl);
return CDFIDL_IsFolderId(&pcdfidl->mkid);
}
BOOL
CDFIDL_IsFolderId(
PCDFITEMID pcdfid
)
{
ASSERT(CDFIDL_IsValidId(pcdfid));
return (CDF_Folder == (CDFITEMTYPE)pcdfid->cdfItemType);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CDFIDL_NonCdfGetName ***
//
//
// Description:
// Gets the name stored in the given non-cdf item id list.
//
// Parameters:
// [In] pcdfidl - A pointer to a cdf item id list. Can be NULL.
// [Out] pName - A pointer to a STRRET structure. STRRET has the following
// structure:
// UINT uType - STRRET_CSTR, _OFFSET or _WSTR
// union {
// LPWSTR pOleStr;
// UINT uOffset;
// char cStr[MAX_PATH];
// }
//
// Return:
// S_OK on success. E_Fail otherwise.
//
// Comments:
// This function returns the name as a cString in the STRRET structure.
//
// ILGetDisplayName returns the full path. This function strips out the
// filename sans extension.
//
////////////////////////////////////////////////////////////////////////////////
#if 0
HRESULT
CDFIDL_NonCdfGetDisplayName(
LPCITEMIDLIST pidl,
LPSTRRET pName
)
{
ASSERT(pName);
HRESULT hr;
//
// REVIEW: Hack to get the name of a shell pidl.
//
if (ILGetDisplayName(pidl, pName->cStr))
{
TCHAR* p1 = pName->cStr;
TCHAR* p2 = p1;
while (*p1++); // Go to the end.
while (*--p1 != TEXT('\\')); // Back to last backslash.
while (TEXT('.') != (*p2++ = *++p1)); // Copy the name.
*--p2 = TEXT('\0'); // NULL terminate.
pName->uType = STRRET_CSTR;
hr = S_OK;
}
else
{
hr = E_FAIL;
}
return hr;
}
#endif