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

2029 lines
74 KiB
C++

#include "priv.h"
#include <mstask.h>
#include "favorite.h"
#include "iehelpid.h"
#ifdef UNIX
#include "subsmgr.h"
#else
#include "webcheck.h"
#endif
#include "chanmgr.h"
#include "chanmgrp.h"
#include "resource.h"
#include <platform.h>
#include <mobsync.h>
#include <mobsyncp.h>
#include <mluisupp.h>
#ifdef UNIX
#include "unixstuff.h"
#include "shalias.h"
#endif
UINT IE_ErrorMsgBox(IShellBrowser* psb,
HWND hwndOwner, HRESULT hrError, LPCWSTR szError, LPCTSTR pszURLparam,
UINT idResource, UINT wFlags);
void ReplaceTransplacedControls (HWND hDlgMaster, HWND hDlgTemplate);
///////////////////////////////////////////////////////////////////////
// helper function for DoOrganizeFavDlgEx
// the org favs dialog returns a list of null terminated strings containing
// all the urls to update.
void OrgFavSynchronize(HWND hwnd, VARIANT *pvarUrlsToSynch)
{
#ifndef DISABLE_SUBSCRIPTIONS
ASSERT(pvarUrlsToSynch);
//if there are no urls to update, it's an empty string so bail
if ( (pvarUrlsToSynch->vt == VT_BSTR) && (pvarUrlsToSynch->bstrVal) &&
*(pvarUrlsToSynch->bstrVal) )
{
PWSTR pwzUrls = pvarUrlsToSynch->bstrVal;
ISubscriptionMgr *psm;
if (SUCCEEDED(JITCoCreateInstance(CLSID_SubscriptionMgr, NULL,
CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
(void**)&psm, hwnd, FIEF_FLAG_FORCE_JITUI)))
{
//SysStringLen doesn't look at the string contents, just the cb of the alloc
while (pwzUrls < (pvarUrlsToSynch->bstrVal + SysStringLen(pvarUrlsToSynch->bstrVal)))
{
psm->UpdateSubscription(pwzUrls);
pwzUrls += lstrlenW(pwzUrls) + 1;
}
psm->Release();
}
}
#endif /* !DISABLE_SUBSCRIPTIONS */
}
/*
* DoOrganizeFavDlgEx
*
* HWND hwnd Owner window for the dialog.
* LPWSTR pszInitDir Dir to use as root. if null, the user's favorites dir is used.
*
* Returns:
* BOOL. TRUE if succeeds. FALSE otherwise.
*
*/
BOOL WINAPI DoOrganizeFavDlgEx(HWND hwnd, LPWSTR pszInitDir)
{
// The easy answer would be to add an about:OrganizeFavorites that
// gets registered in our selfreg.inx file. Unfortunately, multilanguage
// support requires us to generate the URL on the fly.
WCHAR wszUrl[6 + MAX_PATH + 11 + 1]; // "res://MAX_PATH/orgfav.dlg"
StrCpyNW(wszUrl, L"res://", 7);
#ifndef UNIX
GetModuleFileNameWrapW(MLGetHinst(), wszUrl+6, MAX_PATH);
#else
// IEUNIX : GetModuleFilename returns /vobs/...../libbrowseui.so
// We need actual dllname here.
StrCpyNW(wszUrl + 6, L"shdocvw.dll" , 12);
#endif
StrCatW(wszUrl, L"/orgfav.dlg");
IMoniker *pmk;
if (SUCCEEDED(CreateURLMoniker(NULL, wszUrl, &pmk)))
{
ASSERT(pmk);
VARIANT varUrlsToSynch, varInitialDir;
BSTR bstrInitDir;
VariantInit(&varUrlsToSynch);
VariantInit(&varInitialDir);
if (pszInitDir)
{
bstrInitDir = SysAllocString(pszInitDir);
if (bstrInitDir)
{
varInitialDir.vt = VT_BSTR;
varInitialDir.bstrVal = bstrInitDir;
}
}
ShowHTMLDialog(hwnd, pmk, &varInitialDir, L"Resizable=1", &varUrlsToSynch);
OrgFavSynchronize(hwnd, &varUrlsToSynch);
if (pszInitDir && bstrInitDir)
SysFreeString(bstrInitDir);
VariantClear(&varUrlsToSynch);
pmk->Release();
return TRUE;
}
else
return FALSE;
}
/*
* DoOrganizeFavDlg
*
* This API is exported so that it may be called by explorer and mshtml in
* addition to being called internally by shdocvw.
*
* HWND hwndOwner Owner window for the dialog.
* LPWSTR pszInitDir Dir to use as root. if null, the user's favorites dir is used.
*
* Returns:
* BOOL. TRUE if succeeds. FALSE otherwise.
*
*/
BOOL WINAPI DoOrganizeFavDlg(HWND hwnd, LPSTR pszInitDir)
{
BOOL fRet;
WCHAR szInitDir[MAX_PATH];
if (pszInitDir)
{
SHAnsiToUnicode(pszInitDir, szInitDir, ARRAYSIZE(szInitDir));
fRet = DoOrganizeFavDlgEx(hwnd, szInitDir);
}
else
{
fRet = DoOrganizeFavDlgEx(hwnd, NULL);
}
return fRet;
}
BOOL WINAPI DoOrganizeFavDlgW(HWND hwnd, LPWSTR pszInitDir)
{
return DoOrganizeFavDlgEx(hwnd, pszInitDir);
}
#define ADDTOFAVPROP TEXT("SHDOC_ATFPROP")
typedef enum { ATF_FAVORITE,
ATF_CHANNEL,
ATF_CHANNEL_MODIFY,
ATF_CHANNEL_SOFTDIST
} FAVDLGTYPE;
typedef struct _ADDTOFAV
{
PTSTR pszInitDir;
UINT cchInitDir;
PTSTR pszFile;
UINT cchFile;
LPITEMIDLIST pidl;
LPITEMIDLIST pidlSelected;
LPCITEMIDLIST pidlFavorite;
FAVDLGTYPE iDlgType;
SUBSCRIPTIONINFO siSubsInProg;
SUBSCRIPTIONTYPE subsType;
BOOL bIsSoftdist;
BOOL bStartSubscribed;
BOOL bSubscribed;
} ADDTOFAV;
BOOL IsSubscribed(ADDTOFAV *patf);
typedef struct _BFFFavSubStruct
{
WNDPROC lpfnOldWndProc;
HWND hwndNew;
HWND hwndTV;
HWND hwndSave;
HWND hTemplateWnd;
ADDTOFAV * patf;
RECT rcRestored;
} BFFFAVSUBSTRUCT;
BOOL_PTR CALLBACK NewFavDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND hwnd;
ASSERT(lParam);
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
// cross-lang platform support
SHSetDefaultDialogFont(hDlg, IDD_NAME);
hwnd = GetDlgItem(hDlg, IDD_NAME);
#ifndef UNIX
SendMessage(hwnd, EM_LIMITTEXT, MAX_PATH - 1, 0);
#else
// IEUNIX : file/dir name on unix is limited to _MAX_FNAME.
SendMessage(hwnd, EM_LIMITTEXT, (WPARAM)(_MAX_FNAME - 1), (LPARAM)0);
#endif
EnableOKButtonFromID(hDlg, IDD_NAME);
break;
}
case WM_DESTROY:
SHRemoveDefaultDialogFont(hDlg);
return FALSE;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDD_NAME:
{
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE)
{
LPTSTR lpstrName = (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER);
EnableOKButtonFromID(hDlg, IDD_NAME);
GetDlgItemText(hDlg, IDD_NAME, lpstrName, MAX_PATH);
}
break;
}
case IDOK:
{
TCHAR szTmp[MAX_PATH];
StrCpyN(szTmp, (LPTSTR)GetWindowLongPtr(hDlg, DWLP_USER), ARRAYSIZE(szTmp));
if (PathCleanupSpec(NULL,szTmp))
{
HWND hwnd;
MLShellMessageBox(
hDlg,
MAKEINTRESOURCE(IDS_FAVS_INVALIDFN),
MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
MB_OK | MB_ICONHAND);
hwnd = GetDlgItem(hDlg, IDD_NAME);
SetWindowText(hwnd, TEXT('\0'));
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
SetFocus(hwnd);
break;
}
}
// fall through
case IDCANCEL:
EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
// BOGUS - these id's stolen from SHBrowseForFolder implementation
#define IDD_FOLDERLIST 0x3741
#define IDD_BROWSETITLE 0x3742
#define IDD_BROWSESTATUS 0x3743
const static DWORD aAddToFavHelpIDs[] = { // Context Help IDs
IDC_FAVORITE_DESC, NO_HELP,
IDD_BROWSETITLE, NO_HELP,
IDD_BROWSESTATUS, NO_HELP,
IDC_FAVORITE_ICON, NO_HELP,
IDC_NAMESTATIC, IDH_NAMEEDIT,
IDC_FOLDERLISTSTATIC, IDH_BROWSELIST,
IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER, IDH_BROWSELIST,
IDC_FAVORITE_NEWFOLDER, IDH_CREATEIN,
IDC_SUBSCRIBE_CUSTOMIZE, IDH_CHANNEL_SUBSCR_CUST_BUTTON,
IDC_FAVORITE_CREATEIN, IDH_NEWFOLDER,
IDC_FAVORITE_NAME, IDH_NAMEEDIT,
IDC_MAKE_OFFLINE, IDH_MAKE_AVAIL_OFFLINE,
0, 0
};
const static DWORD aAddToChanHelpIDs[] = { // Context Help IDs
IDC_FAVORITE_DESC, NO_HELP,
IDD_BROWSETITLE, NO_HELP,
IDD_BROWSESTATUS, NO_HELP,
IDC_FAVORITE_ICON, NO_HELP,
IDC_NAMESTATIC, IDH_NAMEEDIT,
IDC_FOLDERLISTSTATIC, IDH_BROWSELIST,
IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER, IDH_BROWSELIST,
IDC_FAVORITE_NEWFOLDER, IDH_CREATEIN,
IDC_SUBSCRIBE_CUSTOMIZE, IDH_CHANNEL_SUBSCR_CUST_BUTTON,
IDC_FAVORITE_CREATEIN, IDH_NEWFOLDER,
IDC_FAVORITE_NAME, IDH_NAMEEDIT,
IDC_MAKE_OFFLINE, IDH_MAKE_AVAIL_OFFLINE,
0, 0
};
/*
* Makes sure the item being added to favorites doesn't already exist. If it does,
* puts up a message box to have the user confirm whether they want to overwrite
* the old favorite or not.
*/
BOOL ConfirmAddToFavorites(HWND hwndOwner, ADDTOFAV * patf)
{
BOOL fRet = FALSE;
BOOL fExists;
int iPromptString = 0;
if (patf->subsType == SUBSTYPE_CHANNEL)
{
//patf->pszInitDir now contains the path with a .url on the end; the channel
//will be stored in a directory of that name without .url. Strip it.
TCHAR szPath[MAX_PATH];
StrCpyN(szPath, patf->pszInitDir, ARRAYSIZE(szPath));
PathRemoveExtension (szPath);
fExists = PathFileExists(szPath);
iPromptString = IDS_CHANNELS_FILEEXISTS;
}
else
{
fExists = PathFileExists(patf->pszInitDir);
iPromptString = IDS_FAVS_FILEEXISTS;
}
fRet = ! fExists ||
(MLShellMessageBox(
hwndOwner,
MAKEINTRESOURCE(iPromptString),
NULL, //use owner's title
MB_ICONQUESTION | MB_YESNO) == IDYES);
return fRet;
}
//
// Get the localized date and time
//
typedef HRESULT (*PFVARIANTTIMETOSYSTEMTIME)(DOUBLE, LPSYSTEMTIME);
//
// Subscribe to the current site.
//
HRESULT SubscribeToSite(HWND hwnd, LPCTSTR pszFile, LPCITEMIDLIST pidl, DWORD dwFlags,
SUBSCRIPTIONINFO* pSubs, SUBSCRIPTIONTYPE subsType)
{
#ifndef DISABLE_SUBSCRIPTIONS
TCHAR szURL[MAX_URL_STRING];
ISubscriptionMgr *pISubscriptionMgr;
//
// Get a displayable URL.
//
IEGetDisplayName(pidl, szURL, SHGDN_FORPARSING);
//
// Get a pointer to the subscription manager.
//
HRESULT hr = JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr,
(void**)&pISubscriptionMgr, hwnd, FIEF_FLAG_FORCE_JITUI);
if (SUCCEEDED(hr))
{
//
// Create a default subscription.
//
BSTR bstrURL = SysAllocStringT(szURL);
if (bstrURL)
{
BSTR bstrName = SysAllocStringT(pszFile);
if (bstrName)
{
hr = pISubscriptionMgr->CreateSubscription(hwnd,
bstrURL, bstrName, dwFlags, subsType, pSubs);
SysFreeString(bstrName);
}
SysFreeString(bstrURL);
}
//
// Clean up.
//
pISubscriptionMgr->Release();
}
return hr;
#else /* !DISABLE_SUBSCRIPTIONS */
return E_FAIL;
#endif /* !DISABLE_SUBSCRIPTIONS */
}
//
// Create in-memory subscription, but only optionally save it to subscription manager
//
BOOL StartSiteSubscription (HWND hwnd, ADDTOFAV* patf, BOOL bFinalize)
{
#ifndef DISABLE_SUBCRIPTIONS
//update the changes-only flag (radio buttons here are, effectively, direct access to this flag)
if (patf->subsType == SUBSTYPE_CHANNEL || patf->subsType == SUBSTYPE_DESKTOPCHANNEL)
{
//if set, leave alone; otherwise, put to full download
if (!(patf->siSubsInProg.fChannelFlags & CHANNEL_AGENT_PRECACHE_SOME))
patf->siSubsInProg.fChannelFlags |= CHANNEL_AGENT_PRECACHE_ALL;
patf->siSubsInProg.fUpdateFlags |= SUBSINFO_CHANNELFLAGS | SUBSINFO_SCHEDULE;
}
if (S_OK != SubscribeToSite(hwnd, patf->pszFile, patf->pidlFavorite,
bFinalize ? CREATESUBS_NOUI | CREATESUBS_FROMFAVORITES : CREATESUBS_NOSAVE,
&patf->siSubsInProg, patf->subsType))
{
return FALSE;
}
return TRUE;
#else /* !DISABLE_SUBSCRIPTIONS */
return FALSE;
#endif /* !DISABLE_SUBSCRIPTIONS */
}
/*
Combines the path and the filename of the favorite
and puts it into patf->pszInitDir, so that it has the fully qualified pathname.
*/
#define SZ_URLEXT TEXT(".url")
#define CCH_URLEXT SIZECHARS(SZ_URLEXT)
BOOL QualifyFileName(ADDTOFAV *patf)
{
TCHAR szTemp[MAX_PATH];
BOOL fRet = FALSE;
LPTSTR pstr;
// Can we safely add the extension to this?
if (lstrlen(patf->pszFile) < (int)(patf->cchFile - CCH_URLEXT))
{
//Add extension .url if its not already there
//This is to prevent strings like "com" in "www.microsoft.com" from being interpreted as extensions
pstr = PathFindExtension(patf->pszFile);
if (!pstr || (pstr && StrCmpI(pstr, SZ_URLEXT)))// && StrCmpI(pstr, SZ_CDFEXT)))
StrCatBuff(patf->pszFile, SZ_URLEXT, patf->cchFile);
// Is there a folder associated with the filename?
if (patf->pidlSelected && SHGetPathFromIDList(patf->pidlSelected, szTemp))
{
// Yes
if (PathCombine(szTemp, szTemp, patf->pszFile))
{
if ((UINT)lstrlen(szTemp) < patf->cchInitDir)
{
StrCpyN(patf->pszInitDir, szTemp, patf->cchInitDir);
fRet = TRUE;
}
}
}
}
return fRet;
}
BOOL SubscriptionFailsChannelAuthentication (HWND hDlg, SUBSCRIPTIONINFO* psi)
{
#ifndef DISABLE_SUBSCRIPTIONS
if (psi->bNeedPassword && !(psi->bstrPassword && psi->bstrPassword[0]
&& psi->bstrUserName && psi->bstrUserName[0]))
{ //password would be required
if (IsDlgButtonChecked (hDlg, IDC_MAKE_OFFLINE))
{ //they're trying to subscribe... WRONG!
MLShellMessageBox(
hDlg,
MAKEINTRESOURCE(IDS_NEED_CHANNEL_PASSWORD),
NULL,
MB_ICONINFORMATION | MB_OK);
return TRUE;
}
}
return FALSE;
#else /* !DISABLE_SUBSCRIPTIONS */
return FALSE;
#endif /* !DISABLE_SUBSCRIPTIONS */
}
LRESULT CALLBACK BFFFavSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BFFFAVSUBSTRUCT * pbffFS = (BFFFAVSUBSTRUCT *)GetProp(hwnd, ADDTOFAVPROP);
WNDPROC lpfnOldWndProc = pbffFS->lpfnOldWndProc;
RECT rc;
switch (uMsg) {
case WM_COMMAND:
// Intercept the command for the New Folder button we hacked into
// the SHBrowseForFolder dialog.
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDC_FAVORITE_NAME:
{
HWND hwndedit;
if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
EnableOKButtonFromID(hwnd, IDC_FAVORITE_NAME);
hwndedit = GetDlgItem(hwnd, IDC_FAVORITE_NAME);
SendMessage(hwndedit, EM_LIMITTEXT, MAX_PATH - 1, 0);
break;
}
#ifndef UNIX
// IEUNIX (OFFLINE) : No offline ability
case IDC_MAKE_OFFLINE:
EnableWindow(GetDlgItem(hwnd, IDC_SUBSCRIBE_CUSTOMIZE),
IsDlgButtonChecked(hwnd, IDC_MAKE_OFFLINE));
break;
case IDC_SUBSCRIBE_CUSTOMIZE:
//need to create -- but not store -- subscription
if (StartSiteSubscription (hwnd, pbffFS->patf, FALSE))
SendMessage (hwnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwnd, IDOK), TRUE);
break;
#endif
case IDC_FAVORITE_NEWFOLDER:
TCHAR szPath[MAX_PATH];
TCHAR szName[MAX_PATH];
HWND hwndTV;
TV_ITEM tv_item;
// Bring up the Create New Folder dialog
if ((DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_NEWFOLDER), hwnd,
NewFavDlgProc, (LPARAM)szName) == IDOK) &&
(SHGetPathFromIDList(pbffFS->patf->pidlSelected, szPath)) &&
((lstrlen(szPath) + lstrlen(szName) + 1) < MAX_PATH))
{
PathCombine(szPath, szPath, szName);
BOOL bSuccess = FALSE;
#ifdef CREATEFOLDERSINCHANNELSDIR
if (pbffFS->patf->subsType == SUBSTYPE_CHANNEL)
{
ASSERT(0); //should not be possible in this release
//(I removed this button in the .rc dialogs for channels)
//Note: to make this work in a future release, reenable this code -- it's
//functional. But the folders created here show up ugly in the channel bar
//(just a default folder icon) and if you click on them, you get a shell
//Explorer window instead of a theater-mode browser window. The reason
//for this second happening is that the desktop.ini file created in the new
//folder has no URL=. To remedy this: AddCategory() has to be fixed so it
//doesn't interpret the pszURL argument as a UNC name (I was using a resouce moniker
//pointing into cdfview.dll for the html target), and the OC hosted by the default
//html pages has to learn how to be hosted from a html page without a path -- or we
//actually have to create an html page in the new directory, which is messy.
IChannelMgr* pChanMgr;
HRESULT hr;
hr = JITCoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
IID_IChannelMgr, (void**)&pChanMgr,
hwnd, FIEF_FLAG_FORCE_JITUI);
if (SUCCEEDED(hr))
{
IChannelMgrPriv* pChanMgrPriv;
hr = pChanMgr->QueryInterface (IID_IChannelMgrPriv, (void**)&pChanMgrPriv);
if (SUCCEEDED(hr))
{
char szCFPath[MAX_PATH];
WCHAR wszFolder[MAX_PATH];
IChannelMgrPriv::CHANNELFOLDERLOCATION cflLocation =
(pbffFS->patf->iDlgType == ATF_CHANNEL_SOFTDIST ?
IChannelMgrPriv::CF_SOFTWAREUPDATE :
IChannelMgrPriv::CF_CHANNEL);
hr = pChanMgrPriv->GetChannelFolderPath (szCFPath, ARRAYSIZE(szCFPath), cflLocation);
int cchCommon = PathCommonPrefix (szPath, szCFPath, NULL);
AnsiToUnicode (szPath + cchCommon, wszFolder, ARRAYSIZE(wszFolder));
CHANNELCATEGORYINFO info = {0};
info.cbSize = sizeof(info);
info.pszTitle = wszFolder;
bSuccess = SUCCEEDED (pChanMgr->AddCategory (&info));
pChanMgrPriv->Release();
}
pChanMgr->Release();
}
}
else
#endif
{
bSuccess = CreateDirectory(szPath, NULL);
}
if (bSuccess)
{
// This code assumes the layout of SHBrowseForFolder!
// directory successfully created, must notify registered shell components.
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, szPath, NULL);
// Get the TreeView control
hwndTV = GetDlgItem(hwnd, IDD_FOLDERLIST);
if (hwndTV) {
HTREEITEM hti = TreeView_GetSelection(hwndTV);
// Take the selected item and reset it, then reexpand it so
// that it shows the new directory we just created.
tv_item.mask = TVIF_CHILDREN;
tv_item.hItem = hti;
tv_item.cChildren = -1;
TreeView_SetItem(hwndTV, &tv_item);
TreeView_Expand(hwndTV, hti, TVE_COLLAPSE | TVE_COLLAPSERESET);
TreeView_Expand(hwndTV, hti, TVE_EXPAND);
// Find the new directory we just created and select it by
// walking the tree from the selected item down.
if (hti = TreeView_GetChild(hwndTV, hti)) {
tv_item.mask = TVIF_TEXT;
tv_item.pszText = szPath;
tv_item.cchTextMax = MAX_PATH;
do {
tv_item.hItem = hti;
TreeView_GetItem(hwndTV, &tv_item);
if (StrCmp(szName, szPath) == 0) {
TreeView_Select(hwndTV, hti, TVGN_CARET);
break;
}
} while (hti = TreeView_GetNextSibling(hwndTV, hti));
}
SetFocus(hwndTV);
}
} else {
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
MLShellMessageBox(
hwnd,
(LPCTSTR)lpMsgBuf,
MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
MB_ICONINFORMATION | MB_OK);
// Free the buffer.
LocalFree( lpMsgBuf );
lpMsgBuf = NULL;
}
}
break;
case IDOK:
// first, make sure they're not trying to subscribe to an authenticated
// channel without entering a password.
if (SubscriptionFailsChannelAuthentication (hwnd, &pbffFS->patf->siSubsInProg))
return FALSE;
// Retrieve the text from the Name edit control.
GetDlgItemText(hwnd, IDC_FAVORITE_NAME, pbffFS->patf->pszFile, pbffFS->patf->cchFile);
{ // Just a block to declare variables
BOOL fTooBig = TRUE; // assume failure
TCHAR szTmp[MAX_PATH];
if (lstrlen(pbffFS->patf->pszFile) < MAX_PATH)
{
StrCpyN(szTmp, pbffFS->patf->pszFile, ARRAYSIZE(szTmp));
// PathCleanupSpec deals with MAX_PATH buffers, so we should be fine
if (PathCleanupSpec(NULL, szTmp))
{
MLShellMessageBox(
hwnd,
MAKEINTRESOURCE(IDS_FAVS_INVALIDFN),
MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
MB_OK | MB_ICONHAND);
return FALSE;
}
// Make sure the name is unique and if not, that the user has
// specified that it is OK to override.
if (QualifyFileName(pbffFS->patf))
{
if (!ConfirmAddToFavorites(hwnd, pbffFS->patf))
return FALSE;
// Bogus hack since the ATF stuff is only half done
// Depending on which dlg is shown, look for the appropriate
// check.
if (IsDlgButtonChecked (hwnd, IDC_MAKE_OFFLINE))
{
//they want to subscribe! save subscription we already have in memory
//trouble is, pbffFS->patf->pszFile ends in a bogus .url
TCHAR* pszTemp = pbffFS->patf->pszFile;
TCHAR szNoExt[MAX_PATH];
StrCpyN(szNoExt, pbffFS->patf->pszFile, ARRAYSIZE(szNoExt));
pbffFS->patf->pszFile = szNoExt;
PathRemoveExtension (szNoExt);
pbffFS->patf->bSubscribed =
StartSiteSubscription (hwnd, pbffFS->patf, TRUE);
pbffFS->patf->pszFile = pszTemp;
}
else if (pbffFS->patf->bStartSubscribed)
{
// If we started subscribed and they unchecked make available
// offline, then delete the subscription.
ISubscriptionMgr* pSubsMgr;
if (SUCCEEDED (CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr, (void**)&pSubsMgr)))
{
//url is in patf->pidlFavorite
WCHAR wszURL[MAX_URL_STRING];
IEGetDisplayName(pbffFS->patf->pidlFavorite, wszURL, SHGDN_FORPARSING);
pSubsMgr->DeleteSubscription(wszURL, NULL);
pSubsMgr->Release();
}
}
// Enable and set focus to the tree view so that it is sure to
// be selected so that SHBrowseForFolder will return a pidl.
EnableWindow(pbffFS->hwndTV, TRUE);
SetFocus(pbffFS->hwndTV);
fTooBig = FALSE;
}
}
#ifdef UNIX_FEATURE_ALIAS
if( !fTooBig )
{
TCHAR alias[MAX_ALIAS_LENGTH];
TCHAR szThisURL[MAX_URL_STRING];
HDPA aliasList = GetGlobalAliasList();
if( aliasList )
{
#ifdef UNICODE
// TODO :
#else
// Retrieve the text from the Alias edit control.
GetDlgItemText(hwnd, IDC_ALIAS_NAME, alias, MAX_ALIAS_LENGTH-1);
IEGetDisplayName(pbffFS->patf->pidlFavorite,
szThisURL, SHGDN_FORPARSING);
if(AddAliasToListA( aliasList, alias, szThisURL, hwnd ))
SaveAliases(aliasList);
#endif
}
}
#endif /* UNIX_FEATURE_ALIAS */
if (fTooBig)
{
MLShellMessageBox(
hwnd,
MAKEINTRESOURCE(IDS_FAVS_FNTOOLONG),
MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES),
MB_OK | MB_ICONHAND);
return FALSE;
}
}
break;
case IDC_FAVORITE_CREATEIN:
// The advanced button has been clicked. Enable/disable the tree view
// and New button, set focus to the tree view or ok button, disable the advanced
// button and then resize the dialog.
{
BOOL fExpanding = !IsWindowEnabled(GetDlgItem(hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER)); //random control that gets enabled when dialog expanded
TCHAR szBuffer[100];
EnableWindow(pbffFS->hwndTV, fExpanding);
//don't show New Folder button for channels in the channels folder,
// see code for case IDC_FAVORITE_NEWFOLDER for why
if (fExpanding && pbffFS->patf->subsType == SUBSTYPE_CHANNEL)
{
LPITEMIDLIST pidlFavs = NULL;
TCHAR tzFavsPath[MAX_PATH];
if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_FAVORITES, &pidlFavs))
&& SUCCEEDED(SHGetNameAndFlags(pidlFavs, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, tzFavsPath, SIZECHARS(tzFavsPath), NULL))
&& StrCmpNI(tzFavsPath, pbffFS->patf->pszInitDir, ARRAYSIZE(tzFavsPath))==0)
{
EnableWindow(pbffFS->hwndNew, TRUE);
}
if(pidlFavs)
ILFree(pidlFavs);
}
else
EnableWindow(pbffFS->hwndNew, fExpanding);
GetWindowRect(hwnd, &rc);
if (fExpanding)
{
int lRet = MLLoadString(IDS_FAVS_ADVANCED_COLLAPSE, szBuffer, ARRAYSIZE(szBuffer));
ASSERT(lRet);
SetFocus(pbffFS->hwndTV);
MoveWindow(hwnd, rc.left, rc.top,
pbffFS->rcRestored.right - pbffFS->rcRestored.left,
pbffFS->rcRestored.bottom - pbffFS->rcRestored.top, TRUE);
}
else
{
int lRet = MLLoadString(IDS_FAVS_ADVANCED_EXPAND, szBuffer, ARRAYSIZE(szBuffer));
ASSERT(lRet);
SetFocus(GetDlgItem(hwnd, IDC_FAVORITE_NAME));
MoveWindow(hwnd, rc.left, rc.top,
pbffFS->rcRestored.right - pbffFS->rcRestored.left,
pbffFS->rcRestored.bottom - pbffFS->rcRestored.top, TRUE);
// hide the bottom part of the dialog
int cx, cy;
RECT rc;
GetWindowRect (GetDlgItem (hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER), &rc);
cy = rc.top;
GetWindowRect (hwnd, &rc);
cx = rc.right - rc.left;
cy = cy /*top of ctrl*/ - rc.top; /*top of window*/
SetWindowPos (hwnd, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER);
}
SetWindowText(GetDlgItem(hwnd, IDC_FAVORITE_CREATEIN), szBuffer);
break;
}
}
break;
case WM_DESTROY:
{
DWORD dwValue = IsWindowEnabled(GetDlgItem(hwnd, IDC_FAVORITE_NEWFOLDER)); //random control that gets enabled when dialog expanded
SHRegSetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("AddToFavoritesExpanded"),
REG_DWORD, &dwValue, 4, SHREGSET_HKCU | SHREGSET_FORCE_HKCU);
ReplaceTransplacedControls (hwnd, pbffFS->hTemplateWnd);
DestroyWindow (pbffFS->hTemplateWnd);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) lpfnOldWndProc);
RemoveProp(hwnd, ADDTOFAVPROP);
SHRemoveDefaultDialogFont(hwnd);
ILFree(pbffFS->patf->pidlSelected);
LocalFree((HLOCAL)pbffFS);
pbffFS = NULL;
break;
}
case WM_HELP:
SHWinHelpOnDemandWrap((HWND)((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile,
HELP_WM_HELP, (DWORD_PTR)(LPTSTR) (pbffFS->patf->iDlgType == ATF_FAVORITE
? aAddToFavHelpIDs : aAddToChanHelpIDs));
return TRUE;
break;
case WM_CONTEXTMENU:
SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID) (pbffFS->patf->iDlgType == ATF_FAVORITE
? aAddToFavHelpIDs : aAddToChanHelpIDs));
return TRUE;
break;
}
return CallWindowProc(lpfnOldWndProc, hwnd, uMsg, wParam, lParam);
}
static const TCHAR szTransplacedProp[] = TEXT("tp");
void ReplaceTransplacedControls (HWND hDlgMaster, HWND hDlgTemplate)
{
/*
* This function moves the controls that we moved from our temporary
* dialog over to SHBrowseForFolder's dialog, back to their original
* home, before they get destroyed. This is because otherwise we have
* problems when destroying the template dialog -- specifically, we get
* a GP fault in user.exe when destroying the edit control, because it
* looks to its parent window to figure out where its data segment is.
*
* Solution: (for safety) -- put everything back where it came from.
* Other possibilities: just move the edit control (by ID) back, or
* move all edit controls back, or use DS_LOCALEDIT for edit controls
* (but this is documented only for use with multiline edits.)
* Or modify SHBrowseForFolder to allow other dialog templates...
* but that's over in shell32.
*/
HWND hCtrl = GetWindow (hDlgMaster, GW_CHILD);
while (hCtrl)
{
HWND hNext = GetWindow (hCtrl, GW_HWNDNEXT);
if (GetProp (hCtrl, szTransplacedProp) != NULL)
{
RemoveProp (hCtrl, szTransplacedProp);
SetParent (hCtrl, hDlgTemplate);
}
hCtrl = hNext;
}
}
#define szOriginalWND TEXT("WorkaroundOrigWndProc")
INT_PTR CALLBACK MergeFavoritesDialogControls(HWND hDlgTemplate, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND hDlgMaster = (HWND)lParam;
ASSERT (IsWindow (hDlgMaster));
TCHAR szT[200];
RECT rc;
//resize master like us
GetWindowText (hDlgTemplate, szT, ARRAYSIZE(szT));
SetWindowText (hDlgMaster, szT);
GetClientRect (hDlgTemplate, &rc);
AdjustWindowRect (&rc, GetWindowLong (hDlgMaster, GWL_STYLE), FALSE);
SetWindowPos (hDlgMaster, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOMOVE | SWP_NOZORDER);
// a-msadek; If the owned window is mirrored, a dialog with specifed
// coordinates, the dialog get moved to the worng direction
HWND hWndOwner = GetWindow(hDlgMaster, GW_OWNER);
if(IS_WINDOW_RTL_MIRRORED(hWndOwner))
{
RECT rcOwner, rcDlg;
GetWindowRect(hWndOwner, &rcOwner);
GetWindowRect(hDlgMaster, &rcDlg);
SetWindowPos(hDlgMaster, NULL, rcDlg.left - (rcDlg.right - rcOwner.right), rcDlg.top, 0 ,0,
SWP_NOSIZE | SWP_NOZORDER);
}
#if 0 //now we do this as part of the "move controls from template to master" process,
//if we notice that a ctrl with that id already exists. This way we pick up the
//tab order too. If someone decides my hack (SetParent) to change tab order is
//broken, then that code can be nuked and this reenabled.
//position already-existing controls in master like us
int ID_PREEXIST_CTRLS[] = { IDOK_PLACEHOLDER, IDCANCEL_PLACEHOLDER,
IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER };
for (int iCtrl = 0; iCtrl < ARRAYSIZE(ID_PREEXIST_CTRLS); iCtrl++)
{
GetWindowRect (GetDlgItem (hDlgTemplate, ID_PREEXIST_CTRLS[iCtrl]), &rc);
MapWindowPoints (NULL, hDlgTemplate, (LPPOINT)&rc, 2);
MoveWindow (GetDlgItem (hDlgMaster, ID_PREEXIST_CTRLS[iCtrl]),
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
DestroyWindow (GetDlgItem (hDlgTemplate, ID_PREEXIST_CTRLS[iCtrl]));
}
#endif
//copy other controls from us to master
//find last child
HWND hCtrlTemplate = NULL;
HWND hNextCtrl = GetWindow (hDlgTemplate, GW_CHILD);
if (hNextCtrl) //can't see how this would fail, but...
hCtrlTemplate = GetWindow (hNextCtrl, GW_HWNDLAST);
//have last window in hCtrlTemplate
//now move controls over in reverse order -- they'll end up stacking up in original order from template
while (hCtrlTemplate)
{
hNextCtrl = GetWindow (hCtrlTemplate, GW_HWNDPREV);
DWORD id = GetWindowLong (hCtrlTemplate, GWL_ID);
HWND hCtrlExisting;
if (id != (USHORT)IDC_STATIC && NULL != (hCtrlExisting = GetDlgItem (hDlgMaster, id)))
//it's one of the controls pre-created by SHBrowseForFolder
{ //so don't move this one over -- adjust existing control for size, position, tab order
RECT rc;
GetWindowRect (hCtrlTemplate, &rc);
MapWindowPoints (NULL, hDlgTemplate, (LPPOINT)&rc, 2);
SetWindowPos (hCtrlExisting, NULL, rc.left, rc.top,
rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
DestroyWindow (hCtrlTemplate);
//REVIEW
//hack -- send control to end of tab order
SetParent (hCtrlExisting, hDlgTemplate);
SetParent (hCtrlExisting, hDlgMaster);
}
else //we should move this control from template to master
{
SetProp (hCtrlTemplate, szTransplacedProp, (HANDLE)TRUE); //anything -- it's the existence of the prop that we check for
SetParent (hCtrlTemplate, hDlgMaster); //to know to move this control back later
}
hCtrlTemplate = hNextCtrl;
}
// Let Template know about the child so that it can forward WM_COMMAND notifications to it
// to work around the fact that edit controls cache their parent pointers and ignore SetParents
// when it comes to sending parent notifications
SetProp(hDlgTemplate, szOriginalWND, hDlgMaster);
}
break;
case WM_COMMAND:
// Workaround for above bug
SendMessage((HWND)GetProp(hDlgTemplate, szOriginalWND), uMsg, wParam, lParam);
break;
}
return FALSE;
}
int CALLBACK BFFFavCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
switch (uMsg)
{
case BFFM_INITIALIZED:
{
ADDTOFAV* patf = (ADDTOFAV*)lpData;
ASSERT (patf);
HWND hDlgTemp = CreateDialogParam(MLGetHinst(),
MAKEINTRESOURCE(IDD_ADDTOFAVORITES_TEMPLATE),
NULL, MergeFavoritesDialogControls, (LPARAM)hwnd);
//this results in all the controls being copied over
//if successful, make our other modifications
BFFFAVSUBSTRUCT * pbffFavSubStruct;
if ((IsWindow(GetDlgItem(hwnd, IDC_SUBSCRIBE_CUSTOMIZE))) //verify existence of randomly-selected control
&& (pbffFavSubStruct = (BFFFAVSUBSTRUCT *) LocalAlloc(LPTR, sizeof(BFFFAVSUBSTRUCT))))
{
//done with template, but don't destroy it:
//see MSKB Q84190, owner/owned vs parent/child -- the children
// of template are now children of master, but still OWNED
// by template, and are destroyed when template is destroyed...
// but we'll just keep template around
// invisibly.
//we'll take care of it when we go away
//Do we need to do SetDefaultDialogFont stuff for localization still, since it all comes from the .rc?
//set up window stuff for subclass:
// Get the TreeView control so we can muck with the style bits and move it down
HWND hwndT;
if (hwndT = GetDlgItem(hwnd, IDD_FOLDERLIST))
{
DWORD dwStyle = GetWindowLong(hwndT, GWL_STYLE);
dwStyle |= TVS_SHOWSELALWAYS;
dwStyle &= ~TVS_LINESATROOT;
SetWindowLong(hwndT, GWL_STYLE, dwStyle);
}
// don't allow subscriptions if the URL is not "http:" protocol, or if already subscribed
TCHAR szURL[MAX_URL_STRING];
if (!patf->pidlFavorite ||
FAILED(IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING)) ||
SHRestricted2(REST_NoAddingSubscriptions, szURL, 0) ||
!IsSubscribable(szURL) ||
!IsFeaturePotentiallyAvailable(CLSID_SubscriptionMgr) ||
!IsBrowserFrameOptionsPidlSet(patf->pidlFavorite, BFO_USE_IE_OFFLINE_SUPPORT))
{
CheckDlgButton(hwnd, IDC_MAKE_OFFLINE, 0);
EnableWindow(GetDlgItem (hwnd, IDC_MAKE_OFFLINE), FALSE);
EnableWindow(GetDlgItem (hwnd, IDC_SUBSCRIBE_CUSTOMIZE), FALSE);
}
else if (IsSubscribed(patf))
{
patf->bStartSubscribed = TRUE;
CheckDlgButton(hwnd, IDC_MAKE_OFFLINE, 1);
}
else if (patf->bIsSoftdist)
{
CheckDlgButton(hwnd, IDC_MAKE_OFFLINE, 1);
}
EnableWindow(GetDlgItem(hwnd, IDC_SUBSCRIBE_CUSTOMIZE),
IsDlgButtonChecked(hwnd, IDC_MAKE_OFFLINE));
//set the name
Edit_LimitText(GetDlgItem(hwnd, IDC_FAVORITE_NAME), MAX_PATH - 1);
// Use URL if title string is not displayable
if (SHIsDisplayable(patf->pszFile, g_fRunOnFE, g_bRunOnNT5))
{
SetDlgItemText(hwnd, IDC_FAVORITE_NAME, patf->pszFile);
}
else
{
TCHAR szUrlTemp[MAX_URL_STRING];
IEGetDisplayName(patf->pidlFavorite, szUrlTemp, SHGDN_FORPARSING);
SetDlgItemText(hwnd, IDC_FAVORITE_NAME, szUrlTemp);
}
EnableOKButtonFromID(hwnd, IDC_FAVORITE_NAME);
// hide the (empty) SHBrowseForFolder prompt control
ShowWindow(GetDlgItem (hwnd, IDD_BROWSETITLE), SW_HIDE);
// Fill out the structure and set it as a property so that our subclass
// proc can get to this data.
pbffFavSubStruct->lpfnOldWndProc = (WNDPROC) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)BFFFavSubclass);
pbffFavSubStruct->hwndNew = GetDlgItem(hwnd, IDC_FAVORITE_NEWFOLDER);
pbffFavSubStruct->patf = patf;
pbffFavSubStruct->hwndTV = GetDlgItem(hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER);
pbffFavSubStruct->hwndSave = GetDlgItem(hwnd, IDC_FAVORITE_CREATEIN);
pbffFavSubStruct->hTemplateWnd = hDlgTemp; //save for explicit destruction later
GetWindowRect(hwnd, &(pbffFavSubStruct->rcRestored));
SetProp(hwnd, ADDTOFAVPROP, (HANDLE)pbffFavSubStruct);
patf->pidlSelected = ILClone(patf->pidl);
DWORD dwType, dwValue = 0, dwcData = sizeof(dwValue);
TCHAR szBuffer[100];
SHRegGetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("AddToFavoritesExpanded"),
&dwType, &dwValue, &dwcData, 0, NULL, sizeof(dwValue));
if (dwValue == 0)
{
int lRet = MLLoadString(IDS_FAVS_ADVANCED_EXPAND, szBuffer, ARRAYSIZE(szBuffer));
ASSERT(lRet);
// Disable the tree view and new button so that we can't tab to them.
EnableWindow(GetDlgItem (hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER), FALSE);
EnableWindow(GetDlgItem (hwnd, IDC_FAVORITE_NEWFOLDER), FALSE);
// hide the bottom part of the dialog
int cx, cy;
RECT rc;
GetWindowRect (GetDlgItem (hwnd, IDC_SUBSCRIBE_FOLDERLIST_PLACEHOLDER), &rc);
cy = rc.top;
GetWindowRect (hwnd, &rc);
cx = rc.right - rc.left;
cy = cy /*top of ctrl*/ - rc.top; /*top of window*/
SetWindowPos (hwnd, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER);
}
else
{
//don't show New Folder button for channels in the channels folder,
// see code for case IDC_FAVORITE_NEWFOLDER for why
if (patf->subsType == SUBSTYPE_CHANNEL)
{
LPITEMIDLIST pidlFavs = NULL;
TCHAR tzFavsPath[MAX_PATH];
if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_FAVORITES, &pidlFavs))
&& SUCCEEDED(SHGetNameAndFlags(pidlFavs, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, tzFavsPath, SIZECHARS(tzFavsPath), NULL))
&& 0 == StrCmpNI(tzFavsPath, patf->pszInitDir, ARRAYSIZE(tzFavsPath)))
{
EnableWindow(pbffFavSubStruct->hwndNew, TRUE);
}
else
EnableWindow(pbffFavSubStruct->hwndNew, FALSE);
if(pidlFavs)
ILFree(pidlFavs);
}
else
EnableWindow(pbffFavSubStruct->hwndNew, TRUE);
int lRet = MLLoadString(IDS_FAVS_ADVANCED_COLLAPSE, szBuffer, ARRAYSIZE(szBuffer));
ASSERT(lRet);
}
SetWindowText(GetDlgItem(hwnd, IDC_FAVORITE_CREATEIN), szBuffer);
}
else
{
EndDialog(hwnd, IDCANCEL);
}
break;
}
case BFFM_SELCHANGED:
{
//the first of these comes during BFFM_INITIALIZED, so ignore it
if (((ADDTOFAV *)lpData)->pidlSelected != NULL)
{
ILFree(((ADDTOFAV *)lpData)->pidlSelected);
((ADDTOFAV *)lpData)->pidlSelected = ILClone((LPITEMIDLIST)lParam);
}
break;
}
}
return 0;
}
// This API is not exported. See below (DoAddToFavDlg) for the exported version
//
// hwnd parent window for the dialog.
// pszInitDir input: initial path
// output: fully qualified path and filename
// chInitDir Length of pszInitDir buffer
// pszFile initial (default) filename for shortcut
// cchFile Length of pszFile buffer
// pidlBrowse associated with pszInitDir
//
// Returns:
// TRUE if a directory and filename were selected by user, and no error
// occurs. In this case pszInitDir contains the new destination directory
// and filename, pszFile contains the new file name.
//
// FALSE if an error occurs or the user selects CANCEL.
STDAPI_(BOOL) DoAddToFavDlgEx(HWND hwnd,
TCHAR *pszInitDir, UINT cchInitDir,
TCHAR *pszFile, UINT cchFile,
LPITEMIDLIST pidlBrowse,
LPCITEMIDLIST pidlFavorite,
FAVDLGTYPE atfDlgType,
SUBSCRIPTIONINFO* pInfo)
{
ADDTOFAV atf = {pszInitDir, cchInitDir - 1, pszFile, cchFile - 1, pidlBrowse, NULL,
pidlFavorite, atfDlgType, {sizeof(SUBSCRIPTIONINFO), 0}, SUBSTYPE_URL };
TCHAR szTemp[1]; //NOTE: we're not using SHBrowseForFolder's prompt string (see below)
TCHAR szDisplayName[MAX_PATH];
BROWSEINFO bi = {
hwnd,
pidlBrowse,
szDisplayName,
szTemp,
BIF_RETURNONLYFSDIRS,
// (BFFCALLBACK)
BFFFavCallback,
(LPARAM)&atf,
0
};
LPITEMIDLIST pidl;
if (pInfo)
atf.siSubsInProg = *pInfo;
switch (atfDlgType)
{
case ATF_CHANNEL_SOFTDIST:
atf.bIsSoftdist = TRUE;
// fall through
case ATF_CHANNEL:
atf.subsType = SUBSTYPE_CHANNEL;
break;
//default:
// set in initialize to SUBSTYPE_URL
}
//this string is now in the template dialog in the .rc
//REVIEW -- do we want to do it this way (we're hiding SHBrowse...'s control)? then the template dialog looks more like the finished product...
szTemp[0] = 0;
//init native font control, otherwise dialog may fail to initialize
{
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
InitCommonControlsEx(&icc);
}
pidl = SHBrowseForFolder(&bi);
if (pidl)
{
ILFree(pidl);
}
// If the user created a new subscription, start a download.
if (atf.bSubscribed && !atf.bStartSubscribed)
{
ISubscriptionMgr* pSubsMgr;
if (SUCCEEDED (CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr, (void**)&pSubsMgr)))
{
WCHAR wszURL[MAX_URL_STRING];
IEGetDisplayName(atf.pidlFavorite, wszURL, SHGDN_FORPARSING);
pSubsMgr->UpdateSubscription(wszURL);
pSubsMgr->Release();
}
}
return (pidl != NULL);
}
STDAPI_(BOOL) DoSafeAddToFavDlgEx(HWND hwnd,
TCHAR *pszInitDir, UINT cchInitDir,
TCHAR *pszFile, UINT cchFile,
LPITEMIDLIST pidlBrowse,
LPCITEMIDLIST pidlFavorite,
FAVDLGTYPE atfDlgType,
SUBSCRIPTIONINFO* pInfo)
{
BOOL fRet;
if (IEIsLinkSafe(hwnd, pidlFavorite, ILS_ADDTOFAV))
{
fRet = DoAddToFavDlgEx(hwnd, pszInitDir, cchInitDir, pszFile, cchFile,
pidlBrowse, pidlFavorite, atfDlgType, pInfo);
}
else
{
fRet = FALSE;
}
return fRet;
}
// This API is exported so that it may be called by explorer and mshtml (and MSNVIEWR.EXE)
// in addition to being called internally by shdocvw.
// THEREFORE YOU MUST NOT CHANGE THE SIGNATURE OF THIS API
//
STDAPI_(BOOL) DoAddToFavDlg(HWND hwnd,
CHAR *pszInitDir, UINT cchInitDir,
CHAR *pszFile, UINT cchFile,
LPITEMIDLIST pidlBrowse)
{
BOOL fRet;
WCHAR szInitDir[MAX_PATH];
WCHAR szFile[MAX_PATH];
SHAnsiToUnicode(pszInitDir, szInitDir, ARRAYSIZE(szInitDir));
SHAnsiToUnicode(pszFile, szFile, ARRAYSIZE(szFile));
fRet = DoSafeAddToFavDlgEx(hwnd, szInitDir, ARRAYSIZE(szInitDir), szFile, ARRAYSIZE(szFile), pidlBrowse, NULL, ATF_FAVORITE, NULL);
SHUnicodeToAnsi(szInitDir, pszInitDir, cchInitDir);
SHUnicodeToAnsi(szFile, pszFile, cchFile);
return fRet;
}
STDAPI_(BOOL) DoAddToFavDlgW(HWND hwnd,
WCHAR *pszInitDir, UINT cchInitDir,
WCHAR *pszFile, UINT cchFile,
LPITEMIDLIST pidlBrowse)
{
return DoSafeAddToFavDlgEx(hwnd, pszInitDir, cchInitDir, pszFile, cchFile, pidlBrowse, NULL, ATF_FAVORITE, NULL);
}
STDAPI AddToFavoritesEx(HWND hwnd, LPCITEMIDLIST pidlCur, LPCTSTR pszTitle, DWORD dwFlags,
SUBSCRIPTIONINFO *pInfo, IOleCommandTarget *pCommandTarget, IHTMLDocument2 *pDoc);
STDAPI AddToChannelsEx (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, LPCWSTR pwszURL,
DWORD dwFlags, SUBSCRIPTIONINFO* pInfo);
STDAPI SubscribeFromFavorites (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, DWORD dwFlags,
SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO *pInfo);
// This API is exported privately, and is called by ISubscriptionMgr::CreateSubscription.
// shuioc uses it too.
STDAPI SHAddSubscribeFavoriteEx (
HWND hwnd,
LPCWSTR pwszURL,
LPCWSTR pwszName,
DWORD dwFlags,
SUBSCRIPTIONTYPE subsType,
SUBSCRIPTIONINFO* pInfo,
IOleCommandTarget *pcmdt,
IHTMLDocument2 *pDoc)
{
TCHAR szName[MAX_PATH];
LPITEMIDLIST pidl = NULL;
HRESULT hr;
if (pwszURL==NULL || pwszName == NULL)
return E_INVALIDARG;
//
// Need to put pwszName into a buffer because it comes in const
// but gets modified in SubscribeFromFavorites.
//
StrCpyN(szName, pwszName, ARRAYSIZE(szName));
hr = IECreateFromPath(pwszURL, &pidl);
if (SUCCEEDED(hr))
{
ASSERT (pidl);
if (dwFlags & CREATESUBS_FROMFAVORITES)
{
if (subsType != SUBSTYPE_URL && subsType != SUBSTYPE_CHANNEL)
{
ASSERT(0);
hr = E_INVALIDARG;
}
else
{
hr = SubscribeFromFavorites (hwnd, pidl, szName, dwFlags, subsType, pInfo);
}
}
else
{
if (subsType == SUBSTYPE_URL)
{
hr = AddToFavoritesEx (hwnd, pidl, szName, dwFlags, pInfo, pcmdt, pDoc);
}
else if (subsType == SUBSTYPE_CHANNEL && !SHIsRestricted2W(hwnd, REST_NoChannelUI, NULL, 0))
{
hr = AddToChannelsEx (hwnd, pidl, szName, pwszURL, dwFlags, pInfo);
}
else
{
ASSERT (0);
hr = E_INVALIDARG;
}
}
ILFree(pidl);
}
return hr;
}
STDAPI SHAddSubscribeFavorite (HWND hwnd, LPCWSTR pwszURL, LPCWSTR pwszName, DWORD dwFlags,
SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO* pInfo)
{
return SHAddSubscribeFavoriteEx ( hwnd, pwszURL, pwszName, dwFlags,
subsType, pInfo, NULL, NULL);
}
// this API is also exported via the .def
// Use for backward compatibility only -- note that it is only for URL's (not channels)
// and doesn't know how to subscribe.
STDAPI AddUrlToFavorites(HWND hwnd, LPWSTR pszUrlW, LPWSTR pszTitleW, BOOL fDisplayUI)
{
return SHAddSubscribeFavorite (hwnd, pszUrlW, pszTitleW,
fDisplayUI ? CREATESUBS_NOUI : 0, SUBSTYPE_URL, NULL);
}
// this API is in the .h and is used elsewhere in shdocvw, but is not exported
// Backward compatibility only -- only for URL's (not channels) and can subscribe, but can't
// pass in subscriptioninfo starter.
STDAPI AddToFavorites(
HWND hwnd,
LPCITEMIDLIST pidlCur,
LPCTSTR pszTitle,
BOOL fDisplayUI,
IOleCommandTarget *pCommandTarget,
IHTMLDocument2 *pDoc)
{
return AddToFavoritesEx (hwnd, pidlCur, pszTitle,
fDisplayUI ? 0 : CREATESUBS_NOUI, NULL, pCommandTarget, pDoc);
}
//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_PTR CALLBACK SubscribeFavoriteDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ADDTOFAV * patf = (ADDTOFAV*)GetProp(hDlg, ADDTOFAVPROP);
switch (uMsg)
{
case WM_INITDIALOG:
{
TCHAR szURL[MAX_URL_STRING];
patf = (ADDTOFAV*)lParam;
SetProp(hDlg, ADDTOFAVPROP, (HANDLE)patf);
//set up name and url displays
SetDlgItemText (hDlg, IDC_CHANNEL_NAME, patf->pszFile);
//url is in patf->pidlFavorite
IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING);
SetListViewToString (GetDlgItem (hDlg, IDC_CHANNEL_URL), szURL);
//now the tricky part... this is for modifying the subscription associated with
//an existing ChannelBar shortcut. We need to find out if they are subscribed --
//if so, load the existing subscription into memory so it can be modified in the
//wizard. If not, leave the information that was passed up because it's got the
//schedule extracted from the CDF. In either case, check the radio button that
//corresponds to their current subscription level.
ISubscriptionMgr* pSubsMgr;
BOOL bSubs = FALSE;
HRESULT hr = JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr, (void**)&pSubsMgr,
hDlg, FIEF_FLAG_FORCE_JITUI | FIEF_FLAG_PEEK);
if (SUCCEEDED(hr))
{
pSubsMgr->IsSubscribed(szURL, &bSubs);
patf->bStartSubscribed = bSubs;
pSubsMgr->Release();
}
else if ((E_ACCESSDENIED == hr) || !IsBrowserFrameOptionsPidlSet(patf->pidlFavorite, BFO_USE_IE_OFFLINE_SUPPORT))
{
EnableWindow(GetDlgItem(hDlg, IDC_MAKE_OFFLINE), FALSE);
}
if (!bSubs && patf->bIsSoftdist)
{
bSubs = TRUE;
}
CheckDlgButton(hDlg, IDC_MAKE_OFFLINE, bSubs ? 1 : 0);
EnableWindow(GetDlgItem (hDlg, IDC_SUBSCRIBE_CUSTOMIZE), bSubs);
}
break;
case WM_DESTROY:
RemoveProp (hDlg, ADDTOFAVPROP);
break;
case WM_HELP:
SHWinHelpOnDemandWrap((HWND)((LPHELPINFO) lParam)->hItemHandle, c_szHelpFile,
HELP_WM_HELP, (DWORD_PTR)(LPTSTR) (patf->iDlgType == ATF_FAVORITE
? aAddToFavHelpIDs : aAddToChanHelpIDs));
return TRUE;
break;
case WM_CONTEXTMENU:
SHWinHelpOnDemandWrap((HWND) wParam, c_szHelpFile, HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID) (patf->iDlgType == ATF_FAVORITE
? aAddToFavHelpIDs : aAddToChanHelpIDs));
return TRUE;
break;
case WM_COMMAND:
ASSERT (patf);
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
case IDOK:
// first, make sure they're not trying to subscribe to an authenticated
// channel without entering a password.
if (SubscriptionFailsChannelAuthentication (hDlg, &patf->siSubsInProg))
return FALSE;
//find out whether they WERE subscribed, so if they click OK and they
//were already subscribed, we delete that subscription -- and either leave it
//deleted if "No subs" was the choice, or create the new one.
ISubscriptionMgr* pSubsMgr;
if (SUCCEEDED (JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr, (void**)&pSubsMgr,
hDlg, FIEF_FLAG_FORCE_JITUI)))
{
//url is in patf->pidlFavorite
TCHAR szURL[MAX_URL_STRING];
IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING);
BOOL bAlreadySubs;
if (SUCCEEDED (pSubsMgr->IsSubscribed (szURL, &bAlreadySubs)) && bAlreadySubs)
{
pSubsMgr->DeleteSubscription(szURL, NULL);
}
pSubsMgr->Release();
}
if (IsDlgButtonChecked (hDlg, IDC_MAKE_OFFLINE))
{
//they want to subscribe! save subscription we already have in memory
patf->bSubscribed = StartSiteSubscription (hDlg, patf, TRUE);
}
EndDialog(hDlg, IDOK);
break;
// common code with ATF dialog
case IDC_SUBSCRIBE_CUSTOMIZE:
//need to create -- but not store -- subscription
//need to (temporarily) trash patf->pidlFavorite so that we can go through the
//wizard without colliding with an existing subscription. When we actually create
//the subscription, we'll use the real name.
LPCITEMIDLIST pidlSave = patf->pidlFavorite;
TCHAR szUrlTemp[MAX_URL_STRING+1];
IEGetDisplayName(patf->pidlFavorite, szUrlTemp, SHGDN_FORPARSING);
StrCat (szUrlTemp, TEXT(".")); //just put something nearly invisible on the end
if (SUCCEEDED (IECreateFromPath(szUrlTemp, (LPITEMIDLIST*)&patf->pidlFavorite)))
{
if (StartSiteSubscription (hDlg, patf, FALSE))
SendMessage (hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDOK), TRUE);
ILFree ((LPITEMIDLIST)patf->pidlFavorite);
}
patf->pidlFavorite = pidlSave;
break;
}
break;
}
return FALSE;
}
static const int CREATESUBS_ACTIVATE = 0x8000; //hidden flag meaning channel is already on system
STDAPI SubscribeFromFavorites (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, DWORD dwFlags,
SUBSCRIPTIONTYPE subsType, SUBSCRIPTIONINFO *pInfo)
{
//used to subscribe to a channel that's already in the Favorites
//or a URL that's already a Favorite
//flags are same as ISubscriptionMgr::CreateSubscription
//display our part of the fav's dialog -- no need to go through SHBrowseForFolder
//or any of that, just our radio buttons in a fixed-size dialog with our own DlgProc
INT_PTR iDlgResult;
HRESULT hr = S_OK;
ADDTOFAV atf = {0};
atf.pszFile = pszName;
atf.siSubsInProg.cbSize = sizeof(SUBSCRIPTIONINFO);
if (pInfo && pInfo->cbSize == sizeof(SUBSCRIPTIONINFO))
atf.siSubsInProg = *pInfo;
atf.subsType = subsType;
//figure out what dialog to use
atf.iDlgType = (subsType == SUBSTYPE_URL ? ATF_FAVORITE :
(dwFlags & CREATESUBS_ACTIVATE ? ATF_CHANNEL_MODIFY : ATF_CHANNEL));
// Do we potentially need ANOTHER dialog type for softdist channels?
if (dwFlags & CREATESUBS_SOFTWAREUPDATE)
{
atf.bIsSoftdist = TRUE;
}
atf.pidlFavorite = pidlUrl;
#ifdef OLD_FAVORITES
int iTemplate;
switch (atf.iDlgType)
{
case ATF_CHANNEL_SOFTDIST: // Inappropriate, but it doesn't currently get used
case ATF_CHANNEL:
iTemplate = IDD_SUBSCRIBE_FAV_CHANNEL;
break;
case ATF_CHANNEL_MODIFY:
iTemplate = IDD_ACTIVATE_PLATINUM_CHANNEL;
break;
case ATF_FAVORITE:
iTemplate = IDD_SUBSCRIBE_FAVORITE;
break;
}
iDlgResult = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(iTemplate), hwnd,
SubscribeFavoriteDlgProc, (LPARAM)&atf);
#endif
iDlgResult = DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(IDD_ADDTOFAVORITES_TEMPLATE), hwnd,
SubscribeFavoriteDlgProc, (LPARAM)&atf);
switch (iDlgResult)
{
case -1:
hr = E_FAIL;
break;
case IDCANCEL:
hr = S_FALSE;
break;
default:
if (pInfo && (pInfo->cbSize == sizeof(SUBSCRIPTIONINFO))
&& (dwFlags & CREATESUBS_NOSAVE))
*pInfo = atf.siSubsInProg;
hr = S_OK;
break;
}
return hr;
}
STDAPI AddToChannelsEx (HWND hwnd, LPCITEMIDLIST pidlUrl, LPTSTR pszName, LPCWSTR pwszURL,
DWORD dwFlags, SUBSCRIPTIONINFO* pInfo)
{
HRESULT hr = S_OK;
IChannelMgrPriv* pIChannelMgrPriv;
hr = JITCoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
IID_IChannelMgrPriv, (void**)&pIChannelMgrPriv,
hwnd, FIEF_FLAG_FORCE_JITUI);
if (SUCCEEDED(hr))
{
if (S_OK == pIChannelMgrPriv->IsChannelInstalled (pwszURL))
{
hr = SubscribeFromFavorites (hwnd, pidlUrl, pszName, dwFlags | CREATESUBS_ACTIVATE,
SUBSTYPE_CHANNEL, pInfo);
}
else
{
LPITEMIDLIST pidlChannelFolder;
TCHAR szPath[MAX_PATH];
TCHAR szCFPath[MAX_PATH];
ASSERT(pIChannelMgrPriv);
IChannelMgrPriv::CHANNELFOLDERLOCATION cflLocation =
((dwFlags & CREATESUBS_SOFTWAREUPDATE) ?
IChannelMgrPriv::CF_SOFTWAREUPDATE :
IChannelMgrPriv::CF_CHANNEL);
hr = pIChannelMgrPriv->GetChannelFolder(&pidlChannelFolder, cflLocation);
if (SUCCEEDED (hr))
{
//
// Change IChannelMgrPriv to unicode! This has to get fixed to
// support a unicode "Channels" name. (edwardp)
//
CHAR szBuff[MAX_PATH];
hr = pIChannelMgrPriv->GetChannelFolderPath (szBuff, ARRAYSIZE(szBuff), cflLocation);
if (SUCCEEDED(hr))
SHAnsiToUnicode(szBuff, szCFPath, ARRAYSIZE(szCFPath));
if (SUCCEEDED (hr))
{
TCHAR szDspName[MAX_URL_STRING];
DWORD cchDspName = ARRAYSIZE(szDspName);
StrCpyN(szPath, szCFPath, ARRAYSIZE(szPath));
// When we create a short cut for the URL, we have to make sure it's readable for
// the end user. PrepareURLForDisplay() will unescape the string if it's escaped.
if (!UrlIs(pszName, URLIS_URL) ||
!PrepareURLForDisplay(pszName, szDspName, &cchDspName))
{
// Unescaping wasn't wanted or didn't work.
StrCpyN(szDspName, pszName, ARRAYSIZE(szDspName));
}
PathCleanupSpec(szPath, szDspName);
FAVDLGTYPE iDlgType = (dwFlags & CREATESUBS_SOFTWAREUPDATE ? ATF_CHANNEL_SOFTDIST : ATF_CHANNEL);
if ((dwFlags & CREATESUBS_NOUI) ||
DoSafeAddToFavDlgEx(hwnd, szPath, ARRAYSIZE(szPath),
szDspName, ARRAYSIZE(szDspName), pidlChannelFolder,
pidlUrl, iDlgType, pInfo))
{
//we create the channelbar entry here, instead of cdfview, because here
//we know where in the channels folder the user wants it to go.
IChannelMgr* pChannelMgr = NULL;
hr = pIChannelMgrPriv->QueryInterface (IID_IChannelMgr, (void**)&pChannelMgr);
if (SUCCEEDED (hr))
{
//prepare strings
PathRemoveExtension(szPath);
//strip off absolute part of folder path, and convert to Unicode
int cchCommon = PathCommonPrefix (szPath, szCFPath, NULL);
//pack in the info we have
CHANNELSHORTCUTINFO csiChannel = {0};
csiChannel.cbSize = sizeof(csiChannel);
csiChannel.pszTitle = szPath + cchCommon;
csiChannel.pszURL = (LPWSTR)pwszURL;
csiChannel.bIsSoftware = (dwFlags & CREATESUBS_SOFTWAREUPDATE) ? TRUE : FALSE;
//and tell the channel mgr to add the channel
hr = pChannelMgr->AddChannelShortcut (&csiChannel);
pChannelMgr->Release();
}
}
else
{
hr = S_FALSE; //no failure, but no add
}
}
ILFree (pidlChannelFolder);
}
}
pIChannelMgrPriv->Release();
}
return hr;
}
STDAPI AddToFavoritesEx(
HWND hwnd,
LPCITEMIDLIST pidlCur,
LPCTSTR pszTitle,
DWORD dwFlags,
SUBSCRIPTIONINFO *pInfo,
IOleCommandTarget *pCommandTarget,
IHTMLDocument2 *pDoc)
{
HRESULT hres = S_FALSE;
HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (pidlCur)
{
TCHAR szName[MAX_URL_STRING];
TCHAR szPath[MAX_PATH];
if (pszTitle)
{
StrCpyN(szName, pszTitle, ARRAYSIZE(szName));
}
else
{
szName[0] = 0;
IEGetNameAndFlags(pidlCur, SHGDN_INFOLDER | SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
}
LPITEMIDLIST pidlFavorites;
if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE) &&
(pidlFavorites = SHCloneSpecialIDList(NULL, CSIDL_FAVORITES, TRUE)))
{
TCHAR szDspName[MAX_PATH];
DWORD cchDspName = ARRAYSIZE(szDspName);
// When we create a short cut for the URL, we have to make sure it's readable for
// the end user. PrepareURLForDisplay() will unescape the string if it's escaped.
if (!UrlIs(szName, URLIS_URL) ||
!PrepareURLForDisplay(szName, szDspName, &cchDspName))
{
// Unescaping wasn't wanted or didn't work.
StrCpyN(szDspName, szName, ARRAYSIZE(szDspName));
}
PathCleanupSpec(szPath, szDspName);
// if left with spaces only, use the filename friendly version of the url instead.
StrTrim(szDspName, L" ");
if (szDspName[0] == 0)
{
if (SUCCEEDED(IEGetNameAndFlags(pidlCur, SHGDN_FORPARSING, szDspName, ARRAYSIZE(szDspName), NULL)))
PathCleanupSpec(szPath, szDspName);
}
BOOL fDisplayUI = (dwFlags & CREATESUBS_NOUI) ? FALSE : TRUE;
if (!fDisplayUI ||
DoSafeAddToFavDlgEx(hwnd, szPath, ARRAYSIZE(szPath),
szDspName, ARRAYSIZE(szDspName), pidlFavorites,
pidlCur, ATF_FAVORITE, NULL))
{
if (fDisplayUI)
PathRemoveFileSpec(szPath);
ISHCUT_PARAMS ShCutParams = {0};
PathRemoveExtension(szDspName);
ShCutParams.pidlTarget = pidlCur;
ShCutParams.pszTitle = PathFindFileName(szDspName);
ShCutParams.pszDir = szPath;
ShCutParams.pszOut = NULL;
ShCutParams.bUpdateProperties = FALSE;
ShCutParams.bUniqueName = FALSE;
ShCutParams.bUpdateIcon = TRUE;
ShCutParams.pCommand = pCommandTarget;
ShCutParams.pDoc = pDoc;
hres = CreateShortcutInDirEx(&ShCutParams);
if (fDisplayUI && FAILED(hres))
{
IE_ErrorMsgBox(NULL, hwnd, GetLastError(), NULL, szDspName, IDS_FAV_UNABLETOCREATE, MB_OK| MB_ICONSTOP);
}
}
else
{
hres = S_FALSE;
}
ILFree(pidlFavorites);
}
}
SetCursor(hCursorOld);
return hres;
}
BOOL IsSubscribed(ADDTOFAV *patf)
{
BOOL bSubscribed = FALSE;
TCHAR szURL[MAX_URL_STRING];
if (SUCCEEDED(IEGetDisplayName(patf->pidlFavorite, szURL, SHGDN_FORPARSING)))
{
ISubscriptionMgr *pSubscriptionMgr;
if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr,
NULL, CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr,
(void**)&pSubscriptionMgr)))
{
BSTR bstrURL = SysAllocStringT(szURL);
if (bstrURL)
{
if (SUCCEEDED(pSubscriptionMgr->IsSubscribed(bstrURL, &bSubscribed)) &&
bSubscribed)
{
patf->siSubsInProg.fUpdateFlags = SUBSINFO_ALLFLAGS;
pSubscriptionMgr->GetSubscriptionInfo(bstrURL, &patf->siSubsInProg);
}
SysFreeString(bstrURL);
}
pSubscriptionMgr->Release();
}
}
return bSubscribed;
}
BOOL IsSubscribed(LPCITEMIDLIST pidl)
{
BOOL bSubscribed = FALSE;
TCHAR szURL[MAX_URL_STRING];
if (FAILED(IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szURL, SIZEOF(szURL), NULL)))
return FALSE;
bSubscribed = IsSubscribed(szURL);
return bSubscribed;
}
BOOL IsSubscribed(LPWSTR pwzUrl)
{
#ifndef DISABLE_SUBSCRIPTIONS
BOOL bSubscribed = FALSE;
ISubscriptionMgr * pSubscriptionMgr;
if (FAILED(CoCreateInstance(CLSID_SubscriptionMgr,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISubscriptionMgr,
(void**)&pSubscriptionMgr)))
{
return FALSE;
}
pSubscriptionMgr->IsSubscribed(pwzUrl, &bSubscribed);
pSubscriptionMgr->Release();
return bSubscribed;
#else /* !DISABLE_SUBSCRIPTIONS */
return FALSE;
#endif /* !DISABLE_SUBSCRIPTIONS */
}