Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

3218 lines
88 KiB

#include "priv.h"
#include "sccls.h"
#include <uxtheme.h>
#define WANT_CBANDSITE_CLASS
#include "bandsite.h"
#include "bandobj.h"
#include "caggunk.h"
#include "droptgt.h"
#include "resource.h"
#include "bands.h"
#include "legacy.h"
#include "apithk.h"
#include "mluisupp.h"
#define TF_BANDDD 0x00400000
#define DM_INIT 0 //
#define DM_PERSIST 0 // trace IPS::Load, ::Save, etc.
#define DM_MENU 0 // menu code
#define DM_DRAG 0 // drag&drop
#define DM_FOCUS 0 // focus
#define DM_PERF 0 // perf tune
#define DM_PERF2 0 // perf tune (verbose)
#define IDM_DRAGDROP 1
#define ISMOVEDDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_MOVE, BAND_ADMIN_NOMOVE)) ? TRUE : FALSE)
#define ISDDCLOSEDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_DRAG, BAND_ADMIN_NODDCLOSE)) ? TRUE : FALSE)
// drag state (NOTE from dockbar.h)
#define DRAG_NIL 0 // nil
#define DRAG_MOVE 1 // moving
#define DRAG_SIZE 2 // sizing
typedef struct {
UINT cx;
UINT fStyle;
UINT cxMinChild;
UINT cyMinChild;
UINT cyIntegral;
UINT cyMaxChild;
UINT cyChild;
} PERSISTBANDINFO_V3;
typedef struct {
UINT cx;
UINT fStyle;
UINT cxMinChild; // UNUSED. reclaim!
UINT cyMinChild;
UINT cyIntegral; // UNUSED
UINT cyMaxChild; // UNUSED.
UINT cyChild;
DWORD dwAdminSettings;
BITBOOL fNoTitle:1;
} PERSISTBANDINFO;
#define RBBIM_XPERSIST (RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE)
#ifdef DEBUG
extern unsigned long DbStreamTell(IStream *pstm);
#else
#define DbStreamTell(pstm) ((ULONG) 0)
#endif
UINT _FixMenuIndex(HMENU hmenu, UINT indexMenu)
{
UINT i;
i = GetMenuItemCount(hmenu);
if (indexMenu > i)
indexMenu = i;
return indexMenu;
}
#define SUPERCLASS CAggregatedUnknown
HRESULT CBandSite::v_InternalQueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
// perf: last tuned 980728
QITABENT(CBandSite, IBandSite), // IID_IBandSite
QITABENT(CBandSite, IInputObject), // IID_IInputObject
QITABENT(CBandSite, IServiceProvider), // IID_IServiceProvider
QITABENT(CBandSite, IOleCommandTarget), // IID_IOleCommandTarget
QITABENTMULTI(CBandSite, IOleWindow, IDeskBarClient), // IID_IOleWindow
QITABENT(CBandSite, IWinEventHandler), // IID_IWinEventHandler
QITABENT(CBandSite, IInputObjectSite), // IID_IInputObjectSite
QITABENT(CBandSite, IDeskBarClient), // IID_IDeskBarClient
QITABENTMULTI(CBandSite, IPersist, IPersistStream), // rare IID_IPersist
QITABENT(CBandSite, IPersistStream), // rare IID_IPersistStream
QITABENT(CBandSite, IBandSiteHelper), // rare IBandSiteHelper
QITABENT(CBandSite, IDropTarget), // rare IID_IDropTarget
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
DWORD _SetDataListFlags(IUnknown *punk, DWORD dwMaskBits, DWORD dwValue)
{
DWORD dw = 0;
IShellLinkDataList *pdl;
if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IShellLinkDataList, &pdl))))
{
pdl->GetFlags(&dw);
dw = (dw & ~dwMaskBits) | (dwValue & dwMaskBits);
pdl->SetFlags(dw);
pdl->Release();
}
return dw;
}
///// impl of IServiceProvider
HRESULT CBandSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
{
HRESULT hres = E_FAIL;
*ppvObj = NULL; // assume error
if (IsEqualIID(guidService, SID_IBandProxy))
{
hres = QueryService_SID_IBandProxy(_punkSite, riid, &_pbp, ppvObj);
if(!_pbp)
{
// We need to create it ourselves since our parent couldn't help
ASSERT(FALSE == _fCreatedBandProxy);
hres = CreateIBandProxyAndSetSite(_punkSite, riid, &_pbp, ppvObj);
if(_pbp)
{
ASSERT(S_OK == hres);
_fCreatedBandProxy = TRUE;
}
}
}
else if (IsEqualIID(guidService, SID_ITopViewHost))
{
return QueryInterface(riid, ppvObj);
}
else if (IsEqualIID(guidService, IID_IBandSite))
{
// It is common for bands to save/load pidls for persistence.
// CShellLink is a robust way to do this, so let's share one
// among all the bands.
//
// NOTE: This is shared between bands, so if you request it
// you must complete your use of it within the scope of your
// function call!
//
if (IsEqualIID(riid, IID_IShellLinkA) ||
IsEqualIID(riid, IID_IShellLinkW))
{
if (NULL == _plink)
CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &_plink));
if (_plink)
{
// we know that the bandsite is going to be pointing to local folders
// to avoid a perf hit we get in loading the LINKINFO.DLL we explictly
// disable that functionality here.
_SetDataListFlags(_plink, SLDF_FORCE_NO_LINKINFO, SLDF_FORCE_NO_LINKINFO);
hres = _plink->QueryInterface(riid, ppvObj);
}
}
}
else
{
hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
}
return hres;
}
HRESULT CBandSite::GetWindow(HWND * lphwnd)
{
*lphwnd = _hwnd;
return *lphwnd ? S_OK : E_FAIL;
}
CBandSite::CBandSite(IUnknown* punkAgg) : SUPERCLASS(punkAgg)
{
DWORD dwData = 0;
DWORD dwSize = SIZEOF(dwData);
// We assume this object was zero inited.
ASSERT(!_pbp);
ASSERT(FALSE == _fCreatedBandProxy);
SHRegGetUSValue(SZ_REGKEY_GLOBALADMINSETTINGS, SZ_REGVALUE_GLOBALADMINSETTINGS,
NULL, (LPVOID) &dwData, &dwSize, FALSE, NULL, 0);
if (IsFlagSet(dwData, BAND_ADMIN_ADMINMACHINE))
_fIEAKInstalled = TRUE;
else
_fIEAKInstalled = FALSE;
_dwStyle = BSIS_AUTOGRIPPER;
//
// We check whether or not this succeeded in CBandSite::_Initialize
//
_QueryOuterInterface(IID_PPV_ARG(IBandSite, &_pbsOuter));
DllAddRef();
}
void CBandSite::_ReleaseBandItemData(LPBANDITEMDATA pbid, int iIndex)
{
if (pbid->pdb)
{
REBARBANDINFO rbbi;
pbid->pdb->CloseDW(0);
if (-1 != iIndex)
{
// The band's hwnd is typically destroyed in CloseDW
rbbi.cbSize = sizeof(rbbi);
rbbi.fMask = RBBIM_CHILD | RBBIM_LPARAM;
rbbi.hwndChild = NULL;
rbbi.lParam = NULL;
EVAL( SendMessage(_hwnd, RB_SETBANDINFO, iIndex, (LPARAM) &rbbi) );
}
// this is called from remove and the destroy.
IUnknown_SetSite(pbid->pdb, NULL);
ATOMICRELEASE(pbid->pdb);
}
if (pbid->pweh == _pwehCache)
ATOMICRELEASE(_pwehCache);
ATOMICRELEASE(pbid->pweh);
LocalFree(pbid);
}
CBandSite::~CBandSite()
{
ATOMICRELEASE(_pdtobj);
if(_pbp && _fCreatedBandProxy)
_pbp->SetSite(NULL);
ATOMICRELEASE(_pbp);
ATOMICRELEASE(_pwehCache);
_CacheActiveBand(NULL);
_Close();
SetDeskBarSite(NULL);
if (_plink)
_plink->Release();
RELEASEOUTERINTERFACE(_pbsOuter);
DllRelease();
}
//*** _IsBandDeleteable --
// ENTRY/EXIT
// idBand band ID
// ret TRUE if deletable, o.w. FALSE (also FALSE on bogus band)
BOOL CBandSite::_IsBandDeleteable(DWORD dwBandID)
{
DWORD dwState;
if (FAILED(_pbsOuter->QueryBand(dwBandID, NULL, &dwState, NULL, 0))
|| (dwState & BSSF_UNDELETEABLE))
{
return FALSE;
}
ASSERT(dwBandID != (DWORD)-1); // make sure QueryBand catches this
return TRUE;
}
DWORD CBandSite::_GetAdminSettings(DWORD dwBandID)
{
LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID));
if (EVAL(pbid))
return pbid->dwAdminSettings;
return BAND_ADMIN_NORMAL;
}
void CBandSite::_SetAdminSettings(DWORD dwBandID, DWORD dwNewAdminSettings)
{
LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID));
if (EVAL(pbid))
pbid->dwAdminSettings = dwNewAdminSettings;
}
//*** CBandSite::IBandSite::* {
/*----------------------------------------------------------
Purpose: IBandSite::EnumBands method
*/
HRESULT CBandSite::EnumBands(UINT uBand, DWORD* pdwBandID)
{
ASSERT((NULL == pdwBandID && (UINT)-1 == uBand) ||
IS_VALID_WRITE_PTR(pdwBandID, DWORD));
if (uBand == (UINT)-1)
return _GetBandItemCount(); // query count
LPBANDITEMDATA pbid = _GetBandItem(uBand);
if (pbid)
{
*pdwBandID = pbid->dwBandID;
return S_OK;
}
return E_FAIL;
}
/*----------------------------------------------------------
Purpose: IBandSite::QueryBand method
*/
HRESULT CBandSite::QueryBand(DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
{
ASSERT(NULL == ppstb || IS_VALID_WRITE_PTR(ppstb, IDeskBand));
ASSERT(NULL == pdwState || IS_VALID_WRITE_PTR(pdwState, DWORD));
ASSERT(NULL == pszName || IS_VALID_WRITE_BUFFER(pszName, WCHAR, cchName));
if (ppstb)
*ppstb = NULL;
LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
if (!pbid)
return E_FAIL;
if (pszName)
{
StrCpyNW(pszName, pbid->szTitle, cchName);
}
if (ppstb)
{
*ppstb = pbid->pdb;
if (pbid->pdb)
{
pbid->pdb->AddRef();
}
}
if (pdwState)
{
*pdwState = 0;
if (pbid->fShow)
*pdwState = BSSF_VISIBLE;
if (pbid->fNoTitle)
*pdwState |= BSSF_NOTITLE;
if (pbid->dwModeFlags & DBIMF_UNDELETEABLE)
*pdwState |= BSSF_UNDELETEABLE;
}
return S_OK;
}
/*----------------------------------------------------------
Purpose: IBandSite::SetBandState
* NOTES
* failure handling is inconsistent (1 band vs. all bands case)
*/
HRESULT CBandSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
{
LPBANDITEMDATA pbid;
HRESULT hr;
if (dwBandID == (DWORD) -1)
{
BOOL fChange = FALSE;
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
{
pbid = _GetBandItem(i);
if (pbid)
{
hr = _SetBandStateHelper(pbid->dwBandID, dwMask, dwState);
ASSERT(SUCCEEDED(hr));
fChange |= (hr != S_OK);
}
else
{
return E_FAIL;
}
}
if (fChange)
_UpdateAllBands(FALSE, FALSE);
return S_OK;
}
else
{
hr = _SetBandStateHelper(dwBandID, dwMask, dwState);
if (SUCCEEDED(hr) && hr != S_OK)
{
_UpdateBand(dwBandID);
return S_OK;
}
}
return E_FAIL;
}
//***
// ENTRY/EXIT
// ret S_OK|changed on success, o.w. E_*.
// NOTES
// only a helper for SetBandState, don't call directly
HRESULT CBandSite::_SetBandStateHelper(DWORD dwBandID, DWORD dwMask, DWORD dwState)
{
LPBANDITEMDATA pbid;
pbid = _GetBandItem(_BandIDToIndex(dwBandID));
if (pbid)
{
DWORD dwOldState;
if (FAILED(QueryBand(dwBandID, NULL, &dwOldState, NULL, 0)))
{
ASSERT(0); // 'impossible'
dwOldState = (DWORD)-1;
}
if (dwMask & BSSF_VISIBLE)
_ShowBand(pbid, dwState & BSSF_VISIBLE);
if (dwMask & BSSF_NOTITLE)
pbid->fNoTitle = BOOLIFY(dwState & BSSF_NOTITLE);
// FEATURE: (kkahl): BSSF_UNDELETABLE cannot currently be modified with
// this interface.
return ResultFromShort((dwOldState ^ dwState) & dwMask);
}
return E_FAIL;
}
//*** _CheckNotifyOnAddRemove -- handle notifies for add/remove/empty
// DESCRIPTION
// add/remove always sends a BSID_BANDADDED/BSID_BANDREMOVED.
// remove of last always sends a DBCID_EMPTY.
// in floating mode, a transition to/from 1 band does a refresh.
//
void CBandSite::_CheckNotifyOnAddRemove(DWORD dwBandID, int iCode)
{
int cBands;
if (!_pct)
return;
if (iCode == CNOAR_CLOSEBAR)
{
// Shut down the whole thing
cBands = 0;
}
else
{
VARIANTARG var;
int nCmdID;
cBands = _GetBandItemCount(); // post-op # (since op happened in caller)
VariantInit(&var);
var.vt = VT_UI4;
var.ulVal = dwBandID;
BOOL fOne = FALSE;
switch (iCode)
{
case CNOAR_ADDBAND:
fOne = (cBands == 2); // 1->2
nCmdID = BSID_BANDADDED;
break;
case CNOAR_REMOVEBAND:
fOne = (cBands == 1); // 2->1
nCmdID = BSID_BANDREMOVED;
break;
default:
ASSERT(0);
return;
}
if ((fOne && (_dwMode & DBIF_VIEWMODE_FLOATING)))
{
// n.b. fBSOnly *must* be TRUE for perf
_UpdateAllBands(TRUE, TRUE); // force refresh of optional gripper/title
}
_pct->Exec(&CGID_BandSite, nCmdID, 0, &var, NULL);
}
if (cBands == 0)
{
ASSERT(iCode != CNOAR_ADDBAND); // sanity check
_pct->Exec(&CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
}
return;
}
/*----------------------------------------------------------
Purpose: IBandSite::RemoveBand method
*/
HRESULT CBandSite::RemoveBand(DWORD dwBandID)
{
int iIndex = _BandIDToIndex(dwBandID);
LPBANDITEMDATA pbid = _GetBandItem(iIndex);
if (pbid)
{
// Release the banditem data first, while it can still
// receive cleanup notifications from its control. *Then*
// delete the band item.
_ReleaseBandItemData(pbid, iIndex);
_DeleteBandItem(iIndex); // unhook from host (rebar)
_CheckNotifyOnAddRemove(dwBandID, CNOAR_REMOVEBAND);
return S_OK;
}
return E_FAIL;
}
void CBandSite::_OnCloseBand(DWORD dwBandID)
{
if (dwBandID == -1)
{
// Close everything
_CheckNotifyOnAddRemove(dwBandID, CNOAR_CLOSEBAR);
}
else
{
// Close just this band
LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
USES_CONVERSION;
if (EVAL(pbid) && ConfirmRemoveBand(_hwnd, IDS_CONFIRMCLOSEBAND,W2T(pbid->szTitle)))
RemoveBand(dwBandID);
}
}
void CBandSite::_MinimizeBand(DWORD dwBandID)
{
SendMessage(_hwnd, RB_MINIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
}
void CBandSite::_MaximizeBand(DWORD dwBandID)
{
SendMessage(_hwnd, RB_MAXIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
}
//
// private insert a band into the container control by ID
// returns the band ID in ShortFromResult(hres)
//
HRESULT CBandSite::_AddBandByID(IUnknown *punk, DWORD dwID)
{
IDeskBand *pdb;
HRESULT hr = punk->QueryInterface(IID_PPV_ARG(IDeskBand, &pdb));
if (SUCCEEDED(hr))
{
ASSERT(pdb);
BANDITEMDATA *pbid = (BANDITEMDATA *)LocalAlloc(LPTR, sizeof(BANDITEMDATA));
if (pbid)
{
pbid->dwBandID = dwID;
pbid->pdb = pdb; // ref held by QI above
pbid->fShow = TRUE; // initially visible
pbid->pdb->QueryInterface(IID_PPV_ARG(IWinEventHandler, &pbid->pweh));
hr = IUnknown_SetSite(pbid->pdb, SAFECAST(this, IBandSite*));
if (SUCCEEDED(hr))
{
hr = pbid->pdb->GetWindow(&pbid->hwnd);
if (SUCCEEDED(hr))
{
if (_AddBandItem(pbid))
{
if (_dwShowState == DBC_SHOW)
{
ASSERT(pbid->fShow);
pbid->pdb->ShowDW(TRUE);
_MinimizeBand(pbid->dwBandID);
}
_CheckNotifyOnAddRemove(pbid->dwBandID, CNOAR_ADDBAND);
hr = ResultFromShort(pbid->dwBandID); // success
}
else
{
hr = E_FAIL;
}
}
}
if (FAILED(hr))
{
// clean up
_ReleaseBandItemData(pbid, -1);
}
//
// Now that we've added the band, clear the _SendToToolband cache.
//
// We need to do this because we might have gotten a message for
// the band before it was inserted, in which case we'll have cached
// a NULL handler for the band's hwnd (preventing the band from
// getting any messages thereafter).
//
ATOMICRELEASE(_pwehCache);
_hwndCache = NULL;
}
else
{
hr = E_OUTOFMEMORY;
pdb->Release(); // don't hold on to this
}
}
return hr;
}
/*----------------------------------------------------------
Purpose: IBandSite::AddBand method.
Insert a band into the container control.
Returns: the band ID in ShortFromResult(hres)
*/
HRESULT CBandSite::AddBand(IUnknown *punk)
{
HRESULT hres = _AddBandByID(punk, _dwBandIDNext);
if (SUCCEEDED(hres))
{
_dwBandIDNext++;
}
return hres;
}
void CBandSite::_UpdateBand(DWORD dwBandID)
{
LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID));
if (pbid)
{
_UpdateBandInfo(pbid, FALSE);
_OnRBAutoSize(NULL);
}
}
void CBandSite::_UpdateAllBands(BOOL fBSOnly, BOOL fNoAutoSize)
{
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (pbid)
_UpdateBandInfo(pbid, fBSOnly);
}
SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
if (!fNoAutoSize)
{
SendMessage(_hwnd, RB_SIZETORECT, 0, 0);
_OnRBAutoSize(NULL);
}
}
// *** IOleCommandTarget ***
HRESULT CBandSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
if (pguidCmdGroup)
{
if (IsEqualIID(*pguidCmdGroup, IID_IDockingWindow))
{
for (ULONG i=0 ; i<cCmds ; i++)
{
switch (rgCmds[i].cmdID)
{
case DBID_BANDINFOCHANGED:
case DBID_PUSHCHEVRON:
rgCmds[i].cmdf = OLECMDF_ENABLED;
break;
case DBID_PERMITAUTOHIDE:
// defer decision to the bands
for (int iBand = _GetBandItemCount() - 1; iBand >= 0; iBand--)
{
LPBANDITEMDATA pbid = _GetBandItem(iBand);
if (pbid)
{
if (SUCCEEDED(IUnknown_QueryStatus(pbid->pdb, pguidCmdGroup, 1, &rgCmds[i], pcmdtext)) &&
((rgCmds[i].cmdf & OLECMDF_SUPPORTED) && !(rgCmds[i].cmdf & OLECMDF_ENABLED)))
{
break;
}
}
}
break;
default:
rgCmds[i].cmdf = 0;
break;
}
}
return S_OK;
}
else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
{
return IUnknown_QueryStatus(_ptbActive, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
}
}
// if we got here, we didn't handle it
// forward it down
return MayQSForward(_ptbActive, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
}
int _QueryServiceCallback(LPBANDITEMDATA pbid, void *pv)
{
QSDATA* pqsd = (QSDATA*)pv;
if (pbid->fShow)
pqsd->hres = IUnknown_QueryService(pbid->pdb, *(pqsd->pguidService), *(pqsd->piid), pqsd->ppvObj);
// stop if we found the service
return SUCCEEDED(pqsd->hres) ? FALSE : TRUE;
}
typedef struct {
HRESULT hres;
const GUID *pguidCmdGroup;
DWORD nCmdID;
DWORD nCmdexecopt;
VARIANTARG *pvarargIn;
VARIANTARG *pvarargOut;
} EXECDATA;
int _ExecCallback(LPBANDITEMDATA pbid, void *pv)
{
EXECDATA* ped = (EXECDATA*)pv;
ped->hres = IUnknown_Exec(pbid->pdb, ped->pguidCmdGroup, ped->nCmdID, ped->nCmdexecopt,
ped->pvarargIn, ped->pvarargOut);
return 1;
}
HRESULT CBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
HRESULT hresTmp;
if (pguidCmdGroup == NULL)
{
/*NOTHING*/
;
}
else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBand))
{
switch (nCmdID)
{
case DBID_BANDINFOCHANGED:
if (!pvarargIn)
_UpdateAllBands(FALSE, FALSE);
else if (pvarargIn->vt == VT_I4)
_UpdateBand(pvarargIn->lVal);
hres = S_OK;
// forward this up.
if (_pct)
{
_pct->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}
goto Lret;
case DBID_PUSHCHEVRON:
if (pvarargIn && pvarargIn->vt == VT_I4)
{
int iIndex = _BandIDToIndex(nCmdexecopt);
SendMessage(_hwnd, RB_PUSHCHEVRON, iIndex, pvarargIn->lVal);
hres = S_OK;
}
goto Lret;
case DBID_MAXIMIZEBAND:
if (pvarargIn && pvarargIn->vt == VT_UI4)
_MaximizeBand(pvarargIn->ulVal);
hres = S_OK;
goto Lret;
#if 1 // { FEATURE: temporary until add cbs::Select() mfunc
case DBID_SHOWONLY:
{
int iCount = _GetBandItemCount();
// pvaIn->punkVal:
// punk hide everyone except me
// 0 hide everyone
// 1 show everyone
// FEATURE: we should use pvaIn->lVal not punkVal since we're
// allowing 0 & 1 !!! (and not doing addref/release)
ASSERT(pvarargIn && pvarargIn->vt == VT_UNKNOWN);
if (pvarargIn->punkVal == NULL || pvarargIn->punkVal == (IUnknown*)1)
TraceMsg(TF_BANDDD, "cbs.e: (id=DBID_SHOWONLY, punk=%x)", pvarargIn->punkVal);
// show myself, hide everyone else
TraceMsg(TF_BANDDD, "cbs.Exec(DBID_SHOWONLY): n=%d", _GetBandItemCount());
// wait to show this band until we've hidden the others
LPBANDITEMDATA pbidShow = NULL;
// FEATURE: this (IUnknown*)1 is bogus! Also mentioned above.
BOOL bShowAll = (pvarargIn->punkVal == (IUnknown*)1);
for (int i = iCount - 1; i >= 0; i--)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (pbid)
{
BOOL fShow;
fShow = bShowAll || SHIsSameObject(pbid->pdb, pvarargIn->punkVal);
if (!fShow || bShowAll)
_ShowBand(pbid, fShow);
else
pbidShow = pbid;
}
}
if (pbidShow)
{
_ShowBand(pbidShow, TRUE);
// nash:37290 set focus to band on open
if (_dwShowState == DBC_SHOW)
IUnknown_UIActivateIO(pbidShow->pdb, TRUE, NULL);
else
ASSERT(0);
}
}
break;
#endif // }
}
}
else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
{
return IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
pvarargIn, pvarargOut);
}
else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBarClient))
{
switch (nCmdID)
{
case DBCID_ONDRAG:
if (EVAL(pvarargIn->vt == VT_I4))
{
ASSERT(pvarargIn->lVal == 0 || pvarargIn->lVal == DRAG_MOVE);
TraceMsg(DM_TRACE, "cbs.e: DBCID_ONDRAG i=%d", pvarargIn->lVal);
_fDragging = pvarargIn->lVal;
}
break;
case DBCID_GETBAR:
// return IUnkown of my IDeskBar host
if ((pvarargOut != NULL) && _pdb)
{
::VariantInit(pvarargOut);
V_VT(pvarargOut) = VT_UNKNOWN;
V_UNKNOWN(pvarargOut) = _pdb;
_pdb->AddRef();
hres = S_OK;
goto Lret;
}
break;
}
}
// if we got here, we didn't handle it
// see if we should forward it down
hresTmp = IsExecForward(pguidCmdGroup, nCmdID);
if (SUCCEEDED(hresTmp) && HRESULT_CODE(hresTmp) > 0)
{
// down (singleton or broadcast)
if (HRESULT_CODE(hresTmp) == OCTD_DOWN)
{
// down (singleton)
hres = IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
pvarargIn, pvarargOut);
}
else
{
// down (broadcast)
// n.b. hres is a bit weird: 'last one wins'
// FEATURE: should we just return S_OK?
ASSERT(HRESULT_CODE(hresTmp) == OCTD_DOWNBROADCAST);
EXECDATA ctd = { hres, pguidCmdGroup, nCmdID, nCmdexecopt,
pvarargIn, pvarargOut };
_BandItemEnumCallback(1, _ExecCallback, &ctd);
hres = ctd.hres;
}
}
Lret:
return hres;
}
/*** _ShowBand -- show/hide band (cached state, band, and rebar band)
*/
void CBandSite::_ShowBand(LPBANDITEMDATA pbid, BOOL fShow)
{
int i;
pbid->fShow = BOOLIFY(fShow);
if (pbid->pdb)
{
pbid->pdb->ShowDW(fShow && (_dwShowState == DBC_SHOW));
}
i = _BandIDToIndex(pbid->dwBandID);
SendMessage(_hwnd, RB_SHOWBAND, i, fShow);
// get me a window to draw D&D curosors on. . .
SHGetTopBrowserWindow(SAFECAST(this, IBandSite*), &_hwndDD);
}
/*----------------------------------------------------------
Purpose: IBandSite::GetBandSiteInfo
*/
HRESULT CBandSite::GetBandSiteInfo(BANDSITEINFO * pbsinfo)
{
ASSERT(IS_VALID_WRITE_PTR(pbsinfo, BANDSITEINFO));
if (pbsinfo->dwMask & BSIM_STATE)
pbsinfo->dwState = _dwMode;
if (pbsinfo->dwMask & BSIM_STYLE)
pbsinfo->dwStyle = _dwStyle;
return S_OK;
}
/*----------------------------------------------------------
Purpose: IBandSite::SetBandSiteInfo
*/
HRESULT CBandSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
{
ASSERT(IS_VALID_READ_PTR(pbsinfo, BANDSITEINFO));
if (pbsinfo->dwMask & BSIM_STATE)
_dwMode = pbsinfo->dwState;
if (pbsinfo->dwMask & BSIM_STYLE)
{
// If the BSIS_SINGLECLICK style changed, change the rebar style
if ( _hwnd && ((_dwStyle ^ pbsinfo->dwStyle) & BSIS_SINGLECLICK) )
SHSetWindowBits(_hwnd, GWL_STYLE, RBS_DBLCLKTOGGLE, (pbsinfo->dwStyle & BSIS_SINGLECLICK)?0:RBS_DBLCLKTOGGLE);
_dwStyle = pbsinfo->dwStyle;
}
return S_OK;
}
/*----------------------------------------------------------
Purpose: IBandSite::GetBandObject
*/
HRESULT CBandSite::GetBandObject(DWORD dwBandID, REFIID riid, void **ppvObj)
{
HRESULT hres = E_FAIL;
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IDataObject))
{
*ppvObj = _DataObjForBand(dwBandID);
if (*ppvObj)
hres = S_OK;
}
else
{
LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
if (pbid && pbid->pdb)
{
hres = pbid->pdb->QueryInterface(riid, ppvObj);
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Returns a pointer to the band item data given an
externally known band ID.
Returns: NULL if band ID is illegal
*/
LPBANDITEMDATA CBandSite::_GetBandItemDataStructByID(DWORD uID)
{
int iBand = _BandIDToIndex(uID);
if (iBand == -1)
return NULL;
return _GetBandItem(iBand);
}
__inline HRESULT _FwdWinEvent(IWinEventHandler* pweh, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
{
ASSERT(pweh);
ASSERT(hwnd == HWND_BROADCAST || pweh->IsWindowOwner(hwnd) == S_OK);
return pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
}
/*----------------------------------------------------------
Purpose: Forwards messages to the band that owns the window.
Returns: TRUE if the message was forwarded
*/
BOOL CBandSite::_SendToToolband(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
{
BOOL fSent = FALSE;
LRESULT lres = 0;
if (hwnd)
{
if (hwnd == _hwndCache)
{
ASSERT(hwnd != HWND_BROADCAST);
if (_pwehCache)
{
_FwdWinEvent(_pwehCache, hwnd, uMsg, wParam, lParam, &lres);
fSent = TRUE;
}
}
else
{
LPBANDITEMDATA pbid = NULL;
int i;
for (i = _GetBandItemCount() - 1; i >= 0; i--)
{
pbid = _GetBandItem(i);
if (pbid)
{
if (pbid->pweh)
{
if (hwnd == HWND_BROADCAST ||
(pbid->pweh->IsWindowOwner(hwnd) == S_OK))
{
_FwdWinEvent(pbid->pweh, hwnd, uMsg, wParam, lParam, &lres);
fSent = TRUE;
if (hwnd != HWND_BROADCAST)
{
break;
}
}
}
else
{
if (hwnd == HWND_BROADCAST && pbid->hwnd)
{
lres = SendMessage(pbid->hwnd, uMsg, wParam, lParam);
fSent = TRUE;
}
}
}
}
if (hwnd != HWND_BROADCAST)
{
ATOMICRELEASE(_pwehCache);
_hwndCache = hwnd;
if (fSent && pbid)
{
_pwehCache = pbid->pweh;
_pwehCache->AddRef();
}
}
}
}
if (plres)
*plres = lres;
return fSent;
}
typedef struct {
HWND hwnd;
HRESULT hres;
} WINDOWOWNERDATA;
int _IsWindowOwnerCallback(LPBANDITEMDATA pbid, void *pv)
{
WINDOWOWNERDATA* pwod = (WINDOWOWNERDATA*)pv;
if (pbid->pweh && (pbid->pweh->IsWindowOwner(pwod->hwnd) == S_OK))
{
pwod->hres = S_OK;
return 0;
}
return 1;
}
HRESULT CBandSite::IsWindowOwner(HWND hwnd)
{
if (hwnd == _hwnd)
return S_OK;
WINDOWOWNERDATA wod = { hwnd, S_FALSE };
_BandItemEnumCallback(1, _IsWindowOwnerCallback, &wod);
return wod.hres;
}
//*** CBandSite::IDeskBarClient::* {
HRESULT CBandSite::GetSize(DWORD dwWhich, LPRECT prc)
{
HRESULT hres = E_FAIL;
switch (dwWhich)
{
case DBC_GS_IDEAL:
{
prc->right = 0;
prc->bottom = 0;
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (pbid)
{
RECT rc;
SendMessage(_hwnd, RB_GETBANDBORDERS, _BandIDToIndex(pbid->dwBandID), (LPARAM) &rc);
_UpdateBandInfo(pbid, FALSE);
if (pbid->fShow)
{
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
{
prc->right = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
prc->bottom += pbid->ptActual.y + rc.top + rc.bottom;
}
else
{
prc->bottom = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
prc->right += pbid->ptActual.y + rc.top + rc.bottom;
}
}
hres = S_OK;
}
}
SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
}
break;
case DBC_GS_SIZEDOWN:
{
// Used to make a band change size in chuncks
SendMessage(_hwnd, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)prc);
hres = S_OK;
}
break;
}
return hres;
}
void CBandSite::_Close()
{
if (_hwnd)
{
// (scotth): This method is getting called by the destructor,
// and calls _DeleteAllBandItems, which sends messages to _hwnd.
// _hwnd is already destroyed by this time. If you hit this assert
// it is because in debug windows it RIPs like crazy.
// 970508 (adp): pblm was that we weren't doing DestroyWnd etc.
//
// Do no remove this assert....please fix the root problem.
ASSERT(IS_VALID_HANDLE(_hwnd, WND));
SendMessage(_hwnd, WM_SETREDRAW, 0, 0);
_DeleteAllBandItems();
DestroyWindow(_hwnd);
_hwnd = 0;
}
}
HRESULT CBandSite::UIActivateDBC(DWORD dwState)
{
if (dwState != _dwShowState)
{
BOOL fShow = dwState;
_dwShowState = dwState;
// map UIActivateDBC to ShowDW
if (DBC_SHOWOBSCURE == dwState)
fShow = FALSE;
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (pbid && pbid->pdb)
pbid->pdb->ShowDW(fShow && pbid->fShow);
}
// do this now intead of at creation so that
// rebar doesn't keep trying to autosize us while
// we're not even visible
SHSetWindowBits(_hwnd, GWL_STYLE, RBS_AUTOSIZE, RBS_AUTOSIZE);
SendMessage(_hwnd, WM_SIZE, 0, 0);
SendMessage(_hwnd, WM_SETREDRAW, (DBC_SHOW == dwState) ? TRUE : fRedraw, 0);
}
return S_OK;
}
DWORD CBandSite::_GetWindowStyle(DWORD* pdwExStyle)
{
*pdwExStyle = WS_EX_TOOLWINDOW;
DWORD dwStyle = RBS_REGISTERDROP | RBS_VARHEIGHT | RBS_BANDBORDERS |
WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
if (_dwStyle & BSIS_LEFTALIGN)
{
dwStyle |= RBS_VERTICALGRIPPER;
}
if (!(_dwStyle & BSIS_SINGLECLICK))
{
dwStyle |= RBS_DBLCLKTOGGLE;
}
return dwStyle;
}
HRESULT CBandSite::_Initialize(HWND hwndParent)
{
//
// I hope we have an IBandSite to talk to.
//
if (!_pbsOuter)
return E_FAIL;
if (!_hwnd)
{
DWORD dwExStyle;
DWORD dwStyle = _GetWindowStyle(&dwExStyle);
_hwnd = CreateWindowEx(dwExStyle, REBARCLASSNAME, NULL, dwStyle,
0, 0, 0, 0, hwndParent, (HMENU) FCIDM_REBAR, HINST_THISDLL, NULL);
if (_hwnd)
{
SendMessage(_hwnd, RB_SETTEXTCOLOR, 0, CLR_DEFAULT);
SendMessage(_hwnd, RB_SETBKCOLOR, 0, CLR_DEFAULT);
SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
}
}
return _hwnd ? S_OK : E_OUTOFMEMORY;
}
HRESULT CBandSite::SetDeskBarSite(IUnknown* punkSite)
{
HRESULT hr = S_OK;
if (!punkSite)
{
// Time to tell the bands to free their
// back pointers on us or we never get freed...
// 970325 for now bs::SetDeskBarSite(NULL) is 'overloaded'
// to mean do both a CloseDW and a SetSite.
// when we clean up our act and have a bs::Close iface
// we'll go back to the '#else' code below.
if (_hwnd)
_Close();
}
ATOMICRELEASE(_pct);
ATOMICRELEASE(_pdb);
ATOMICRELEASE(_punkSite);
if (_pbp && _fCreatedBandProxy)
_pbp->SetSite(punkSite);
if (punkSite)
{
_punkSite = punkSite;
_punkSite->AddRef();
if (!_hwnd)
{
HWND hwndParent;
IUnknown_GetWindow(punkSite, &hwndParent);
hr = _Initialize(hwndParent);
}
punkSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_pct));
punkSite->QueryInterface(IID_PPV_ARG(IDeskBar, &_pdb));
}
return hr;
}
HRESULT CBandSite::SetModeDBC(DWORD dwMode)
{
if (dwMode != _dwMode)
{
_dwMode = dwMode;
if (_hwnd)
{
DWORD dwStyle = 0;
if (dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
{
dwStyle |= CCS_VERT;
}
SHSetWindowBits(_hwnd, GWL_STYLE, CCS_VERT, dwStyle);
}
_UpdateAllBands(FALSE, FALSE);
}
return S_OK;
}
// }
IDropTarget* CBandSite::_WrapDropTargetForBand(IDropTarget* pdtBand)
{
if (!pdtBand || (_dwStyle & BSIS_NODROPTARGET))
{
// addref it for the new pointer
if (pdtBand)
pdtBand->AddRef();
return pdtBand;
}
else
{
return DropTargetWrap_CreateInstance(pdtBand, SAFECAST(this, IDropTarget*), _hwndDD);
}
}
LRESULT CBandSite::_OnNotify(LPNMHDR pnm)
{
NMOBJECTNOTIFY *pnmon = (NMOBJECTNOTIFY *)pnm;
switch (pnm->code)
{
case RBN_GETOBJECT:
{
pnmon->hResult = E_FAIL;
// if we're the drag source, then a band is dragging... we want to only
// give out the bandsite's drop target
if (pnmon->iItem != -1 && !_fDragSource)
{
LPBANDITEMDATA pbid = _GetBandItemDataStructByID(pnmon->iItem);
if (EVAL(pbid) && pbid->pdb)
{
pnmon->hResult = pbid->pdb->QueryInterface(*pnmon->piid, &pnmon->pObject);
// give a wrapped droptarget instead of the band's droptarget
if (IsEqualIID(*pnmon->piid, IID_IDropTarget))
{
IDropTarget* pdtBand;
BOOL fNeedReleasePdtBand = FALSE;
if (SUCCEEDED(pnmon->hResult))
{
pdtBand = (IDropTarget*)(pnmon->pObject);
}
else
{
CDropDummy *pdtgt = new CDropDummy(_hwndDD);
pdtBand = SAFECAST(pdtgt, IDropTarget*);
fNeedReleasePdtBand = TRUE;
}
IDropTarget* pdt = _WrapDropTargetForBand(pdtBand);
if (pdt)
{
pnmon->pObject = pdt;
pnmon->hResult = S_OK;
// we've handed off pdtBand to pdt
fNeedReleasePdtBand = TRUE;
}
if (fNeedReleasePdtBand && pdtBand)
pdtBand->Release();
}
if (FAILED(pnmon->hResult) && !(_dwStyle & BSIS_NODROPTARGET))
pnmon->hResult = QueryInterface(*pnmon->piid, &pnmon->pObject);
}
}
break;
}
case RBN_BEGINDRAG:
return _OnBeginDrag((NMREBAR*)pnm);
case RBN_AUTOSIZE:
_OnRBAutoSize((NMRBAUTOSIZE*)pnm);
break;
case RBN_CHEVRONPUSHED:
{
LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnm;
LPBANDITEMDATA pbid = _GetBandItem(pnmch->uBand);
if (EVAL(pbid))
{
MapWindowPoints(_hwnd, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2);
ToolbarMenu_Popup(_hwnd, &pnmch->rc, pbid->pdb, pbid->hwnd, 0, (DWORD)pnmch->lParamNM);
}
break;
}
case RBN_AUTOBREAK:
{
if (_dwStyle & BSIS_PREFERNOLINEBREAK)
{
Comctl32_FixAutoBreak(pnm);
}
break;
}
}
return 0;
}
void CBandSite::_OnRBAutoSize(NMRBAUTOSIZE* pnm)
{
// DRAG_MOVE: we turn off autosize during (most of) a move because
// fVertical is out of sync until the very end
if (_pdb && _GetBandItemCount() && _fDragging != DRAG_MOVE)
{
RECT rc;
int iHeightCur;
int iHeight = (int)SendMessage(_hwnd, RB_GETBARHEIGHT, 0, 0);
#ifdef DEBUG
DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
#endif
GetWindowRect(_hwnd, &rc);
MapWindowRect(HWND_DESKTOP, GetParent(_hwnd), &rc);
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
{
ASSERT((dwStyle & CCS_VERT));
iHeightCur = RECTWIDTH(rc);
rc.right = rc.left + iHeight;
}
else
{
ASSERT(!(dwStyle & CCS_VERT));
iHeightCur = RECTHEIGHT(rc);
rc.bottom = rc.top + iHeight;
}
if ((iHeightCur != iHeight) || (IsOS(OS_WHISTLERORGREATER)))
{
_pdb->OnPosRectChangeDB(&rc);
}
}
}
IDataObject* CBandSite::_DataObjForBand(DWORD dwBandID)
{
IDataObject* pdtobjReturn = NULL;
LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
if (EVAL(pbid) && pbid->pdb)
{
HRESULT hres;
CBandDataObject* pdtobj = new CBandDataObject();
if (pdtobj)
{
hres = pdtobj->Init(pbid->pdb, this, dwBandID);
if (SUCCEEDED(hres))
{
pdtobjReturn = pdtobj;
pdtobjReturn->AddRef();
}
pdtobj->Release();
}
}
return pdtobjReturn;
}
LRESULT CBandSite::_OnBeginDrag(NMREBAR* pnm)
{
LRESULT lres = 0;
DWORD dwBandID = _IndexToBandID(pnm->uBand);
IDataObject* pdtobj = _DataObjForBand(dwBandID);
ATOMICRELEASE(_pdtobj);
_uDragBand = pnm->uBand;
_pdtobj = pdtobj;
// because the RBN_BEGINDRAG is synchronous and so is SHDoDragDrop
// post this message to ourselves instead of calling dragdrop directly.
// note that we don't have a window of our own, so we post to our parent
// and let the message reflector send it back to us
PostMessage(GetParent(_hwnd), WM_COMMAND, MAKELONG(0, IDM_DRAGDROP), (LPARAM)_hwnd);
return 1;
}
// return TRUE if the user drags out of the rect of the rebar meaning that we should
// go into ole drag drop.
BOOL CBandSite::_PreDragDrop()
{
BOOL f = FALSE;
RECT rc;
POINT pt;
DWORD dwBandID = _IndexToBandID(_uDragBand); // Find the BandID before an reordering that may happen.
GetWindowRect(_hwnd, &rc);
SetCapture(_hwnd);
InflateRect(&rc, GetSystemMetrics(SM_CXEDGE) * 3, GetSystemMetrics(SM_CYEDGE) * 3);
while (GetCapture() == _hwnd)
{
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
switch (msg.message)
{
case WM_MOUSEMOVE:
GetCursorPos(&pt);
if (!ISMOVEDDISABLED(dwBandID))
{
if (PtInRect(&rc, pt))
{
SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
} else if (!ISDDCLOSEDISABLED(dwBandID) && _pdtobj)
{
// we've moved out of the bounds of the rebar.. switch to ole drag
f = TRUE;
SetCapture(NULL);
}
}
break;
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
// bail on any mouse button action
SetCapture(NULL);
break;
case WM_KEYDOWN:
switch (msg.wParam)
{
case VK_ESCAPE:
SetCapture(NULL);
break;
}
// fall through
default:
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
if (ISDDCLOSEDISABLED(dwBandID) || !_IsBandDeleteable(dwBandID))
{
/// if don't allow close, never return true for ole drag.
f = FALSE;
}
return f;
}
void CBandSite::_DoDragDrop()
{
DWORD dwBandID = _IndexToBandID(_uDragBand);
DWORD dwEffect = DROPEFFECT_MOVE;
_fDragSource = TRUE;
SendMessage(_hwnd, RB_BEGINDRAG, _uDragBand, (LPARAM)-2);
HRESULT hres = S_OK;
// first check to see if we even need to go into Ole drag, or if
// it can all be contained within the rebar
if (_PreDragDrop())
{
SHLoadOLE(SHELLNOTIFY_OLELOADED); // Browser Only - our shell32 doesn't know ole has been loaded
hres = SHDoDragDrop(_hwnd, _pdtobj, NULL, dwEffect, &dwEffect);
}
else
{
// if we kept it all within win32 dragging, then set no drop effect
dwEffect = DROPEFFECT_NONE;
}
SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
_fDragSource = FALSE;
if (dwEffect & DROPEFFECT_MOVE)
{
RemoveBand(dwBandID);
}
else if (!dwEffect && hres == DRAGDROP_S_DROP)
{
// if the drop was done, but the target didn't allow
// then we float the band.
}
ATOMICRELEASE(_pdtobj);
}
HMENU CBandSite::_LoadContextMenu()
{
return LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE1);
}
HRESULT CBandSite::_OnBSCommand(int idCmd, DWORD idBandActive, LPBANDITEMDATA pbid)
{
HRESULT hr = S_OK;
switch (idCmd)
{
case BSIDM_CLOSEBAND:
_OnCloseBand(idBandActive);
break;
case BSIDM_SHOWTITLEBAND:
ASSERT(idBandActive != (DWORD)-1 && pbid);
if (pbid)
{
pbid->fNoTitle = !pbid->fNoTitle;
_UpdateBandInfo(pbid, FALSE);
}
break;
case BSIDM_IEAK_DISABLE_MOVE:
case BSIDM_IEAK_DISABLE_DDCLOSE:
ASSERT(idBandActive != (DWORD)-1);
if (idBandActive != (DWORD)-1)
{
static const int idCmds[] = { BSIDM_IEAK_DISABLE_MOVE, BSIDM_IEAK_DISABLE_DDCLOSE };
static const int idFlags[] = { BAND_ADMIN_NOMOVE, BAND_ADMIN_NODDCLOSE };
DWORD dwFlag = SHSearchMapInt(idCmds, idFlags, ARRAYSIZE(idCmds), idCmd);
DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
// Toggle Setting.
ToggleFlag(dwAdminSettings, dwFlag);
// Set Menu Item Check Mark appropriately.
_SetAdminSettings(idBandActive, dwAdminSettings);
}
break;
default:
ASSERT(0);
hr = E_FAIL;
break;
}
return hr;
}
// returns the index of the band hit by lParam using context menu semantics (lParam == -1 for keyboard)
int CBandSite::_ContextMenuHittest(LPARAM lParam, POINT* ppt)
{
int iBandIndex;
if (lParam == (LPARAM) -1)
{
// Keyboard activation. Use active band.
DWORD dwBandID = _BandIDFromPunk(_ptbActive);
iBandIndex = _BandIDToIndex(dwBandID);
LPBANDITEMDATA pbid = _GetBandItem(iBandIndex);
if (pbid)
{
RECT rc;
GetWindowRect(pbid->hwnd, &rc);
ppt->x = rc.left;
ppt->y = rc.top;
}
}
else
{
// Mouse activation. Figure out which band got clicked.
RBHITTESTINFO rbht;
ppt->x = GET_X_LPARAM(lParam);
ppt->y = GET_Y_LPARAM(lParam);
rbht.pt = *ppt;
ScreenToClient(_hwnd, &rbht.pt);
SendMessage(_hwnd, RB_HITTEST, 0, (LPARAM)&rbht);
iBandIndex = rbht.iBand;
}
return iBandIndex;
}
HRESULT CBandSite::_OnContextMenu(WPARAM wParam, LPARAM lParam)
{
HRESULT hres = S_OK;
HMENU hmenu = CreatePopupMenu();
if (hmenu)
{
HRESULT hresT;
int idCmd = 1;
IContextMenu *pcm, *pcmParent = NULL, *pcmChild = NULL;
POINT pt;
int iBandIndex = _ContextMenuHittest(lParam, &pt);
// map rebar index to band id
// get band info for that band id
DWORD idBandActive = _IndexToBandID(iBandIndex);
LPBANDITEMDATA pbid = _GetBandItemDataStructByID(idBandActive);
//
// self (top)
//
int idCmdBS1 = idCmd;
HMENU hmenuMe = _LoadContextMenu();
if (hmenuMe)
{
BOOL fDeleteShowTitle = TRUE;
if (pbid && !(_dwStyle & BSIS_LOCKED))
{
DESKBANDINFO dbi;
CheckMenuItem(hmenuMe, BSIDM_SHOWTITLEBAND,
pbid->fNoTitle ? MF_BYCOMMAND|MF_UNCHECKED : MF_BYCOMMAND|MF_CHECKED);
dbi.dwMask = 0; // paranoia (and needed for taskband!)
_GetBandInfo(pbid, &dbi);
// make sure pbid in sync
ASSERT((dbi.dwMask & DBIM_TITLE) || pbid->fNoTitle);
if ((dbi.dwMask & DBIM_TITLE) && _IsEnableTitle(pbid))
{
fDeleteShowTitle = FALSE;
}
}
if (fDeleteShowTitle)
{
DeleteMenu(hmenuMe, BSIDM_SHOWTITLEBAND, MF_BYCOMMAND);
}
idCmd += Shell_MergeMenus(hmenu, hmenuMe, 0, idCmd, 0x7fff, 0) - (idCmd);
DestroyMenu(hmenuMe);
}
//
// child
//
int idCmdChild = idCmd;
if (pbid && pbid->pdb)
{
// merge in band's menu (at front)
hresT = pbid->pdb->QueryInterface(IID_PPV_ARG(IContextMenu, &pcmChild));
if (SUCCEEDED(hresT))
{
// 0=at front
hresT = pcmChild->QueryContextMenu(hmenu, 0, idCmd, 0x7fff, 0);
if (SUCCEEDED(hresT))
idCmd += HRESULT_CODE(hresT);
}
}
//
// self (bottom)
//
int idCmdBS2 = idCmd;
if (!(_dwStyle & BSIS_NOCONTEXTMENU))
{
hmenuMe = LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE2);
if (hmenuMe)
{
// disable 'Close Band' if it's marked undeleteable
// nash:17821: don't disable when 0 bands (so user can easily
// get out of toasted mode)
if ((idBandActive == (DWORD)-1) || // if mouse not over a band, delete close menu item
(!_IsBandDeleteable(idBandActive) ||
ISDDCLOSEDISABLED(idBandActive)) ||
(_dwStyle & BSIS_LOCKED))
{
DeleteMenu(hmenuMe, BSIDM_CLOSEBAND, MF_BYCOMMAND);
}
if (!_fIEAKInstalled)
{
DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, MF_BYCOMMAND);
DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, MF_BYCOMMAND);
}
else
{
DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NODDCLOSE))
_CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, TRUE);
if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NOMOVE))
_CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, TRUE);
}
idCmd += Shell_MergeMenus(hmenu, hmenuMe, (UINT) -1, idCmd, 0x7fff, 0) - (idCmd);
DestroyMenu(hmenuMe);
}
}
//
// parent
//
int idCmdParent = idCmd;
if (_punkSite)
{
UINT uFlags = 0;
ASSERT(_pcm3Parent == NULL);
if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3Parent))))
{
uFlags |= CMF_ICM3;
}
hresT = _punkSite->QueryInterface(IID_PPV_ARG(IContextMenu, &pcmParent));
if (SUCCEEDED(hresT))
{
// APPCOMPAT: fix parents and kids to handle...
// we'd like to pass in -1 but not everyone handles that.
// workaround: use _FixMenuIndex...
hresT = pcmParent->QueryContextMenu(hmenu, _FixMenuIndex(hmenu, -1), idCmd, 0x7fff, uFlags);
ASSERT(SUCCEEDED(hresT));
idCmd += HRESULT_CODE(hresT);
}
}
//
// do it
//
{
HWND hwndParent = GetParent(_hwnd);
if (!hwndParent)
hwndParent = _hwnd;
idCmd = TrackPopupMenu(hmenu,
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
pt.x, pt.y, 0, hwndParent, NULL);
}
if (idCmd)
{
// must test from smallest to largest
ASSERT(idCmdBS1 <= idCmdChild);
ASSERT(idCmdChild <= idCmdBS2); // o.w. test in wrong order
ASSERT(idCmdBS2 <= idCmdParent);
if ((idCmd>= idCmdBS1) && (idCmd < idCmdChild))
{
idCmd -= idCmdBS1;
hres = _OnBSCommand(idCmd, idBandActive, pbid);
}
else if ((idCmd>= idCmdBS2) && (idCmd < idCmdParent))
{
idCmd -= idCmdBS2;
hres = _OnBSCommand(idCmd, idBandActive, pbid);
}
else
{
// A parent or child command
if (idCmd < idCmdParent)
{
pcm = pcmChild;
idCmd -= idCmdChild;
}
else
{
pcm = pcmParent;
idCmd -= idCmdParent;
}
ASSERT(pcm);
//
// Call InvokeCommand
//
CMINVOKECOMMANDINFOEX ici =
{
SIZEOF(CMINVOKECOMMANDINFOEX),
0L,
_hwnd,
(LPSTR)MAKEINTRESOURCE(idCmd),
NULL, NULL,
SW_NORMAL,
};
hres = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
}
}
ATOMICRELEASE(_pcm3Parent);
if (pcmParent)
pcmParent->Release();
if (pcmChild)
pcmChild->Release();
DestroyMenu(hmenu);
}
return hres;
}
/*----------------------------------------------------------
Purpose: IWinEventHandler::OnWinEvent
Processes messages passed on from the bar. Forward
messages to the bands as appropriate.
*/
HRESULT CBandSite::OnWinEvent(HWND h, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
{
HRESULT hres = E_FAIL;
HWND hwnd = HWND_BROADCAST;
switch (uMsg)
{
case WM_WININICHANGE:
_UpdateAllBands(FALSE, FALSE);
goto L_WM_SYSCOLORCHANGE;
case WM_SYSCOLORCHANGE:
case WM_PALETTECHANGED:
L_WM_SYSCOLORCHANGE:
// propagate to rebar
if (_hwnd)
SendMessage(_hwnd, uMsg, wParam, lParam);
// by not returning here, it will get forwarded to the bands also...
break;
case WM_CONTEXTMENU:
// if it came from the keyboard, wParam is somewhat useless. it's always out hwnd
if (IS_WM_CONTEXTMENU_KEYBOARD(lParam))
hwnd = GetFocus();
else
hwnd = (HWND)wParam;
break;
case WM_COMMAND:
hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
break;
case WM_NOTIFY:
if (lParam)
hwnd = ((LPNMHDR)lParam)->hwndFrom;
break;
case WM_INITMENUPOPUP:
case WM_MEASUREITEM:
case WM_DRAWITEM:
case WM_MENUCHAR:
if (_pcm3Parent)
{
//
// If _pcm3Parent, then we've got a context menu up and
// an ICM3 client who might care about this message.
//
hwnd = _hwnd;
}
break;
default:
return E_FAIL;
}
LRESULT lres = 0;
if (hwnd)
{
if (_hwnd == hwnd)
{
// a message for us
switch (uMsg)
{
case WM_NOTIFY:
lres = _OnNotify((LPNMHDR)lParam);
hres = S_OK;
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_CMD(wParam, lParam))
{
case IDM_DRAGDROP:
_DoDragDrop();
break;
}
break;
case WM_INITMENUPOPUP:
case WM_MEASUREITEM:
case WM_DRAWITEM:
case WM_MENUCHAR:
ASSERT(_pcm3Parent);
hres = _pcm3Parent->HandleMenuMsg2(uMsg, wParam, lParam, &lres);
break;
}
}
else
{
if (_SendToToolband(hwnd, uMsg, wParam, lParam, &lres))
hres = S_OK;
}
}
switch (uMsg)
{
case WM_WININICHANGE:
SendMessage(_hwnd, WM_SIZE, 0, 0);
break;
case WM_CONTEXTMENU:
if (!lres)
return _OnContextMenu(wParam, lParam);
break;
}
if (plres)
*plres = lres;
return hres;
}
HRESULT CBandSite_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CBandSite *pbs = new CBandSite(pUnkOuter);
if (pbs)
{
*ppunk = pbs->_GetInner();
return S_OK;
}
*ppunk = NULL;
return E_OUTOFMEMORY;
}
//*** CBandSite::IPersistStream*::* {
//
HRESULT CBandSite::GetClassID(CLSID *pClassID)
{
*pClassID = CLSID_RebarBandSite;
return S_OK;
}
HRESULT CBandSite::IsDirty(void)
{
ASSERT(0);
return S_FALSE; // FEATURE: never be dirty?
}
HRESULT CBandSite::_AddBand(IUnknown* punk)
{
if (_pbsOuter)
{
// Give the outer guy first crack
return _pbsOuter->AddBand(punk);
}
else
{
return AddBand(punk);
}
}
//
// Persisted CBandSite, use types that have fixes sizes
//
struct SBandSite
{
DWORD cbSize;
DWORD cbVersion;
DWORD cBands;
// ...followed by length-preceded bands
};
#define SBS_WOADMIN_VERSION 3 // Before we added admin settings.
#define SBS_VERSION 8
//*** CBandSite::Load, Save --
// DESCRIPTION
// for each band...
// Load Read (i); OLFS(obj)+AddBand; Read (rbbi); RB_SBI
// Save RB_GBI; Write(i); OSTS(obj)+nil ; Write(rbbi)
// NOTES
// FEATURE: needs error recovery
// WARNING: we might have done a CreateBand w/o an AddBand; if so our
// assumption about the rebar bands and the iunknowns being 'parallel'
// is bogus.
HRESULT CBandSite::Load(IStream *pstm)
{
HRESULT hres;
SBandSite sfoo;
hres = IStream_Read(pstm, &sfoo, SIZEOF(sfoo)); // pstm->Read
if (hres == S_OK)
{
if (!(sfoo.cbSize == SIZEOF(SBandSite) &&
(sfoo.cbVersion == SBS_VERSION || sfoo.cbVersion == SBS_WOADMIN_VERSION)))
{
hres = E_FAIL;
}
IBandSiteHelper *pbsh;
hres = QueryInterface(IID_PPV_ARG(IBandSiteHelper, &pbsh));
if (EVAL(SUCCEEDED(hres)))
{
BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
for (DWORD i = 0; i < sfoo.cBands && SUCCEEDED(hres); ++i)
{
DWORD j;
hres = IStream_Read(pstm, &j, SIZEOF(j)); // pstm->Read
if (hres == S_OK)
{
if (j == i) // for sanity check
{
IUnknown* punk;
hres = pbsh->LoadFromStreamBS(pstm, IID_PPV_ARG(IUnknown, &punk));
if (SUCCEEDED(hres))
{
hres = _AddBand(punk);
if (SUCCEEDED(hres))
{
hres = _LoadBandInfo(pstm, i, sfoo.cbVersion);
}
punk->Release();
}
}
else
{
hres = E_FAIL;
}
}
}
SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
pbsh->Release();
}
_UpdateAllBands(FALSE, TRUE); // force refresh
}
return hres;
}
HRESULT CBandSite::Save(IStream *pstm, BOOL fClearDirty)
{
HRESULT hres;
SBandSite sfoo;
TraceMsg(DM_PERSIST, "cbs.s enter(this=%x pstm=%x) tell()=%x", this, pstm, DbStreamTell(pstm));
sfoo.cbSize = SIZEOF(SBandSite);
sfoo.cbVersion = SBS_VERSION;
sfoo.cBands = _GetBandItemCount();
TraceMsg(DM_PERSIST, "cdb.s: cbands=%d", sfoo.cBands);
hres = pstm->Write(&sfoo, SIZEOF(sfoo), NULL);
if (SUCCEEDED(hres))
{
for (DWORD i = 0; i < sfoo.cBands; i++)
{
// FEATURE: put seek ptr so can resync after bogus streams
hres = pstm->Write(&i, SIZEOF(i), NULL); // for sanity check
if (SUCCEEDED(hres))
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (EVAL(pbid) && pbid->pdb)
{
IBandSiteHelper *pbsh;
hres = QueryInterface(IID_PPV_ARG(IBandSiteHelper, &pbsh));
if (SUCCEEDED(hres))
{
hres = pbsh->SaveToStreamBS(SAFECAST(pbid->pdb, IUnknown*), pstm);
pbsh->Release();
}
}
hres = _SaveBandInfo(pstm, i);
ASSERT(SUCCEEDED(hres));
}
}
}
TraceMsg(DM_PERSIST, "cbs.s leave tell()=%x", DbStreamTell(pstm));
return hres;
}
HRESULT CBandSite::GetSizeMax(ULARGE_INTEGER *pcbSize)
{
static const ULARGE_INTEGER cbMax = { SIZEOF(SBandSite), 0 };
*pcbSize = cbMax;
return S_OK;
}
BOOL CBandSite::_IsHeightReasonable(UINT cy)
{
static UINT s_cyMon = 0;
if (s_cyMon == 0)
{
HMONITOR hmon = MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST);
if (hmon)
{
RECT rc;
if (GetMonitorRect(hmon, &rc))
{
s_cyMon = RECTHEIGHT(rc);
}
}
}
return (s_cyMon != 0) ? (cy < 4 * s_cyMon) : TRUE;
}
// returns: IStream::Read() semantics, S_OK means complete read
HRESULT CBandSite::_LoadBandInfo(IStream *pstm, int i, DWORD dwVersion)
{
PERSISTBANDINFO bi;
HRESULT hres;
DWORD dwSize = SIZEOF(bi);
bi.dwAdminSettings = BAND_ADMIN_NORMAL; // Assume Normal since it's not specified
if (SBS_WOADMIN_VERSION == dwVersion)
dwSize = SIZEOF(PERSISTBANDINFO_V3);
hres = IStream_Read(pstm, &bi, dwSize); // pstm->Read
if (hres == S_OK)
{
//
// Sanity-check the height specified by PERSISTBANDINFO before proceeding.
// Some people are hitting a stress scenario where a bad height gets
// persisted out. If the height is not reasonable, then just discard
// the sizing values (leaving the defaults in place).
//
if (_IsHeightReasonable(bi.cyChild))
{
REBARBANDINFO rbbi;
rbbi.cbSize = SIZEOF(rbbi);
rbbi.fMask = RBBIM_XPERSIST;
rbbi.cx = bi.cx;
rbbi.fStyle = bi.fStyle;
// these things can change from instantiation to instantiation.
// we want to restore the visual state, not the sizing rules.
// the sizing rules re retreived each time in getbandinfo
rbbi.cyMinChild = -1;
rbbi.cyMaxChild = -1;
rbbi.cyIntegral = -1;
rbbi.cxMinChild = -1;
if (rbbi.fStyle & RBBS_VARIABLEHEIGHT)
{
rbbi.cyChild = bi.cyChild;
}
else
{
rbbi.cyMinChild = bi.cyMinChild;
}
SendMessage(_hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi);
}
LPBANDITEMDATA pbid = _GetBandItem(i);
if (pbid)
{
pbid->dwAdminSettings = bi.dwAdminSettings;
pbid->fNoTitle = bi.fNoTitle;
}
}
return hres;
}
HRESULT CBandSite::_SaveBandInfo(IStream *pstm, int i)
{
REBARBANDINFO rbbi = {0};
PERSISTBANDINFO bi = {0};
LPBANDITEMDATA pbid;
rbbi.cbSize = SIZEOF(rbbi);
rbbi.fMask = RBBIM_XPERSIST;
SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi);
ASSERT((rbbi.fMask & RBBIM_XPERSIST) == RBBIM_XPERSIST);
bi.cx = rbbi.cx;
bi.fStyle = rbbi.fStyle;
bi.cyMinChild = rbbi.cyMinChild;
bi.cyChild = rbbi.cyChild;
pbid = _GetBandItem(i);
if (pbid)
{
bi.dwAdminSettings = pbid->dwAdminSettings;
bi.fNoTitle = pbid->fNoTitle;
}
return pstm->Write(&bi, SIZEOF(bi), NULL);
}
void CBandSite::_CacheActiveBand(IUnknown *ptb)
{
if (ptb == _ptbActive)
return;
if (SHIsSameObject(ptb, _ptbActive))
return;
ATOMICRELEASE(_ptbActive);
if (ptb != NULL)
{
#ifdef DEBUG
// better be an IInputObject or else why did you call us?
IInputObject *pio;
if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_PPV_ARG(IInputObject, &pio)))))
pio->Release();
// overly strict, but in our case it's true...
IDeskBand *pdb;
if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_PPV_ARG(IDeskBand, &pdb)))))
pdb->Release();
#endif
_ptbActive = ptb;
_ptbActive->AddRef();
}
return;
}
DWORD CBandSite::_BandIDFromPunk(IUnknown* punk)
{
DWORD dwBandID = -1;
DWORD dwBandIDTest;
int cBands = EnumBands(-1, NULL);
IUnknown* punkTest;
if (punk)
{
for (int i = 0; i < cBands; i++)
{
if (SUCCEEDED(EnumBands(i, &dwBandIDTest)))
{
if (SUCCEEDED(GetBandObject(dwBandIDTest, IID_PPV_ARG(IUnknown, &punkTest))))
{
BOOL fEq = SHIsSameObject(punk, punkTest);
punkTest->Release();
if (fEq)
{
dwBandID = dwBandIDTest;
break;
}
}
}
}
}
return dwBandID;
}
//*** IInputObjectSite methods ***
HRESULT CBandSite::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
{
if (_ptbActive)
{
if (!SHIsSameObject(_ptbActive, punk))
{
// Deactivate current band since the current band is
// not the caller
TraceMsg(TF_ACCESSIBILITY, "CBandSite::OnFocusChangeIS (hwnd=0x%08X) deactivate band", _hwnd);
UIActivateIO(FALSE, NULL);
}
}
if (fSetFocus)
_CacheActiveBand(punk);
return IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), fSetFocus);
}
//*** IInputObject methods ***
HRESULT CBandSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
{
HRESULT hres = E_FAIL;
TraceMsg(TF_ACCESSIBILITY, "CBandSite::UIActivateIO (hwnd=0x%08X) fActivate=%d", _hwnd, fActivate);
ASSERT(NULL == lpMsg || IS_VALID_WRITE_PTR(lpMsg, MSG));
if (_ptbActive)
{
hres = IUnknown_UIActivateIO(_ptbActive, fActivate, lpMsg);
}
else
{
hres = OnFocusChangeIS(NULL, fActivate);
}
if (fActivate)
{
if (!_ptbActive)
{
if (IsVK_TABCycler(lpMsg))
hres = _CycleFocusBS(lpMsg);
else
hres = S_OK;
}
}
else
{
_CacheActiveBand(NULL);
}
return hres;
}
HRESULT CBandSite::HasFocusIO()
{
// Rebar should never get focus
// NT #288832 Is one case where (GetFocus() == _hwnd)
// which is caused when the "Folder Bar" disappears.
// CExplorerBand::ShowDW() calls ShowWindow(hwndTreeView, SW_HIDE)
// which by default sets focus to the parent (us).
// This is ok because when this function is called,
// it will return E_FAIL which the caller will treat
// as S_FALSE and give the focus to the next deserving
// dude in line.
return IUnknown_HasFocusIO(_ptbActive);
}
HRESULT CBandSite::TranslateAcceleratorIO(LPMSG lpMsg)
{
TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, lpMsg->wParam);
if (IUnknown_TranslateAcceleratorIO(_ptbActive, lpMsg) == S_OK)
{
TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d; handled by active band", _hwnd, lpMsg->wParam);
// active band handled it
return S_OK;
}
else if (IsVK_TABCycler(lpMsg))
{
TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) cycle focus", _hwnd);
// it's a tab; cycle focus
return _CycleFocusBS(lpMsg);
}
return S_FALSE;
}
int CBandSite::_BandIndexFromPunk(IUnknown *punk)
{
for (int i = 0; i < _GetBandItemCount(); i++)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (EVAL(pbid) && SHIsSameObject(pbid->pdb, punk))
return i;
}
return -1;
}
BOOL CBandSite::_IsBandTabstop(LPBANDITEMDATA pbid)
{
// A band is a tabstop if it is visible and has WS_TABSTOP
if (pbid->fShow && pbid->hwnd && IsWindowVisible(pbid->hwnd))
{
if (WS_TABSTOP & GetWindowStyle(pbid->hwnd))
return TRUE;
}
return FALSE;
}
#define INCDEC(i, fDec) (fDec ? i - 1 : i + 1)
IUnknown* CBandSite::_GetNextTabstopBand(IUnknown* ptb, BOOL fBackwards)
{
// Find the first tabstop candidate
int iBandCount = _GetBandItemCount();
int iBand = _BandIndexFromPunk(ptb);
if (iBand == -1)
{
// Start at the end/beginning
if (fBackwards)
iBand = iBandCount - 1;
else
iBand = 0;
}
else
{
// Start one off the current band
iBand = INCDEC(iBand, fBackwards);
}
// Loop til we find a tabstop band or we run off the end
while (0 <= iBand && iBand < iBandCount)
{
LPBANDITEMDATA pbid = _GetBandItem(iBand);
if (EVAL(pbid))
{
if (_IsBandTabstop(pbid))
return pbid->pdb;
}
// Try the next band
iBand = INCDEC(iBand, fBackwards);
}
return NULL;
}
HRESULT CBandSite::_CycleFocusBS(LPMSG lpMsg)
{
HRESULT hr = S_FALSE;
IUnknown* ptbSave = NULL;
if (_ptbActive)
{
// Save off the active band in ptbSave
ptbSave = _ptbActive;
ptbSave->AddRef();
// Deactivate active band and clear cache
IUnknown_UIActivateIO(_ptbActive, FALSE, NULL);
_CacheActiveBand(NULL);
}
if (ptbSave && IsVK_CtlTABCycler(lpMsg))
{
// If ctl-tab and a band was active, then reject focus
ASSERT(hr == S_FALSE);
}
else
{
BOOL fShift = (GetKeyState(VK_SHIFT) < 0);
// Loop til we find a tabstop and successfully activate it
// or til we run out of bands.
// FEATURE: todo -- call SetFocus if UIActivateIO fails?
IUnknown* ptbNext = ptbSave;
while (ptbNext = _GetNextTabstopBand(ptbNext, fShift))
{
if (IUnknown_UIActivateIO(ptbNext, TRUE, lpMsg) == S_OK)
{
hr = S_OK;
break;
}
}
}
ATOMICRELEASE(ptbSave);
return hr;
}
//*** CBandSite::IBandSiteHelper::* {
// stuff to make it possible to overload the OleLoad/Save stuff so the
// taskbar band does not have to be CoCreat able. kinda a hack...
HRESULT CBandSite::LoadFromStreamBS(IStream *pstm, REFIID riid, void **ppv)
{
return OleLoadFromStream(pstm, riid, ppv);
}
HRESULT CBandSite::SaveToStreamBS(IUnknown *punk, IStream *pstm)
{
IPersistStream *ppstm;
HRESULT hres = punk->QueryInterface(IID_PPV_ARG(IPersistStream, &ppstm));
if (SUCCEEDED(hres))
{
hres = OleSaveToStream(ppstm, pstm);
ppstm->Release();
}
return hres;
}
// }
// *** IDropTarget *** {
HRESULT CBandSite::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
TraceMsg(TF_BANDDD, "CBandSite::DragEnter %d %d", pt.x, pt.y);
if (!_fDragSource)
{
FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
_dwDropEffect = DROPEFFECT_NONE;
if (pdtobj->QueryGetData(&fmte) == S_OK)
{
_dwDropEffect = DROPEFFECT_MOVE;
}
else
{
LPITEMIDLIST pidl;
if (SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
{
ASSERT(pidl && IS_VALID_PIDL(pidl));
DWORD dwAttrib = SFGAO_FOLDER | SFGAO_BROWSABLE;
IEGetAttributesOf(pidl, &dwAttrib);
ILFree(pidl);
DWORD dwRAction;
if (FAILED(IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, RA_DROP, NULL, &dwRAction)))
dwRAction = RR_ALLOW;
if (dwRAction == RR_DISALLOW)
_dwDropEffect = DROPEFFECT_NONE;
else
{
// if it's not a folder nor a browseable object, we can't host it.
if ((dwAttrib & SFGAO_FOLDER) ||
(dwAttrib & SFGAO_BROWSABLE) && (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
_dwDropEffect = DROPEFFECT_LINK | DROPEFFECT_COPY;
_dwDropEffect |= GetPreferedDropEffect(pdtobj);
}
}
}
*pdwEffect &= _dwDropEffect;
}
return S_OK;
}
HRESULT CBandSite::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
TraceMsg(TF_BANDDD, "CBandSite::DragOver %d %d", ptl.x, ptl.y);
if (_fDragSource)
{
RECT rc;
POINT pt;
pt.x = ptl.x;
pt.y = ptl.y;
GetWindowRect(_hwnd, &rc);
if (PtInRect(&rc, pt))
SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
}
else
{
*pdwEffect &= _dwDropEffect;
}
return S_OK;
}
HRESULT CBandSite::DragLeave(void)
{
return S_OK;
}
HRESULT CBandSite::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
HRESULT hres = E_FAIL;
TraceMsg(TF_BANDDD, "CBandSite::Drop");
if (_fDragSource)
{
SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
*pdwEffect = DROPEFFECT_NONE;
hres = S_OK;
}
else
{
FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
STGMEDIUM stg;
IUnknown *punk = NULL;
LPITEMIDLIST pidl;
// if it was an object of our type, create it!
if ((*pdwEffect & DROPEFFECT_MOVE) &&
SUCCEEDED(pdtobj->GetData(&fmte, &stg)))
{
hres = OleLoadFromStream(stg.pstm, IID_PPV_ARG(IUnknown, &punk));
if (SUCCEEDED(hres))
{
*pdwEffect = DROPEFFECT_MOVE;
}
ReleaseStgMedium(&stg);
}
else if ((*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK)) &&
SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
{
hres = SHCreateBandForPidl(pidl, &punk, (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT));
ILFree(pidl);
if (SUCCEEDED(hres))
{
if (*pdwEffect & DROPEFFECT_LINK)
*pdwEffect = DROPEFFECT_LINK;
else
*pdwEffect = DROPEFFECT_COPY;
}
}
if (punk)
{
hres = _AddBand(punk);
if (SUCCEEDED(hres))
{
DWORD dwState;
dwState = IDataObject_GetDeskBandState(pdtobj);
SetBandState(ShortFromResult(hres), BSSF_NOTITLE, dwState & BSSF_NOTITLE);
}
punk->Release();
}
}
if (FAILED(hres))
*pdwEffect = DROPEFFECT_NONE;
return hres;
}
// }
//*** ::_MergeBS -- merge two bandsites into one
// ENTRY/EXIT
// pdtDst [INOUT] destination DropTarget (always from bandsite)
// pbsSrc [INOUT] source bandsite; deleted if all bands moved successfully
// ret S_OK if all bands moved; S_FALSE if some moved; E_* o.w.
// NOTES
// note that if all the bands are moved successfully, pbsSrc will be deleted
// as a side-effect.
// pdtDst is assumed to accept multiple drops (bandsite does).
// pdtDst may be from marshal/unmarshal (tray bandsite).
HRESULT _MergeBS(IDropTarget *pdtDst, IBandSite *pbsSrc)
{
HRESULT hres = E_FAIL;
DWORD idBand;
pbsSrc->AddRef(); // don't go away until we're all done!
// drag each band in turn
while (SUCCEEDED(pbsSrc->EnumBands(0, &idBand)))
{
// note our (bogus?) assumption that bands which can't be
// dragged will percolate down to a contiguous range of
// iBands 0..n. if that's bogus i'm not sure how we can
// keep track of where we are.
IDataObject *pdoSrc;
hres = pbsSrc->GetBandObject(idBand, IID_PPV_ARG(IDataObject, &pdoSrc));
if (SUCCEEDED(hres))
{
DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY;
hres = SHSimulateDrop(pdtDst, pdoSrc, 0, NULL, &dwEffect);
pdoSrc->Release();
if (SUCCEEDED(hres) && (dwEffect & DROPEFFECT_MOVE))
{
hres = pbsSrc->RemoveBand(idBand);
ASSERT(SUCCEEDED(hres));
}
}
// we failed to move the band, bail
if (FAILED(hres))
{
ASSERT(0);
break;
}
}
pbsSrc->Release();
TraceMsg(DM_DRAG, "dba.ms: ret hres=%x", hres);
return hres;
}
void CBandSite::_BandItemEnumCallback(int dincr, PFNBANDITEMENUMCALLBACK pfnCB, void *pv)
{
UINT iFirst = 0;
ASSERT(dincr == 1 || dincr == -1);
if (dincr < 0)
{
iFirst = _GetBandItemCount() - 1; // start from last
}
for (UINT i = iFirst; i < (UINT) _GetBandItemCount(); i += dincr)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
if (pbid && !pfnCB(pbid, pv))
break;
}
}
void CBandSite::_DeleteAllBandItems()
{
for (int i = _GetBandItemCount() - 1; i >= 0; i--)
{
LPBANDITEMDATA pbid = _GetBandItem(i);
// Release the banditem data first, while it can still
// receive cleanup notifications from its control. *Then*
// delete the band item.
if (pbid)
_ReleaseBandItemData(pbid, i);
// REARCHITECT: chrisfra 5/13/97 if you skip deleting, rebar can
// rearrange on delete, moving a band so that it is never seen
// and consequently we leak BrandBand and much else
_DeleteBandItem(i); // unhook from host (rebar)
}
}
LPBANDITEMDATA CBandSite::_GetBandItem(int i)
{
REBARBANDINFO rbbi;
rbbi.cbSize = SIZEOF(rbbi);
rbbi.fMask = RBBIM_LPARAM;
rbbi.lParam = NULL; // in case of failure below
if (_hwnd)
SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi);
return (LPBANDITEMDATA)rbbi.lParam;
}
int CBandSite::_GetBandItemCount()
{
int cel = 0;
if (_hwnd)
{
ASSERT(IS_VALID_HANDLE(_hwnd, WND));
cel = (int)SendMessage(_hwnd, RB_GETBANDCOUNT, 0, 0);
}
return cel;
}
void CBandSite::_GetBandInfo(LPBANDITEMDATA pbid, DESKBANDINFO *pdbi)
{
pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
pdbi->ptMinSize = pbid->ptMinSize;
pdbi->ptMaxSize = pbid->ptMaxSize;
pdbi->ptIntegral = pbid->ptIntegral;
pdbi->ptActual = pbid->ptActual;
StrCpyW(pdbi->wszTitle, pbid->szTitle);
pdbi->dwModeFlags = pbid->dwModeFlags;
pdbi->crBkgnd = pbid->crBkgnd;
if (pbid->pdb)
{
pbid->pdb->GetBandInfo(pbid->dwBandID, _dwMode, pdbi);
}
if (pdbi->wszTitle[0] == 0)
{
pdbi->dwMask &= ~DBIM_TITLE;
}
pbid->ptMinSize = pdbi->ptMinSize;
pbid->ptMaxSize = pdbi->ptMaxSize;
pbid->ptIntegral = pdbi->ptIntegral;
pbid->ptActual = pdbi->ptActual;
StrCpyW(pbid->szTitle, pdbi->wszTitle);
pbid->dwModeFlags = pdbi->dwModeFlags;
pbid->crBkgnd = pdbi->crBkgnd;
if (!(pdbi->dwMask & DBIM_TITLE)) // title not supported
pbid->fNoTitle = TRUE;
ASSERT(pdbi->dwModeFlags & DBIMF_VARIABLEHEIGHT ? pbid->ptIntegral.y : TRUE);
}
void CBandSite::_BandInfoFromBandItem(REBARBANDINFO *prbbi, LPBANDITEMDATA pbid, BOOL fBSOnly)
{
// REVIEW: could be optimized more
DESKBANDINFO dbi;
if (!fBSOnly)
_GetBandInfo(/*INOUT*/ pbid, &dbi);
// now add the view as a band in the rebar
// add links band
prbbi->fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_TEXT;
if (fBSOnly)
prbbi->fMask = RBBIM_STYLE|RBBIM_TEXT;
// clear the bits the are band settable
prbbi->fStyle |= RBBS_FIXEDBMP;
prbbi->fStyle &= ~(RBBS_NOGRIPPER | RBBS_GRIPPERALWAYS | RBBS_VARIABLEHEIGHT | RBBS_USECHEVRON);
if (_dwStyle & BSIS_NOGRIPPER)
prbbi->fStyle |= RBBS_NOGRIPPER;
else if (_dwStyle & BSIS_ALWAYSGRIPPER)
prbbi->fStyle |= RBBS_GRIPPERALWAYS;
else
{
// BSIS_AUTOGRIPPER...
if (!(prbbi->fStyle & RBBS_FIXEDSIZE) &&
!(_dwMode & DBIF_VIEWMODE_FLOATING))
prbbi->fStyle |= RBBS_GRIPPERALWAYS;
}
if (pbid->dwModeFlags & DBIMF_VARIABLEHEIGHT)
prbbi->fStyle |= RBBS_VARIABLEHEIGHT;
if (pbid->dwModeFlags & DBIMF_USECHEVRON)
prbbi->fStyle |= RBBS_USECHEVRON;
if (pbid->dwModeFlags & DBIMF_BREAK)
prbbi->fStyle |= RBBS_BREAK;
if (pbid->dwModeFlags & DBIMF_TOPALIGN)
prbbi->fStyle |= RBBS_TOPALIGN;
if (!fBSOnly)
{
prbbi->hwndChild = pbid->hwnd;
prbbi->wID = pbid->dwBandID;
// set up the geometries
prbbi->cxMinChild = pbid->ptMinSize.x;
prbbi->cyMinChild = pbid->ptMinSize.y;
prbbi->cyMaxChild = pbid->ptMaxSize.y;
prbbi->cyIntegral = pbid->ptIntegral.y;
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
{
// after we're up, it's the "ideal" point
prbbi->cxIdeal = pbid->ptActual.y;
}
else
{
// after we're up, it's the "ideal" point
prbbi->cxIdeal = pbid->ptActual.x;
}
if (prbbi->cxIdeal == (UINT)-1)
prbbi->cxIdeal = 0;
if (pbid->dwModeFlags & DBIMF_BKCOLOR)
{
if (dbi.dwMask & DBIM_BKCOLOR)
{
prbbi->fMask |= RBBIM_COLORS;
prbbi->clrFore = CLR_DEFAULT;
prbbi->clrBack = dbi.crBkgnd;
}
}
ASSERT(pbid->fNoTitle || (dbi.dwMask & DBIM_TITLE)); // pbid in sync?
}
SHUnicodeToTChar(pbid->szTitle, prbbi->lpText, prbbi->cch);
if (!pbid->fNoTitle && _IsEnableTitle(pbid) && !(_dwStyle & BSIS_NOCAPTION))
{
prbbi->fStyle &= ~RBBS_HIDETITLE;
}
else
{
// No text please
prbbi->fStyle |= RBBS_HIDETITLE;
}
// Make this band a tabstop. Itbar will override v_SetTabstop
// since for the browser we don't want every band to be a tabstop.
v_SetTabstop(prbbi);
}
void CBandSite::v_SetTabstop(LPREBARBANDINFO prbbi)
{
// We specify that a band should be a tabstop by setting the WS_TABSTOP
// bit. Never make RBBS_FIXEDSIZE bands (i.e., the brand) tabstops.
if (prbbi && prbbi->hwndChild && !(prbbi->fStyle & RBBS_FIXEDSIZE))
SHSetWindowBits(prbbi->hwndChild, GWL_STYLE, WS_TABSTOP, WS_TABSTOP);
}
//*** cbs::_IsEnableTitle -- should we enable (ungray) title
// DESCRIPTION
// used for handing back title and for enabling menu
// NOTES
// pbid unused...
//
#ifndef UNIX
_inline
#endif
BOOL CBandSite::_IsEnableTitle(LPBANDITEMDATA pbid)
{
ASSERT(pbid);
return (/*pbid && !pbid->fNoTitle &&*/
!((_dwMode & DBIF_VIEWMODE_FLOATING) && _GetBandItemCount() <= 1));
}
BOOL CBandSite::_UpdateBandInfo(LPBANDITEMDATA pbid, BOOL fBSOnly)
{
REBARBANDINFO rbbi = {SIZEOF(rbbi)};
int iRB = _BandIDToIndex(pbid->dwBandID);
// now update the info
rbbi.fMask = RBBIM_ID | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
if (fBSOnly)
rbbi.fMask = RBBIM_STYLE;
SendMessage(_hwnd, RB_GETBANDINFO, iRB, (LPARAM)&rbbi);
if (!fBSOnly)
{
if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
{
pbid->ptActual.x = rbbi.cyChild;
pbid->ptActual.y = rbbi.cxIdeal;
}
else
{
pbid->ptActual.x = rbbi.cxIdeal;
pbid->ptActual.y = rbbi.cyChild;
}
pbid->ptMinSize.x = rbbi.cxMinChild;
pbid->ptMinSize.y = rbbi.cyMinChild;
pbid->ptMaxSize.y = rbbi.cyMaxChild;
}
TCHAR szBand[40];
rbbi.lpText = szBand;
rbbi.cch = ARRAYSIZE(szBand);
_BandInfoFromBandItem(&rbbi, pbid, fBSOnly);
return BOOLFROMPTR(SendMessage(_hwnd, RB_SETBANDINFO, (UINT)iRB, (LPARAM)&rbbi));
}
BOOL CBandSite::_AddBandItem(LPBANDITEMDATA pbid)
{
REBARBANDINFO rbbi = {SIZEOF(rbbi)};
pbid->ptActual.x = -1;
pbid->ptActual.y = -1;
TCHAR szBand[40];
rbbi.lpText = szBand;
rbbi.cch = ARRAYSIZE(szBand);
_BandInfoFromBandItem(&rbbi, pbid, FALSE);
rbbi.cyChild = pbid->ptActual.y;
rbbi.fMask |= RBBIM_LPARAM;
rbbi.lParam = (LPARAM)pbid;
ASSERT(rbbi.fMask & RBBIM_ID);
return BOOLFROMPTR(SendMessage(_hwnd, RB_INSERTBAND, (UINT) (pbid->dwModeFlags & DBIMF_ADDTOFRONT) ? 0 : -1, (LPARAM)&rbbi));
}
void CBandSite::_DeleteBandItem(int i)
{
SendMessage(_hwnd, RB_DELETEBAND, i, 0);
}
DWORD CBandSite::_IndexToBandID(int i)
{
REBARBANDINFO rbbi = {SIZEOF(rbbi)};
rbbi.fMask = RBBIM_ID;
if (SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi))
return rbbi.wID;
else
return -1;
}
/*----------------------------------------------------------
Purpose: Given the band ID, returns the internal band index.
*/
int CBandSite::_BandIDToIndex(DWORD dwBandID)
{
int nRet = -1;
if (_hwnd)
nRet = (int)SendMessage(_hwnd, RB_IDTOINDEX, (WPARAM) dwBandID, (LPARAM) 0);
return nRet;
}
/*----------------------------------------------------------
Purpose: The Parent Site may want to override what the admin
specified.
Return Values:
S_OK: Do lock band.
S_FALSE: Do NOT Lock band.
*/
HRESULT CBandSite::_IsRestricted(DWORD dwBandID, DWORD dwRestrictAction, DWORD dwBandFlags)
{
HRESULT hr;
DWORD dwRestrictionAction;
hr = IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, dwRestrictAction, NULL, &dwRestrictionAction);
if (RR_NOCHANGE == dwRestrictionAction) // If our parent didn't handle it, we will.
dwRestrictionAction = IsFlagSet(_GetAdminSettings(dwBandID), dwBandFlags) ? RR_DISALLOW : RR_ALLOW;
if (RR_DISALLOW == dwRestrictionAction)
hr = S_OK;
else
hr = S_FALSE;
ASSERT(SUCCEEDED(hr)); // FAIL(hr) other than hr == E_NOTIMPLE; is not good.
return hr;
}
BOOL ConfirmRemoveBand(HWND hwnd, UINT uID, LPCTSTR pszName)
{
TCHAR szTemp[1024], *pszTemp2, *pszStr, szTitle[80];
BOOL bRet = TRUE;
DWORD dwLen;
MLLoadString(IDS_CONFIRMCLOSETITLE, szTitle, ARRAYSIZE(szTitle));
// Calling FormatMessage with FORMAT_MESSAGE_FROM_HMODULE fails
MLLoadString(uID, szTemp, ARRAYSIZE(szTemp));
dwLen = (lstrlen(szTemp) + lstrlen(pszName) + 1) * sizeof(TCHAR);
if((pszTemp2 = (TCHAR *)LocalAlloc(LPTR, dwLen)) != NULL)
{
_FormatMessage(szTemp, pszTemp2, dwLen, pszName);
MLLoadString(IDS_CONFIRMCLOSETEXT, szTemp, ARRAYSIZE(szTemp));
dwLen = (lstrlen(szTemp) + lstrlen(pszTemp2) + 1) * sizeof(TCHAR);
if((pszStr = (TCHAR *)LocalAlloc(LPTR, dwLen)) != NULL)
{
_FormatMessage(szTemp, pszStr, dwLen, pszTemp2);
bRet = (IDOK == SHMessageBoxCheck(hwnd, pszStr, szTitle, MB_OKCANCEL, IDOK, TEXT("WarnBeforeCloseBand")));
LocalFree(pszStr);
}
LocalFree(pszTemp2);
}
return bRet;
}