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

384 lines
11 KiB
C++

//
// This Channel OC code was copied from browseui. Once it is reenabled in
// browseui it can be removed from shdocvw.
//
#include "priv.h"
#include "cobjsafe.h"
STDAPI ChannelOC_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);
HRESULT IUnknown_SetBandInfoSFB(IUnknown *punkBand, BANDINFOSFB *pbi);
IDeskBand * ChannelBand_Create(LPCITEMIDLIST pidlDefault);
//LPITEMIDLIST Channel_GetFolderPidl();
void Channels_SetBandInfoSFB(IUnknown* punkBand);
//////////////////////////////////////////////////
//
// ChannelOC
//
// This is an OC that wraps the above band for
// inclusion in the Active Desktop.
//
// TODO:
// - listen to ISFBand for resizes and request them
// from our container
//
// Do we need to register as a drop target?
#undef SUPERCLASS
#define SUPERCLASS CShellEmbedding
#undef THISCLASS
#define THISCLASS ChannelOC
class ChannelOC : public SUPERCLASS
, public IServiceProvider
, public IPersistPropertyBag
, public CObjectSafety
{
public:
// *** IUnknown ***
virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) { return SUPERCLASS::QueryInterface(riid, ppvObj); };
virtual STDMETHODIMP_(ULONG) AddRef(void) { return SUPERCLASS::AddRef(); }
virtual STDMETHODIMP_(ULONG) Release(void) { return SUPERCLASS::Release(); }
// *** CAggregatedUnknown ***
virtual HRESULT v_InternalQueryInterface(REFIID riid, LPVOID * ppvObj);
// *** IServiceProvider ***
virtual STDMETHODIMP QueryService(REFGUID guidService,
REFIID riid, void **ppvObj);
// *** IPersistPropertyBag ***
virtual STDMETHODIMP Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog);
virtual STDMETHODIMP Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
virtual STDMETHODIMP InitNew();
virtual STDMETHODIMP GetClassID(CLSID *pClassID) { return SUPERCLASS::GetClassID(pClassID); };
// *** IOleInPlaceObject ***
virtual STDMETHODIMP SetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect);
protected:
ChannelOC(IUnknown* punkOuter, LPCOBJECTINFO poi);
~ChannelOC();
friend HRESULT ChannelOC_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);
virtual LRESULT v_WndProc(HWND, UINT, WPARAM, LPARAM);
LPITEMIDLIST _GetInitialPidl(void);
virtual void _OnInPlaceActivate(void); // called when we actually go in-place-active
virtual void _OnInPlaceDeactivate(void); // called when we actually deactivate
IDeskBand* _pBand;
IWinEventHandler* _pweh;
COLORREF _crBkgndOC;
COLORREF _crBorder;
// for GetBandInfo, not currently used
DESKBANDINFO _dbi;
};
ChannelOC::ChannelOC(IUnknown* punkOuter, LPCOBJECTINFO poi) :
CShellEmbedding(punkOuter, poi, NULL)
{
TraceMsg(TF_SHDLIFE, "ctor ChannelOC %x", this);
_crBkgndOC = CLR_DEFAULT;
_crBorder = CLR_DEFAULT;
}
ChannelOC::~ChannelOC()
{
TraceMsg(TF_SHDLIFE, "dtor ChannelOC %x", this);
}
HRESULT ChannelOC::v_InternalQueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(THISCLASS, IServiceProvider),
QITABENT(THISCLASS, IPersistPropertyBag),
QITABENT(THISCLASS, IObjectSafety),
{ 0 },
};
HRESULT hres = QISearch(this, qit, riid, ppvObj);
if (FAILED(hres))
hres = SUPERCLASS::v_InternalQueryInterface(riid, ppvObj);
return hres;
}
HRESULT ChannelOC::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
{
return IUnknown_QueryService(_pcli, guidService, riid, ppvObj);
}
//*** ChannelOC::IPersistPropertyBag::* {
//
HRESULT THISCLASS::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
{
ASSERT(_crBkgndOC == CLR_DEFAULT); // paranoia
_crBkgndOC = PropBag_ReadInt4(pPropBag, L"BGColor", CLR_DEFAULT);
TraceMsg(TF_WARNING, "coc.l: BGColor=%x", _crBkgndOC);
_crBorder = PropBag_ReadInt4(pPropBag, L"BorderColor", CLR_DEFAULT);
return S_OK;
}
HRESULT THISCLASS::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
{
ASSERT(0);
return E_NOTIMPL;
}
HRESULT THISCLASS::InitNew()
{
ASSERT(_crBkgndOC == CLR_DEFAULT);
ASSERT(_crBorder == CLR_DEFAULT);
return E_NOTIMPL;
}
// }
LRESULT ChannelOC::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lres = 0;
switch(uMsg)
{
case WM_CONTEXTMENU:
return 1;
case WM_WINDOWPOSCHANGED:
if (_hwndChild)
{
LPWINDOWPOS lpwp = (LPWINDOWPOS)lParam;
if (!(lpwp->flags & SWP_NOSIZE))
{
SetWindowPos(_hwndChild, NULL,
0,0,
lpwp->cx, lpwp->cy,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|
(lpwp->flags&(SWP_NOREDRAW|SWP_NOCOPYBITS)));
}
}
return 0;
case WM_ERASEBKGND:
if ( _crBorder == CLR_DEFAULT )
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
else
{
HDC hdc = (HDC) wParam;
RECT rcClient;
GetClientRect( hwnd, &rcClient );
COLORREF crSave = SetBkColor(hdc, _crBorder);
ExtTextOut(hdc,0,0,ETO_OPAQUE,&rcClient,NULL,0,NULL);
SetBkColor(hdc, crSave);
}
case WM_COMMAND:
case WM_NOTIFY:
if (_pweh)
{
LRESULT lres;
if (SUCCEEDED(_pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, &lres)))
return lres;
}
// fall through
default:
return SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
}
}
LPITEMIDLIST ChannelOC::_GetInitialPidl()
{
LPITEMIDLIST pidl = NULL;
// Figure out what directory this ChannelOC is looking at.
// If we're looking at a specific channel category, use it,
// otherwise use the top-level Channels folder.
//
if (EVAL(_pcli))
{
IOleContainer *pContainer;
if (SUCCEEDED(_pcli->GetContainer(&pContainer)))
{
IHTMLDocument2 *pDoc;
if (SUCCEEDED(pContainer->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&pDoc)))
{
IHTMLLocation *pLocation;
if (SUCCEEDED(pDoc->get_location(&pLocation)))
{
BSTR bstrURL;
if (SUCCEEDED(pLocation->get_href(&bstrURL)) && bstrURL)
{
TCHAR szPath[MAX_PATH];
DWORD cchT = ARRAYSIZE(szPath);
if (SUCCEEDED(PathCreateFromUrl(bstrURL, szPath, &cchT, 0)))
{
PathRemoveFileSpec(szPath);
// if we're not under the channels folder, then
// ignore this location
//
if (SUCCEEDED(IECreateFromPath(szPath, &pidl)))
{
LPITEMIDLIST pidlChannels = Channel_GetFolderPidl();
if (!pidlChannels || !ILIsParent(pidlChannels, pidl, FALSE))
{
ILFree(pidl);
pidl = NULL;
}
ILFree(pidlChannels);
}
TraceMsg(TF_BAND, "ChannelOC::_OnInPlaceActivate [%s] (%x)", szPath, pidl);
}
SysFreeString(bstrURL);
}
pLocation->Release();
}
pDoc->Release();
}
pContainer->Release();
}
}
return pidl;
}
void ChannelOC::_OnInPlaceActivate()
{
SUPERCLASS::_OnInPlaceActivate();
// we should never get called twice, but might as well be safe
//
if (EVAL(!_pBand))
{
LPITEMIDLIST pidl = _GetInitialPidl();
// Now create the band and initialize it properly
//
_pBand = ChannelBand_Create(pidl);
if (_pBand)
{
IDropTarget* pdt;
Channels_SetBandInfoSFB(_pBand);
_pBand->QueryInterface(IID_IWinEventHandler, (LPVOID*)&_pweh);
IUnknown_SetSite(_pBand, SAFECAST(this, IOleObject*));
// now that band is sited and init'ed, we can override defaults
if (_crBkgndOC != CLR_DEFAULT) {
BANDINFOSFB bi;
TraceMsg(TF_WARNING, "coc.oipa: BGColor=%x _pBand=%x", _crBkgndOC, _pBand);
bi.dwMask = ISFB_MASK_BKCOLOR;
bi.crBkgnd = _crBkgndOC;
IUnknown_SetBandInfoSFB(_pBand, &bi);
}
_dbi.dwMask = DBIM_MINSIZE|DBIM_MAXSIZE|DBIM_INTEGRAL|DBIM_ACTUAL|DBIM_TITLE|DBIM_MODEFLAGS|DBIM_BKCOLOR;
_pBand->GetBandInfo(0, DBIF_VIEWMODE_VERTICAL, &_dbi);
_pBand->GetWindow(&_hwndChild);
SetWindowPos(_hwndChild, NULL, 0, 0,
_rcPos.right - _rcPos.left,
_rcPos.bottom - _rcPos.top,
SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_SHOWWINDOW);
_pBand->ShowDW(TRUE);
// Register the band as a drop target
if (SUCCEEDED(_pBand->QueryInterface(IID_IDropTarget, (LPVOID*)&pdt)))
{
THR(RegisterDragDrop(_hwnd, pdt));
pdt->Release();
}
TraceMsg(TF_BAND, "ISFBandOC::_OnInPlaceActivate()d to cx=%d cy=%d", _size.cx, _size.cy);
}
ILFree(pidl);
}
}
void ChannelOC::_OnInPlaceDeactivate()
{
IDeskBand * pBand = _pBand;
// set to NULL to avoid re-entrancy...
_pBand = NULL;
if (pBand)
{
_hwndChild = NULL;
RevokeDragDrop(_hwnd);
pBand->ShowDW(FALSE);
IUnknown_SetSite(pBand, NULL);
pBand->CloseDW(0);
TraceMsg(TF_BAND, "ISFBandOC::_OnInPlaceDeactivate()d");
}
// we need to keep _pweh because we need the notifies during destruction to
// free everything properly
// the _pBand = NULL above is sufficient to keep from reentrancy
ATOMICRELEASE(_pweh);
ATOMICRELEASE(pBand);
SUPERCLASS::_OnInPlaceDeactivate();
}
HRESULT ChannelOC::SetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
{
HRESULT hres = SUPERCLASS::SetObjectRects(lprcPosRect, lprcClipRect);
if (_hwndChild)
{
SetWindowPos(_hwndChild, NULL, 0,0,
_rcPos.right - _rcPos.left,
_rcPos.bottom - _rcPos.top, SWP_NOZORDER);
}
return hres;
}
STDAPI ChannelOC_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
HRESULT hres = E_OUTOFMEMORY;
ChannelOC* pBand = new ChannelOC(punkOuter, poi);
if (pBand)
{
*ppunk = pBand->_GetInner();
hres = S_OK;
}
return hres;
}