windows-nt/Source/XPSP1/NT/shell/ext/webcheck/admin.cpp
2020-09-26 16:20:57 +08:00

1334 lines
46 KiB
C++

//----------------------------------------------------------------------------
//
// 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 ProcessAddScheduleGroups(HKEY hkey);
HRESULT ProcessRemoveScheduleGroups(HKEY hkey);
HRESULT ProcessAddDesktopComponents(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_szRemoveScheduleGroups, &ProcessRemoveScheduleGroups },
{ c_szAddChannels, &ProcessAddChannels },
{ c_szAddDesktopComponents, &ProcessAddDesktopComponents },
{ c_szAddScheduleGroups, &ProcessAddScheduleGroups },
{ 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 dwLen)
{
ASSERT(m_hkey);
DWORD dwType = REG_SZ;
LONG lRet = RegQueryValueEx(m_hkey, szValueName, 0, &dwType, (LPBYTE)szValue, &dwLen);
return (ERROR_SUCCESS == lRet)?(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);
*pbstr = NULL;
TCHAR szValue[INTERNET_MAX_URL_LENGTH];
DWORD dwType = REG_SZ;
DWORD dwLen = sizeof(szValue);
LONG lRet = RegQueryValueEx(m_hkey, szValueName, 0, &dwType, (LPBYTE)szValue, &dwLen);
if (ERROR_SUCCESS == lRet)
{
*pbstr = SysAllocStringLen(NULL, dwLen); // dwLen includes null terminator
if (*pbstr)
{
MyStrToOleStrN(*pbstr, dwLen, szValue);
return S_OK;
}
}
return E_FAIL;
}
};
// 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;
}
//
// IsScheduleGroupReserved
//
HRESULT IsScheduleGroupReserved(LPCWSTR wzName, SUBSCRIPTIONSCHEDULE *pSched)
{
HRESULT hr = S_OK;
if (!StrCmpIW(wzName, c_szScheduleAuto))
*pSched = SUBSSCHED_AUTO;
else if (!StrCmpIW(wzName, c_szScheduleDaily))
*pSched = SUBSSCHED_DAILY;
else if (!StrCmpIW(wzName, c_szScheduleWeekly))
*pSched = SUBSSCHED_WEEKLY;
else if (!StrCmpIW(wzName, c_szScheduleManual))
*pSched = SUBSSCHED_MANUAL;
else
{
*pSched = SUBSSCHED_CUSTOM;
hr = E_FAIL;
}
return hr;
}
//
// FindScheduleGroupFromName
//
HRESULT FindScheduleGroupFromName(LPCWSTR wzName, PNOTIFICATIONCOOKIE pCookie)
{
// FEATURE: Need to worry about localized names.
HRESULT hrRet = E_FAIL;
HRESULT hr;
INotificationMgr *pNotMgr = NULL;
hr = CoCreateInstance(CLSID_StdNotificationMgr, NULL, CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&pNotMgr);
if (SUCCEEDED(hr))
{
// what flags?
IEnumScheduleGroup *pEnumScheduleGroup = NULL;
hr = pNotMgr->GetEnumScheduleGroup(0, &pEnumScheduleGroup);
if (SUCCEEDED(hr))
{
// Iterate through schedule groups
for (;;)
{
IScheduleGroup *pScheduleGroup = NULL;
ULONG uFetched;
hr = pEnumScheduleGroup->Next(1, &pScheduleGroup, &uFetched);
if (SUCCEEDED(hr) && (1 == uFetched))
{
GROUPINFO info = { 0 };
hr = pScheduleGroup->GetAttributes(NULL, NULL, pCookie, &info, NULL, NULL);
if (SUCCEEDED(hr))
{
ASSERT(info.cbSize == SIZEOF(GROUPINFO));
ASSERT(info.pwzGroupname != NULL);
if (!StrCmpW(info.pwzGroupname, wzName))
{
// found it
hrRet = S_OK;
SAFEDELETE(info.pwzGroupname);
break;
}
SAFEDELETE(info.pwzGroupname);
}
pScheduleGroup->Release();
}
else
{
break;
}
}
pEnumScheduleGroup->Release();
}
pNotMgr->Release();
}
return hrRet;
}
//
// 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.
}
hr = IsScheduleGroupReserved(bstrGroup, &si.schedule);
if (FAILED(hr))
{
hr = FindScheduleGroupFromName(bstrGroup, &si.customGroupCookie);
}
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;
}
//
// ProcessAddScheduleGroups
//
HRESULT ProcessAddScheduleGroups(HKEY hkey)
{
// Enumerate the schedule group keys in the AddScheduleGroups key
HRESULT hr;
CRegKey reg;
reg.SetKey(hkey);
TCHAR szScheduleGroup[MAX_PATH];
while (S_OK == reg.Next(szScheduleGroup))
{
// Read the Title and the Earliest, Latest, and Interval times
// Currently times must be in minutes.
// FEATURE: Currently we don't look for StartDate or EndDate.
CRegKey regScheduleGroup;
regScheduleGroup.OpenForRead(hkey, szScheduleGroup);
BSTR bstrTitle;
DWORD dwET, dwIT, dwLT;
hr = regScheduleGroup.GetBSTRValue(c_szTitle, &bstrTitle);
if (SUCCEEDED(hr)
&& SUCCEEDED(regScheduleGroup.GetValue(c_szEarliestTime, &dwET))
&& SUCCEEDED(regScheduleGroup.GetValue(c_szIntervalTime, &dwIT))
&& SUCCEEDED(regScheduleGroup.GetValue(c_szLatestTime, &dwLT)))
{
INotificationMgr *pNotMgr = NULL;
hr = CoCreateInstance(CLSID_StdNotificationMgr, NULL, CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&pNotMgr);
if (SUCCEEDED(hr))
{
// Create the schedule group
IScheduleGroup *pScheduleGroup = NULL;
NOTIFICATIONCOOKIE cookie;
hr = pNotMgr->CreateScheduleGroup(0, &pScheduleGroup, &cookie, 0);
if (SUCCEEDED(hr))
{
TASK_TRIGGER tt;
GROUPINFO gi = { 0 };
SYSTEMTIME st;
GetLocalTime(&st);
tt.cbTriggerSize = sizeof(tt);
if (SUCCEEDED(ScheduleToTaskTrigger(&tt, &st, NULL, (long)dwIT, (long)dwET, (long)dwLT)))
{
gi.cbSize = sizeof(GROUPINFO);
gi.pwzGroupname = bstrTitle;
hr = pScheduleGroup->SetAttributes(&tt, NULL, &cookie, &gi, 0);
}
pScheduleGroup->Release();
}
pNotMgr->Release();
}
}
SAFEFREEBSTR(bstrTitle);
}
reg.SetKey(NULL);
return S_OK;
}
//
// ProcessRemoveScheduleGroups
//
HRESULT ProcessRemoveScheduleGroups(HKEY hkey)
{
// Enumerate the schedule group keys in the RemoveScheduleGroups key
HRESULT hr;
CRegKey reg;
reg.SetKey(hkey);
TCHAR szScheduleGroup[MAX_PATH];
while (S_OK == reg.Next(szScheduleGroup))
{
// Find the title to delete
CRegKey regScheduleGroup;
regScheduleGroup.OpenForRead(hkey, szScheduleGroup);
BSTR bstrTitle;
if (SUCCEEDED(regScheduleGroup.GetBSTRValue(c_szTitle, &bstrTitle)))
{
GUID groupCookie;
if (SUCCEEDED(FindScheduleGroupFromName(bstrTitle, &groupCookie)))
{
INotificationMgr *pNotMgr = NULL;
hr = CoCreateInstance(CLSID_StdNotificationMgr, NULL, CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&pNotMgr);
if (SUCCEEDED(hr))
{
hr = pNotMgr->RevokeScheduleGroup(&groupCookie, NULL, 0);
pNotMgr->Release();
}
}
SysFreeString(bstrTitle);
}
}
reg.SetKey(NULL);
return S_OK;
}
//
// ProcessAddDesktopComponents
//
HRESULT ProcessAddDesktopComponents(HKEY hkey)
{
return S_OK;
}
//
// 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);
HRESULT hr = E_FAIL;
HKEY hKey;
DWORD dwLen = cch;
if (RegOpenKey(HKEY_CURRENT_USER, SHELLFOLDERS, &hKey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hKey, TEXT("Favorites"), NULL, NULL,
(LPBYTE)pszPath, &dwLen) == ERROR_SUCCESS)
{
hr = S_OK;
}
RegCloseKey(hKey);
}
return hr;
}
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);
}
}
}
return;
}
//
// Hide or show channel directories
//
void ShowChannelDirectories(BOOL fShow)
{
ShowChannelDirectory(fShow, DOC_CHANNEL);
ShowChannelDirectory(fShow, DOC_SOFTWAREUPDATE);
return;
}