|
|
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// chanenum.cpp
//
// The enumerator object for channels.
//
// History:
//
// 8/7/97 edwardp Created.
//
////////////////////////////////////////////////////////////////////////////////
//
// Includes
//
#include "stdinc.h"
#include "chanenum.h"
#include "cdfidl.h"
#include "xmlutil.h"
#include "chanapi.h"
#include "dll.h"
//
// Helper functions.
//
//
// Constructor and destructor.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::CChannelEnum ***
//
// Constructor.
//
////////////////////////////////////////////////////////////////////////////////
CChannelEnum::CChannelEnum ( DWORD dwEnumFlags, LPCWSTR pszURL ) : m_cRef(1) { ASSERT(NULL == m_pseDirectoryStack);
TraceMsg(TF_OBJECTS, "+ IEnumChannels");
if (pszURL) { int cch = StrLenW(pszURL) + 1;
m_pszURL = new TCHAR[cch];
SHUnicodeToTChar(pszURL, m_pszURL, cch); }
m_dwEnumFlags = dwEnumFlags;
DirectoryStack_InitFromFlags(dwEnumFlags);
DllAddRef();
return; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::~CChannelEnum **
//
// Destructor.
//
////////////////////////////////////////////////////////////////////////////////
CChannelEnum::~CChannelEnum( void ) { TraceMsg(TF_OBJECTS, "- IEnumChannels");
if (m_pszURL) delete []m_pszURL;
DirectoryStack_FreeStack();
DllRelease();
return; }
//
// IUnknown methods.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::CChannelEnum ***
//
// CChannelEnum QI.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CChannelEnum::QueryInterface ( REFIID riid, void **ppv ) { ASSERT(ppv);
HRESULT hr;
if (IID_IUnknown == riid || IID_IEnumChannels == riid) { AddRef(); *ppv = (IEnumChannels*)this; hr = S_OK; } else { *ppv = NULL; hr = E_NOINTERFACE; }
ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && NULL == *ppv));
return hr; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::AddRef ***
//
// CChannelEnum AddRef.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CChannelEnum::AddRef ( void ) { ASSERT(m_cRef != 0); ASSERT(m_cRef < (ULONG)-1);
return ++m_cRef; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::Release ***
//
// Cdf view Release.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CChannelEnum::Release ( void ) { ASSERT (m_cRef != 0);
ULONG cRef = --m_cRef; if (0 == cRef) delete this;
return cRef; }
//
// IEnumIDList methods.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::Next ***
//
//
// Description:
// Returns the next n item id lists associated with this enumerator.
//
// Parameters:
// [in] celt - Number of item id lists to return.
// [Out] rgelt - A pointer to an array of item id list pointers that
// will receive the id item lists.
// [Out] pceltFetched - A pointer to a ULONG that receives a count of the
// number of id lists fetched.
//
// Return:
// S_OK if celt items where fetched.
// S_FALSE if celt items where not fetched.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CChannelEnum::Next( ULONG celt, CHANNELENUMINFO* rgelt, ULONG* pceltFetched) { ASSERT(rgelt || 0 == celt); ASSERT(pceltFetched || 1 == celt);
//
// pceltFetched can be NULL if and only if celt is 1.
//
ULONG lFetched;
if (1 == celt && NULL == pceltFetched) pceltFetched = &lFetched;
for (*pceltFetched = 0; *pceltFetched < celt; (*pceltFetched)++) { if (!FindNextChannel(&rgelt[*pceltFetched])) break; }
return (*pceltFetched == celt) ? S_OK : S_FALSE; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::Skip ***
//
// Shell doesn't call this member.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CChannelEnum::Skip( ULONG celt) { CHANNELENUMINFO ci = {0};
//
// Don't alocated any data on the FindNextChannel call.
//
DWORD dwOldFlags = m_dwEnumFlags; m_dwEnumFlags = 0;
while (celt && FindNextChannel(&ci)) celt--;
m_dwEnumFlags = dwOldFlags;
return 0 == celt ? S_OK : S_FALSE; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::Reset ***
//
// Set the current item to the index of the first item in CFolderItems.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CChannelEnum::Reset( void ) { DirectoryStack_FreeStack(); DirectoryStack_InitFromFlags(m_dwEnumFlags);
return S_OK; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::Clone ***
//
// Shell doesn't call this method.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CChannelEnum::Clone( IEnumChannels **ppenum ) { return E_NOTIMPL; }
//
// Directory stack functions.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_IsEmpty ***
//
// Is the stack empty.
//
////////////////////////////////////////////////////////////////////////////////
inline BOOL CChannelEnum::DirectoryStack_IsEmpty( void ) { return NULL == m_pseDirectoryStack; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_FreeEntry ***
//
// Free a stack entry item.
//
////////////////////////////////////////////////////////////////////////////////
void CChannelEnum::DirectoryStack_FreeEntry( STACKENTRY* pse ) { ASSERT(pse) ASSERT(pse->pszPath); ASSERT(!pse->pNext);
delete []pse->pszPath; delete pse;
return; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_FreeStack ***
//
// Free all items on the stack.
//
////////////////////////////////////////////////////////////////////////////////
void CChannelEnum::DirectoryStack_FreeStack( void ) { while (!DirectoryStack_IsEmpty()) DirectoryStack_FreeEntry(DirectoryStack_Pop());
return; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_Pop ***
//
// Remove an item from the stack. The caller must free the item.
//
////////////////////////////////////////////////////////////////////////////////
STACKENTRY* CChannelEnum::DirectoryStack_Pop( void ) { STACKENTRY* pse = m_pseDirectoryStack;
if (m_pseDirectoryStack) { m_pseDirectoryStack = m_pseDirectoryStack->pNext; pse->pNext = NULL; }
return pse; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_Push ***
//
// Put a new directory on the stack.
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::DirectoryStack_Push( LPCTSTR pszPath ) { ASSERT(pszPath);
BOOL fRet = FALSE;
STACKENTRY* pse = new STACKENTRY;
if (pse) { pse->pszPath = new TCHAR[StrLen(pszPath) + 1];
if (pse->pszPath) { StrCpy(pse->pszPath, pszPath); pse->pNext = m_pseDirectoryStack; m_pseDirectoryStack = pse;
fRet = TRUE; } else { delete pse; } }
return fRet; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_IntitFromFlags ***
//
// Put initial search directories on the stack.
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::DirectoryStack_InitFromFlags( DWORD dwEnumFlags ) { ASSERT(NULL == m_pseDirectoryStack);
TCHAR szPath[MAX_PATH];
szPath[0] = 0;
if (dwEnumFlags & CHANENUM_DESKTOPFOLDER) { LPITEMIDLIST pidl;
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidl))) { ASSERT(pidl);
if (SHGetPathFromIDList(pidl, szPath)) DirectoryStack_Push(szPath);
ILFree(pidl); } }
if (dwEnumFlags & CHANENUM_CHANNELFOLDER) { if (SUCCEEDED(Channel_GetFolder(szPath, DOC_CHANNEL))) DirectoryStack_Push(szPath); }
if (dwEnumFlags & CHANENUM_SOFTUPDATEFOLDER) { TCHAR szSoftDistFolder[MAX_PATH];
if (SUCCEEDED(Channel_GetFolder(szSoftDistFolder, DOC_SOFTWAREUPDATE)) && (StrCmpI(szSoftDistFolder, szPath) != 0)) { DirectoryStack_Push(szSoftDistFolder); } }
return m_pseDirectoryStack != NULL; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::DirectoryStack_PushSubdirectories ***
//
// Put all subdirectories of the given directory on to the stack.
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::DirectoryStack_PushSubdirectories( LPCTSTR pszPath ) { ASSERT(pszPath);
BOOL fRet = FALSE; TCHAR szBuffer[MAX_PATH]; int cch = StrLen(pszPath);
StrCpyN(szBuffer, pszPath, ARRAYSIZE(szBuffer)); #ifndef UNIX
lstrcatn(szBuffer, TEXT("\\*.*"), ARRAYSIZE(szBuffer)); #else
lstrcatn(szBuffer, TEXT("/*"), ARRAYSIZE(szBuffer)); #endif /* UNIX */
WIN32_FIND_DATA fd;
HANDLE hSearch = FindFirstFile(szBuffer, &fd);
if (INVALID_HANDLE_VALUE != hSearch) { if (cch < ARRAYSIZE(szBuffer) - 2) { do { if ((FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes) && !StrEql(fd.cFileName, TEXT(".")) && !StrEql(fd.cFileName, TEXT("..")) ) { StrCpyN(szBuffer + cch + 1, fd.cFileName, ARRAYSIZE(szBuffer) - cch - 1);
if (DirectoryStack_Push(szBuffer)) fRet = TRUE; }
} while (TRUE == FindNextFile(hSearch, &fd)); }
FindClose(hSearch); }
return fRet; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::FindNextChannel ***
//
// Find the next channel.
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::FindNextChannel( CHANNELENUMINFO* pInfo ) { ASSERT(pInfo);
BOOL fRet;
if (DirectoryStack_IsEmpty()) { fRet = FALSE; } else { STACKENTRY* pse = DirectoryStack_Pop();
DirectoryStack_PushSubdirectories(pse->pszPath);
if (ReadChannelInfo(pse->pszPath, pInfo)) { fRet = TRUE; } else { fRet = FindNextChannel(pInfo); }
DirectoryStack_FreeEntry(pse); }
return fRet; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::FindNextChannel ***
//
// Find the next channel.
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::ReadChannelInfo( LPCTSTR pszPath, CHANNELENUMINFO* pInfo ) { ASSERT(pszPath); ASSERT(pInfo);
BOOL fRet = FALSE;
DWORD dwAttributes = GetFileAttributes(pszPath);
#ifndef UNIX
if ((-1 != dwAttributes) && (FILE_ATTRIBUTE_SYSTEM & dwAttributes)) #else
if ((-1 != dwAttributes)) #endif /* UNIX */
{ if (ContainsChannelDesktopIni(pszPath)) { if (NULL == m_pszURL || URLMatchesIni(pszPath, m_pszURL)) { fRet = TRUE;
TCHAR szURL[INTERNET_MAX_URL_LENGTH]; szURL[0] = 0;
if (m_dwEnumFlags & CHANENUM_TITLE) pInfo->pszTitle = OleAllocString(PathFindFileName(pszPath));
if (m_dwEnumFlags & CHANENUM_PATH) pInfo->pszPath = OleAllocString(pszPath);
if (m_dwEnumFlags & CHANENUM_URL) { ReadFromIni(pszPath, szURL, ARRAYSIZE(szURL), INI_URL);
pInfo->pszURL = OleAllocString(szURL); }
if (m_dwEnumFlags & CHANENUM_SUBSCRIBESTATE) { if (TEXT('\0') == *szURL) ReadFromIni(pszPath, szURL, ARRAYSIZE(szURL), INI_URL);
pInfo->stSubscriptionState = GetSubscriptionState(szURL); } } } }
return fRet; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::ContainsChannelDesktopIni ***
//
// See if the directory contains a "channel" desktop.ini
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::ContainsChannelDesktopIni( LPCTSTR pszPath ) { ASSERT(pszPath);
BOOL fRet = FALSE;
TCHAR szFolderGUID[GUID_STR_LEN];
if (ReadFromIni(pszPath, szFolderGUID, ARRAYSIZE(szFolderGUID), INI_GUID)) { TCHAR szChannelGUID[GUID_STR_LEN];
if (SHStringFromGUID(CLSID_CDFINI, szChannelGUID, ARRAYSIZE(szChannelGUID))) { fRet = StrEql(szFolderGUID, szChannelGUID); } }
return fRet; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::URLMatchesIni ***
//
// See if the given url matches the url in the desktop.ini
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::URLMatchesIni( LPCTSTR pszPath, LPCTSTR pszURL ) { ASSERT(pszPath); ASSERT(pszURL);
BOOL fRet = FALSE;
TCHAR szIniURL[INTERNET_MAX_URL_LENGTH];
if (ReadFromIni(pszPath, szIniURL, ARRAYSIZE(szIniURL), INI_URL)) { TCHAR szCanonicalURL[INTERNET_MAX_URL_LENGTH]; DWORD cch = ARRAYSIZE(szCanonicalURL);
if (InternetCanonicalizeUrl(szIniURL, szCanonicalURL, &cch, ICU_NO_ENCODE)) { fRet = StrEql((LPTSTR)pszURL, szCanonicalURL); } else { fRet = StrEql((LPTSTR)pszURL, szIniURL); } }
return fRet; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::ReadFromIni ***
//
// Read a value from the channel desktop.ini
//
////////////////////////////////////////////////////////////////////////////////
BOOL CChannelEnum::ReadFromIni( LPCTSTR pszPath, LPTSTR pszOut, int cch, INIVALUE iv ) { static const struct _tagINISTRINGS { LPCTSTR pszSection; LPCTSTR pszKey; INIVALUE iv; } aIniTable[] = { {TEXT(".ShellClassInfo"), TEXT("CLSID"), INI_GUID}, {TEXT("Channel") , TEXT("CDFURL"), INI_URL } };
ASSERT(pszPath); ASSERT(pszOut || 0 == cch); ASSERT(aIniTable[iv].iv == iv);
TCHAR szIniFile[MAX_PATH];
PathCombine(szIniFile, pszPath, TEXT("desktop.ini"));
return GetPrivateProfileString(aIniTable[iv].pszSection, aIniTable[iv].pszKey, TEXT(""), pszOut, cch, szIniFile); }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::OleAllocString ***
//
// Allocate an OLESTR for the given string.
//
////////////////////////////////////////////////////////////////////////////////
LPOLESTR CChannelEnum::OleAllocString( LPCTSTR psz ) { ASSERT(psz);
int cch = StrLen(psz) + 1;
LPOLESTR polestr = (LPOLESTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
if (polestr) SHTCharToUnicode(psz, polestr, cch);
return polestr; }
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ //
// *** CChannelEnum::GetSubscriptionState ***
//
// Read a value from the channel desktop.ini
//
////////////////////////////////////////////////////////////////////////////////
SUBSCRIPTIONSTATE CChannelEnum::GetSubscriptionState( LPCTSTR pszURL ) { ASSERT(pszURL);
SUBSCRIPTIONSTATE stRet = SUBSTATE_NOTSUBSCRIBED;
ISubscriptionMgr* pISubscriptionMgr;
HRESULT hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&pISubscriptionMgr);
if (SUCCEEDED(hr)) { ASSERT(pISubscriptionMgr);
WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
if (SHTCharToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL))) { BOOL fSubscribed = FALSE;
pISubscriptionMgr->IsSubscribed(wszURL, &fSubscribed);
if (fSubscribed) { stRet = SUBSTATE_PARTIALSUBSCRIPTION;
SUBSCRIPTIONINFO si = { 0 };
si.cbSize = sizeof SUBSCRIPTIONINFO;
hr = pISubscriptionMgr->GetSubscriptionInfo(wszURL, &si);
if (SUCCEEDED(hr)) { if (!(si.fChannelFlags & CHANNEL_AGENT_PRECACHE_SOME)) stRet = SUBSTATE_FULLSUBSCRIPTION; }
} }
pISubscriptionMgr->Release(); }
return stRet; }
|