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