windows-nt/Source/XPSP1/NT/shell/shell32/menuband/menusite.cpp

553 lines
12 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "shellprv.h"
#include "menusite.h"
CMenuSite::CMenuSite() : _cRef(1)
{
}
CMenuSite::~CMenuSite()
{
// Make sure that SetDeskBarSite(NULL) was called
ASSERT(_punkSite == NULL);
ASSERT(_punkSubActive == NULL);
ASSERT(_pweh == NULL);
ASSERT(_pdb == NULL);
ASSERT(_hwnd == NULL);
}
STDAPI CMenuBandSite_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppv)
{
HRESULT hr = E_OUTOFMEMORY;
*ppv = NULL;
CMenuSite *pbs = new CMenuSite();
if (pbs)
{
hr = pbs->QueryInterface(riid, ppv);
pbs->Release();
}
return hr;
}
/*----------------------------------------------------------
Purpose: IUnknown::QueryInterface method
*/
STDMETHODIMP CMenuSite::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
static const QITAB qit[] = {
QITABENT(CMenuSite, IBandSite),
QITABENT(CMenuSite, IDeskBarClient),
QITABENT(CMenuSite, IOleCommandTarget),
QITABENT(CMenuSite, IInputObject),
QITABENT(CMenuSite, IInputObjectSite),
QITABENT(CMenuSite, IWinEventHandler),
QITABENT(CMenuSite, IServiceProvider),
QITABENT(CMenuSite, IOleWindow),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
/*----------------------------------------------------------
Purpose: IUnknown::AddRef method
*/
STDMETHODIMP_(ULONG) CMenuSite::AddRef(void)
{
_cRef++;
return _cRef;
}
/*----------------------------------------------------------
Purpose: IUnknown::Release method
*/
STDMETHODIMP_(ULONG) CMenuSite::Release()
{
ASSERT(_cRef > 0);
_cRef--;
if (_cRef > 0)
return _cRef;
delete this;
return 0;
}
/*----------------------------------------------------------
Purpose: IServiceProvider::QueryService method
*/
STDMETHODIMP CMenuSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
{
HRESULT hres = E_FAIL;
*ppvObj = NULL; // assume error
if (IsEqualIID(guidService, SID_SMenuBandBottom) ||
IsEqualIID(guidService, SID_SMenuBandBottomSelected)||
IsEqualIID(guidService, SID_SMenuBandChild))
{
if (_punkSubActive)
hres = IUnknown_QueryService(_punkSubActive, guidService, riid, ppvObj);
}
else
{
ASSERT(_punkSite);
hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
}
return hres;
}
/*----------------------------------------------------------
Purpose: IOleCommandTarget::QueryStatus
*/
STDMETHODIMP CMenuSite::QueryStatus(const GUID *pguidCmdGroup,
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
{
ASSERT(_punkSite);
return IUnknown_QueryStatus(_punkSite, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
}
/*----------------------------------------------------------
Purpose: IOleCommandTarget::Exec
*/
STDMETHODIMP CMenuSite::Exec(const GUID *pguidCmdGroup,
DWORD nCmdID, DWORD nCmdexecopt,
VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
ASSERT(_punkSite);
return IUnknown_Exec(_punkSite, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}
/*----------------------------------------------------------
Purpose: IInputObjectSite::OnFocusChangeIS
This function is called by the client band to negotiate
which band in this bandsite gets the focus. Typically
this function will then change its focus to the given
client band.
CMenuSite only maintains one and only one band, which
is set at AddBand time, so this function is a nop.
*/
STDMETHODIMP CMenuSite::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
{
// Return S_OK since the menu site only ever has one band.
// No need to negotiate which other band in this bandsite
// might have the "activation".
return S_OK;
}
/*----------------------------------------------------------
Purpose: IInputObject::UIActivateIO method
*/
STDMETHODIMP CMenuSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
{
ASSERT(NULL == lpMsg || IS_VALID_WRITE_PTR(lpMsg, MSG));
// Forward onto the client band
return IUnknown_UIActivateIO(_punkSubActive, fActivate, lpMsg);
}
/*----------------------------------------------------------
Purpose: IInputObject::HasFocusIO
Since the menuband can never have true activation (from
the browser's perspective) this always returns S_FALSE.
See comments in CMenuBand::UIActivateIO for more details
about this.
*/
STDMETHODIMP CMenuSite::HasFocusIO()
{
return S_FALSE;
}
/*----------------------------------------------------------
Purpose: IInputObject::TranslateAcceleratorIO
Menubands cannot ever have the activation, so this method
should never be called.
*/
STDMETHODIMP CMenuSite::TranslateAcceleratorIO(LPMSG lpMsg)
{
AssertMsg(0, TEXT("Menuband has the activation but it shouldn't!"));
return S_FALSE;
}
// Utility Functions
void CMenuSite::_CacheSubActiveBand(IUnknown * punk)
{
if (SHIsSameObject(punk, _punkSubActive))
return;
IUnknown_SetSite(_punkSubActive, NULL);
ATOMICRELEASE(_punkSubActive);
ATOMICRELEASE(_pdb);
ATOMICRELEASE(_pweh);
_hwndChild = NULL;
if (punk != NULL)
{
EVAL(SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IDeskBand, &_pdb))));
EVAL(SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IWinEventHandler, &_pweh))));
IUnknown_SetSite(punk, SAFECAST(this, IOleWindow*));
IUnknown_GetWindow(punk, &_hwndChild);
_punkSubActive = punk;
_punkSubActive->AddRef();
}
}
/*----------------------------------------------------------
Purpose: IBandSite::AddBand
*/
STDMETHODIMP CMenuSite::AddBand(IUnknown* punk)
{
_CacheSubActiveBand(punk);
return NOERROR;
}
/*----------------------------------------------------------
Purpose: IBandSite::EnumBands
*/
STDMETHODIMP CMenuSite::EnumBands(UINT uBand, DWORD* pdwBandID)
{
HRESULT hres = NOERROR;
// The menusite only holds one band ever
if (0 == uBand)
*pdwBandID = 0;
else
hres = E_FAIL;
return hres;
}
/*----------------------------------------------------------
Purpose: IBandSite::QueryBand
*/
HRESULT CMenuSite::QueryBand(DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
{
HRESULT hres = E_NOINTERFACE;
ASSERT(dwBandID == 0);
ASSERT(IS_VALID_WRITE_PTR(ppstb, IDeskBand *));
if (_punkSubActive && 0 == dwBandID)
{
hres = _punkSubActive->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
*pdwState = BSSF_VISIBLE; // Only band....
if (cchName > 0)
*pszName = L'\0';
}
else
*ppstb = NULL;
return hres;
}
/*----------------------------------------------------------
Purpose: IBandSite::SetBandState
*/
HRESULT CMenuSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IBandSite::RemoveBand
*/
HRESULT CMenuSite::RemoveBand(DWORD dwBandID)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IBandSite::GetBandObject
*/
HRESULT CMenuSite::GetBandObject(DWORD dwBandID, REFIID riid, LPVOID *ppvObj)
{
HRESULT hres;
ASSERT(dwBandID == 0);
if (_punkSubActive && 0 == dwBandID)
hres = _punkSubActive->QueryInterface(riid, ppvObj);
else
{
*ppvObj = NULL;
hres = E_NOINTERFACE;
}
return hres;
}
/*----------------------------------------------------------
Purpose: IBandSite::SetBandSiteInfo
*/
HRESULT CMenuSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IBandSite::GetBandSiteInfo
*/
HRESULT CMenuSite::GetBandSiteInfo(BANDSITEINFO * pbsinfo)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IOleWindow::GetWindow
*/
HRESULT CMenuSite::GetWindow(HWND * lphwnd)
{
ASSERT(IS_VALID_HANDLE(_hwnd, WND));
*lphwnd = _hwnd;
return NOERROR;
}
/*----------------------------------------------------------
Purpose: IOleWindow::ContextSensitiveHelp
*/
HRESULT CMenuSite::ContextSensitiveHelp(BOOL fEnterMode)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IDeskBarClient::SetDeskBarSite
*/
HRESULT CMenuSite::SetDeskBarSite(IUnknown* punkSite)
{
if (punkSite)
{
ATOMICRELEASE(_punkSite);
HWND hwnd;
IUnknown_GetWindow(punkSite, &hwnd);
if (hwnd)
{
_CreateSite(hwnd);
_punkSite = punkSite;
_punkSite->AddRef();
}
}
else
{
if (_pdb)
{
_pdb->CloseDW(0);
}
_CacheSubActiveBand(NULL); // This is asymetric by design
if (_hwnd)
{
DestroyWindow(_hwnd);
_hwnd = NULL;
}
ATOMICRELEASE(_punkSite);
}
return _hwnd ? NOERROR : E_FAIL;
}
/*----------------------------------------------------------
Purpose: IDeskBarClient::SetModeDBC
*/
HRESULT CMenuSite::SetModeDBC(DWORD dwMode)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IDeskBarClient::UIActivateDBC
*/
HRESULT CMenuSite::UIActivateDBC(DWORD dwState)
{
HRESULT hr = S_OK;
ASSERT(_pdb);
if (_pdb)
hr = _pdb->ShowDW(0 != dwState);
return hr;
}
/*----------------------------------------------------------
Purpose: IDeskBarClient::GetSize
*/
HRESULT CMenuSite::GetSize(DWORD dwWhich, LPRECT prc)
{
if (dwWhich == DBC_GS_IDEAL)
{
if (_pdb)
{
DESKBANDINFO dbi = {0};
_pdb->GetBandInfo(0, 0, &dbi);
prc->right = dbi.ptMaxSize.x;
prc->bottom = dbi.ptMaxSize.y;
}
}
return NOERROR;
}
/*----------------------------------------------------------
Purpose: IWinEventHandler::OnWinEvent
*/
HRESULT CMenuSite::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
{
if (_pweh)
return _pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
return NOERROR;
}
/*----------------------------------------------------------
Purpose: IWinEventHandler::IsWindowOwner
*/
HRESULT CMenuSite::IsWindowOwner(HWND hwnd)
{
if (_hwnd == hwnd || (_pweh && _pweh->IsWindowOwner(hwnd) != S_FALSE))
return S_OK;
else
return S_FALSE;
}
LRESULT CMenuSite::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lres = 0;
AddRef();
switch(uMsg)
{
case WM_SIZE:
{
IMenuPopup* pmp;
if (_punkSubActive && SUCCEEDED(_punkSubActive->QueryInterface(IID_PPV_ARG(IMenuPopup, &pmp))))
{
RECT rc = {0};
GetClientRect(_hwnd, &rc);
pmp->OnPosRectChangeDB(&rc);
pmp->Release();
}
lres = 1;
}
break;
case WM_NOTIFY:
hwnd = ((LPNMHDR)lParam)->hwndFrom;
break;
case WM_COMMAND:
hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
break;
default:
Release();
return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
break;
}
if (hwnd && _pweh && _pweh->IsWindowOwner(hwnd) == S_OK)
{
_pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, &lres);
}
Release();
return lres;
}
void CMenuSite::_CreateSite(HWND hwndParent)
{
if (_hwnd)
{
ASSERT(IS_VALID_HANDLE(_hwnd, WND)); // just to be safe...
return;
}
WNDCLASS wc = {0};
wc.style = 0;
wc.lpfnWndProc = s_WndProc;
wc.cbWndExtra = SIZEOF(CMenuSite*);
wc.hInstance = HINST_THISDLL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_MENU+1);
wc.lpszClassName = TEXT("MenuSite");
SHRegisterClass(&wc);
_hwnd = CreateWindow(TEXT("MenuSite"), NULL, WS_VISIBLE | WS_CHILD, 0, 0, 0, 0,
hwndParent, NULL, HINST_THISDLL, (LPVOID)SAFECAST(this, CImpWndProc*));
}