879 lines
23 KiB
C++
879 lines
23 KiB
C++
|
|
||
|
#include "priv.h"
|
||
|
#include "sccls.h"
|
||
|
#include "bands.h"
|
||
|
#include "bsmenu.h"
|
||
|
#include "isfband.h"
|
||
|
#include "legacy.h"
|
||
|
#include "resource.h"
|
||
|
#include "uemapp.h"
|
||
|
#include "enumband.h"
|
||
|
|
||
|
#include "mluisupp.h"
|
||
|
|
||
|
static const CLSID g_clsidNull = {0};
|
||
|
|
||
|
#define DPA_SafeGetPtrCount(hdpa) (hdpa ? DPA_GetPtrCount(hdpa) : 0)
|
||
|
|
||
|
HRESULT CBandSiteMenu_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
|
||
|
{
|
||
|
// aggregation checking is handled in class factory
|
||
|
|
||
|
CBandSiteMenu *p = new CBandSiteMenu();
|
||
|
if (p)
|
||
|
{
|
||
|
*ppunk = SAFECAST(p, IShellService*);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
CBandSiteMenu::CBandSiteMenu() : _cRef(1)
|
||
|
{
|
||
|
DllAddRef();
|
||
|
}
|
||
|
|
||
|
CBandSiteMenu::~CBandSiteMenu()
|
||
|
{
|
||
|
DPA_DestroyCallback(_hdpaBandClasses, _DPA_FreeBandClassInfo, 0);
|
||
|
_hdpaBandClasses = NULL;
|
||
|
SetOwner(NULL);
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
int CBandSiteMenu::_DPA_FreeBandClassInfo(LPVOID p, LPVOID d)
|
||
|
{
|
||
|
BANDCLASSINFO *pbci = (BANDCLASSINFO*)p;
|
||
|
|
||
|
// req'd
|
||
|
ASSERT(pbci->pszName || (*(int *)&pbci->clsid == 0));
|
||
|
|
||
|
if (pbci->pszName)
|
||
|
LocalFree(pbci->pszName);
|
||
|
|
||
|
// optional
|
||
|
if (pbci->pszIcon != NULL)
|
||
|
LocalFree(pbci->pszIcon);
|
||
|
if (pbci->pszMenu != NULL)
|
||
|
LocalFree(pbci->pszMenu);
|
||
|
if (pbci->pszHelp != NULL)
|
||
|
LocalFree(pbci->pszHelp);
|
||
|
if (pbci->pszMenuPUI != NULL)
|
||
|
LocalFree(pbci->pszMenuPUI);
|
||
|
if (pbci->pszHelpPUI != NULL)
|
||
|
LocalFree(pbci->pszHelpPUI);
|
||
|
|
||
|
LocalFree(pbci);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG CBandSiteMenu::AddRef()
|
||
|
{
|
||
|
_cRef++;
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
ULONG CBandSiteMenu::Release()
|
||
|
{
|
||
|
ASSERT(_cRef > 0);
|
||
|
_cRef--;
|
||
|
|
||
|
if (_cRef > 0)
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::SetOwner(IUnknown* punk)
|
||
|
{
|
||
|
ATOMICRELEASE(_pbs);
|
||
|
|
||
|
if (punk)
|
||
|
{
|
||
|
punk->QueryInterface(IID_IBandSite, (LPVOID*)&_pbs);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
return HandleMenuMsg2(uMsg, wParam, lParam, NULL);
|
||
|
}
|
||
|
|
||
|
UINT CBandSiteMenu::_IDToInternal(UINT uID)
|
||
|
{
|
||
|
if (uID != -1)
|
||
|
{
|
||
|
uID -= _idCmdFirst;
|
||
|
}
|
||
|
|
||
|
return uID;
|
||
|
}
|
||
|
|
||
|
UINT CBandSiteMenu::_IDToExternal(UINT uID)
|
||
|
{
|
||
|
if (uID != -1)
|
||
|
{
|
||
|
uID += _idCmdFirst;
|
||
|
}
|
||
|
|
||
|
return uID;
|
||
|
}
|
||
|
|
||
|
LRESULT CBandSiteMenu::_OnInitMenuPopup(HMENU hmenu, UINT uPos)
|
||
|
{
|
||
|
//
|
||
|
// Is this is the "Toolbars >" submenu (which we populate
|
||
|
// lazily), and has it not yet been populated?
|
||
|
//
|
||
|
UINT uID = GetMenuItemID(hmenu, 0);
|
||
|
uID = _IDToInternal(uID);
|
||
|
if (uID == DBIDM_DESKTOPBAND)
|
||
|
{
|
||
|
// Yes
|
||
|
_PopulateSubmenu(hmenu);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
|
||
|
{
|
||
|
LRESULT lres = 0;
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_INITMENUPOPUP:
|
||
|
lres = _OnInitMenuPopup((HMENU)wParam, LOWORD(lParam));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (plres)
|
||
|
*plres = lres;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
||
|
{
|
||
|
static const QITAB qit[] =
|
||
|
{
|
||
|
QITABENT(CBandSiteMenu, IContextMenu3),
|
||
|
QITABENTMULTI(CBandSiteMenu, IContextMenu2, IContextMenu3),
|
||
|
QITABENTMULTI(CBandSiteMenu, IContextMenu, IContextMenu3),
|
||
|
QITABENT(CBandSiteMenu, IShellService),
|
||
|
{ 0 },
|
||
|
};
|
||
|
|
||
|
HRESULT hres = QISearch(this, qit, riid, ppvObj);
|
||
|
|
||
|
if (FAILED(hres))
|
||
|
{
|
||
|
if (IsEqualIID(riid, CLSID_BandSiteMenu))
|
||
|
{
|
||
|
*ppvObj = (void *) this;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
#define MAX_BANDS 50
|
||
|
|
||
|
void CBandSiteMenu::_PopulateSubmenu(HMENU hmenuSub)
|
||
|
{
|
||
|
// the start id is the last of the fixed bands.
|
||
|
// when we do the Shell_MergeMenus below, it will be incremented by idCmdFirst
|
||
|
|
||
|
ASSERT(hmenuSub);
|
||
|
|
||
|
CATID catid = CATID_DeskBand;
|
||
|
|
||
|
if (_hdpaBandClasses)
|
||
|
{
|
||
|
DPA_DestroyCallback(_hdpaBandClasses, _DPA_FreeBandClassInfo, 0);
|
||
|
_hdpaBandClasses = NULL;
|
||
|
}
|
||
|
|
||
|
LoadFromComCat(&catid);
|
||
|
|
||
|
// Kick off an asynchronous update of the comcat cache
|
||
|
SHWriteClassesOfCategories(1, &catid, 0, NULL, TRUE, FALSE, NULL);
|
||
|
|
||
|
_idCmdEnumFirst = CreateMergeMenu(hmenuSub, MAX_BANDS, 0, _IDToExternal(DBIDM_NEWBANDFIXEDLAST), 0, FALSE);
|
||
|
|
||
|
_AddEnumMenu(hmenuSub, GetMenuItemCount(hmenuSub) - 2); // -2 to go before "New Toolbar" and separator
|
||
|
|
||
|
int iIndex = GetMenuItemCount(hmenuSub);
|
||
|
if (SHRestricted(REST_NOCLOSE_DRAGDROPBAND) || SHRestricted(REST_CLASSICSHELL))
|
||
|
{
|
||
|
// We also need to disable turning On or Off the Bands.
|
||
|
// In classic mode, don't allow them either.
|
||
|
int nIter;
|
||
|
for (nIter = 0; nIter < iIndex; nIter++)
|
||
|
EnableMenuItem(hmenuSub, nIter, MF_BYPOSITION | MF_GRAYED);
|
||
|
}
|
||
|
|
||
|
if (SHRestricted(REST_CLASSICSHELL))
|
||
|
{
|
||
|
// Disable New Toolbar menu also.
|
||
|
EnableMenuItem(hmenuSub, DBIDM_NEWFOLDERBAND, MF_BYCOMMAND | MF_GRAYED);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::QueryContextMenu(HMENU hmenu,
|
||
|
UINT indexMenu,
|
||
|
UINT idCmdFirst,
|
||
|
UINT idCmdLast,
|
||
|
UINT uFlags)
|
||
|
{
|
||
|
if (!_pbs)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (SHRestricted(REST_NOTOOLBARSONTASKBAR))
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
HMENU hmenuSrc = LoadMenuPopup_PrivateNoMungeW(MENU_DESKBARAPP);
|
||
|
if (hmenuSrc)
|
||
|
{
|
||
|
_idCmdFirst = idCmdFirst;
|
||
|
|
||
|
Shell_MergeMenus(hmenu, hmenuSrc, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
|
||
|
DestroyMenu(hmenuSrc);
|
||
|
|
||
|
if (_SHIsMenuSeparator(hmenu, indexMenu))
|
||
|
{
|
||
|
//
|
||
|
// Adjust indexMenu to point to the spot where the Toolbars
|
||
|
// submenu was actually inserted.
|
||
|
//
|
||
|
indexMenu++;
|
||
|
}
|
||
|
|
||
|
if (!(uFlags & CMF_ICM3))
|
||
|
{
|
||
|
//
|
||
|
// Caller doesn't speak ICM3, so won't give us a chance to
|
||
|
// populate submenu on WM_INITMENUPOPUP. Thus we need to
|
||
|
// populate it now.
|
||
|
//
|
||
|
HMENU hmenuSub = GetSubMenu(hmenu, indexMenu);
|
||
|
|
||
|
if (hmenuSub)
|
||
|
_PopulateSubmenu(hmenuSub);
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// _OnInitMenuPopup assumes DBIDM_DESKTOPBAND is the first item
|
||
|
// in the "Toolbars >" submenu. If that assumption breaks (and
|
||
|
// you see this ASSERT rip), be sure to fix up the code there.
|
||
|
//
|
||
|
HMENU hmenuSub = GetSubMenu(hmenu, indexMenu);
|
||
|
ASSERT(GetMenuItemID(hmenuSub, 0) == _IDToExternal(DBIDM_DESKTOPBAND));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Assert that our caller gave us enough room to accomodate
|
||
|
// the worst-case count.
|
||
|
//
|
||
|
ASSERT((idCmdFirst + DBIDM_NEWBANDFIXEDLAST + MAX_BANDS) < idCmdLast);
|
||
|
|
||
|
return idCmdFirst + DBIDM_NEWBANDFIXEDLAST + MAX_BANDS;
|
||
|
}
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
BOOL CBandSiteMenu::_CheckUnique(IDeskBand* pdb, HMENU hmenu)
|
||
|
{
|
||
|
// check to see if this band is unique. (not already added by comcat list or
|
||
|
// hard coded list
|
||
|
// if it is unique, return TRUE.
|
||
|
// if it's not, check the other menu item
|
||
|
CLSID clsid;
|
||
|
DWORD dwPrivID;
|
||
|
BOOL fRet = TRUE;
|
||
|
UINT idCmd = (UINT)-1;
|
||
|
|
||
|
if (SUCCEEDED(_GetBandIdentifiers(pdb, &clsid, &dwPrivID)))
|
||
|
{
|
||
|
// check the comcat list
|
||
|
if (dwPrivID == (DWORD)-1)
|
||
|
{
|
||
|
for (int i = 0; i < DPA_SafeGetPtrCount(_hdpaBandClasses) ; i++)
|
||
|
{
|
||
|
BANDCLASSINFO *pbci = (BANDCLASSINFO*)DPA_GetPtr(_hdpaBandClasses, i);
|
||
|
if (IsEqualGUID(clsid, pbci->clsid))
|
||
|
{
|
||
|
idCmd = i + DBIDM_NEWBANDFIXEDLAST;
|
||
|
goto FoundIt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualGUID(clsid, CLSID_ISFBand))
|
||
|
{
|
||
|
// check our hardcoded list
|
||
|
|
||
|
switch (dwPrivID)
|
||
|
{
|
||
|
case CSIDL_DESKTOP:
|
||
|
idCmd = DBIDM_DESKTOPBAND;
|
||
|
break;
|
||
|
|
||
|
case CSIDL_APPDATA:
|
||
|
idCmd = DBIDM_LAUNCHBAND;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FoundIt:
|
||
|
if (idCmd != (UINT)-1)
|
||
|
{
|
||
|
// we found a menu for this already.... if it wasn't already checked,
|
||
|
// check it now and it will represent us
|
||
|
if (!(GetMenuState(hmenu, _IDToExternal(idCmd), MF_BYCOMMAND) & MF_CHECKED))
|
||
|
{
|
||
|
CheckMenuItem(hmenu, _IDToExternal(idCmd), MF_BYCOMMAND | MF_CHECKED);
|
||
|
fRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
void CBandSiteMenu::_AddEnumMenu(HMENU hmenu, int iInsert)
|
||
|
{
|
||
|
DWORD dwID;
|
||
|
|
||
|
int iMax = MAX_BANDS - (_IDToInternal(_idCmdEnumFirst) - DBIDM_NEWBANDFIXEDLAST);
|
||
|
|
||
|
for (int i = 0; i < iMax && SUCCEEDED(_pbs->EnumBands(i, &dwID)); i++)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
WCHAR szName[80];
|
||
|
DWORD dwFlags = MF_BYPOSITION;
|
||
|
DWORD dwState;
|
||
|
IDeskBand *pdb;
|
||
|
|
||
|
hr = _pbs->QueryBand(dwID, &pdb, &dwState, szName, ARRAYSIZE(szName));
|
||
|
if (EVAL(SUCCEEDED(hr)))
|
||
|
{
|
||
|
if (_CheckUnique(pdb, hmenu))
|
||
|
{
|
||
|
if (dwState & BSSF_VISIBLE)
|
||
|
dwFlags |= MF_CHECKED;
|
||
|
|
||
|
if (!(dwState & BSSF_UNDELETEABLE))
|
||
|
{
|
||
|
InsertMenu(hmenu, iInsert, dwFlags, _idCmdEnumFirst + i, szName);
|
||
|
iInsert++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pdb)
|
||
|
pdb->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::_GetBandIdentifiers(IUnknown *punk, CLSID* pclsid, DWORD* pdwPrivID)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
IPersist* pp;
|
||
|
|
||
|
if (SUCCEEDED(punk->QueryInterface(IID_IPersist, (LPVOID*)&pp)))
|
||
|
{
|
||
|
pp->GetClassID(pclsid);
|
||
|
|
||
|
VARIANTARG v = {0};
|
||
|
*pdwPrivID = (DWORD) -1;
|
||
|
if (SUCCEEDED(IUnknown_Exec(punk, &CGID_ISFBand, ISFBID_PRIVATEID, 0, NULL, &v)))
|
||
|
{
|
||
|
if (v.vt == VT_I4)
|
||
|
{
|
||
|
*pdwPrivID = (DWORD)v.lVal;
|
||
|
}
|
||
|
}
|
||
|
hr = S_OK;
|
||
|
pp->Release();
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// we use IPersist to find the class id of bands.
|
||
|
// we have a few special case bands (such as Quick Launch and Desktop) that are
|
||
|
// the same band, but pointing to different objects.
|
||
|
HRESULT CBandSiteMenu::_FindBand(const CLSID* pclsid, DWORD dwPrivID, DWORD* pdwBandID)
|
||
|
{
|
||
|
int i = 0;
|
||
|
BOOL fFound = FALSE;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
DWORD dwBandID = -1;
|
||
|
|
||
|
while (hr == E_FAIL && SUCCEEDED(_pbs->EnumBands(i, &dwBandID)))
|
||
|
{
|
||
|
IDeskBand* pdb;
|
||
|
|
||
|
if (SUCCEEDED(_pbs->QueryBand(dwBandID, &pdb, NULL, NULL, 0)))
|
||
|
{
|
||
|
CLSID clsid;
|
||
|
DWORD dwPrivData;
|
||
|
if (SUCCEEDED(_GetBandIdentifiers(pdb, &clsid, &dwPrivData)))
|
||
|
{
|
||
|
// special case for differentiating between all of the isfbands
|
||
|
// find out if the private id this holds is the same as what we're asking for
|
||
|
if (IsEqualIID(clsid, *pclsid) && (dwPrivData == dwPrivID))
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
pdb->Release();
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (pdwBandID)
|
||
|
*pdwBandID = dwBandID;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||
|
{
|
||
|
int idCmd;
|
||
|
|
||
|
if (!_pbs)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (!HIWORD(pici->lpVerb))
|
||
|
idCmd = LOWORD(pici->lpVerb);
|
||
|
else
|
||
|
return E_FAIL;
|
||
|
|
||
|
//
|
||
|
// N.B.: Caller has mapped idCmd to internal for us
|
||
|
//
|
||
|
|
||
|
int idCmdEnumFirstInt = _IDToInternal(_idCmdEnumFirst);
|
||
|
|
||
|
if (idCmd >= idCmdEnumFirstInt)
|
||
|
{
|
||
|
// these are the bands that they're turning on and off
|
||
|
|
||
|
DWORD dwID;
|
||
|
if (SUCCEEDED(_pbs->EnumBands(idCmd - idCmdEnumFirstInt, &dwID)))
|
||
|
{
|
||
|
_pbs->RemoveBand(dwID);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// these are our merged menus from MENU_DESKBARAPP
|
||
|
switch (idCmd)
|
||
|
{
|
||
|
case DBIDM_NEWFOLDERBAND:
|
||
|
_BrowseForNewFolderBand();
|
||
|
break;
|
||
|
|
||
|
case DBIDM_DESKTOPBAND:
|
||
|
_ToggleSpecialFolderBand(CSIDL_DESKTOP, NULL, FALSE);
|
||
|
break;
|
||
|
|
||
|
case DBIDM_LAUNCHBAND:
|
||
|
{
|
||
|
TCHAR szSubDir[MAX_PATH];
|
||
|
MLLoadString(IDS_QLAUNCHAPPDATAPATH, szSubDir, ARRAYSIZE(szSubDir));
|
||
|
// Microsoft\\Internet Explorer\\Quick Launch
|
||
|
_ToggleSpecialFolderBand(CSIDL_APPDATA, szSubDir, TRUE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
ASSERT(idCmd >= DBIDM_NEWBANDFIXEDLAST);
|
||
|
_ToggleComcatBand(idCmd - DBIDM_NEWBANDFIXEDLAST);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CBandSiteMenu::_BandClassEnum(REFCATID rcatid, REFCLSID rclsid, LPARAM lParam)
|
||
|
{
|
||
|
TCHAR szName[128],
|
||
|
szRegName[128],
|
||
|
szClass[GUIDSTR_MAX];
|
||
|
DWORD cbName;
|
||
|
|
||
|
HDPA hdpa = (HDPA)lParam;
|
||
|
ASSERT(NULL != hdpa);
|
||
|
|
||
|
// IE4 introduced this band, suppress it since we cut support for it in IE6
|
||
|
if (IsEqualCLSID(CLSID_ChannelBand, rclsid))
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
BANDCLASSINFO *pbci = (BANDCLASSINFO*)LocalAlloc(LPTR, sizeof(*pbci));
|
||
|
if (NULL == pbci)
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
pbci->clsid = rclsid;
|
||
|
pbci->catid = rcatid;
|
||
|
// now that we have the clsid,
|
||
|
// look in the registry for the display name
|
||
|
SHStringFromGUID(pbci->clsid, szClass, ARRAYSIZE(szClass));
|
||
|
wnsprintf(szRegName, ARRAYSIZE(szRegName), TEXT("CLSID\\%s"), szClass);
|
||
|
|
||
|
cbName = ARRAYSIZE(szName);
|
||
|
if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, szRegName, NULL, NULL, szName, &cbName))
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
|
||
|
pbci->pszName = StrDup(szName);
|
||
|
if (NULL == pbci->pszName)
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, szRegName, &hkey))
|
||
|
{
|
||
|
const struct regstrs rstab[] =
|
||
|
{
|
||
|
{ TEXT("DefaultIcon"), FIELD_OFFSET(BANDCLASSINFO, pszIcon) },
|
||
|
{ TEXT("MenuText") , FIELD_OFFSET(BANDCLASSINFO, pszMenu) },
|
||
|
{ TEXT("HelpText") , FIELD_OFFSET(BANDCLASSINFO, pszHelp) },
|
||
|
{ TEXT("MenuTextPUI"), FIELD_OFFSET(BANDCLASSINFO, pszMenuPUI) },
|
||
|
{ TEXT("HelpTextPUI"), FIELD_OFFSET(BANDCLASSINFO, pszHelpPUI) },
|
||
|
{ 0, 0 },
|
||
|
};
|
||
|
|
||
|
// szBuf big enough for "path,-32767" or for status text
|
||
|
TCHAR szBuf[MAX_PATH+7];
|
||
|
|
||
|
Reg_GetStrs(hkey, rstab, szBuf, (int)ARRAYSIZE(szBuf), (LPVOID)pbci);
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
|
||
|
DPA_AppendPtr(hdpa, pbci);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//***
|
||
|
// Collect band class info from registry...
|
||
|
int CBandSiteMenu::LoadFromComCat(const CATID *pcatid )
|
||
|
{
|
||
|
if (NULL == _hdpaBandClasses)
|
||
|
{
|
||
|
_hdpaBandClasses = DPA_Create(4);
|
||
|
}
|
||
|
|
||
|
if (NULL != _hdpaBandClasses && NULL != pcatid)
|
||
|
{
|
||
|
SHEnumClassesImplementingCATID(*pcatid, CBandSiteMenu::_BandClassEnum, (LPARAM)_hdpaBandClasses);
|
||
|
}
|
||
|
|
||
|
return DPA_SafeGetPtrCount(_hdpaBandClasses);
|
||
|
}
|
||
|
|
||
|
|
||
|
int CBandSiteMenu::CreateMergeMenu(HMENU hmenu, UINT cMax, UINT iPosition, UINT idCmdFirst, UINT iStart, BOOL fMungeAllowed)
|
||
|
{
|
||
|
int j = 0;
|
||
|
int iMax = DPA_SafeGetPtrCount(_hdpaBandClasses);
|
||
|
|
||
|
for (int i = iStart; i < iMax; i++)
|
||
|
{
|
||
|
if ((UINT)j >= cMax)
|
||
|
{
|
||
|
TraceMsg(DM_WARNING, "cbsm.cmm: cMax=%u menu overflow, truncated", cMax);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
BANDCLASSINFO *pbci = (BANDCLASSINFO*)DPA_GetPtr(_hdpaBandClasses, i);
|
||
|
DWORD dwFlags = IsEqualCLSID(g_clsidNull,pbci->clsid) ? MF_BYPOSITION|MF_SEPARATOR : MF_BYPOSITION;
|
||
|
LPTSTR pszMenuText = pbci->pszMenuPUI ? pbci->pszMenuPUI : (pbci->pszMenu ? pbci->pszMenu : pbci->pszName) ;
|
||
|
|
||
|
if (pszMenuText && *pszMenuText)
|
||
|
{
|
||
|
BOOL fInsert;
|
||
|
|
||
|
if (fMungeAllowed)
|
||
|
{
|
||
|
fInsert = InsertMenu(hmenu, iPosition + j, dwFlags, idCmdFirst + j, pszMenuText);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fInsert = InsertMenu_PrivateNoMungeW(hmenu, iPosition + j, dwFlags, idCmdFirst + j, pszMenuText);
|
||
|
}
|
||
|
|
||
|
if (fInsert)
|
||
|
{
|
||
|
// update menuitem cmd ID:
|
||
|
pbci->idCmd = idCmdFirst + j;
|
||
|
j++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return j + idCmdFirst;
|
||
|
}
|
||
|
|
||
|
|
||
|
BANDCLASSINFO * CBandSiteMenu::GetBandClassDataStruct(UINT uBand)
|
||
|
{
|
||
|
BANDCLASSINFO * pbci = (BANDCLASSINFO *)DPA_GetPtr(_hdpaBandClasses, uBand);
|
||
|
return pbci;
|
||
|
}
|
||
|
|
||
|
BOOL CBandSiteMenu::DeleteBandClass( REFCLSID rclsid )
|
||
|
{
|
||
|
if( _hdpaBandClasses )
|
||
|
{
|
||
|
for( int i = 0, cnt = GetBandClassCount( NULL, FALSE ); i< cnt; i++ )
|
||
|
{
|
||
|
BANDCLASSINFO * pbci = (BANDCLASSINFO *)DPA_GetPtr( _hdpaBandClasses, i );
|
||
|
ASSERT( pbci );
|
||
|
|
||
|
if( IsEqualCLSID( rclsid, pbci->clsid ) )
|
||
|
{
|
||
|
EVAL( DPA_DeletePtr( _hdpaBandClasses, i ) == (LPVOID)pbci );
|
||
|
|
||
|
if( pbci->pszName )
|
||
|
LocalFree(pbci->pszName);
|
||
|
LocalFree( pbci );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
int CBandSiteMenu::GetBandClassCount(const CATID* pcatid /*NULL*/, BOOL bMergedOnly /*FALSE*/)
|
||
|
{
|
||
|
int cRet = 0;
|
||
|
|
||
|
if( _hdpaBandClasses != NULL )
|
||
|
{
|
||
|
int cBands = DPA_GetPtrCount(_hdpaBandClasses);
|
||
|
|
||
|
if( pcatid || bMergedOnly ) // filter request
|
||
|
{
|
||
|
for( int i = 0; i < cBands; i++ )
|
||
|
{
|
||
|
BANDCLASSINFO * pbci = (BANDCLASSINFO *)DPA_FastGetPtr( _hdpaBandClasses, i );
|
||
|
|
||
|
if( pbci->idCmd || !bMergedOnly )
|
||
|
{
|
||
|
if( pcatid )
|
||
|
{
|
||
|
if( IsEqualGUID( pbci->catid, *pcatid ) )
|
||
|
cRet++;
|
||
|
}
|
||
|
else
|
||
|
cRet++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
cRet = cBands;
|
||
|
}
|
||
|
return cRet;
|
||
|
}
|
||
|
|
||
|
void CBandSiteMenu::_AddNewFSBand(LPCITEMIDLIST pidl, BOOL fNoTitleText, DWORD dwPrivID)
|
||
|
{
|
||
|
IDeskBand *ptb = NULL;
|
||
|
BOOL fISF = FALSE;
|
||
|
|
||
|
// this was a drag of a link or folder
|
||
|
// FEATURE: We should use a different test:
|
||
|
// DWORD dwAttrib = (SFGAO_FOLDER | SFGAO_BROWSABLE);
|
||
|
// IEGetAttributesOf(pidl, &dwAttrib);
|
||
|
// if (SFGAO_BROWSABLE != dwAttrib)
|
||
|
// or we could reuse SHCreateBandForPidl().
|
||
|
if (IsURLChild(pidl, TRUE))
|
||
|
{
|
||
|
// create browser to show web sites
|
||
|
ptb = CBrowserBand_Create(pidl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IFolderBandPriv *pfbp;
|
||
|
// create an ISF band to show folders as hotlinks
|
||
|
fISF = TRUE;
|
||
|
ASSERT(pidl); // o.w. CISFBand_CreateEx will fail
|
||
|
if (FAILED(CISFBand_CreateEx(NULL, pidl, IID_PPV_ARG(IFolderBandPriv, &pfbp))))
|
||
|
{
|
||
|
// we need to give a pretty
|
||
|
// generic message: "can't create toolbar for %1".
|
||
|
TCHAR szName[MAX_URL_STRING];
|
||
|
|
||
|
szName[0] = 0;
|
||
|
SHGetNameAndFlags(pidl, SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
|
||
|
MLShellMessageBox(NULL,
|
||
|
MAKEINTRESOURCE(IDS_CANTISFBAND),
|
||
|
MAKEINTRESOURCE(IDS_WEBBARTITLE),
|
||
|
MB_OK|MB_ICONERROR, szName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pfbp->SetNoText(fNoTitleText);
|
||
|
if (SUCCEEDED(pfbp->QueryInterface(IID_PPV_ARG(IDeskBand, &ptb))))
|
||
|
{
|
||
|
if (dwPrivID != -1)
|
||
|
{
|
||
|
VARIANTARG v;
|
||
|
v.vt = VT_I4;
|
||
|
v.lVal = dwPrivID;
|
||
|
// find out if the private id this holds is the same as what we're asking for
|
||
|
IUnknown_Exec(ptb, &CGID_ISFBand, ISFBID_PRIVATEID, 0, &v, NULL);
|
||
|
// qlaunch and qlinks get logged
|
||
|
// (should we key off of host or CSIDL or both?)
|
||
|
// FEATURE: UASSIST todo: qlinks NYI
|
||
|
if (dwPrivID == CSIDL_APPDATA)
|
||
|
{
|
||
|
ASSERT(v.vt == VT_I4);
|
||
|
v.lVal = UEMIND_SHELL; // UEMIND_SHELL/BROWSER
|
||
|
IUnknown_Exec(ptb, &CGID_ShellDocView, SHDVID_UEMLOG, 0, &v, NULL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pfbp->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ptb)
|
||
|
{
|
||
|
HRESULT hr = _pbs->AddBand(ptb);
|
||
|
if (SUCCEEDED(hr) && fISF)
|
||
|
_pbs->SetBandState(ShortFromResult(hr), BSSF_NOTITLE, fNoTitleText ? BSSF_NOTITLE : 0);
|
||
|
ptb->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CBandSiteMenu::_ToggleSpecialFolderBand(int iFolder, LPTSTR pszSubPath, BOOL fNoTitleText)
|
||
|
{
|
||
|
|
||
|
DWORD dwBandID;
|
||
|
if (SUCCEEDED(_FindBand(&CLSID_ISFBand, iFolder, &dwBandID)))
|
||
|
{
|
||
|
_pbs->RemoveBand(dwBandID);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPITEMIDLIST pidl;
|
||
|
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, iFolder, &pidl)))
|
||
|
{
|
||
|
if (pszSubPath)
|
||
|
{
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
SHGetPathFromIDList(pidl, szPath);
|
||
|
PathCombine(szPath, szPath, pszSubPath);
|
||
|
ILFree(pidl);
|
||
|
pidl = ILCreateFromPath(szPath);
|
||
|
ASSERT(pidl); // o.w. AddNewFSBand will fail
|
||
|
}
|
||
|
_AddNewFSBand(pidl, fNoTitleText, iFolder);
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int CALLBACK SetCaptionCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||
|
{
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case BFFM_INITIALIZED:
|
||
|
TCHAR szTitle[80];
|
||
|
MLLoadShellLangString(IDS_NEWFSBANDCAPTION, szTitle, ARRAYSIZE(szTitle));
|
||
|
SetWindowText(hwnd, szTitle);
|
||
|
break;
|
||
|
|
||
|
case BFFM_VALIDATEFAILEDA:
|
||
|
case BFFM_VALIDATEFAILEDW:
|
||
|
MLShellMessageBox(hwnd,
|
||
|
uMsg == BFFM_VALIDATEFAILEDA ? MAKEINTRESOURCE(IDS_ERROR_GOTOA)
|
||
|
: MAKEINTRESOURCE(IDS_ERROR_GOTOW),
|
||
|
MAKEINTRESOURCE(IDS_WEBBARTITLE),
|
||
|
MB_OK|MB_ICONERROR, (LPVOID)lParam);
|
||
|
return 1; // 1:leave dialog up for another try...
|
||
|
/*NOTREACHED*/
|
||
|
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CBandSiteMenu::_BrowseForNewFolderBand()
|
||
|
{
|
||
|
BROWSEINFO bi = {0};
|
||
|
LPITEMIDLIST pidl;
|
||
|
TCHAR szTitle[256];
|
||
|
TCHAR szPath[MAX_URL_STRING];
|
||
|
|
||
|
if (_pbs)
|
||
|
IUnknown_GetWindow(_pbs, &bi.hwndOwner);
|
||
|
|
||
|
ASSERT(bi.pidlRoot == NULL);
|
||
|
|
||
|
MLLoadShellLangString(IDS_NEWFSBANDTITLE, szTitle, ARRAYSIZE(szTitle));
|
||
|
bi.lpszTitle = szTitle;
|
||
|
|
||
|
bi.pszDisplayName = szPath;
|
||
|
bi.ulFlags = (BIF_EDITBOX | BIF_VALIDATE | BIF_USENEWUI | BIF_BROWSEINCLUDEURLS);
|
||
|
bi.lpfn = SetCaptionCallback;
|
||
|
|
||
|
pidl = SHBrowseForFolder(&bi);
|
||
|
if (pidl)
|
||
|
{
|
||
|
_AddNewFSBand(pidl, FALSE, -1);
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CBandSiteMenu::_ToggleComcatBand(UINT idCmd)
|
||
|
{
|
||
|
BANDCLASSINFO* pbci = (BANDCLASSINFO*)DPA_GetPtr(_hdpaBandClasses, idCmd);
|
||
|
IUnknown* punk;
|
||
|
DWORD dwBandID;
|
||
|
|
||
|
if (SUCCEEDED(_FindBand(&pbci->clsid, -1, &dwBandID)))
|
||
|
{
|
||
|
_pbs->RemoveBand(dwBandID);
|
||
|
}
|
||
|
else if (S_OK == CoCreateInstance(pbci->clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (LPVOID*)&punk))
|
||
|
{
|
||
|
// Language returns S_FALSE and doesn't initialize punk leave us to fault
|
||
|
IPersistStreamInit * ppsi;
|
||
|
|
||
|
// Some Bands don't work if IPersistStreamInit::InitNew() isn't called.
|
||
|
// This includes the QuickLinks Band.
|
||
|
if (SUCCEEDED(punk->QueryInterface(IID_IPersistStreamInit, (LPVOID*)&ppsi)))
|
||
|
{
|
||
|
ppsi->InitNew();
|
||
|
ppsi->Release();
|
||
|
}
|
||
|
|
||
|
_pbs->AddBand(punk);
|
||
|
punk->Release();
|
||
|
}
|
||
|
}
|