You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
952 lines
31 KiB
952 lines
31 KiB
#include "shellprv.h"
|
|
#include "ids.h"
|
|
#include "util.h"
|
|
#include "datautil.h"
|
|
#include "foldertypes.h"
|
|
#include "basefvcb.h"
|
|
|
|
#define PROPSTR_LOGO L"Logo"
|
|
|
|
typedef struct
|
|
{
|
|
UINT uIDFriendly;
|
|
LPCTSTR pszFolderType;
|
|
DWORD dwFlags;
|
|
} WEBVIEWTEMPLATEINFO;
|
|
|
|
#define WVTI_SHOWIFOLDTEMPLATE 0x00000001
|
|
|
|
// documents must be first.
|
|
const WEBVIEWTEMPLATEINFO c_wvtiList[] =
|
|
{
|
|
{ IDS_CUSTOMIZE_USELEGACYHTT, STR_TYPE_USELEGACYHTT, WVTI_SHOWIFOLDTEMPLATE },
|
|
{ IDS_CUSTOMIZE_DOCUMENTS, STR_TYPE_DOCUMENTS, 0 },
|
|
{ IDS_CUSTOMIZE_PICTURES, STR_TYPE_PICTURES, 0 },
|
|
{ IDS_CUSTOMIZE_PHOTOALBUM, STR_TYPE_PHOTOALBUM, 0 },
|
|
{ IDS_CUSTOMIZE_MUSIC, STR_TYPE_MUSIC, 0 },
|
|
{ IDS_CUSTOMIZE_MUSICARTIST, STR_TYPE_MUSICARTIST, 0 },
|
|
{ IDS_CUSTOMIZE_MUSICALBUM, STR_TYPE_MUSICALBUM, 0 },
|
|
{ IDS_CUSTOMIZE_VIDEOS, STR_TYPE_VIDEOS, 0 },
|
|
// note: are these gonna happen?
|
|
// { IDS_CUSTOMIZE_VIDEOALBUM, STR_TYPE_VIDEOALBUM, 0 },
|
|
// { IDS_CUSTOMIZE_BOOKS, STR_TYPE_BOOKS, 0 }
|
|
};
|
|
|
|
typedef enum
|
|
{
|
|
FOLDERCUST_MODE_GENERATING,
|
|
FOLDERCUST_MODE_ICON,
|
|
FOLDERCUST_MODE_BITMAP
|
|
} FOLDERCUSTMODE;
|
|
|
|
class CFolderCustomize : public IShellExtInit,
|
|
public IShellPropSheetExt
|
|
{
|
|
public:
|
|
// IUnknown
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
// IShellExtInit
|
|
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
|
|
|
|
// IShellPropSheetExt
|
|
STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
|
|
STDMETHODIMP ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
|
|
{ return S_OK; };
|
|
|
|
CFolderCustomize();
|
|
|
|
private:
|
|
~CFolderCustomize();
|
|
static UINT CALLBACK _PrshtCallback(HWND hwnd, UINT uMsg, PROPSHEETPAGE *ppsp);
|
|
void _SetRecurseBox(HWND hwnd);
|
|
void _HideIconSection(HWND hwnd);
|
|
void _InitDialog(HWND hwnd);
|
|
BOOL _HandleWMCommand(HWND hwndDlg, WORD wNotify, WORD wID, HWND hwndCtrl);
|
|
void _EnableApply(HWND hwnd);
|
|
|
|
static DWORD WINAPI _ExtractThreadProc(void *pv);
|
|
HRESULT _ExtractOnSeparateThread(IPropertyBag *ppb, HWND hwndDlg);
|
|
HRESULT _CreateThumbnailBitmap(HWND hwndDlg);
|
|
HRESULT _CreateFolderIcon(HWND hwndDlg);
|
|
void _SetThumbnail(HWND hwnd);
|
|
void _FreeDlgItems(HWND hwndDlg);
|
|
void _SetPreviewToNewState(HWND hwndDlg, FOLDERCUSTMODE fcMode, HBITMAP hbitmap, HICON hicon);
|
|
|
|
BOOL _ShouldEnableChangeOfIcon();
|
|
void _ChangeFolderIcon(HWND hwndDlg);
|
|
HRESULT _ProcessIconChange(LPCTSTR pszPickIconDialogCaption, HWND hwndDlg);
|
|
|
|
void _DirTouch(LPITEMIDLIST pidl);
|
|
void _DeleteCustomizationInBag(IPropertyBag *ppb);
|
|
BOOL _NotifyAboutWebView(HWND hwnd);
|
|
static BOOL CALLBACK _RefreshView(HWND hwnd, LPCITEMIDLIST pidl, LPARAM lParam);
|
|
void _RefreshWindows(BOOL fTurnOnWebView, BOOL fApplyToChildren);
|
|
HRESULT _ApplyChangesToBag(HWND hwndDlg, IPropertyBag *ppb);
|
|
HRESULT _ApplyChanges(HWND hwndDlg);
|
|
|
|
void _UpdateViewState(HWND hwndDlg, IPropertyBag *ppb, int iIndex);
|
|
void _FillTemplateComboBox(HWND hwndTemplates);
|
|
int _GetTemplateIndexFromType(LPCTSTR pszType);
|
|
|
|
static BOOL_PTR CALLBACK _DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
LONG _cRef;
|
|
|
|
LPITEMIDLIST _pidl;
|
|
IPropertyBag *_ppb;
|
|
|
|
// used for background thread extraction
|
|
HWND _hwnd;
|
|
IPropertyBag *_ppbBackground;
|
|
|
|
// cached info
|
|
HBITMAP _hbmDefault;
|
|
HBITMAP _hbmLogo;
|
|
TCHAR _szCachedLogoFile[MAX_PATH];
|
|
|
|
BOOL _fUsingThumb;
|
|
|
|
ICustomIconManager *_pIconManager;
|
|
TCHAR _szLogoFile[MAX_PATH];
|
|
TCHAR _szIconPath[MAX_PATH];
|
|
int _iIconIndex;
|
|
HRESULT _hrFromIconChange;
|
|
|
|
};
|
|
|
|
CFolderCustomize::CFolderCustomize() : _cRef(1), _hrFromIconChange(E_FAIL)
|
|
{
|
|
}
|
|
|
|
CFolderCustomize::~CFolderCustomize()
|
|
{
|
|
ILFree(_pidl);
|
|
if (_ppb)
|
|
_ppb->Release();
|
|
if (_pIconManager)
|
|
_pIconManager->Release();
|
|
if (_ppbBackground)
|
|
_ppbBackground->Release();
|
|
if (_hbmDefault)
|
|
DeleteObject(_hbmDefault);
|
|
if (_hbmLogo)
|
|
DeleteObject(_hbmLogo);
|
|
}
|
|
|
|
STDAPI CFolderCustomize_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvOut)
|
|
{
|
|
// aggregation checking is handled in class factory
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CFolderCustomize* pfc = new CFolderCustomize();
|
|
if (pfc)
|
|
{
|
|
hr = pfc->QueryInterface(riid, ppvOut);
|
|
pfc->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFolderCustomize::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CFolderCustomize, IShellExtInit),
|
|
QITABENT(CFolderCustomize, IShellPropSheetExt),
|
|
{ 0 }
|
|
};
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|
|
|
|
ULONG CFolderCustomize::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_cRef);
|
|
}
|
|
|
|
ULONG CFolderCustomize::Release()
|
|
{
|
|
ASSERT( 0 != _cRef );
|
|
ULONG cRef = InterlockedDecrement(&_cRef);
|
|
if ( 0 == cRef )
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
STDMETHODIMP CFolderCustomize::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
|
|
{
|
|
HRESULT hr;
|
|
if (!pidlFolder)
|
|
{
|
|
hr = PidlFromDataObject(pdtobj, &_pidl);
|
|
}
|
|
else
|
|
{
|
|
hr = Pidl_Set(&_pidl, pidlFolder) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHGetViewStatePropertyBag(_pidl, VS_BAGSTR_EXPLORER, SHGVSPB_PERUSER | SHGVSPB_PERFOLDER, IID_PPV_ARG(IPropertyBag, &_ppb));
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// from defview.cpp
|
|
BOOL IsCustomizable(LPCITEMIDLIST pidlFolder);
|
|
|
|
UINT CALLBACK CFolderCustomize::_PrshtCallback(HWND hwnd, UINT uMsg, PROPSHEETPAGE *ppsp)
|
|
{
|
|
if (uMsg == PSPCB_RELEASE)
|
|
{
|
|
((CFolderCustomize *)ppsp->lParam)->Release();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP CFolderCustomize::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
if (IsCustomizable(_pidl))
|
|
{
|
|
PROPSHEETPAGE psp = {0};
|
|
psp.dwSize = sizeof(psp);
|
|
psp.dwFlags = PSP_USECALLBACK;
|
|
psp.hInstance = HINST_THISDLL;
|
|
psp.pszTemplate = MAKEINTRESOURCE(DLG_FOLDER_CUSTOMIZE);
|
|
psp.pfnDlgProc = _DlgProc;
|
|
psp.pfnCallback = _PrshtCallback;
|
|
psp.lParam = (LPARAM)this;
|
|
|
|
HPROPSHEETPAGE hpsp = CreatePropertySheetPage(&psp);
|
|
if (hpsp)
|
|
{
|
|
AddRef(); // HPROPSHEETPAGE holds ref, released on _PrshtCallback
|
|
if (!pfnAddPage(hpsp, lParam))
|
|
{
|
|
DestroyPropertySheetPage(hpsp);
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
#define IDH_FOLDER_TEMPLATES 10005
|
|
#define IDH_FOLDER_RECURSE 10006
|
|
#define IDH_FOLDER_PICKBROWSE 10007
|
|
#define IDH_FOLDER_DEFAULT 10008
|
|
#define IDH_FOLDER_CHANGEICON 10009
|
|
|
|
const static DWORD aPrshtHelpIDs[] =
|
|
{
|
|
IDC_FOLDER_TEMPLATES, IDH_FOLDER_TEMPLATES,
|
|
IDC_FOLDER_RECURSE, IDH_FOLDER_RECURSE,
|
|
IDC_FOLDER_PICKBROWSE, IDH_FOLDER_PICKBROWSE,
|
|
IDC_FOLDER_DEFAULT, IDH_FOLDER_DEFAULT,
|
|
IDC_FOLDER_CHANGEICON, IDH_FOLDER_CHANGEICON,
|
|
IDC_FOLDER_PREVIEW_ICON, NO_HELP,
|
|
IDC_FOLDER_PREVIEW_BITMAP, NO_HELP,
|
|
IDC_FOLDER_ICON, NO_HELP,
|
|
IDC_FOLDER_CHANGEICONTEXT, NO_HELP,
|
|
IDC_FOLDER_CHANGEICONGROUP, NO_HELP,
|
|
IDC_NO_HELP_1, NO_HELP,
|
|
IDC_NO_HELP_2, NO_HELP,
|
|
0, 0
|
|
};
|
|
|
|
BOOL_PTR CALLBACK CFolderCustomize::_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
CFolderCustomize *pfc = (CFolderCustomize*)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
pfc = (CFolderCustomize*)((PROPSHEETPAGE *)lParam)->lParam;
|
|
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pfc);
|
|
pfc->_InitDialog(hwnd);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, L"filefold.hlp", HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aPrshtHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND)wParam, L"filefold.hlp", HELP_CONTEXTMENU, (ULONG_PTR)(void *)aPrshtHelpIDs);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
fRet = pfc->_HandleWMCommand(hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
if (((LPNMHDR)lParam)->code == PSN_APPLY)
|
|
{
|
|
pfc->_ApplyChanges(hwnd);
|
|
}
|
|
fRet = TRUE;
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
pfc->_FreeDlgItems(hwnd);
|
|
break;
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
void CFolderCustomize::_FreeDlgItems(HWND hwndDlg)
|
|
{
|
|
HICON hicon = (HICON)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_ICON, STM_SETICON, NULL, NULL);
|
|
if (hicon)
|
|
DestroyIcon(hicon);
|
|
HBITMAP hbitmap = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, NULL);
|
|
if (hbitmap)
|
|
DeleteObject(hbitmap);
|
|
ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, NULL);
|
|
}
|
|
|
|
void CFolderCustomize::_SetPreviewToNewState(HWND hwndDlg, FOLDERCUSTMODE fcMode, HBITMAP hbitmap, HICON hicon)
|
|
{
|
|
// if fcMode == FOLDERCUST_MODE_ICON, we need hicon and not hbitmap
|
|
// if fcMode == FOLDERCUST_MODE_BITMAP, we need hbitmap and not hicon.
|
|
// otherwise we dont want either.
|
|
ASSERT((fcMode != FOLDERCUST_MODE_ICON) || (hicon && !hbitmap));
|
|
ASSERT((fcMode != FOLDERCUST_MODE_BITMAP) || (!hicon && hbitmap));
|
|
ASSERT((fcMode != FOLDERCUST_MODE_GENERATING) || (!hicon && !hbitmap));
|
|
|
|
switch (fcMode)
|
|
{
|
|
case FOLDERCUST_MODE_GENERATING:
|
|
{
|
|
TCHAR szText[100];
|
|
LoadString(HINST_THISDLL, IDS_CUSTOMIZE_GENERATING, szText, ARRAYSIZE(szText));
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), szText);
|
|
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), SW_SHOW);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_ICON), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP), SW_HIDE);
|
|
}
|
|
break;
|
|
|
|
case FOLDERCUST_MODE_ICON:
|
|
{
|
|
HICON hiconOld = (HICON)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_ICON, STM_SETICON, NULL, NULL);
|
|
if (hiconOld)
|
|
DestroyIcon(hiconOld);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_ICON), SW_SHOW);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP), SW_HIDE);
|
|
|
|
SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon);
|
|
}
|
|
break;
|
|
|
|
case FOLDERCUST_MODE_BITMAP:
|
|
{
|
|
HBITMAP hbitmapOld = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, NULL);
|
|
if (hbitmapOld)
|
|
DeleteObject(hbitmapOld);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_ICON), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP), SW_SHOW);
|
|
|
|
SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HRESULT CFolderCustomize::_CreateFolderIcon(HWND hwndDlg)
|
|
{
|
|
IExtractIcon *peic;
|
|
HRESULT hr = SHGetUIObjectFromFullPIDL(_pidl, NULL, IID_PPV_ARG(IExtractIcon, &peic));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
INT iIndex;
|
|
UINT wFlags;
|
|
hr = peic->GetIconLocation(0, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UINT nIconSize = MAKELONG(32, 32); // 32 for both large and small
|
|
HICON hiconLarge;
|
|
hr = peic->Extract(szPath, iIndex, NULL, &hiconLarge, nIconSize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, hiconLarge);
|
|
}
|
|
}
|
|
peic->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
DWORD WINAPI CFolderCustomize::_ExtractThreadProc(void *pv)
|
|
{
|
|
CFolderCustomize *pfc = (CFolderCustomize*)pv;
|
|
|
|
pfc->_SetPreviewToNewState(pfc->_hwnd, FOLDERCUST_MODE_GENERATING, NULL, NULL);
|
|
|
|
IExtractImage *pei;
|
|
HRESULT hr = SHGetUIObjectFromFullPIDL(pfc->_pidl, NULL, IID_PPV_ARG(IExtractImage, &pei));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHLoadFromPropertyBag(pei, pfc->_ppbBackground);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
SIZE sz = {96, 96};
|
|
DWORD dwFlags = IEIFLAG_QUALITY;
|
|
hr = pei->GetLocation(szPath, ARRAYSIZE(szPath), NULL, &sz, 24, &dwFlags);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HBITMAP hbitmap;
|
|
hr = pei->Extract(&hbitmap);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pfc->_SetPreviewToNewState(pfc->_hwnd, FOLDERCUST_MODE_BITMAP, hbitmap, NULL);
|
|
|
|
TCHAR szLogo[MAX_PATH];
|
|
if (SUCCEEDED(SHPropertyBag_ReadStr(pfc->_ppbBackground, PROPSTR_LOGO, szLogo, ARRAYSIZE(szLogo))))
|
|
{
|
|
HBITMAP *phbm = szLogo[0] ? &pfc->_hbmLogo : &pfc->_hbmDefault;
|
|
if (*phbm)
|
|
DeleteObject(*phbm);
|
|
*phbm = (HBITMAP)CopyImage(hbitmap, IMAGE_BITMAP, 0, 0, 0);
|
|
|
|
if (szLogo[0])
|
|
{
|
|
if (FAILED(StringCchCopy(pfc->_szCachedLogoFile, ARRAYSIZE(pfc->_szCachedLogoFile), szLogo)))
|
|
{
|
|
pfc->_szCachedLogoFile[0] = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pei->Release();
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// IExtractImage on a folder without any jpegs inside will fail.
|
|
// in that case we need IExtractIcon.
|
|
IExtractIcon *peic;
|
|
hr = SHGetUIObjectFromFullPIDL(pfc->_pidl, NULL, IID_PPV_ARG(IExtractIcon, &peic));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
INT iIndex;
|
|
UINT wFlags;
|
|
hr = peic->GetIconLocation(0, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UINT nIconSize = MAKELONG(96, 96); // 96 for both large and small
|
|
HICON hiconLarge;
|
|
hr = peic->Extract(szPath, iIndex, NULL, &hiconLarge, nIconSize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pfc->_SetPreviewToNewState(pfc->_hwnd, FOLDERCUST_MODE_ICON, NULL, hiconLarge);
|
|
}
|
|
}
|
|
peic->Release();
|
|
}
|
|
}
|
|
|
|
pfc->Release(); // this thread holds a ref
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CFolderCustomize::_ExtractOnSeparateThread(IPropertyBag *ppb, HWND hwndDlg)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
IUnknown_Set((IUnknown**)&_ppbBackground, ppb);
|
|
_hwnd = hwndDlg;
|
|
|
|
AddRef();
|
|
if (SHCreateThread(_ExtractThreadProc, this, CTF_COINIT, NULL))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
Release(); // thread failed to take ref
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFolderCustomize::_CreateThumbnailBitmap(HWND hwndDlg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
// see if the bitmap is one we've already extracted.
|
|
// can't use the thumbs.db cache for this kind of stuff, since the changes
|
|
// havent been committed yet we really shouldnt be poking around in data.
|
|
if (!_fUsingThumb && _hbmDefault)
|
|
{
|
|
_SetPreviewToNewState(hwndDlg, FOLDERCUST_MODE_BITMAP, (HBITMAP)CopyImage(_hbmDefault, IMAGE_BITMAP, 0, 0, 0), NULL);
|
|
}
|
|
else if (_fUsingThumb && _hbmLogo && (lstrcmpi(_szLogoFile, _szCachedLogoFile) == 0))
|
|
{
|
|
_SetPreviewToNewState(hwndDlg, FOLDERCUST_MODE_BITMAP, (HBITMAP)CopyImage(_hbmLogo, IMAGE_BITMAP, 0, 0, 0), NULL);
|
|
}
|
|
else
|
|
{
|
|
// cache miss, figure it out again.
|
|
IPropertyBag *ppb;
|
|
hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &ppb));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHPropertyBag_WriteStr(ppb, PROPSTR_LOGO, _fUsingThumb ? _szLogoFile : TEXT(""));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ExtractOnSeparateThread(ppb, hwndDlg);
|
|
}
|
|
ppb->Release();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// dont want OFN_NODEREFERENCELINKS so use the rundlg.cpp helper directly
|
|
STDAPI_(BOOL) _GetFileNameFromBrowse(HWND hwnd, LPTSTR szFilePath, UINT cbFilePath, LPCTSTR szWorkingDir, LPCTSTR szDefExt, LPCTSTR szFilters, LPCTSTR szTitle, DWORD dwFlags);
|
|
BOOL CFolderCustomize::_HandleWMCommand(HWND hwndDlg, WORD wNotify, WORD wID, HWND hwndCtrl)
|
|
{
|
|
switch(wID)
|
|
{
|
|
case IDC_FOLDER_TEMPLATES:
|
|
if (wNotify == LBN_SELCHANGE)
|
|
{
|
|
_EnableApply(hwndDlg);
|
|
}
|
|
break;
|
|
|
|
case IDC_FOLDER_DEFAULT:
|
|
_EnableApply(hwndDlg);
|
|
_fUsingThumb = FALSE;
|
|
_CreateThumbnailBitmap(hwndDlg);
|
|
break;
|
|
|
|
case IDC_FOLDER_CHANGEICON:
|
|
_ChangeFolderIcon(hwndDlg);
|
|
break;
|
|
|
|
case IDC_FOLDER_PICKBROWSE:
|
|
TCHAR szFilePath[MAX_PATH] = {0};
|
|
TCHAR szInitialDir[MAX_PATH] = {0};
|
|
|
|
// initial directory is current folder
|
|
// todo: load supported file types at runtime
|
|
if (SHGetPathFromIDList(_pidl, szInitialDir) &&
|
|
_GetFileNameFromBrowse(hwndDlg, szFilePath, ARRAYSIZE(szFilePath), szInitialDir,
|
|
MAKEINTRESOURCE(IDS_IMAGES), MAKEINTRESOURCE(IDS_IMAGESFILTER), MAKEINTRESOURCE(IDS_BROWSE),
|
|
OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR))
|
|
{
|
|
if (SUCCEEDED(StringCchCopy(_szLogoFile, ARRAYSIZE(_szLogoFile), szFilePath)))
|
|
{
|
|
_EnableApply(hwndDlg);
|
|
_fUsingThumb = TRUE;
|
|
_CreateThumbnailBitmap(hwndDlg);
|
|
}
|
|
else
|
|
{
|
|
_szLogoFile[0] = TEXT('\0'); // don't use truncated name
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CFolderCustomize::_NotifyAboutWebView(HWND hwnd)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
SHELLSTATE ss;
|
|
SHGetSetSettings(&ss, SSF_WEBVIEW, FALSE);
|
|
if (!ss.fWebView &&
|
|
(IDYES == ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_CUSTOMIZE_TURNONWEBVIEW),
|
|
MAKEINTRESOURCE(IDS_CUSTOMIZE), MB_YESNO | MB_ICONQUESTION)))
|
|
{
|
|
ss.fWebView = TRUE;
|
|
SHGetSetSettings(&ss, SSF_WEBVIEW, TRUE);
|
|
fRet = TRUE;
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
LPCITEMIDLIST pidlChanged;
|
|
BOOL fTurnOnWebView;
|
|
BOOL fApplyToChildren;
|
|
} CUSTENUMSTRUCT;
|
|
|
|
BOOL CALLBACK CFolderCustomize::_RefreshView(HWND hwnd, LPCITEMIDLIST pidl, LPARAM lParam)
|
|
{
|
|
CUSTENUMSTRUCT *pes = (CUSTENUMSTRUCT *)lParam;
|
|
|
|
if (pes->fTurnOnWebView)
|
|
{
|
|
PostMessage(hwnd, WM_COMMAND, SFVIDM_MISC_SETWEBVIEW, TRUE);
|
|
}
|
|
if (ILIsEqual(pes->pidlChanged, pidl) || (pes->fApplyToChildren && ILIsParent(pes->pidlChanged, pidl, FALSE)))
|
|
{
|
|
PostMessage(hwnd, WM_COMMAND, SFVIDM_MISC_HARDREFRESH, 0L);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CFolderCustomize::_RefreshWindows(BOOL fTurnOnWebView, BOOL fApplyToChildren)
|
|
{
|
|
CUSTENUMSTRUCT es = { _pidl, fTurnOnWebView, fApplyToChildren };
|
|
EnumShellWindows(_RefreshView, (LPARAM)&es);
|
|
}
|
|
|
|
void CFolderCustomize::_UpdateViewState(HWND hwndDlg, IPropertyBag *ppb, int iIndex)
|
|
{
|
|
TCHAR szOriginalType[25];
|
|
szOriginalType[0] = 0;
|
|
SHPropertyBag_ReadStr(ppb, PROPSTR_FOLDERTYPE, szOriginalType, ARRAYSIZE(szOriginalType));
|
|
// only apply view state change if the folder type is changing.
|
|
// also special case so that we dont apply a view state change if the folder has no
|
|
// current folder type and the user didnt change the selection from "documents"
|
|
// (i.e. they changed folder thumbnail but nothing else).
|
|
if ((lstrcmpi(c_wvtiList[iIndex].pszFolderType, szOriginalType) != 0) &&
|
|
(szOriginalType[0] || iIndex))
|
|
{
|
|
// knock out existing state, they don't want it any more.
|
|
SHPropertyBag_Delete(ppb, VS_PROPSTR_MODE);
|
|
SHPropertyBag_Delete(ppb, VS_PROPSTR_VID);
|
|
|
|
SHPropertyBag_WriteStr(ppb, PROPSTR_FOLDERTYPE, c_wvtiList[iIndex].pszFolderType);
|
|
|
|
_RefreshWindows(_NotifyAboutWebView(hwndDlg), Button_GetCheck(GetDlgItem(hwndDlg, IDC_FOLDER_RECURSE)) == BST_CHECKED);
|
|
}
|
|
}
|
|
|
|
void CFolderCustomize::_DirTouch(LPITEMIDLIST pidl)
|
|
{
|
|
FILETIME ftCurrent;
|
|
GetSystemTimeAsFileTime(&ftCurrent);
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
if (SHGetPathFromIDList(pidl, szPath))
|
|
{
|
|
// woohoo yay for private flags
|
|
// 0x100 lets us open a directory in write access
|
|
HANDLE h = CreateFile(szPath, GENERIC_READ | 0x100,
|
|
FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
{
|
|
SetFileTime(h, NULL, NULL, &ftCurrent);
|
|
CloseHandle(h);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFolderCustomize::_DeleteCustomizationInBag(IPropertyBag *ppb)
|
|
{
|
|
// this is only called when the inherit bag is getting written out.
|
|
// so we need to scorch the existing non-inherit bag so it doesn't
|
|
// override the inherit bag.
|
|
SHPropertyBag_Delete(ppb, PROPSTR_FOLDERTYPE);
|
|
SHPropertyBag_Delete(ppb, PROPSTR_LOGO);
|
|
SHPropertyBag_Delete(ppb, VS_PROPSTR_MODE);
|
|
SHPropertyBag_Delete(ppb, VS_PROPSTR_VID);
|
|
}
|
|
|
|
HRESULT CFolderCustomize::_ApplyChangesToBag(HWND hwndDlg, IPropertyBag *ppb)
|
|
{
|
|
// handle webview template
|
|
HWND hwndTemplates = GetDlgItem(hwndDlg, IDC_FOLDER_TEMPLATES);
|
|
if (hwndTemplates)
|
|
{
|
|
int iIndex = ComboBox_GetCurSel(hwndTemplates);
|
|
if (iIndex != CB_ERR)
|
|
{
|
|
int iViewIndex = (int)ComboBox_GetItemData(hwndTemplates, iIndex);
|
|
_UpdateViewState(hwndDlg, ppb, iViewIndex);
|
|
}
|
|
}
|
|
|
|
TCHAR szThumb[MAX_PATH];
|
|
szThumb[0] = 0;
|
|
if (_fUsingThumb)
|
|
{
|
|
if (FAILED(StringCchCopy(szThumb, ARRAYSIZE(szThumb), _szLogoFile)))
|
|
{
|
|
szThumb[0] = TEXT('\0');
|
|
}
|
|
}
|
|
|
|
TCHAR szOriginalLogo[MAX_PATH];
|
|
szOriginalLogo[0] = 0;
|
|
SHPropertyBag_ReadStr(ppb, PROPSTR_LOGO, szOriginalLogo, ARRAYSIZE(szOriginalLogo));
|
|
if (lstrcmpi(szThumb, szOriginalLogo) != 0)
|
|
{
|
|
SHPropertyBag_WriteStr(ppb, PROPSTR_LOGO, szThumb);
|
|
_DirTouch(_pidl);
|
|
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, _pidl, NULL);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CFolderCustomize::_ApplyChanges(HWND hwndDlg)
|
|
{
|
|
// handle icon change
|
|
switch (_hrFromIconChange)
|
|
{
|
|
case S_OK:
|
|
_pIconManager->SetIcon(_szIconPath, _iIconIndex);
|
|
break;
|
|
|
|
case S_FALSE:
|
|
_pIconManager->SetDefaultIcon();
|
|
break;
|
|
}
|
|
|
|
if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_FOLDER_RECURSE)) == BST_CHECKED)
|
|
{
|
|
IPropertyBag *ppbInherit;
|
|
if (SUCCEEDED(SHGetViewStatePropertyBag(_pidl, VS_BAGSTR_EXPLORER, SHGVSPB_INHERIT, IID_PPV_ARG(IPropertyBag, &ppbInherit))))
|
|
{
|
|
_DeleteCustomizationInBag(_ppb);
|
|
_ApplyChangesToBag(hwndDlg, ppbInherit);
|
|
ppbInherit->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_ApplyChangesToBag(hwndDlg, _ppb);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
int CFolderCustomize::_GetTemplateIndexFromType(LPCTSTR pszType)
|
|
{
|
|
// default to "documents"
|
|
int iIndexFound = 0;
|
|
for (int iIndex = 0; iIndex < ARRAYSIZE(c_wvtiList); iIndex++)
|
|
{
|
|
if (lstrcmpi(c_wvtiList[iIndex].pszFolderType, pszType) == 0)
|
|
{
|
|
iIndexFound = iIndex;
|
|
break;
|
|
}
|
|
}
|
|
return iIndexFound;
|
|
}
|
|
|
|
// Fill the combobox with templates' friendly names.
|
|
void CFolderCustomize::_FillTemplateComboBox(HWND hwndTemplates)
|
|
{
|
|
// Disable redraws while we mess repeatedly with the contents.
|
|
SendMessage(hwndTemplates, WM_SETREDRAW, FALSE, 0);
|
|
|
|
TCHAR szType[25];
|
|
szType[0] = 0;
|
|
SHPropertyBag_ReadStr(_ppb, PROPSTR_FOLDERTYPE, szType, ARRAYSIZE(szType));
|
|
|
|
int nFolderTypeIndex = _GetTemplateIndexFromType(szType); // store index into c_wvtiList
|
|
int iIndex = 0; // index into combobox
|
|
// Add each template to the listview.
|
|
for (int nTemplate = 0; nTemplate < ARRAYSIZE(c_wvtiList); nTemplate++)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
SFVM_WEBVIEW_TEMPLATE_DATA wvData;
|
|
if (!(c_wvtiList[nTemplate].dwFlags & WVTI_SHOWIFOLDTEMPLATE) ||
|
|
(SHGetPathFromIDList(_pidl, szPath) && SUCCEEDED(DefaultGetWebViewTemplateFromPath(szPath, &wvData))))
|
|
{
|
|
TCHAR szFriendlyName[100];
|
|
LoadString(HINST_THISDLL, c_wvtiList[nTemplate].uIDFriendly, szFriendlyName, ARRAYSIZE(szFriendlyName));
|
|
|
|
int iIndexAdd = ComboBox_AddString(hwndTemplates, szFriendlyName);
|
|
if (iIndexAdd != -1)
|
|
{
|
|
if (nTemplate == nFolderTypeIndex)
|
|
{
|
|
iIndex = iIndexAdd;
|
|
}
|
|
ComboBox_SetItemData(hwndTemplates, iIndexAdd, nTemplate);
|
|
}
|
|
}
|
|
}
|
|
|
|
// pick default
|
|
ComboBox_SetCurSel(hwndTemplates, iIndex);
|
|
|
|
// Reenable redraws.
|
|
SendMessage(hwndTemplates, WM_SETREDRAW, TRUE, 0);
|
|
InvalidateRect(hwndTemplates, NULL, TRUE);
|
|
}
|
|
|
|
void CFolderCustomize::_SetThumbnail(HWND hwnd)
|
|
{
|
|
_szLogoFile[0] = 0;
|
|
SHPropertyBag_ReadStr(_ppb, PROPSTR_LOGO, _szLogoFile, ARRAYSIZE(_szLogoFile));
|
|
|
|
_fUsingThumb = _szLogoFile[0];
|
|
|
|
_CreateThumbnailBitmap(hwnd);
|
|
}
|
|
|
|
void CFolderCustomize::_SetRecurseBox(HWND hwnd)
|
|
{
|
|
IPropertyBag *ppbInherit;
|
|
if (SUCCEEDED(SHGetViewStatePropertyBag(_pidl, VS_BAGSTR_EXPLORER, SHGVSPB_INHERIT, IID_PPV_ARG(IPropertyBag, &ppbInherit))))
|
|
{
|
|
TCHAR szTypeInherit[MAX_PATH];
|
|
if (SUCCEEDED(SHPropertyBag_ReadStr(ppbInherit, PROPSTR_FOLDERTYPE, szTypeInherit, ARRAYSIZE(szTypeInherit))) && szTypeInherit[0])
|
|
{
|
|
TCHAR szType[MAX_PATH];
|
|
if (SUCCEEDED(SHPropertyBag_ReadStr(_ppb, PROPSTR_FOLDERTYPE, szType, ARRAYSIZE(szType))) &&
|
|
(lstrcmpi(szTypeInherit, szType) == 0))
|
|
{
|
|
Button_SetCheck(GetDlgItem(hwnd, IDC_FOLDER_RECURSE), TRUE);
|
|
}
|
|
}
|
|
ppbInherit->Release();
|
|
}
|
|
}
|
|
|
|
// since changing the icon isn't in the peruser property bag (yet [it was punted from whistler])
|
|
// we need to disable this section if we know it can't be modified.
|
|
void CFolderCustomize::_HideIconSection(HWND hwndDlg)
|
|
{
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_CHANGEICONGROUP), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_CHANGEICON), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_CHANGEICONTEXT), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_ICON), SW_HIDE);
|
|
}
|
|
|
|
void CFolderCustomize::_InitDialog(HWND hwndDlg)
|
|
{
|
|
HWND hwndTemplates = GetDlgItem(hwndDlg, IDC_FOLDER_TEMPLATES);
|
|
if (hwndTemplates)
|
|
{
|
|
_FillTemplateComboBox(GetDlgItem(hwndDlg, IDC_FOLDER_TEMPLATES));
|
|
EnableWindow(hwndTemplates, TRUE);
|
|
|
|
_SetThumbnail(hwndDlg);
|
|
|
|
// Disable the Icon Change button if we the IShellFolder doesn't support ICustomIconManager interface.
|
|
if (_ShouldEnableChangeOfIcon())
|
|
{
|
|
_CreateFolderIcon(hwndDlg);
|
|
}
|
|
else
|
|
{
|
|
_HideIconSection(hwndDlg);
|
|
}
|
|
|
|
_SetRecurseBox(hwndDlg);
|
|
}
|
|
}
|
|
|
|
// helpers moved from mulprsht
|
|
|
|
// How do we selectively disable for .exe
|
|
BOOL CFolderCustomize::_ShouldEnableChangeOfIcon()
|
|
{
|
|
if (!_pIconManager)
|
|
{
|
|
SHGetUIObjectFromFullPIDL(_pidl, NULL, IID_PPV_ARG(ICustomIconManager, &_pIconManager));
|
|
}
|
|
|
|
return BOOLIFY(_pIconManager);
|
|
}
|
|
|
|
void CFolderCustomize::_EnableApply(HWND hwnd)
|
|
{
|
|
PropSheet_Changed(GetParent(hwnd), hwnd);
|
|
}
|
|
|
|
void CFolderCustomize::_ChangeFolderIcon(HWND hwndDlg)
|
|
{
|
|
ASSERT(_pIconManager);
|
|
|
|
TCHAR szDialogCaptionFmt[MAX_PATH];
|
|
LoadString(HINST_THISDLL, IDS_FOLDER_PICKICONDLG_CAPTION, szDialogCaptionFmt, ARRAYSIZE(szDialogCaptionFmt));
|
|
|
|
TCHAR szFileName[MAX_PATH], szDialogCaption[MAX_PATH];
|
|
if (SUCCEEDED(SHGetNameAndFlags(_pidl, SHGDN_NORMAL, szFileName, ARRAYSIZE(szFileName), NULL)))
|
|
{
|
|
StringCchPrintf(szDialogCaption, ARRAYSIZE(szDialogCaption), szDialogCaptionFmt, PathFindFileName(szFileName)); // ok to truncate - display only
|
|
}
|
|
|
|
if (SUCCEEDED(_ProcessIconChange(szDialogCaption, hwndDlg)))
|
|
{
|
|
_EnableApply(hwndDlg);
|
|
}
|
|
}
|
|
|
|
HRESULT CFolderCustomize::_ProcessIconChange(LPCTSTR pszPickIconDialogCaption, HWND hwndDlg)
|
|
{
|
|
int nIconIndex = -1;
|
|
|
|
TCHAR szIconPath[MAX_PATH];
|
|
szIconPath[0] = 0;
|
|
|
|
HRESULT hr = PickIconDlgWithTitle(hwndDlg, pszPickIconDialogCaption, TRUE, szIconPath, ARRAYSIZE(szIconPath), &nIconIndex);
|
|
_hrFromIconChange = hr;
|
|
switch (hr)
|
|
{
|
|
case S_OK:
|
|
{
|
|
HICON hIcon = ExtractIcon(HINST_THISDLL, szIconPath, nIconIndex);
|
|
if (hIcon != NULL)
|
|
{
|
|
if (SUCCEEDED(StringCchCopy(_szIconPath, ARRAYSIZE(_szIconPath), szIconPath)))
|
|
{
|
|
_iIconIndex = nIconIndex;
|
|
ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, hIcon);
|
|
}
|
|
else
|
|
{
|
|
DestroyIcon(hIcon);
|
|
_hrFromIconChange = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_hrFromIconChange = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case S_FALSE:
|
|
{
|
|
HICON hIcon;
|
|
if (SUCCEEDED(_pIconManager->GetDefaultIconHandle(&hIcon)))
|
|
{
|
|
ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, hIcon);
|
|
}
|
|
else
|
|
{
|
|
_hrFromIconChange = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case HRESULT_FROM_WIN32(ERROR_CANCELLED):
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|