1373 lines
38 KiB
C++
1373 lines
38 KiB
C++
|
#include "private.h"
|
||
|
#include "chanmgr.h"
|
||
|
#include "chanmgrp.h"
|
||
|
#include "shguidp.h"
|
||
|
#include "resource.h"
|
||
|
#define DECL_CRTFREE
|
||
|
#include <crtfree.h>
|
||
|
|
||
|
|
||
|
#include <mluisupp.h>
|
||
|
|
||
|
#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 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
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;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
void FileTimeToVariantTime(FILETIME& ft, double *pdt)
|
||
|
{
|
||
|
SYSTEMTIME st;
|
||
|
|
||
|
FileTimeToSystemTime(&ft, &st);
|
||
|
SystemTimeToVariantTime(&st, pdt);
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// 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)
|
||
|
{
|
||
|
long lResult;
|
||
|
HKEY hkey;
|
||
|
DWORD dwType;
|
||
|
|
||
|
lResult = RegOpenKey(hkeyRoot, pszKey, &hkey);
|
||
|
if (lResult != ERROR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
lResult = RegQueryValueEx(hkey, pszValue, NULL, &dwType, (BYTE *)pData,
|
||
|
&dwBytes);
|
||
|
RegCloseKey(hkey);
|
||
|
|
||
|
if (lResult != ERROR_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
if(dwType == REG_SZ) {
|
||
|
// null terminate string
|
||
|
((TCHAR *)pData)[dwBytes] = 0;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
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 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 = MAX_PATH * sizeof(TCHAR);
|
||
|
if (ERROR_SUCCESS != RegQueryValueEx(hk, REGSTR_VAL_DIRECTORY , NULL, NULL, (LPBYTE)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)))
|
||
|
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)))
|
||
|
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)))
|
||
|
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)
|
||
|
{
|
||
|
SYSTEMTIME st;
|
||
|
|
||
|
if (ft == 0) {
|
||
|
if (szUnknown[0] == 0)
|
||
|
MLLoadString(IDS_UNKNOWN, szUnknown, ARRAYSIZE(szUnknown));
|
||
|
|
||
|
StrCpy(pszText, szUnknown);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!FileTimeToSystemTime(&ft, &st))
|
||
|
{
|
||
|
if (szNone[0] == 0)
|
||
|
MLLoadString(IDS_NONE, szNone, ARRAYSIZE(szNone));
|
||
|
|
||
|
StrCpy(pszText, szNone);
|
||
|
return FALSE;
|
||
|
}
|
||
|
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszText, 64);
|
||
|
pszText += lstrlen(pszText);
|
||
|
*pszText++ = ' ';
|
||
|
GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszText, 64);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL Date2LocalDateString(SYSTEMTIME * st, LPTSTR dtStr, int size)
|
||
|
{
|
||
|
ASSERT(dtStr);
|
||
|
|
||
|
return GetDateFormat(LOCALE_USER_DEFAULT, 0, st, NULL, dtStr, size);
|
||
|
}
|
||
|
|
||
|
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), MAX_URL);
|
||
|
StrCpyN(pBuf->m_Name, NAME(pooe), MAX_NAME);
|
||
|
StrCpyN(pBuf->username, UNAME(pooe), MAX_USERNAME);
|
||
|
StrCpyN(pBuf->password, PASSWD(pooe), MAX_PASSWORD);
|
||
|
StrCpyN(pBuf->statusStr, STATUS(pooe), MAX_STATUS);
|
||
|
}
|
||
|
|
||
|
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]);
|
||
|
|
||
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
||
|
szTextFmt, 0, 0, (LPTSTR)&pszText, 0, &va);
|
||
|
|
||
|
result = MessageBox(hwnd, pszText, szCaption, uType);
|
||
|
|
||
|
LocalFree(pszText);
|
||
|
|
||
|
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
|