#include "private.h" #include "chanmgr.h" #include "chanmgrp.h" #include "shguidp.h" #include "resource.h" #define DECL_CRTFREE #include #include #define TF_DUMPTRIGGER 0x80000000 #define PtrDifference(x,y) ((LPBYTE)(x)-(LPBYTE)(y)) // Invoke Command verb strings const CHAR c_szOpen[] = "open"; const CHAR c_szDelete[] = "delete"; const CHAR c_szProperties[] = "properties"; const CHAR c_szCopy[] = "copy"; const CHAR c_szRename[] = "rename"; const CHAR c_szPaste[] = "paste"; static TCHAR szNone[40] = {0}; static TCHAR szUnknown[40] = {0}; // For each notification handler CLSID in the registry, send a single CommandId and Cookie to each handler. void FireSubscriptionEvent(int nCmdID, const SUBSCRIPTIONCOOKIE UNALIGNED *pCookie_ua) { HKEY hkey; SUBSCRIPTIONCOOKIE cookie_buf; SUBSCRIPTIONCOOKIE *pCookie; ASSERT( pCookie_ua ); if ( ! pCookie_ua ) { TraceMsg(TF_ERROR, "FireSubscriptionEvent() - pCookie_ua is NULL!"); return; } // // Make an aligned copy of pCookie_ua and set a pointer to it. // cookie_buf = *pCookie_ua; pCookie = &cookie_buf; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WEBCHECK_REGKEY_NOTF, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { LPOLESTR pszCookie; if (SUCCEEDED(StringFromCLSID(*pCookie, &pszCookie))) { VARIANT varCookie; varCookie.vt = VT_BSTR; varCookie.bstrVal = SysAllocString(pszCookie); if (varCookie.bstrVal) { for (int i = 0; ; i++) { TCHAR szClsid[GUIDSTR_MAX]; DWORD cchClsid = ARRAYSIZE(szClsid); DWORD dwType; DWORD dwData; DWORD cbData = sizeof(dwData); int result = RegEnumValue(hkey, i, szClsid, &cchClsid, NULL, &dwType, (LPBYTE)&dwData, &cbData); if (ERROR_NO_MORE_ITEMS == result) { break; } if ((ERROR_SUCCESS == result) && (dwData & nCmdID)) { WCHAR wszClsid[GUIDSTR_MAX]; CLSID clsid; SHTCharToUnicode(szClsid, wszClsid, ARRAYSIZE(wszClsid)); HRESULT hr = CLSIDFromString(wszClsid, &clsid); if (SUCCEEDED(hr)) { IOleCommandTarget *pCmdTarget; hr = CoCreateInstance(*(&clsid), NULL, CLSCTX_ALL, IID_IOleCommandTarget, (void **)&pCmdTarget); if (SUCCEEDED(hr)) { pCmdTarget->Exec(&CLSID_SubscriptionMgr, nCmdID, 0, &varCookie, NULL); pCmdTarget->Release(); } } } } VariantClear(&varCookie); } CoTaskMemFree(pszCookie); } RegCloseKey( hkey ); } } HRESULT IExtractIcon_GetIconLocationThunk(IExtractIconW *peiw, UINT uFlags, LPSTR szIconFile, UINT cchMax, int * piIndex, UINT * pwFlags) { HRESULT hr; WCHAR *pwszIconFile = new WCHAR[cchMax]; if (NULL != pwszIconFile) { hr = peiw->GetIconLocation(uFlags, pwszIconFile, cchMax, piIndex, pwFlags); if (SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP, 0, pwszIconFile, -1, szIconFile, cchMax, NULL, NULL); } delete [] pwszIconFile; } else { hr = E_OUTOFMEMORY; } return hr; } HRESULT IExtractIcon_ExtractThunk(IExtractIconW *peiw, LPCSTR pszFile, UINT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIconSize) { HRESULT hr; int len = lstrlenA(pszFile) + 1; WCHAR *pwszFile = new WCHAR[len]; if (NULL != pwszFile) { MultiByteToWideChar(CP_ACP, 0, pszFile, len, pwszFile, len); hr = peiw->Extract(pwszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize); delete [] pwszFile; } else { hr = E_OUTOFMEMORY; } return hr; } DWORD Random(DWORD nMax) { static DWORD dwSeed = GetTickCount(); if (nMax) { return dwSeed = (dwSeed * 214013L + 2531011L) % nMax; } else { return 0; } } void CreateCookie(GUID UNALIGNED *pCookie_ua) { static DWORD dwCount = 0; union CUCookie { GUID guidCookie; struct XCookie { FILETIME ft; DWORD dwCount; DWORD dwRand; } x; }; CUCookie uc; GetSystemTimeAsFileTime(&uc.x.ft); uc.x.dwCount = dwCount++; uc.x.dwRand = Random(0xffffffff); *pCookie_ua = uc.guidCookie; } void VariantTimeToFileTime(double dt, FILETIME& ft) { SYSTEMTIME st; VariantTimeToSystemTime(dt, &st); SystemTimeToFileTime(&st, &ft); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // // Cache helper functions // // Caller should MemFree *lpCacheConfigInfo when done. Should pass *lpCacheConfigInfo // into SetCacheSize HRESULT GetCacheInfo( LPINTERNET_CACHE_CONFIG_INFOA *lplpCacheConfigInfo, DWORD *pdwSizeInKB, DWORD *pdwPercent) { HRESULT hr = S_OK; LPINTERNET_CACHE_CONFIG_INFOA lpCCI = NULL; DWORD dwSize; dwSize = sizeof(INTERNET_CACHE_CONFIG_INFOA); lpCCI = (LPINTERNET_CACHE_CONFIG_INFOA)MemAlloc(LPTR, dwSize); if (!lpCCI) { hr = E_OUTOFMEMORY; goto cleanup; } lpCCI->dwStructSize = sizeof(INTERNET_CACHE_CONFIG_INFOA); if (!GetUrlCacheConfigInfoA(lpCCI, &dwSize, CACHE_CONFIG_CONTENT_PATHS_FC)) { hr = E_FAIL; // HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } // there should be at least one cache path structure if (dwSize < sizeof(INTERNET_CACHE_CONFIG_INFOA) || lpCCI->dwNumCachePaths != 1) { // something is messed up hr = E_FAIL; goto cleanup; } *lplpCacheConfigInfo = lpCCI; *pdwSizeInKB = lpCCI->dwQuota; *pdwPercent = 10; // good faith estimate ASSERT(*pdwSizeInKB); // Better not be 0... cleanup: if (FAILED(hr)) { SAFELOCALFREE(lpCCI); } return hr; } HRESULT SetCacheSize( LPINTERNET_CACHE_CONFIG_INFOA lpCacheConfigInfo, DWORD dwSizeInKB) { // lpCacheConfigInfo->dwNumCachePaths = 1; // lpCacheConfigInfo->CachePaths[0].dwCacheSize = dwSizeInKB; lpCacheConfigInfo->dwContainer = 0; // CONTENT; lpCacheConfigInfo->dwQuota = dwSizeInKB; if (!SetUrlCacheConfigInfoA(lpCacheConfigInfo, CACHE_CONFIG_QUOTA_FC)) { return E_FAIL; // HRESULT_FROM_WIN32(GetLastError()); } return S_OK; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // // Registry helper functions // BOOL ReadRegValue(HKEY hkeyRoot, const TCHAR *pszKey, const TCHAR *pszValue, void *pData, DWORD dwBytes) { return ERROR_SUCCESS == SHRegGetValue(hkeyRoot, pszKey, pszValue, SRRF_RT_ANY | SRRF_NOEXPAND, NULL, pData, &dwBytes); } BOOL WriteRegValue(HKEY hkeyRoot, const TCHAR *pszKey, const TCHAR *pszValue, void *pData, DWORD dwBytes, DWORD dwType) { HKEY hkey; long lResult; DWORD dwStatus; lResult = RegCreateKeyEx(hkeyRoot, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkey, &dwStatus); if (lResult != ERROR_SUCCESS) { return FALSE; } lResult = RegSetValueEx(hkey, pszValue, 0, dwType, (BYTE *)pData, dwBytes); RegCloseKey(hkey); return (lResult == ERROR_SUCCESS) ? TRUE : FALSE; } DWORD ReadRegDWORD(HKEY hkeyRoot, const TCHAR *pszKey, const TCHAR *pszValue) { DWORD dwData; if (ReadRegValue(hkeyRoot, pszKey, pszValue, &dwData, sizeof(dwData))) return dwData; else return 0; } HRESULT CreateShellFolderPath(LPCTSTR pszPath, LPCTSTR pszGUID, BOOL bUICLSID) { if (!PathFileExists(pszPath)) CreateDirectory(pszPath, NULL); // Mark the folder as a system directory if (SetFileAttributes(pszPath, FILE_ATTRIBUTE_READONLY)) { TCHAR szDesktopIni[MAX_PATH]; // Write in the desktop.ini the cache folder class ID PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini")); // If the desktop.ini already exists, make sure it is writable if (PathFileExists(szDesktopIni)) SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL); // (First, flush the cache to make sure the desktop.ini // file is really created.) WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni); WritePrivateProfileString(TEXT(".ShellClassInfo"), bUICLSID ? TEXT("UICLSID") : TEXT("CLSID"), pszGUID, szDesktopIni); WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni); // Hide the desktop.ini since the shell does not selectively // hide it. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_HIDDEN); return NOERROR; } else { DebugMsg(DM_TRACE, TEXT("Cannot make %s a system folder"), pszPath); return E_FAIL; } } void CleanupShellFolder(LPCTSTR pszPath) { if (PathFileExists(pszPath)) { TCHAR szDesktopIni[MAX_PATH]; // make the history a normal folder SetFileAttributes(pszPath, FILE_ATTRIBUTE_NORMAL); PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini")); // If the desktop.ini already exists, make sure it is writable if (PathFileExists(szDesktopIni)) { SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL); DeleteFile(szDesktopIni); } // remove the history directory RemoveDirectory(pszPath); } } BOOL GetSubscriptionFolderPath(LPTSTR pszPath, DWORD cchPath) { DWORD dwDummy; HKEY hk; if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &hk, &dwDummy)) { DWORD cbData = cchPath * sizeof(TCHAR); if (ERROR_SUCCESS != SHRegGetValue(hk, NULL, REGSTR_VAL_DIRECTORY, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, pszPath, &cbData)) { TCHAR szWindows[MAX_PATH]; GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows)); PathCombine(pszPath, szWindows, TEXT("Offline Web Pages")); } RegCloseKey(hk); return TRUE; } return FALSE; } HRESULT GetChannelPath(LPCTSTR pszURL, LPTSTR pszPath, int cch, IChannelMgrPriv** ppIChannelMgrPriv) { ASSERT(pszURL); ASSERT(pszPath || 0 == cch); ASSERT(ppIChannelMgrPriv); HRESULT hr; BOOL bCoinit = FALSE; hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgrPriv, (void**)ppIChannelMgrPriv); if ((hr == CO_E_NOTINITIALIZED || hr == REGDB_E_IIDNOTREG) && SUCCEEDED(CoInitialize(NULL))) { bCoinit = TRUE; hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgrPriv, (void**)ppIChannelMgrPriv); } if (SUCCEEDED(hr)) { ASSERT(*ppIChannelMgrPriv); IChannelMgr* pIChannelMgr; hr = (*ppIChannelMgrPriv)->QueryInterface(IID_IChannelMgr, (void**)&pIChannelMgr); if (SUCCEEDED(hr)) { ASSERT(pIChannelMgr); WCHAR wszURL[INTERNET_MAX_URL_LENGTH]; MyStrToOleStrN(wszURL, ARRAYSIZE(wszURL), pszURL); IEnumChannels* pIEnumChannels; hr = pIChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH, wszURL, &pIEnumChannels); if (SUCCEEDED(hr)) { ASSERT(pIEnumChannels); CHANNELENUMINFO ci; if (S_OK == pIEnumChannels->Next(1, &ci, NULL)) { MyOleStrToStrN(pszPath, cch, ci.pszPath); CoTaskMemFree(ci.pszPath); } else { hr = E_FAIL; } pIEnumChannels->Release(); } pIChannelMgr->Release(); } } if (bCoinit) CoUninitialize(); ASSERT((SUCCEEDED(hr) && *ppIChannelMgrPriv) || FAILED(hr)); return hr; } // Caller is responsible for calling ILFree on *ppidl. HRESULT ConvertPathToPidl(LPCTSTR path, LPITEMIDLIST * ppidl) { WCHAR wszPath[MAX_PATH]; IShellFolder * pDesktopFolder; HRESULT hr; ASSERT(path && ppidl); * ppidl = NULL; MyStrToOleStrN(wszPath, MAX_PATH, path); hr = SHGetDesktopFolder(&pDesktopFolder); if (hr != NOERROR) return hr; ULONG uChEaten; hr = pDesktopFolder->ParseDisplayName(NULL, NULL, wszPath, &uChEaten, ppidl, NULL); SAFERELEASE(pDesktopFolder); return hr; } LPITEMIDLIST GetSubscriptionFolderPidl(void) { TCHAR szPath[MAX_PATH]; static LPITEMIDLIST pidlFolder = NULL; // We leak here. if (!pidlFolder) { if (!(GetSubscriptionFolderPath(szPath, ARRAYSIZE(szPath)))) return NULL; if (FAILED(ConvertPathToPidl(szPath, &pidlFolder))) return NULL; ASSERT(pidlFolder); } return (LPITEMIDLIST)pidlFolder; } STDAPI OfflineFolderRegisterServer(void) { TCHAR szOldSubscriptionPath[MAX_PATH]; GetWindowsDirectory(szOldSubscriptionPath, ARRAYSIZE(szOldSubscriptionPath)); PathCombine(szOldSubscriptionPath, szOldSubscriptionPath, TEXT("Subscriptions")); CleanupShellFolder(szOldSubscriptionPath); TCHAR szPath[MAX_PATH]; if (!(GetSubscriptionFolderPath(szPath, ARRAYSIZE(szPath)))) goto CleanUp; // we pass FALSE because history folder uses CLSID if (FAILED(CreateShellFolderPath(szPath, TEXT("{F5175861-2688-11d0-9C5E-00AA00A45957}"), FALSE))) goto CleanUp; return NOERROR; CleanUp: // cleanup stuff if any of our reg stuff fails return E_FAIL; } STDAPI OfflineFolderUnregisterServer(void) { TCHAR szPath[MAX_PATH]; if (!(GetSubscriptionFolderPath(szPath, ARRAYSIZE(szPath)))) goto CleanUp; // we pass FALSE because history folder uses CLSID CleanupShellFolder(szPath); return NOERROR; CleanUp: // cleanup stuff if any of our reg stuff fails return E_FAIL; } HMENU LoadPopupMenu(UINT id, UINT uSubOffset) { HMENU hmParent, hmPopup; hmParent = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(id)); if (!hmParent) return NULL; hmPopup = GetSubMenu(hmParent, uSubOffset); RemoveMenu(hmParent, uSubOffset, MF_BYPOSITION); DestroyMenu(hmParent); return hmPopup; } UINT MergePopupMenu(HMENU *phMenu, UINT idResource, UINT uSubOffset, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast) { HMENU hmMerge; if (*phMenu == NULL) { *phMenu = CreatePopupMenu(); if (*phMenu == NULL) return 0; indexMenu = 0; // at the bottom } hmMerge = LoadPopupMenu(idResource, uSubOffset); if (!hmMerge) return 0; idCmdLast = Shell_MergeMenus(*phMenu, hmMerge, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR); DestroyMenu(hmMerge); return idCmdLast; } HMENU GetMenuFromID(HMENU hmenu, UINT idm) { MENUITEMINFO mii = { sizeof(mii), MIIM_SUBMENU, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0 }; GetMenuItemInfo(hmenu, idm, FALSE, &mii); return mii.hSubMenu; } UINT MergeMenuHierarchy(HMENU hmenuDst, HMENU hmenuSrc, UINT idcMin, UINT idcMax, BOOL bTop) { UINT idcMaxUsed = idcMin; int imi = GetMenuItemCount(hmenuSrc); while (--imi >= 0) { MENUITEMINFO mii = { sizeof(MENUITEMINFO), MIIM_ID | MIIM_SUBMENU, 0,/* fType */ 0,/* fState */ 0,/*wId*/ NULL, NULL, NULL, 0, NULL, 0 }; if (GetMenuItemInfo(hmenuSrc, imi, TRUE, &mii)) { UINT idcT = Shell_MergeMenus( GetMenuFromID(hmenuDst, mii.wID), mii.hSubMenu, (bTop)?0:1024, idcMin, idcMax, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS); idcMaxUsed = max(idcMaxUsed, idcT); } } return idcMaxUsed; } /////////////////////////////////////////////////////////////////////////////// // // Helper Fuctions for item.cpp and folder.cpp // /////////////////////////////////////////////////////////////////////////////// int _CompareURL(LPMYPIDL pooi1, LPMYPIDL pooi2) { return UrlCompare(URL(&(pooi1->ooe)), URL(&(pooi2->ooe)), TRUE); } int _CompareShortName(LPMYPIDL pooi1, LPMYPIDL pooi2) { PCTSTR pszNameLocal1; PCTSTR pszNameLocal2; LPTSTR szNameUnaligned1 = NAME(&(pooi1->ooe)); LPTSTR szNameUnaligned2 = NAME(&(pooi2->ooe)); TSTR_ALIGNED_STACK_COPY( &pszNameLocal1, szNameUnaligned1 ); TSTR_ALIGNED_STACK_COPY( &pszNameLocal2, szNameUnaligned2 ); return StrCmp( pszNameLocal1, pszNameLocal2 ); } int _CompareLastUpdate(LPMYPIDL pooi1, LPMYPIDL pooi2) { if (pooi1->ooe.m_LastUpdated - pooi2->ooe.m_LastUpdated > 0) return 1; return -1; } int _CompareCookie(REFCLSID cookie1, REFCLSID cookie2) { return memcmp(&cookie1, &cookie2, sizeof(CLSID)); } int _CompareStatus(LPMYPIDL pooi1, LPMYPIDL pooi2) { return StrCmp(STATUS(&(pooi1->ooe)), STATUS(&(pooi2->ooe))); } int _CompareIdentities(LPMYPIDL pooi1, LPMYPIDL pooi2) { if (pooi1->ooe.clsidDest != pooi2->ooe.clsidDest) return -1; if (!IsNativeAgent(pooi1->ooe.clsidDest)) return _CompareCookie(pooi1->ooe.m_Cookie, pooi2->ooe.m_Cookie); return _CompareURL(pooi1, pooi2); } BOOL _ValidateIDListArray(UINT cidl, LPCITEMIDLIST *ppidl) { UINT i; for (i = 0; i < cidl; i++) { if (!IS_VALID_MYPIDL(ppidl[i])) return FALSE; } return TRUE; } int _LaunchApp(HWND hwnd, LPCTSTR pszPath) { SHELLEXECUTEINFO ei = { 0 }; ei.cbSize = sizeof(SHELLEXECUTEINFO); ei.hwnd = hwnd; ei.lpFile = pszPath; ei.nShow = SW_SHOWNORMAL; return ShellExecuteEx(&ei); } void _GenerateEvent(LONG lEventId, LPITEMIDLIST pidlIn, LPITEMIDLIST pidlNewIn, BOOL bRefresh) { LPITEMIDLIST pidlFolder = GetSubscriptionFolderPidl(); if (!pidlFolder) return; LPITEMIDLIST pidl = ILCombine(pidlFolder, pidlIn); if (pidl) { if (pidlNewIn) { LPITEMIDLIST pidlNew = ILCombine(pidlFolder, pidlNewIn); if (pidlNew) { SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, pidlNew); ILFree(pidlNew); } } else { SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, NULL); } if (bRefresh) SHChangeNotifyHandleEvents(); ILFree(pidl); } } BOOL _InitComCtl32() { static BOOL fInitialized = FALSE; if (!fInitialized) { INITCOMMONCONTROLSEX icc; icc.dwSize = sizeof(INITCOMMONCONTROLSEX); icc.dwICC = ICC_NATIVEFNTCTL_CLASS | ICC_DATE_CLASSES; fInitialized = InitCommonControlsEx(&icc); } return fInitialized; } const struct { LPCSTR pszVerb; UINT idCmd; } rgcmds[] = { { c_szOpen, RSVIDM_OPEN }, { c_szCopy, RSVIDM_COPY }, { c_szRename, RSVIDM_RENAME}, { c_szPaste, RSVIDM_PASTE}, { c_szDelete, RSVIDM_DELETE }, { c_szProperties, RSVIDM_PROPERTIES } }; int _GetCmdID(LPCSTR pszCmd) { if (HIWORD(pszCmd)) { int i; for (i = 0; i < ARRAYSIZE(rgcmds); i++) { if (lstrcmpiA(rgcmds[i].pszVerb, pszCmd) == 0) { return rgcmds[i].idCmd; } } return -1; // unknown } return (int)LOWORD(pszCmd); } BOOL CALLBACK _AddOnePropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam) { PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *) lParam; if (ppsh->nPages < MAX_PROP_PAGES) { ppsh->phpage[ppsh->nPages++] = hpage; return TRUE; } return FALSE; } HRESULT _CreatePropSheet(HWND hwnd, POOEBuf pBuf) { ASSERT(pBuf); ISubscriptionMgr * pSub= NULL; HRESULT hr = CoInitialize(NULL); RETURN_ON_FAILURE(hr); hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void **)&pSub); CoUninitialize(); RETURN_ON_FAILURE(hr); ASSERT(pSub); BSTR bstrURL = NULL; hr = CreateBSTRFromTSTR(&bstrURL, pBuf->m_URL); if (S_OK == hr) hr = pSub->ShowSubscriptionProperties(bstrURL, hwnd); SAFERELEASE(pSub); SAFEFREEBSTR(bstrURL); return hr; } // Note: // We return FALSE on illegal DATE data. BOOL DATE2DateTimeString(CFileTime& ft, LPTSTR pszText, int cchText) { SYSTEMTIME st; if (ft == 0) { if (szUnknown[0] == 0) MLLoadString(IDS_UNKNOWN, szUnknown, ARRAYSIZE(szUnknown)); StrCpyN(pszText, szUnknown, cchText); return FALSE; } if (!FileTimeToSystemTime(&ft, &st)) { if (szNone[0] == 0) MLLoadString(IDS_NONE, szNone, ARRAYSIZE(szNone)); StrCpyN(pszText, szNone, cchText); return FALSE; } GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszText, cchText); StrCatBuff(pszText, L" ", cchText); int nLen = lstrlen(pszText); if (nLen >= cchText) { return FALSE; } pszText += nLen; GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszText, cchText - nLen); return TRUE; } void CopyToOOEBuf(POOEntry pooe, POOEBuf pBuf) { ASSERT(pooe); ASSERT(pBuf); pBuf->dwFlags = pooe->dwFlags; pBuf->m_LastUpdated = pooe->m_LastUpdated; pBuf->m_NextUpdate = pooe->m_NextUpdate; pBuf->m_SizeLimit = pooe->m_SizeLimit; pBuf->m_ActualSize = pooe->m_ActualSize; pBuf->m_RecurseLevels = pooe->m_RecurseLevels; pBuf->m_RecurseFlags = pooe->m_RecurseFlags; pBuf->m_Priority = pooe->m_Priority; pBuf->bDesktop = pooe->bDesktop; pBuf->bChannel = pooe->bChannel; pBuf->bMail = pooe->bMail; pBuf->bGleam = pooe->bGleam; pBuf->bChangesOnly = pooe->bChangesOnly; pBuf->fChannelFlags = pooe->fChannelFlags; pBuf->bNeedPassword = pooe->bNeedPassword; pBuf->m_Cookie = pooe->m_Cookie; pBuf->groupCookie = pooe->groupCookie; pBuf->grfTaskTrigger = pooe->grfTaskTrigger; pBuf->m_Trigger = pooe->m_Trigger; pBuf->clsidDest = pooe->clsidDest; pBuf->status = pooe->status; StrCpyN(pBuf->m_URL, URL(pooe), ARRAYSIZE(pBuf->m_URL)); StrCpyN(pBuf->m_Name, NAME(pooe), ARRAYSIZE(pBuf->m_Name)); StrCpyN(pBuf->username, UNAME(pooe), ARRAYSIZE(pBuf->username)); StrCpyN(pBuf->password, PASSWD(pooe), ARRAYSIZE(pBuf->password)); StrCpyN(pBuf->statusStr, STATUS(pooe), ARRAYSIZE(pBuf->statusStr)); } void CopyToMyPooe(POOEBuf pBuf, POOEntry pooe) { UINT offset = sizeof(OOEntry); UINT srcLen = lstrlen(pBuf->m_URL) + 1; ASSERT(pooe); ASSERT(pBuf); pooe->dwFlags = pBuf->dwFlags; pooe->m_LastUpdated = pBuf->m_LastUpdated; pooe->m_NextUpdate = pBuf->m_NextUpdate; pooe->m_SizeLimit = pBuf->m_SizeLimit; pooe->m_ActualSize = pBuf->m_ActualSize; pooe->m_RecurseLevels = pBuf->m_RecurseLevels; pooe->m_Priority = pBuf->m_Priority; pooe->m_RecurseFlags = pBuf->m_RecurseFlags; pooe->bDesktop = pBuf->bDesktop; pooe->bChannel = pBuf->bChannel; pooe->bMail = pBuf->bMail; pooe->bGleam = pBuf->bGleam; pooe->bChangesOnly = pBuf->bChangesOnly; pooe->fChannelFlags = pBuf->fChannelFlags; pooe->bNeedPassword = pBuf->bNeedPassword; pooe->m_Cookie = pBuf->m_Cookie; pooe->groupCookie = pBuf->groupCookie; pooe->m_Trigger = pBuf->m_Trigger; pooe->grfTaskTrigger = pBuf->grfTaskTrigger; pooe->clsidDest = pBuf->clsidDest; pooe->status = pBuf->status; pooe->m_URL = (LPTSTR)((LPBYTE)pooe + offset); srcLen = lstrlen(pBuf->m_URL) + 1; StrCpyN(pooe->m_URL, pBuf->m_URL, srcLen); offset += srcLen * sizeof (TCHAR); pooe->m_URL = (LPTSTR) PtrDifference(pooe->m_URL, pooe); pooe->m_Name = (LPTSTR)((LPBYTE)pooe + offset); srcLen = lstrlen(pBuf->m_Name) + 1; StrCpyN(pooe->m_Name, pBuf->m_Name, srcLen); offset += srcLen * sizeof (TCHAR); pooe->m_Name = (LPTSTR) PtrDifference(pooe->m_Name, pooe); pooe->username = (LPTSTR)((LPBYTE)pooe + offset); srcLen = lstrlen(pBuf->username) + 1; StrCpyN(pooe->username, pBuf->username, srcLen); offset += srcLen * sizeof (TCHAR); pooe->username = (LPTSTR) PtrDifference(pooe->username, pooe); pooe->password = (LPTSTR)((LPBYTE)pooe + offset); srcLen = lstrlen(pBuf->password) + 1; StrCpyN(pooe->password, pBuf->password, srcLen); offset += srcLen * sizeof (TCHAR); pooe->password = (LPTSTR) PtrDifference(pooe->password, pooe); pooe->statusStr = (LPTSTR)((LPBYTE)pooe + offset); srcLen = lstrlen(pBuf->statusStr) + 1; StrCpyN(pooe->statusStr, pBuf->statusStr, srcLen); offset += srcLen * sizeof (TCHAR); pooe->statusStr = (LPTSTR) PtrDifference(pooe->statusStr, pooe); pooe->dwSize = offset; } UINT BufferSize(POOEBuf pBuf) { UINT strLen = 0; ASSERT(pBuf); strLen += lstrlen(pBuf->m_URL) + 1; strLen += lstrlen(pBuf->m_Name) + 1; strLen += lstrlen(pBuf->username) + 1; strLen += lstrlen(pBuf->password) + 1; strLen += lstrlen(pBuf->statusStr) + 1; return strLen * sizeof(TCHAR); } typedef struct { int cItems; LPCTSTR pszName; LPCTSTR pszUrl; } DELETE_CONFIRM_INFO; INT_PTR CALLBACK ConfirmDeleteDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: { DELETE_CONFIRM_INFO* pInfo = (DELETE_CONFIRM_INFO*)lParam; ASSERT (pInfo); ASSERT(pInfo->cItems == 1); SetListViewToString (GetDlgItem (hDlg, IDC_NAME), pInfo->pszName); SetListViewToString (GetDlgItem (hDlg, IDC_LOCATION), pInfo->pszUrl); } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDYES: case IDNO: case IDCANCEL: EndDialog(hDlg, wParam); break; } break; case WM_NOTIFY: if (LOWORD(wParam) == IDC_LOCATION) { NM_LISTVIEW * pnmlv = (NM_LISTVIEW *)lParam; ASSERT(pnmlv); if (pnmlv->hdr.code == LVN_GETINFOTIP) { TCHAR szURL[MAX_URL]; LV_ITEM lvi = {0}; lvi.mask = LVIF_TEXT; lvi.pszText = szURL; lvi.cchTextMax = ARRAYSIZE(szURL); if (!ListView_GetItem (GetDlgItem (hDlg, IDC_LOCATION), &lvi)) return FALSE; NMLVGETINFOTIP * pTip = (NMLVGETINFOTIP *)pnmlv; ASSERT(pTip->pszText); StrCpyN(pTip->pszText, szURL, pTip->cchTextMax); return TRUE; } } return FALSE; default: return FALSE; } // end of switch return TRUE; } BOOL ConfirmDelete(HWND hwnd, UINT cItems, LPMYPIDL * ppidl) { ASSERT(ppidl); INT_PTR iRet; // Check if the user is restricted from deleting URLs. // If they're deleting multiple, we'll fail if any can fail. UINT i; for (i = 0; i < cItems; i++) { if (ppidl[i]->ooe.bChannel) { if (SHRestricted2(REST_NoRemovingChannels, URL(&(ppidl[i]->ooe)), 0)) { if (IsWindow(hwnd)) SGMessageBox(hwnd, IDS_RESTRICTED, MB_OK); return FALSE; } } if (!ppidl[i]->ooe.bDesktop) { // FEATURE: What about desktop components? if (SHRestricted2(REST_NoRemovingSubscriptions, URL(&(ppidl[i]->ooe)), 0)) { if (IsWindow(hwnd)) SGMessageBox(hwnd, IDS_RESTRICTED, MB_OK); return FALSE; } } } if (IsWindow(hwnd)) { DELETE_CONFIRM_INFO dci = {0}; dci.cItems = cItems; if (cItems == 1) { dci.pszName = NAME(&(ppidl[0]->ooe)); dci.pszUrl = URL(&(ppidl[0]->ooe)); iRet = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_OBJECTDEL_WARNING), hwnd, ConfirmDeleteDlgProc, (LPARAM)&dci); } else { TCHAR szFormat[200]; // Enough room for format string and int as string TCHAR szBuf[ARRAYSIZE(szFormat) + 11]; MLLoadString(IDS_DEL_MULTIPLE_FMT, szFormat, ARRAYSIZE(szFormat)); wnsprintf(szBuf, ARRAYSIZE(szBuf), szFormat, cItems); MLLoadString(IDS_DELETE_CAPTION, szFormat, ARRAYSIZE(szFormat)); MSGBOXPARAMS mbp; mbp.cbSize = sizeof(MSGBOXPARAMS); mbp.hwndOwner = hwnd; mbp.hInstance = MLGetHinst(); mbp.lpszText = szBuf; mbp.lpszCaption = szFormat; mbp.dwStyle = MB_YESNO | MB_USERICON; mbp.lpszIcon = MAKEINTRESOURCE(IDI_OBJECTDELETED); iRet = MessageBoxIndirect(&mbp); } if (iRet == IDYES) return TRUE; return FALSE; } else { return TRUE; } } BOOL IsHTTPPrefixed(LPCTSTR szURL) { TCHAR szCanonicalURL[MAX_URL]; DWORD dwSize = MAX_URL; URL_COMPONENTS uc; memset(&uc, 0, sizeof(URL_COMPONENTS)); uc.dwStructSize = sizeof(URL_COMPONENTS); // Note: We explicitly check for and allow the "about:home" URL to pass through here. This allows // the Active Desktop "My Current Home Page" component to specify that URL when creating and managing // it's subscription which is consistent with it's use of that form in the browser. if (!InternetCanonicalizeUrl(szURL, szCanonicalURL, &dwSize, ICU_DECODE) || !InternetCrackUrl(szCanonicalURL, 0, 0, &uc) || ((INTERNET_SCHEME_HTTP != uc.nScheme) && (INTERNET_SCHEME_HTTPS != uc.nScheme) && (0 != StrCmpI(TEXT("about:home"), szURL)))) { return FALSE; } return TRUE; } // Checks if global state is offline BOOL IsGlobalOffline(void) { DWORD dwState = 0, dwSize = sizeof(DWORD); BOOL fRet = FALSE; HANDLE hModuleHandle = LoadLibraryA("wininet.dll"); if(!hModuleHandle) return FALSE; if(InternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize)) { if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER) fRet = TRUE; } return fRet; } void SetGlobalOffline(BOOL fOffline) { INTERNET_CONNECTED_INFO ci; memset(&ci, 0, sizeof(ci)); if(fOffline) { ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER; ci.dwFlags = ISO_FORCE_DISCONNECTED; } else { ci.dwConnectedState = INTERNET_STATE_CONNECTED; } InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci)); } //helper function to create one column in a ListView control, add one item to that column, //size the column to the width of the control, and color the control like a static... //basically, like SetWindowText for a ListView. Because we use a lot of ListViews to display //urls that would otherwise be truncated... the ListView gives us automatic ellipsis and ToolTip. void SetListViewToString (HWND hLV, LPCTSTR pszString) { ASSERT(hLV); LV_COLUMN lvc = {0}; RECT lvRect; GetClientRect (hLV, &lvRect); lvc.mask = LVCF_WIDTH; lvc.cx = lvRect.right - lvRect.left; if (-1 == ListView_InsertColumn(hLV, 0, &lvc)) { ASSERT(0); } SendMessage(hLV, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_INFOTIP, LVS_EX_INFOTIP); LV_ITEM lvi = {0}; lvi.iSubItem = 0; lvi.pszText = (LPTSTR)pszString; lvi.mask = LVIF_TEXT; ListView_InsertItem(hLV, &lvi); ListView_EnsureVisible(hLV, 0, TRUE); ListView_SetBkColor(hLV, GetSysColor(COLOR_BTNFACE)); ListView_SetTextBkColor(hLV, GetSysColor(COLOR_BTNFACE)); } int WCMessageBox(HWND hwnd, UINT idTextFmt, UINT idCaption, UINT uType, ...) { TCHAR szCaption[256]; TCHAR szTextFmt[512]; LPTSTR pszText; int result; va_list va; va_start(va, uType); szCaption[0] = 0; MLLoadString(idTextFmt, szTextFmt, ARRAYSIZE(szTextFmt)); if (idCaption <= 0) { if (NULL != hwnd) { GetWindowText(hwnd, szCaption, ARRAYSIZE(szCaption)); } // This handles GetWindowText failure and a NULL hwnd if (0 == szCaption[0]) { #if IDS_DEFAULT_MSG_CAPTION < 1 #error IDS_DEFAULT_MSG_CAPTION is defined incorrectly #endif idCaption = IDS_DEFAULT_MSG_CAPTION; } } if (idCaption > 0) { MLLoadString(idCaption, szCaption, ARRAYSIZE(szCaption)); } ASSERT(0 != szCaption[0]); if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, szTextFmt, 0, 0, (LPTSTR)&pszText, 0, &va)) { result = MessageBox(hwnd, pszText, szCaption, uType); LocalFree(pszText); } else { // FormatMessage failed. Oh well. Guess we'll just ask the question // with the format string. Sure it's ugly but it's better than picking a // totally random return value. result = MessageBox(hwnd, szTextFmt, szCaption, uType); } return result; } ///////////////////////////////////////////////////////////////////////////// // SGMessageBox ///////////////////////////////////////////////////////////////////////////// int SGMessageBox ( HWND hwndParent, UINT idStringRes, UINT uType ) { ASSERT(hwndParent != NULL); ASSERT(IsWindow(hwndParent)); TCHAR szError[512]; if (!MLLoadString(idStringRes, szError, ARRAYSIZE(szError))) return 0; TCHAR szTitle[128]; szTitle[0] = 0; if (hwndParent != NULL) GetWindowText(hwndParent, szTitle, ARRAYSIZE(szTitle)); return MessageBox( hwndParent, szError, ((hwndParent != NULL) ? szTitle : NULL), uType); } #ifdef DEBUG ///////////////////////////////////////////////////////////////////////////// // DumpTaskTrigger ///////////////////////////////////////////////////////////////////////////// void DumpTaskTrigger ( TASK_TRIGGER * pTT ) { TraceMsg(TF_DUMPTRIGGER, "----- BEGIN DumpTaskTrigger -----"); TraceMsg(TF_DUMPTRIGGER, "cbTriggerSize = %d", pTT->cbTriggerSize); TraceMsg(TF_DUMPTRIGGER, "Reserved1 = %d", pTT->Reserved1); TraceMsg(TF_DUMPTRIGGER, "wBeginYear = %d", pTT->wBeginYear); TraceMsg(TF_DUMPTRIGGER, "wBeginMonth = %d", pTT->wBeginMonth); TraceMsg(TF_DUMPTRIGGER, "wBeginDay = %d", pTT->wBeginDay); TraceMsg(TF_DUMPTRIGGER, "wEndYear = %d", pTT->wEndYear); TraceMsg(TF_DUMPTRIGGER, "wEndMonth = %d", pTT->wEndMonth); TraceMsg(TF_DUMPTRIGGER, "wEndDay = %d", pTT->wEndDay); TraceMsg(TF_DUMPTRIGGER, "wStartHour = %d", pTT->wStartHour); TraceMsg(TF_DUMPTRIGGER, "wStartMinute = %d", pTT->wStartMinute); TraceMsg(TF_DUMPTRIGGER, "MinutesDuration = %d", pTT->MinutesDuration); TraceMsg(TF_DUMPTRIGGER, "MinutesInterval = %d", pTT->MinutesInterval); TraceMsg(TF_DUMPTRIGGER, "rgFlags = %d", pTT->rgFlags); TraceMsg(TF_DUMPTRIGGER, "Reserved2 = %d", pTT->Reserved2); TraceMsg(TF_DUMPTRIGGER, "wRandomMinutesInterval = %d", pTT->wRandomMinutesInterval); switch (pTT->TriggerType) { case TASK_TIME_TRIGGER_DAILY: { TraceMsg(TF_DUMPTRIGGER, "DAILY"); TraceMsg(TF_DUMPTRIGGER, "DaysInterval = %d", pTT->Type.Daily.DaysInterval); break; } case TASK_TIME_TRIGGER_WEEKLY: { TraceMsg(TF_DUMPTRIGGER, "WEEKLY"); TraceMsg(TF_DUMPTRIGGER, "WeeksInterval = %d", pTT->Type.Weekly.WeeksInterval); TraceMsg(TF_DUMPTRIGGER, "rgfDaysOfTheWeek = %d", pTT->Type.Weekly.rgfDaysOfTheWeek); break; } case TASK_TIME_TRIGGER_MONTHLYDATE: { TraceMsg(TF_DUMPTRIGGER, "MONTHLY DATE"); TraceMsg(TF_DUMPTRIGGER, "rgfDays = %d", pTT->Type.MonthlyDate.rgfDays); TraceMsg(TF_DUMPTRIGGER, "rgfMonths = %d", pTT->Type.MonthlyDate.rgfMonths); break; } case TASK_TIME_TRIGGER_MONTHLYDOW: { TraceMsg(TF_DUMPTRIGGER, "MONTHLY DOW"); TraceMsg(TF_DUMPTRIGGER, "wWhichWeek = %d", pTT->Type.MonthlyDOW.wWhichWeek); TraceMsg(TF_DUMPTRIGGER, "rgfDaysOfTheWeek = %d", pTT->Type.MonthlyDOW.rgfDaysOfTheWeek); TraceMsg(TF_DUMPTRIGGER, "rgfMonths = %d", pTT->Type.MonthlyDOW.rgfMonths); break; } default: { ASSERT(FALSE); break; } } TraceMsg(TF_DUMPTRIGGER, "----- END DumpTaskTrigger -----"); } #endif // DEBUG