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.
1142 lines
41 KiB
1142 lines
41 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997
|
|
//
|
|
// File: admin.cpp
|
|
//
|
|
// Contents:
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "private.h"
|
|
#include "shguidp.h"
|
|
#include "chanmgr.h"
|
|
#include "chanmgrp.h"
|
|
#include "winineti.h"
|
|
|
|
#include <mluisupp.h>
|
|
|
|
// Infodelivery Policies registry locations
|
|
#define INFODELIVERY_POLICIES TEXT("Software\\Policies\\Microsoft\\Internet Explorer\\Infodelivery")
|
|
// const TCHAR c_szRegKeyRestrictions[] = INFODELIVERY_POLICIES TEXT("\\Restrictions");
|
|
const TCHAR c_szRegKeyModifications[] = INFODELIVERY_POLICIES TEXT("\\Modifications");
|
|
const TCHAR c_szRegKeyCompletedMods[] = INFODELIVERY_POLICIES TEXT("\\CompletedModifications");
|
|
const TCHAR c_szRegKeyIESetup[] = TEXT("Software\\Microsoft\\IE4\\Setup");
|
|
|
|
// Wininet cache preload directory
|
|
const TCHAR c_szRegKeyCachePreload[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Preload");
|
|
|
|
// Registry key names of supported Modifications
|
|
const TCHAR c_szAddChannels[] = TEXT("AddChannels");
|
|
const TCHAR c_szRemoveChannels[] = TEXT("RemoveChannels");
|
|
const TCHAR c_szRemoveAllChannels[] = TEXT("RemoveAllChannels");
|
|
const TCHAR c_szAddSubscriptions[] = TEXT("AddSubscriptions");
|
|
const TCHAR c_szRemoveSubscriptions[] = TEXT("RemoveSubscriptions");
|
|
const TCHAR c_szAddScheduleGroups[] = TEXT("AddScheduleGroups");
|
|
const TCHAR c_szRemoveScheduleGroups[] = TEXT("RemoveScheduleGroups");
|
|
const TCHAR c_szAddDesktopComponents[] = TEXT("AddDesktopComponents");
|
|
const TCHAR c_szRemoveDesktopComponents[] = TEXT("RemoveDesktopComponents");
|
|
|
|
// Registry value names of supported Modifications
|
|
const TCHAR c_szURL[] = TEXT("URL");
|
|
const TCHAR c_szTitle[] = TEXT("Title");
|
|
const TCHAR c_szLogo[] = TEXT("Logo");
|
|
const TCHAR c_szWideLogo[] = TEXT("WideLogo");
|
|
const TCHAR c_szIcon[] = TEXT("Icon");
|
|
const TCHAR c_szCategory[] = TEXT("Category");
|
|
const TCHAR c_szChannelGuide[] = TEXT("ChannelGuide"); // DO NOTE CHANGE THIS STRING WITHOUT UPDATING CDFVIEW!!!
|
|
const TCHAR c_szPreloadURL[] = TEXT("PreloadURL");
|
|
const TCHAR c_szLCID[] = TEXT("LangId"); // This must be an LCID despite its name
|
|
const TCHAR c_szSoftware[] = TEXT("Software");
|
|
const TCHAR c_szSubscriptionType[] = TEXT("SubscriptionType");
|
|
const TCHAR c_szScheduleGroup[] = TEXT("ScheduleGroup");
|
|
const TCHAR c_szEarliestTime[] = TEXT("EarliestTime");
|
|
const TCHAR c_szIntervalTime[] = TEXT("IntervalTime");
|
|
const TCHAR c_szLatestTime[] = TEXT("LatestTime");
|
|
const TCHAR c_szComponentType[] = TEXT("DesktopComponentType");
|
|
const TCHAR c_szUsername[] = TEXT("Username");
|
|
const TCHAR c_szPassword[] = TEXT("Password");
|
|
const TCHAR c_szOldIEVersion[] = TEXT("OldIEVersion");
|
|
const TCHAR c_szNonActive[] = TEXT("NonActive");
|
|
const TCHAR c_szOffline[] = TEXT("Offline");
|
|
const TCHAR c_szSynchronize[] = TEXT("Synchronize");
|
|
|
|
// Names of reserved schedule groups that we support even in localized version
|
|
const WCHAR c_szScheduleAuto[] = L"Auto";
|
|
const WCHAR c_szScheduleDaily[] = L"Daily";
|
|
const WCHAR c_szScheduleWeekly[] = L"Weekly";
|
|
const WCHAR c_szScheduleManual[] = L"Manual";
|
|
|
|
// Function prototypes for Modification handlers
|
|
HRESULT ProcessAddChannels(HKEY hkey);
|
|
HRESULT ProcessRemoveChannels(HKEY hkey);
|
|
HRESULT ProcessRemoveAllChannels(HKEY hkey);
|
|
HRESULT ProcessAddSubscriptions(HKEY hkey);
|
|
HRESULT ProcessRemoveSubscriptions(HKEY hkey);
|
|
HRESULT ProcessRemoveDesktopComponents(HKEY hkey);
|
|
|
|
HRESULT Channel_GetBasePath(LPTSTR pszPath, int cch);
|
|
|
|
// Helper functions
|
|
void ShowChannelDirectories(BOOL fShow);
|
|
|
|
// Table of supported Actions and corresponding functions
|
|
// NOTE: The table must be ordered appropriately (RemoveAll must come before Add)
|
|
typedef HRESULT (*PFNACTION)(HKEY);
|
|
typedef struct { LPCTSTR szAction; PFNACTION pfnAction; } ACTIONTABLE;
|
|
ACTIONTABLE rgActionTable[] = {
|
|
{ c_szRemoveAllChannels, &ProcessRemoveAllChannels },
|
|
{ c_szRemoveSubscriptions, &ProcessRemoveSubscriptions },
|
|
{ c_szRemoveChannels, &ProcessRemoveChannels },
|
|
{ c_szRemoveDesktopComponents, &ProcessRemoveDesktopComponents },
|
|
{ c_szAddChannels, &ProcessAddChannels },
|
|
{ c_szAddSubscriptions, &ProcessAddSubscriptions }
|
|
};
|
|
#define ACTIONTABLECOUNT (sizeof(rgActionTable) / sizeof(ACTIONTABLE))
|
|
#define ACTIONTABLE_ADDCHANNELS 5
|
|
|
|
// Helper class to manipulate registry keys
|
|
class CRegKey
|
|
{
|
|
HKEY m_hkey;
|
|
DWORD dwIndex;
|
|
public:
|
|
CRegKey(void)
|
|
{
|
|
m_hkey = NULL;
|
|
dwIndex = 0;
|
|
}
|
|
~CRegKey(void)
|
|
{
|
|
if (m_hkey)
|
|
{
|
|
LONG lRet = RegCloseKey(m_hkey);
|
|
ASSERT(ERROR_SUCCESS == lRet);
|
|
m_hkey = NULL;
|
|
}
|
|
}
|
|
void SetKey(HKEY hkey)
|
|
{
|
|
m_hkey = hkey;
|
|
}
|
|
HKEY GetKey(void)
|
|
{
|
|
return m_hkey;
|
|
}
|
|
HRESULT OpenForRead(HKEY hkey, LPCTSTR szSubKey)
|
|
{
|
|
ASSERT(NULL == m_hkey);
|
|
LONG lRet = RegOpenKeyEx(hkey, szSubKey, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &m_hkey);
|
|
ASSERT((ERROR_SUCCESS == lRet) || !m_hkey);
|
|
return (ERROR_SUCCESS == lRet)?(S_OK):(E_FAIL);
|
|
}
|
|
HRESULT CreateForWrite(HKEY hkey, LPCTSTR szSubKey)
|
|
{
|
|
ASSERT(NULL == m_hkey);
|
|
DWORD dwDisp;
|
|
LONG lRet = RegCreateKeyEx(hkey, szSubKey, 0, TEXT(""), 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &m_hkey, &dwDisp);
|
|
ASSERT(ERROR_SUCCESS == lRet);
|
|
return (ERROR_SUCCESS == lRet)?(S_OK):(E_FAIL);
|
|
}
|
|
HRESULT GetSubKeyCount(PDWORD pdwKeys)
|
|
{
|
|
ASSERT(NULL != m_hkey);
|
|
LONG lRet = RegQueryInfoKey(m_hkey, NULL, NULL, NULL, pdwKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
ASSERT(ERROR_SUCCESS == lRet);
|
|
return (ERROR_SUCCESS == lRet)?(S_OK):(E_FAIL);
|
|
}
|
|
HRESULT Next(LPTSTR szSubKey)
|
|
{
|
|
ASSERT(NULL != m_hkey);
|
|
DWORD dwLen = MAX_PATH; // Assumes size of incoming buffer.
|
|
LONG lRet = RegEnumKeyEx(m_hkey, dwIndex, szSubKey, &dwLen, NULL, NULL, NULL, NULL);
|
|
dwIndex++;
|
|
if (ERROR_SUCCESS == lRet)
|
|
return S_OK;
|
|
else if (ERROR_NO_MORE_ITEMS == lRet)
|
|
return S_FALSE;
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
HRESULT Reset(void)
|
|
{
|
|
dwIndex = 0;
|
|
return S_OK;
|
|
}
|
|
HRESULT SetValue(LPCTSTR szValueName, DWORD dwValue)
|
|
{
|
|
ASSERT(m_hkey);
|
|
LONG lRet = RegSetValueEx(m_hkey, szValueName, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
ASSERT(ERROR_SUCCESS == lRet);
|
|
return (ERROR_SUCCESS == lRet)?(S_OK):(E_FAIL);
|
|
}
|
|
HRESULT GetValue(LPCTSTR szValueName, DWORD *pdwValue)
|
|
{
|
|
ASSERT(m_hkey);
|
|
DWORD dwType = REG_DWORD;
|
|
DWORD dwLen = sizeof(DWORD);
|
|
LONG lRet = RegQueryValueEx(m_hkey, szValueName, 0, &dwType, (LPBYTE)pdwValue, &dwLen);
|
|
return (ERROR_SUCCESS == lRet)?(S_OK):(E_FAIL);
|
|
}
|
|
HRESULT GetStringValue(LPCTSTR szValueName, LPTSTR szValue, DWORD cbValue)
|
|
{
|
|
ASSERT(m_hkey);
|
|
|
|
return SHRegGetValue(m_hkey, NULL, szValueName, SRRF_RT_REG_SZ | SRRF_NOEXPAND, NULL, szValue, &cbValue) == ERROR_SUCCESS
|
|
? S_OK
|
|
: E_FAIL;
|
|
}
|
|
HRESULT SetBSTRValue(LPCTSTR szValueName, BSTR bstr)
|
|
{
|
|
ASSERT(m_hkey);
|
|
TCHAR szValue[INTERNET_MAX_URL_LENGTH];
|
|
MyOleStrToStrN(szValue, ARRAYSIZE(szValue), bstr);
|
|
LONG lRet = RegSetValueEx(m_hkey, szValueName, 0, REG_SZ, (LPBYTE)szValue, lstrlen(szValue) + 1);
|
|
ASSERT(ERROR_SUCCESS == lRet);
|
|
return (ERROR_SUCCESS == lRet)?(S_OK):(E_FAIL);
|
|
}
|
|
HRESULT GetBSTRValue(LPCTSTR szValueName, BSTR *pbstr)
|
|
{
|
|
ASSERT(m_hkey);
|
|
TCHAR szValue[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cbValue = sizeof(szValue);
|
|
HRESULT hr;
|
|
|
|
*pbstr = NULL;
|
|
|
|
LONG lRet = SHRegGetValue(m_hkey, NULL, szValueName, SRRF_RT_REG_SZ | SRRF_NOEXPAND, NULL, szValue, &cbValue);
|
|
if (ERROR_SUCCESS == lRet)
|
|
{
|
|
DWORD cchValue = cbValue / sizeof(TCHAR);
|
|
*pbstr = SysAllocStringLen(NULL, cchValue); // cchValue includes null terminator
|
|
if (*pbstr)
|
|
{
|
|
MyStrToOleStrN(*pbstr, cchValue, szValue);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lRet);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
// Helper class to manage Dynamic Pointer Arrays of HKEYs.
|
|
class CRegKeyDPA
|
|
{
|
|
HDPA m_hdpa;
|
|
int m_count;
|
|
public:
|
|
CRegKeyDPA(void)
|
|
{
|
|
m_hdpa = NULL;
|
|
m_count = 0;
|
|
}
|
|
~CRegKeyDPA(void)
|
|
{
|
|
if (m_hdpa)
|
|
{
|
|
ASSERT(m_count);
|
|
int i;
|
|
for (i = 0; i < m_count; i++)
|
|
RegCloseKey(GetKey(i));
|
|
DPA_Destroy(m_hdpa);
|
|
}
|
|
}
|
|
int GetCount(void)
|
|
{
|
|
return m_count;
|
|
}
|
|
HKEY GetKey(int i)
|
|
{
|
|
ASSERT(i >= 0 && i < m_count);
|
|
return (HKEY)DPA_GetPtr(m_hdpa, i);
|
|
}
|
|
HRESULT Add(HKEY hkey, LPCTSTR szSubKey)
|
|
{
|
|
if (!m_hdpa)
|
|
{
|
|
m_hdpa = DPA_CreateEx(5, NULL); // Choose arbitrary growth value
|
|
if (!m_hdpa)
|
|
return E_FAIL;
|
|
}
|
|
HKEY hkeyNew;
|
|
LONG lRet = RegOpenKeyEx(hkey, szSubKey, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkeyNew);
|
|
if (ERROR_SUCCESS != lRet)
|
|
return E_FAIL;
|
|
if (-1 == DPA_InsertPtr(m_hdpa, DPA_APPEND, hkeyNew))
|
|
{
|
|
RegCloseKey(hkeyNew);
|
|
return E_FAIL;
|
|
}
|
|
m_count++;
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
//
|
|
// 8/18/98 darrenmi
|
|
// Copied (and butchered) from shdocvw\util.cpp so we don't have to load it at startup
|
|
//
|
|
DWORD WCRestricted2W(BROWSER_RESTRICTIONS rest, LPCWSTR pwzUrl, DWORD dwReserved)
|
|
{
|
|
DWORD dwType, dw = 0, dwSize = sizeof(DWORD);
|
|
|
|
// we only handle NoChannelUI restriction
|
|
if(rest != REST_NoChannelUI)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// read registry setting
|
|
SHGetValue(HKEY_CURRENT_USER,
|
|
TEXT("Software\\Policies\\Microsoft\\Internet Explorer\\Infodelivery\\Restrictions"),
|
|
TEXT("NoChannelUI"),
|
|
&dwType, &dw, &dwSize);
|
|
|
|
return dw;
|
|
}
|
|
|
|
|
|
// ProcessInfodeliveryPolicies
|
|
//
|
|
// This is the main Admin API for Infodelivery. It returns E_FAIL for errors,
|
|
// S_FALSE for nothing to process, and S_OK for correctly processed items.
|
|
//
|
|
// Reg key organization [Modifications] - the key to process
|
|
// [GUID1] - group of actions
|
|
// [AddChannels] - sample action
|
|
// [Channel1] - element of an action
|
|
//
|
|
HRESULT ProcessInfodeliveryPolicies(void)
|
|
{
|
|
HRESULT hr;
|
|
CRegKey regModifications;
|
|
TCHAR szGUID[MAX_PATH];
|
|
|
|
// Check if channels should be hidden.
|
|
if (WCRestricted2W(REST_NoChannelUI, NULL, 0))
|
|
{
|
|
ShowChannelDirectories(FALSE);
|
|
}
|
|
else
|
|
{
|
|
ShowChannelDirectories(TRUE);
|
|
}
|
|
|
|
// Bail out quickly if there are no Modifications to perform. (Return S_FALSE)
|
|
hr = regModifications.OpenForRead(HKEY_CURRENT_USER, c_szRegKeyModifications);
|
|
if (FAILED(hr))
|
|
return S_FALSE;
|
|
|
|
// Prepare to use the CompletedModifications key.
|
|
CRegKey regCompletedMods;
|
|
hr = regCompletedMods.CreateForWrite(HKEY_CURRENT_USER, c_szRegKeyCompletedMods);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Prepare queues of registry keys to actions
|
|
CRegKeyDPA rgKeyQueue[ACTIONTABLECOUNT];
|
|
|
|
// Enumerate the GUID keys, skipping the completed ones.
|
|
// Enumerate the Actions beneath them and add them to queues.
|
|
// ignoring errors here too.
|
|
while (S_OK == regModifications.Next(szGUID))
|
|
{
|
|
DWORD dwValue;
|
|
if (FAILED(regCompletedMods.GetValue(szGUID, &dwValue)))
|
|
{
|
|
CRegKey regGUID;
|
|
TCHAR szAction[MAX_PATH];
|
|
hr = regGUID.OpenForRead(regModifications.GetKey(), szGUID);
|
|
while (S_OK == regGUID.Next(szAction))
|
|
{
|
|
// Search the table to see if it's a key we understand.
|
|
// If so, add it to the queue.
|
|
int i;
|
|
for (i = 0; i < ACTIONTABLECOUNT; i++)
|
|
{
|
|
if (!StrCmpI(rgActionTable[i].szAction, szAction))
|
|
{
|
|
rgKeyQueue[i].Add(regGUID.GetKey(), szAction);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process all the keys we've accumulated. (Correct order is assumed.)
|
|
int i;
|
|
for (i = 0; i < ACTIONTABLECOUNT; i++)
|
|
{
|
|
if (rgKeyQueue[i].GetCount())
|
|
{
|
|
int iKey;
|
|
for (iKey = 0; iKey < rgKeyQueue[i].GetCount(); iKey++)
|
|
{
|
|
(rgActionTable[i].pfnAction)(rgKeyQueue[i].GetKey(iKey));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Walk the GUIDs we've processed and mark them completed with the time.
|
|
// Updating ones we skipped as well will help with garbage collection.
|
|
regModifications.Reset();
|
|
while (S_OK == regModifications.Next(szGUID))
|
|
{
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ft);
|
|
regCompletedMods.SetValue(szGUID, ft.dwHighDateTime);
|
|
}
|
|
|
|
// Delete the Actions. NOTE: NT's RegDeleteKey() doesn't delete sub-keys.
|
|
// This shlwapi API uses KEY_ALL_ACCESS.
|
|
// We probably have to close all the keys here.
|
|
SHDeleteKey(HKEY_CURRENT_USER, c_szRegKeyModifications);
|
|
|
|
// If any channels were processed, tell the cache to reload.
|
|
// We should only do this for default channels.
|
|
if (rgKeyQueue[ACTIONTABLE_ADDCHANNELS].GetCount())
|
|
{
|
|
ASSERT(!StrCmpI(rgActionTable[ACTIONTABLE_ADDCHANNELS].szAction, c_szAddChannels));
|
|
LoadUrlCacheContent();
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ProcessAddChannels_SortCallback - sort in reverse order
|
|
//
|
|
int ProcessAddChannels_SortCallback(PVOID p1, PVOID p2, LPARAM lparam)
|
|
{
|
|
return StrCmpI((LPTSTR)p2, (LPTSTR)p1);
|
|
}
|
|
|
|
//
|
|
// ProcessAddChannels
|
|
//
|
|
HRESULT ProcessAddChannels(HKEY hkey)
|
|
{
|
|
// Enumerate the channels in the AddChannels key
|
|
HRESULT hr;
|
|
DWORD dwChannels;
|
|
CRegKey regAdd;
|
|
regAdd.SetKey(hkey);
|
|
hr = regAdd.GetSubKeyCount(&dwChannels);
|
|
if (SUCCEEDED(hr) && dwChannels)
|
|
{
|
|
// Check if the channels are the same code page as the system default.
|
|
BOOL bCodePageMatch = TRUE;
|
|
LCID lcidChannel = 0;
|
|
if (SUCCEEDED(regAdd.GetValue(c_szLCID, &lcidChannel)))
|
|
{
|
|
TCHAR szCodePageSystem[8];
|
|
TCHAR szCodePageChannel[8];
|
|
szCodePageChannel[0] = 0; // Init in case there's no locale info
|
|
GetLocaleInfo(lcidChannel, LOCALE_IDEFAULTANSICODEPAGE, szCodePageChannel, ARRAYSIZE(szCodePageChannel));
|
|
int iRet = GetLocaleInfo(GetSystemDefaultLCID(), LOCALE_IDEFAULTANSICODEPAGE, szCodePageSystem, ARRAYSIZE(szCodePageSystem));
|
|
ASSERT(iRet);
|
|
if (StrCmpI(szCodePageSystem, szCodePageChannel))
|
|
bCodePageMatch = FALSE;
|
|
}
|
|
|
|
hr = E_FAIL;
|
|
TCHAR *pch = (TCHAR *)MemAlloc(LMEM_FIXED, dwChannels * MAX_PATH * sizeof(TCHAR));
|
|
if (pch)
|
|
{
|
|
HDPA hdpa = DPA_Create(dwChannels);
|
|
if (hdpa)
|
|
{
|
|
DWORD i;
|
|
TCHAR *pchCur = pch;
|
|
for (i = 0; i < dwChannels; i++)
|
|
{
|
|
if ((S_OK != regAdd.Next(pchCur)) || (-1 == DPA_InsertPtr(hdpa, DPA_APPEND, pchCur)))
|
|
break;
|
|
pchCur += MAX_PATH;
|
|
}
|
|
if (i >= dwChannels)
|
|
{
|
|
// Sort channels by registry key name,
|
|
DPA_Sort(hdpa, ProcessAddChannels_SortCallback, 0);
|
|
// Now create them.
|
|
for (i = 0; i < dwChannels; i++)
|
|
{
|
|
BSTR bstrURL = NULL;
|
|
BSTR bstrTitle = NULL;
|
|
BSTR bstrLogo = NULL;
|
|
BSTR bstrWideLogo = NULL;
|
|
BSTR bstrIcon = NULL;
|
|
BSTR bstrPreloadURL = NULL;
|
|
DWORD dwCategory = 0; // default to channel
|
|
DWORD dwChannelGuide = 0; // default to not a guide
|
|
DWORD dwSoftware = 0; // default to non-software channel
|
|
DWORD dwOffline = 0;
|
|
DWORD dwSynchronize = 0;
|
|
CRegKey regChannel;
|
|
regChannel.OpenForRead(hkey, (LPCTSTR)DPA_GetPtr(hdpa, i));
|
|
hr = regChannel.GetBSTRValue(c_szURL, &bstrURL);
|
|
hr = regChannel.GetBSTRValue(c_szTitle, &bstrTitle);
|
|
hr = regChannel.GetBSTRValue(c_szLogo, &bstrLogo);
|
|
hr = regChannel.GetBSTRValue(c_szWideLogo, &bstrWideLogo);
|
|
hr = regChannel.GetBSTRValue(c_szIcon, &bstrIcon);
|
|
hr = regChannel.GetBSTRValue(c_szPreloadURL, &bstrPreloadURL);
|
|
hr = regChannel.GetValue(c_szCategory, &dwCategory);
|
|
hr = regChannel.GetValue(c_szChannelGuide, &dwChannelGuide);
|
|
hr = regChannel.GetValue(c_szSoftware, &dwSoftware);
|
|
hr = regChannel.GetValue(c_szOffline, &dwOffline);
|
|
hr = regChannel.GetValue(c_szSynchronize, &dwSynchronize);
|
|
if (bstrTitle)
|
|
{
|
|
IChannelMgr *pChannelMgr = NULL;
|
|
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgr, (void**)&pChannelMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// See if channel already exists - do nothing if it does (62976)
|
|
IEnumChannels *pEnumChannels = NULL;
|
|
if (SUCCEEDED(pChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS, bstrURL, &pEnumChannels)))
|
|
{
|
|
CHANNELENUMINFO Bogus={0};
|
|
ULONG cFetched=0;
|
|
|
|
if ((S_OK == pEnumChannels->Next(1, &Bogus, &cFetched)) && cFetched)
|
|
{
|
|
// Oops. It exists. Skip all this goo.
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
SAFERELEASE(pEnumChannels);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (dwCategory && bCodePageMatch)
|
|
{
|
|
// create a category (useless if code page doesn't match)
|
|
CHANNELCATEGORYINFO csi = {0};
|
|
csi.cbSize = sizeof(csi);
|
|
csi.pszURL = bstrURL;
|
|
csi.pszTitle = bstrTitle;
|
|
csi.pszLogo = bstrLogo;
|
|
csi.pszIcon = bstrIcon;
|
|
csi.pszWideLogo = bstrWideLogo;
|
|
hr = pChannelMgr->AddCategory(&csi);
|
|
}
|
|
else if (!dwCategory && bstrURL)
|
|
{
|
|
// update the registry if it's a channel guide
|
|
if (dwChannelGuide)
|
|
{
|
|
CRegKey reg;
|
|
hr = reg.CreateForWrite(HKEY_CURRENT_USER, c_szRegKey);
|
|
if (SUCCEEDED(hr))
|
|
reg.SetBSTRValue(c_szChannelGuide, bstrTitle);
|
|
}
|
|
// tell wininet if there's preload content
|
|
if (bstrPreloadURL)
|
|
{
|
|
CRegKey reg;
|
|
hr = reg.CreateForWrite(HKEY_CURRENT_USER, c_szRegKeyCachePreload);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
MyOleStrToStrN(szURL, ARRAYSIZE(szURL), bstrURL);
|
|
reg.SetBSTRValue(szURL, bstrPreloadURL);
|
|
}
|
|
}
|
|
// create a channel (use URL instead of Title if code page doesn't match)
|
|
CHANNELSHORTCUTINFO csi = {0};
|
|
csi.cbSize = sizeof(csi);
|
|
csi.pszURL = bstrURL;
|
|
if (bCodePageMatch)
|
|
csi.pszTitle = bstrTitle;
|
|
else
|
|
csi.pszTitle = bstrURL;
|
|
csi.pszLogo = bstrLogo;
|
|
csi.pszIcon = bstrIcon;
|
|
csi.pszWideLogo = bstrWideLogo;
|
|
if (dwSoftware)
|
|
csi.bIsSoftware = TRUE;
|
|
hr = pChannelMgr->AddChannelShortcut(&csi);
|
|
}
|
|
}
|
|
SAFERELEASE(pChannelMgr);
|
|
|
|
if (dwOffline)
|
|
{
|
|
ISubscriptionMgr2 *pSubMgr2 = NULL;
|
|
hr = CoCreateInstance(CLSID_SubscriptionMgr,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ISubscriptionMgr2,
|
|
(void**)&pSubMgr2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pSubMgr2->CreateSubscription(NULL,
|
|
bstrURL,
|
|
bstrTitle,
|
|
CREATESUBS_NOUI,
|
|
SUBSTYPE_CHANNEL,
|
|
NULL);
|
|
|
|
if (dwSynchronize)
|
|
{
|
|
BOOL bIsSubscribed;
|
|
SUBSCRIPTIONCOOKIE cookie;
|
|
|
|
if (SUCCEEDED(pSubMgr2->IsSubscribed(bstrURL, &bIsSubscribed))
|
|
&& bIsSubscribed &&
|
|
SUCCEEDED(ReadCookieFromInetDB(bstrURL, &cookie)))
|
|
{
|
|
pSubMgr2->UpdateItems(SUBSMGRUPDATE_MINIMIZE, 1, &cookie);
|
|
}
|
|
}
|
|
pSubMgr2->Release();
|
|
}
|
|
}
|
|
}
|
|
SAFEFREEBSTR(bstrURL);
|
|
SAFEFREEBSTR(bstrTitle);
|
|
SAFEFREEBSTR(bstrLogo);
|
|
SAFEFREEBSTR(bstrWideLogo);
|
|
SAFEFREEBSTR(bstrIcon);
|
|
SAFEFREEBSTR(bstrPreloadURL);
|
|
}
|
|
}
|
|
DPA_Destroy(hdpa);
|
|
}
|
|
MemFree(pch);
|
|
}
|
|
}
|
|
regAdd.SetKey(NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ProcessRemoveChannels
|
|
//
|
|
HRESULT ProcessRemoveChannels(HKEY hkey)
|
|
{
|
|
// Enumerate the channel keys in the RemoveChannels key
|
|
HRESULT hr;
|
|
CRegKey reg;
|
|
reg.SetKey(hkey);
|
|
TCHAR szChannel[MAX_PATH];
|
|
while (S_OK == reg.Next(szChannel))
|
|
{
|
|
CRegKey regChannel;
|
|
DWORD dwNonActive = 0; // default to deleting Active & NonActive channels
|
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
regChannel.OpenForRead(hkey, szChannel);
|
|
regChannel.GetValue(c_szNonActive, &dwNonActive);
|
|
if (SUCCEEDED(regChannel.GetStringValue(c_szURL, szURL, sizeof(szURL))))
|
|
{
|
|
// Check if the channel is Active to determine if we can delete it
|
|
if (dwNonActive)
|
|
{
|
|
CRegKey regPreload;
|
|
if (SUCCEEDED(regPreload.OpenForRead(HKEY_CURRENT_USER, c_szRegKeyCachePreload)))
|
|
{
|
|
if (SUCCEEDED(regPreload.GetStringValue(szURL, NULL, 0)))
|
|
{
|
|
dwNonActive = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now delete the channel if appropriate
|
|
if (!dwNonActive)
|
|
{
|
|
IChannelMgr *pChannelMgr = NULL;
|
|
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgr, (void**)&pChannelMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrURL;
|
|
if (SUCCEEDED(regChannel.GetBSTRValue(c_szURL, &bstrURL)))
|
|
{
|
|
IEnumChannels *pEnum;
|
|
hr = pChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH, bstrURL, &pEnum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CHANNELENUMINFO info;
|
|
while (S_OK == pEnum->Next(1, &info, NULL))
|
|
{
|
|
hr = pChannelMgr->DeleteChannelShortcut(info.pszPath);
|
|
ASSERT(SUCCEEDED(hr));
|
|
CoTaskMemFree(info.pszPath);
|
|
}
|
|
pEnum->Release();
|
|
}
|
|
SysFreeString(bstrURL);
|
|
}
|
|
pChannelMgr->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reg.SetKey(NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ProcessAddSubscriptions
|
|
//
|
|
HRESULT ProcessAddSubscriptions(HKEY hkey)
|
|
{
|
|
// Enumerate the subscription keys in the AddSubscriptions key
|
|
HRESULT hr;
|
|
CRegKey reg;
|
|
reg.SetKey(hkey);
|
|
TCHAR szSubscription[MAX_PATH];
|
|
while (S_OK == reg.Next(szSubscription))
|
|
{
|
|
// Create the subscription
|
|
// What if there is one already?
|
|
CRegKey regSubscription;
|
|
regSubscription.OpenForRead(hkey, szSubscription);
|
|
BSTR bstrURL, bstrTitle, bstrGroup, bstrUsername, bstrPassword;
|
|
DWORD dwSubType;
|
|
DWORD dwSynchronize = 0;
|
|
hr = regSubscription.GetBSTRValue(c_szURL, &bstrURL);
|
|
hr = regSubscription.GetBSTRValue(c_szTitle, &bstrTitle);
|
|
hr = regSubscription.GetBSTRValue(c_szScheduleGroup, &bstrGroup);
|
|
hr = regSubscription.GetBSTRValue(c_szUsername, &bstrUsername);
|
|
hr = regSubscription.GetBSTRValue(c_szPassword, &bstrPassword);
|
|
hr = regSubscription.GetValue(c_szSynchronize, &dwSynchronize);
|
|
if (bstrURL && bstrTitle && bstrGroup && SUCCEEDED(regSubscription.GetValue(c_szSubscriptionType, &dwSubType)))
|
|
{
|
|
SUBSCRIPTIONINFO si = {0};
|
|
si.cbSize = sizeof(SUBSCRIPTIONINFO);
|
|
si.fUpdateFlags = SUBSINFO_SCHEDULE;
|
|
if (bstrUsername && bstrPassword)
|
|
{
|
|
si.fUpdateFlags |= (SUBSINFO_USER | SUBSINFO_PASSWORD);
|
|
si.bstrUserName = bstrUsername;
|
|
si.bstrPassword = bstrPassword;
|
|
}
|
|
if (dwSubType == SUBSTYPE_CHANNEL || dwSubType == SUBSTYPE_DESKTOPCHANNEL)
|
|
{
|
|
si.fUpdateFlags |= SUBSINFO_CHANNELFLAGS;
|
|
si.fChannelFlags = 0; // Notify only.
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ISubscriptionMgr2 *pSubMgr2 = NULL;
|
|
hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr2, (void**)&pSubMgr2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pSubMgr2->CreateSubscription(NULL, bstrURL, bstrTitle, CREATESUBS_NOUI,
|
|
(SUBSCRIPTIONTYPE)dwSubType, &si);
|
|
if (dwSynchronize)
|
|
{
|
|
BOOL bIsSubscribed;
|
|
SUBSCRIPTIONCOOKIE cookie;
|
|
|
|
if (SUCCEEDED(pSubMgr2->IsSubscribed(bstrURL, &bIsSubscribed)) &&
|
|
bIsSubscribed &&
|
|
SUCCEEDED(ReadCookieFromInetDB(bstrURL, &cookie)))
|
|
{
|
|
pSubMgr2->UpdateItems(SUBSMGRUPDATE_MINIMIZE, 1, &cookie);
|
|
}
|
|
}
|
|
|
|
pSubMgr2->Release();
|
|
}
|
|
}
|
|
}
|
|
SAFEFREEBSTR(bstrURL);
|
|
SAFEFREEBSTR(bstrTitle);
|
|
SAFEFREEBSTR(bstrGroup);
|
|
SAFEFREEBSTR(bstrUsername);
|
|
SAFEFREEBSTR(bstrPassword);
|
|
}
|
|
reg.SetKey(NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ProcessRemoveSubscriptions
|
|
//
|
|
HRESULT ProcessRemoveSubscriptions(HKEY hkey)
|
|
{
|
|
// Enumerate the subscription keys in the RemoveSubscriptions key
|
|
HRESULT hr;
|
|
CRegKey reg;
|
|
reg.SetKey(hkey);
|
|
TCHAR szSubscription[MAX_PATH];
|
|
while (S_OK == reg.Next(szSubscription))
|
|
{
|
|
// Find the URL to delete
|
|
CRegKey regSubscription;
|
|
regSubscription.OpenForRead(hkey, szSubscription);
|
|
BSTR bstrURL;
|
|
if (SUCCEEDED(regSubscription.GetBSTRValue(c_szURL, &bstrURL)))
|
|
{
|
|
ISubscriptionMgr *pSubMgr = NULL;
|
|
hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&pSubMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pSubMgr->DeleteSubscription(bstrURL, NULL);
|
|
pSubMgr->Release();
|
|
}
|
|
SysFreeString(bstrURL);
|
|
}
|
|
}
|
|
reg.SetKey(NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// PRIVATE VERSION HANDLING CODE - REVIEW THIS CODE SHOULD HAVE BEEN STOLEN
|
|
// FROM SETUP
|
|
//
|
|
struct MYVERSION
|
|
{
|
|
DWORD dw1; // most sig version number
|
|
DWORD dw2;
|
|
DWORD dw3;
|
|
DWORD dw4; // least sig version number
|
|
};
|
|
|
|
int CompareDW(DWORD dw1, DWORD dw2)
|
|
{
|
|
if (dw1 > dw2)
|
|
return 1;
|
|
if (dw1 < dw2)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CompareVersion(MYVERSION * pv1, MYVERSION * pv2)
|
|
{
|
|
int rv;
|
|
|
|
rv = CompareDW(pv1->dw1, pv2->dw1);
|
|
|
|
if (rv == 0)
|
|
{
|
|
rv = CompareDW(pv1->dw2, pv2->dw2);
|
|
|
|
if (rv == 0)
|
|
{
|
|
rv = CompareDW(pv1->dw3, pv2->dw3);
|
|
|
|
if (rv == 0)
|
|
{
|
|
rv = CompareDW(pv1->dw4, pv2->dw4);
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
//
|
|
// Returns TRUE if an INT was parsed and *pwsz is NOT NULL
|
|
// if a . was found
|
|
//
|
|
BOOL GetDWORDFromStringAndAdvancePtr(DWORD *pdw, LPWSTR *pwsz)
|
|
{
|
|
if (!StrToIntExW(*pwsz, 0, (int *)pdw))
|
|
return FALSE;
|
|
|
|
*pwsz = StrChrW(*pwsz, L'.');
|
|
|
|
if (*pwsz)
|
|
*pwsz = *pwsz +1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GetVersionFromString(MYVERSION *pver, LPWSTR pwsz)
|
|
{
|
|
BOOL rv;
|
|
|
|
rv = GetDWORDFromStringAndAdvancePtr(&pver->dw1, &pwsz);
|
|
if (!rv || pwsz == NULL)
|
|
return FALSE;
|
|
|
|
rv = GetDWORDFromStringAndAdvancePtr(&pver->dw2, &pwsz);
|
|
if (!rv || pwsz == NULL)
|
|
return FALSE;
|
|
|
|
rv = GetDWORDFromStringAndAdvancePtr(&pver->dw3, &pwsz);
|
|
if (!rv || pwsz == NULL)
|
|
return FALSE;
|
|
|
|
rv = GetDWORDFromStringAndAdvancePtr(&pver->dw4, &pwsz);
|
|
if (!rv)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// ProcessRemoveAllChannels
|
|
//
|
|
HRESULT ProcessRemoveAllChannels(HKEY hkey)
|
|
{
|
|
HRESULT hr;
|
|
HINSTANCE hAdvPack = NULL;
|
|
DELNODE pfDELNODE = NULL;
|
|
IChannelMgrPriv *pChannelMgrPriv = NULL;
|
|
CRegKey regAdd;
|
|
regAdd.SetKey(hkey);
|
|
TCHAR szChannelFolder[MAX_PATH];
|
|
|
|
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgrPriv, (void**)&pChannelMgrPriv);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ((hAdvPack = LoadLibrary(TEXT("advpack.dll"))) != NULL)
|
|
{
|
|
pfDELNODE = (DELNODE)GetProcAddress( hAdvPack, "DelNode");
|
|
if (!pfDELNODE)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// Loop Through Channel Folders to delete
|
|
while (S_OK == regAdd.Next(szChannelFolder))
|
|
{
|
|
DWORD dwSoftware = 0, dwChannelGuide = 0;
|
|
CRegKey regChannelFolder;
|
|
|
|
CHAR szChannelPath[MAX_PATH];
|
|
TCHAR szChannelPathT[MAX_PATH];
|
|
TCHAR szFavsT[MAX_PATH]; //Retrieve Unicode data from registry
|
|
|
|
BSTR bstrOldIEVersion = NULL;
|
|
BOOL bVersion = TRUE;
|
|
regChannelFolder.OpenForRead(hkey, szChannelFolder);
|
|
|
|
// Check whether old IE version is correct.
|
|
hr = regChannelFolder.GetBSTRValue(c_szOldIEVersion, &bstrOldIEVersion);
|
|
if (SUCCEEDED(hr) && bstrOldIEVersion)
|
|
{
|
|
CRegKey regKeyIESetup;
|
|
hr = regKeyIESetup.OpenForRead(HKEY_LOCAL_MACHINE, c_szRegKeyIESetup);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrRealOldIEVersion = NULL;
|
|
hr = regKeyIESetup.GetBSTRValue(c_szOldIEVersion, &bstrRealOldIEVersion);
|
|
if (SUCCEEDED(hr) && bstrRealOldIEVersion)
|
|
{
|
|
MYVERSION verOldIEVersion, verRealOldIEVersion;
|
|
|
|
if (GetVersionFromString(&verOldIEVersion, bstrOldIEVersion) &&
|
|
GetVersionFromString(&verRealOldIEVersion, bstrRealOldIEVersion))
|
|
{
|
|
//
|
|
// If the old version of IE that was on this machine (verRealOldIEVersion)
|
|
// is infact NEWER than the old version number in the CABs that we want to
|
|
// delete (verOldIEVersion) then dont blow away old channel folder.
|
|
// Otherwise default to blow away channels.
|
|
//
|
|
if (CompareVersion(&verRealOldIEVersion, &verOldIEVersion) > 0)
|
|
{
|
|
bVersion = FALSE;
|
|
}
|
|
}
|
|
|
|
SAFEFREEBSTR(bstrRealOldIEVersion);
|
|
}
|
|
}
|
|
SAFEFREEBSTR(bstrOldIEVersion);
|
|
}
|
|
|
|
if (!bVersion)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
hr = regChannelFolder.GetValue(c_szChannelGuide, &dwChannelGuide);
|
|
if (FAILED(hr) || (SUCCEEDED(hr) && !dwChannelGuide))
|
|
{
|
|
if (SUCCEEDED(pChannelMgrPriv->GetChannelFolderPath(szChannelPath, MAX_PATH, IChannelMgrPriv::CF_CHANNEL)))
|
|
{
|
|
// Retrieve Favorites Path from registry
|
|
if (SUCCEEDED(Channel_GetBasePath((LPTSTR)szFavsT, ARRAYSIZE(szFavsT))))
|
|
{
|
|
// Convert from ANSI
|
|
SHAnsiToTChar(szChannelPath, szChannelPathT, ARRAYSIZE(szChannelPathT));
|
|
// If channel folder doesn't exist, then szChannelPath will contain the Favorites path.
|
|
// Don't delete the entries.
|
|
if (StrCmpI(szFavsT, szChannelPathT))
|
|
pfDELNODE(szChannelPath, ADN_DONT_DEL_DIR);
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = regChannelFolder.GetValue(c_szSoftware, &dwSoftware);
|
|
if (FAILED(hr) || (SUCCEEDED(hr) && !dwSoftware))
|
|
{
|
|
if (SUCCEEDED(pChannelMgrPriv->GetChannelFolderPath(szChannelPath, MAX_PATH, IChannelMgrPriv::CF_SOFTWAREUPDATE)))
|
|
{
|
|
pfDELNODE(szChannelPath, ADN_DONT_DEL_DIR);
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
regAdd.SetKey(NULL);
|
|
|
|
Exit:
|
|
SAFERELEASE(pChannelMgrPriv);
|
|
|
|
if (hAdvPack) {
|
|
FreeLibrary(hAdvPack);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// ProcessRemoveDesktopComponents
|
|
//
|
|
HRESULT ProcessRemoveDesktopComponents(HKEY hkey)
|
|
{
|
|
// Enumerate the component keys in the ProcessRemoveDesktopComponents key
|
|
// HRESULT hr;
|
|
CRegKey reg;
|
|
reg.SetKey(hkey);
|
|
TCHAR szComponent[MAX_PATH];
|
|
while (S_OK == reg.Next(szComponent))
|
|
{
|
|
// Find the URL to delete
|
|
CRegKey regComponent;
|
|
regComponent.OpenForRead(hkey, szComponent);
|
|
BSTR bstrURL;
|
|
if (SUCCEEDED(regComponent.GetBSTRValue(c_szURL, &bstrURL)))
|
|
{
|
|
SysFreeString(bstrURL);
|
|
}
|
|
}
|
|
reg.SetKey(NULL);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// NoChannelUI processing.
|
|
//
|
|
|
|
#define SHELLFOLDERS \
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
|
|
|
|
|
|
typedef enum _tagXMLDOCTYPE {
|
|
DOC_CHANNEL,
|
|
DOC_SOFTWAREUPDATE
|
|
} XMLDOCTYPE;
|
|
|
|
//
|
|
// Get the path to the favorites directory.
|
|
//
|
|
HRESULT Channel_GetBasePath(LPTSTR pszPath, int cch)
|
|
{
|
|
ASSERT(pszPath || 0 == cch);
|
|
|
|
DWORD cbPath = cch * sizeof(TCHAR);
|
|
|
|
return SHRegGetValue(HKEY_CURRENT_USER, SHELLFOLDERS, TEXT("Favorites"), SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, pszPath, &cbPath) == ERROR_SUCCESS
|
|
? S_OK
|
|
: E_FAIL;
|
|
}
|
|
|
|
HRESULT Channel_GetFolder(LPTSTR pszPath, XMLDOCTYPE xdt )
|
|
{
|
|
TCHAR szFavs[MAX_PATH];
|
|
TCHAR szChannel[MAX_PATH];
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (SUCCEEDED(Channel_GetBasePath(szFavs, ARRAYSIZE(szFavs))))
|
|
{
|
|
//
|
|
// Get the potentially localized name of the Channel folder from
|
|
// tack this on the Favorites path
|
|
//
|
|
MLLoadString(
|
|
((xdt == DOC_CHANNEL)? IDS_CHANNEL_FOLDER : IDS_SOFTWAREUPDATE_FOLDER),
|
|
szChannel, MAX_PATH);
|
|
PathCombine(pszPath, szFavs, szChannel);
|
|
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Set/Clear the "hidden" attribute of a channel directory.
|
|
//
|
|
|
|
void ShowChannelDirectory(BOOL fShow, XMLDOCTYPE xdt)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
DWORD dwAttributes;
|
|
|
|
if (SUCCEEDED(Channel_GetFolder(szPath, xdt)))
|
|
{
|
|
dwAttributes = GetFileAttributes(szPath);
|
|
|
|
if (0xffffffff != dwAttributes)
|
|
{
|
|
if (fShow && (dwAttributes & FILE_ATTRIBUTE_HIDDEN))
|
|
{
|
|
SetFileAttributes(szPath, dwAttributes & ~FILE_ATTRIBUTE_HIDDEN);
|
|
}
|
|
else if (!fShow && !(dwAttributes & FILE_ATTRIBUTE_HIDDEN))
|
|
{
|
|
SetFileAttributes(szPath, dwAttributes | FILE_ATTRIBUTE_HIDDEN);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Hide or show channel directories
|
|
//
|
|
|
|
void ShowChannelDirectories(BOOL fShow)
|
|
{
|
|
ShowChannelDirectory(fShow, DOC_CHANNEL);
|
|
ShowChannelDirectory(fShow, DOC_SOFTWAREUPDATE);
|
|
}
|