|
|
#include "private.h"
#include "notfcvt.h"
#include "subsmgrp.h"
#include "subitem.h"
#include "chanmgr.h"
#include "chanmgrp.h"
#include "helper.h"
#include "shguidp.h" // IID_IChannelMgrPriv
#include <mluisupp.h>
#undef TF_THISMODULE
#define TF_THISMODULE TF_ADMIN
const CHAR c_pszRegKeyNotfMgr[] = "Software\\Microsoft\\Windows\\CurrentVersion\\NotificationMgr"; const CHAR c_pszRegKeyScheduleItems[] = "Software\\Microsoft\\Windows\\CurrentVersion\\NotificationMgr\\SchedItems 0.6"; const CHAR c_pszRegKeyScheduleGroup[] = "Software\\Microsoft\\Windows\\CurrentVersion\\NotificationMgr\\ScheduleGroup 0.6";
const WCHAR c_wszIE4IntlPre[] = L"http://www.microsoft.com/ie_intl/"; const WCHAR c_wszIE4IntlPre2[] = L"http://www.microsoft.com/windows/ie_intl/"; const WCHAR c_wszIE4IntlPost[] = L"/ie40/download/cdf/ie4updates-"; const WCHAR c_wszIE4English[] = L"http://www.microsoft.com/ie/ie40/download/cdf/ie4updates-"; const WCHAR c_wszIE4English2[] = L"http://www.microsoft.com/windows/ie/ie40/download/cdf/ie4updates-";
HRESULT ConvertNotfMgrScheduleGroup(NOTIFICATIONCOOKIE *pSchedCookie);
BOOL IsIE4UpdateChannel(LPCWSTR pwszURL) { BOOL bResult = FALSE; int len = lstrlenW(pwszURL);
// For update channels from the non-international version, simply compare the
// English base name witht the passed in URL.
//
// International update channels look like:
// http://www.microsoft.com/ie_intl/XX/ie40/download/cdf/ie4updates-XX.cdf
// So we do two compares skipping the middle XX
if ( ( (len > ARRAYSIZE(c_wszIE4English)) && (0 == memcmp(c_wszIE4English, pwszURL, sizeof(c_wszIE4English) - sizeof(WCHAR))) ) || ( (len > ARRAYSIZE(c_wszIE4English2)) && (0 == memcmp(c_wszIE4English2, pwszURL, sizeof(c_wszIE4English2) - sizeof(WCHAR))) ) || ( (len > (ARRAYSIZE(c_wszIE4IntlPre) + ARRAYSIZE(c_wszIE4IntlPost) + 4)) && (0 == memcmp(c_wszIE4IntlPre, pwszURL, sizeof(c_wszIE4IntlPre) - sizeof(WCHAR))) && (0 == memcmp(c_wszIE4IntlPost, pwszURL + ARRAYSIZE(c_wszIE4IntlPre) + 1, sizeof(c_wszIE4IntlPost) - sizeof(WCHAR))) ) || ( (len > (ARRAYSIZE(c_wszIE4IntlPre2) + ARRAYSIZE(c_wszIE4IntlPost) + 4)) && (0 == memcmp(c_wszIE4IntlPre2, pwszURL, sizeof(c_wszIE4IntlPre2) - sizeof(WCHAR))) && (0 == memcmp(c_wszIE4IntlPost, pwszURL + ARRAYSIZE(c_wszIE4IntlPre2) + 1, sizeof(c_wszIE4IntlPost) - sizeof(WCHAR))) ) ) { bResult = TRUE; }
return bResult; }
struct NOTFSUBS { NOTIFICATIONITEM ni; NOTIFICATIONITEMEXTRA nix; CLSID clsidItem; // Ignore
NOTIFICATIONCOOKIE notfCookie; NOTIFICATIONTYPE notfType; ULONG nProps;
// Variable length data here:
//SaveSTATPROPMAP statPropMap;
//char szPropName[];
//BYTE variant property data
//...
//SaveSTATPROPMAP statPropMap;
//char szPropName[];
//BYTE variant property data
};
HRESULT SubscriptionFromNotification(NOTFSUBS *pns, LPCWSTR pwszURL, LPCWSTR pwszName, const LPWSTR rgwszName[], VARIANT rgValue[]) { HRESULT hr;
ASSERT(NULL != pns); ASSERT(NULL != rgwszName); ASSERT(NULL != rgValue);
if ((pns->ni.NotificationType == NOTIFICATIONTYPE_AGENT_START) && (pns->nix.PackageFlags & PF_SCHEDULED) && (NULL != pwszURL) && (NULL != pwszName) && (!IsIE4UpdateChannel(pwszURL))) {
SUBSCRIPTIONITEMINFO sii;
sii.cbSize = sizeof(SUBSCRIPTIONITEMINFO); sii.dwFlags = 0; sii.dwPriority = 0; sii.ScheduleGroup = CLSID_NULL; sii.clsidAgent = pns->ni.clsidDest;
hr = AddUpdateSubscription(&pns->notfCookie, &sii, pwszURL, pns->nProps, rgwszName, rgValue);
if (SUCCEEDED(hr)) { if (NOTFCOOKIE_SCHEDULE_GROUP_MANUAL != pns->ni.groupCookie) { ISubscriptionItem *psi;
hr = SubscriptionItemFromCookie(FALSE, &pns->notfCookie, &psi);
if (SUCCEEDED(hr)) { SYNCSCHEDULECOOKIE schedCookie = GUID_NULL;
if (GUID_NULL == pns->ni.groupCookie) { WCHAR wszSchedName[MAX_PATH];
CreatePublisherScheduleNameW(wszSchedName, ARRAYSIZE(wszSchedName), NULL, pwszName);
// Create the schedule
hr = CreateSchedule(wszSchedName, SYNCSCHEDINFO_FLAGS_READONLY, &schedCookie, &pns->ni.TaskTrigger, FALSE);
// If we created a new one or for some strange reason
// "MSN Recommended Schedule" already exists we go with it
if (SUCCEEDED(hr) || (hr == SYNCMGR_E_NAME_IN_USE)) { // sii should have been initialized and set above
ASSERT(sizeof(SUBSCRIPTIONITEMINFO) == sii.cbSize); ASSERT(GUID_NULL == sii.ScheduleGroup);
sii.ScheduleGroup = schedCookie; hr = psi->SetSubscriptionItemInfo(&sii); } } else { schedCookie = pns->ni.groupCookie; hr = ConvertNotfMgrScheduleGroup(&schedCookie); }
if (SUCCEEDED(hr)) { SYNC_HANDLER_ITEM_INFO shii;
shii.handlerID = CLSID_WebCheckOfflineSync; shii.itemID = pns->notfCookie; shii.hIcon = NULL; StrCpyNW(shii.wszItemName, pwszName, ARRAYSIZE(shii.wszItemName)); shii.dwCheckState = SYNCMGRITEMSTATE_CHECKED;
// Not much we can do if this fails other than jump up and down
// and scream like a baby.
hr = AddScheduledItem(&shii, &schedCookie); } psi->Release(); } } } } else { TraceMsgA(TF_THISMODULE, "Not converting Notification subscription %S URL: %S", pwszName, pwszURL); hr = S_FALSE; }
return hr; }
HRESULT ConvertScheduleItem(CHAR *pszSubsName) { HRESULT hr = E_FAIL; HKEY hkey; CHAR szKeyName[MAX_PATH];
// Build path to this notification item
strcpy(szKeyName, c_pszRegKeyScheduleItems); szKeyName[sizeof(c_pszRegKeyScheduleItems) - 1] = '\\'; strcpy(szKeyName + sizeof(c_pszRegKeyScheduleItems), pszSubsName);
// We just enumerated so this should be here!
if (RegOpenKeyExA(HKEY_CURRENT_USER, szKeyName, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { DWORD dwType; DWORD dwSize;
// Read the {GUID} value. We need to alloc a buffer but don't know how big yet.
// This gets us the size and type. If it's not binary or not big enough, bail.
if ((RegQueryValueExA(hkey, pszSubsName, NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS) && (dwType == REG_BINARY) && (dwSize >= sizeof(NOTFSUBS))) { BYTE *pData = new BYTE[dwSize];
if (NULL != pData) { if (RegQueryValueExA(hkey, pszSubsName, NULL, &dwType, pData, &dwSize) == ERROR_SUCCESS) { // Shouldn't have gotten here based on the check above.
ASSERT(dwType == REG_BINARY); ASSERT(dwSize >= sizeof(NOTFSUBS));
ULONG i; NOTFSUBS *pns = (NOTFSUBS *)pData;
// Point to the repeated variable size block
BYTE *pVarData = pData + FIELD_OFFSET(NOTFSUBS, nProps) + sizeof(ULONG);
// Allocate buffers to hold the arrays of property names and values
WCHAR **ppwszPropNames = new WCHAR *[pns->nProps]; VARIANT *pVars = new VARIANT[pns->nProps]; WCHAR *pwszURL = NULL; WCHAR *pwszName = NULL;
if ((NULL != ppwszPropNames) && (NULL != pVars)) { // adjust size remaining
dwSize -= sizeof(NOTFSUBS);
for (i = 0, hr = S_OK; (i < pns->nProps) && (dwSize >= sizeof(SaveSTATPROPMAP)) && SUCCEEDED(hr); i++) { SaveSTATPROPMAP *pspm = (SaveSTATPROPMAP *)pVarData; CHAR *pszPropName = (CHAR *)(pVarData + sizeof(SaveSTATPROPMAP)); DWORD cbUsed;
ppwszPropNames[i] = new WCHAR[pspm->cbStrLen + 1]; if (NULL == ppwszPropNames[i]) { hr = E_OUTOFMEMORY; break; } MultiByteToWideChar(CP_ACP, 0, pszPropName, pspm->cbStrLen, ppwszPropNames[i], pspm->cbStrLen);
// Point to where the variant blob starts
pVarData += sizeof(SaveSTATPROPMAP) + pspm->cbStrLen;
// adjust size remaining
dwSize -= sizeof(SaveSTATPROPMAP) + pspm->cbStrLen; hr = BlobToVariant(pVarData, dwSize, &pVars[i], &cbUsed, TRUE);
if ((3 == pspm->cbStrLen) && (StrCmpNIA(pszPropName, "URL", 3) == 0)) { pwszURL = pVars[i].bstrVal; } else if ((4 == pspm->cbStrLen) && (StrCmpNIA(pszPropName, "Name", 4) == 0)) { pwszName = pVars[i].bstrVal; }
// Point to start of next SaveSTATPROPMAP
pVarData += cbUsed;
// adjust size remaining
dwSize -= cbUsed; }
if (SUCCEEDED(hr)) { hr = SubscriptionFromNotification(pns, pwszURL, pwszName, ppwszPropNames, pVars); } else { TraceMsgA(TF_THISMODULE, "Not converting notification subscription %s", pszSubsName); }
for (i = 0; i < pns->nProps; i++) { if (ppwszPropNames[i]) { delete [] ppwszPropNames[i]; } VariantClear(&pVars[i]); } } else { hr = E_OUTOFMEMORY; }
SAFEDELETE(ppwszPropNames); SAFEDELETE(pVars); } delete [] pData; } else { hr = E_OUTOFMEMORY; } } }
return hr; }
HRESULT ConvertNotfMgrSubscriptions() { HRESULT hr = S_OK; HKEY hkey;
if (RegOpenKeyExA(HKEY_CURRENT_USER, c_pszRegKeyScheduleItems, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { int i = 0; CHAR szSubsName[MAX_PATH];
TraceMsg(TF_THISMODULE, "Converting Notification Mgr subscriptions");
while (RegEnumKeyA(hkey, i++, szSubsName, sizeof(szSubsName)) == ERROR_SUCCESS) { HRESULT hrConvert = ConvertScheduleItem(szSubsName); if (FAILED(hrConvert)) { ASSERT(0); hr = S_FALSE; // Something failed, should we break or keep on truckin'?
// break;
} } RegCloseKey(hkey); } else { TraceMsg(TF_THISMODULE, "No Notification Mgr subscriptions to convert"); // No Notification Manager schedule items key so there's nothing to do...
hr = S_FALSE; }
return hr; }
struct NOTFSCHED { SCHEDULEGROUPITEM sgi; DWORD cchName; WCHAR wszName[1]; // varies depending on cchName
};
HRESULT ConvertNotfMgrScheduleGroup(NOTIFICATIONCOOKIE *pSchedCookie) { HRESULT hr = S_OK;
if (!ScheduleCookieExists(pSchedCookie)) { HKEY hkey; DWORD dwResult;
dwResult = RegOpenKeyExA(HKEY_CURRENT_USER, c_pszRegKeyScheduleGroup, 0, KEY_READ, &hkey);
if (ERROR_SUCCESS == dwResult) { TCHAR szGuid[GUIDSTR_MAX]; DWORD dwType; DWORD cbSize; SHStringFromGUID(*pSchedCookie, szGuid, ARRAYSIZE(szGuid));
dwResult = RegQueryValueEx(hkey, szGuid, NULL, &dwType, NULL, &cbSize);
if (ERROR_SUCCESS == dwResult) { BYTE *pData = new BYTE[cbSize];
if (NULL != pData) { dwResult = RegQueryValueEx(hkey, szGuid, NULL, &dwType, pData, &cbSize); if (ERROR_SUCCESS == dwResult) { if (dwType == REG_BINARY) { NOTFSCHED *pns = (NOTFSCHED *)pData;
hr = CreateSchedule(pns->wszName, 0, &pns->sgi.GroupCookie, &pns->sgi.TaskTrigger, TRUE); if (SYNCMGR_E_NAME_IN_USE == hr) { hr = S_OK; } } else { hr = E_UNEXPECTED; } } else { hr = HRESULT_FROM_WIN32(dwResult); }
delete [] pData; } else { hr = E_OUTOFMEMORY; } } else { hr = HRESULT_FROM_WIN32(dwResult); } RegCloseKey(hkey); } else { hr = HRESULT_FROM_WIN32(dwResult); } } else { hr = S_FALSE; } return hr; }
HRESULT WhackIE4UpdateChannel() { HRESULT hr; IChannelMgr *pChannelMgr;
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgr, (void**)&pChannelMgr);
if (SUCCEEDED(hr)) { IEnumChannels *pEnumChannels;
hr = pChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH | CHANENUM_URL, NULL, &pEnumChannels);
if (SUCCEEDED(hr)) { CHANNELENUMINFO cei;
while (S_OK == pEnumChannels->Next(1, &cei, NULL)) { if (IsIE4UpdateChannel(cei.pszURL)) { TraceMsgA(TF_THISMODULE, "Whacking IE 4 update channel: %S %S", cei.pszURL, cei.pszPath); hr = pChannelMgr->DeleteChannelShortcut(cei.pszPath);
ASSERT(SUCCEEDED(hr)); }
CoTaskMemFree(cei.pszURL); CoTaskMemFree(cei.pszPath); } pEnumChannels->Release(); } pChannelMgr->Release(); }
return hr; }
HRESULT FixupChannelScreenSaver() { HRESULT hr; IChannelMgrPriv2 *pChannelMgrPriv2;
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgrPriv2, (void**)&pChannelMgrPriv2);
if (SUCCEEDED(hr)) { TraceMsg(TF_THISMODULE, "Refreshing IE 4 Screen Saver URLs"); hr = pChannelMgrPriv2->RefreshScreenSaverURLs(); #ifdef DEBUG
if (FAILED(hr)) { DBG("Error refreshing screen saver urls!"); } #endif
pChannelMgrPriv2->Release(); }
return hr; }
HRESULT ConvertIE4Subscriptions() { HRESULT hr;
hr = ConvertNotfMgrSubscriptions(); ASSERT(SUCCEEDED(hr));
hr = WhackIE4UpdateChannel();
ASSERT(SUCCEEDED(hr)); hr = FixupChannelScreenSaver();
ASSERT(SUCCEEDED(hr));
return hr; }
|