|
|
#include "priv.h"
#include <varutil.h>
#ifdef ENABLE_CHANNELS
#include "channel.h"
#include "bands.h"
#include "isfband.h"
#include "itbar.h"
#include "qlink.h"
#define WANT_CBANDSITE_CLASS
#include "bandsite.h"
#include "resource.h"
#include "deskbar.h"
#include "dpastuff.h"
#include "dbapp.h"
#include "chanbar.h"
#include "subsmgr.h"
#include "chanmgr.h"
#include "chanmgrp.h"
#include "mluisupp.h"
void FrameTrack(HDC hdc, LPRECT prc, UINT uFlags);
HRESULT Channel_GetFolder(LPTSTR pszPath, int cchPath) { TCHAR szChannel[MAX_PATH]; TCHAR szFav[MAX_PATH]; ULONG cbChannel = sizeof(szChannel); HRESULT hr = E_FAIL;
if (SHGetSpecialFolderPath(NULL, szFav, CSIDL_FAVORITES, TRUE)) { //
// Get the potentially localized name of the Channel folder from the
// registry if it is there. Otherwise just read it from the resource.
// Then tack this on the favorites path.
//
if (ERROR_SUCCESS != SHRegGetUSValue(L"Software\\Microsoft\\Windows\\CurrentVersion", L"ChannelFolderName", NULL, (void*)szChannel, &cbChannel, TRUE, NULL, 0)) { MLLoadString(IDS_CHANNEL, szChannel, ARRAYSIZE(szChannel)); }
if (PathCombine(pszPath, szFav, szChannel) && PathFileExists(pszPath)) { // Use the channel folder name we just verified
hr = S_OK; } else { //
// For IE5+ use the channels dir if it exists - else use favorites
//
hr = StringCchCopy(pszPath, cchPath, szFav); } } return hr; }
LPITEMIDLIST Channel_GetFolderPidl() { LPITEMIDLIST pidl = NULL; TCHAR szPath[MAX_PATH]; if (SUCCEEDED(Channel_GetFolder(szPath, ARRAYSIZE(szPath)))) { pidl = ILCreateFromPath(szPath); if (!pidl && CreateDirectory(szPath, NULL)) { pidl = ILCreateFromPath(szPath); } } return pidl; }
HRESULT ChannelBand_CreateInstance(IUnknown** ppunk) { *ppunk = NULL; HRESULT hr = E_OUTOFMEMORY; LPITEMIDLIST pidl = Channel_GetFolderPidl(); if (pidl) { IFolderBandPriv *pfbp; hr = CISFBand_CreateEx(NULL, pidl, IID_PPV_ARG(IFolderBandPriv, &pfbp)); if (SUCCEEDED(hr)) { hr = pfbp->SetCascade(TRUE); if (SUCCEEDED(hr)) { hr = pfbp->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); } pfbp->Release(); } ILFree(pidl); }
return hr; }
//
// Navigates the left browser pane to the channels directory.
//
void NavigateBrowserBarToChannels(IWebBrowser2* pwb) { ASSERT(pwb);
IChannelMgrPriv* pIChannelMgrPriv;
if (SUCCEEDED(CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER, IID_IChannelMgrPriv, (void**)&pIChannelMgrPriv))) { ASSERT(pIChannelMgrPriv);
LPITEMIDLIST pidl;
if (SUCCEEDED(pIChannelMgrPriv->GetChannelFolder(&pidl, IChannelMgrPriv::CF_CHANNEL))) { ASSERT(pidl);
VARIANT varPath;
if (SUCCEEDED(InitVariantFromIDList(&varPath, pidl))) { VARIANT varFlags;
varFlags.vt = VT_I4; varFlags.lVal = navBrowserBar;
pwb->Navigate2(&varPath, &varFlags, PVAREMPTY, PVAREMPTY, PVAREMPTY);
VariantClear(&varPath); }
ILFree(pidl); }
pIChannelMgrPriv->Release(); }
return; }
STDAPI NavigateToPIDL(IWebBrowser2* pwb, LPCITEMIDLIST pidl) { ASSERT(pwb); ASSERT(pidl);
VARIANT varThePidl; HRESULT hr = InitVariantFromIDList(&varThePidl, pidl); if (SUCCEEDED(hr)) { hr = pwb->Navigate2(&varThePidl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY); VariantClear(&varThePidl); // Needed to free the copy of the PIDL in varThePidl.
} return hr; }
//
// Implements the IE4 channel quick launch shell control file functionality.
// This gets called from shdoc401 on pre-NT5 platforms and from shell32 on
// Nt5 or greater.
//
HRESULT Channel_QuickLaunch(void) { IWebBrowser2* pIWebBrowser2;
HRESULT hr = Channels_OpenBrowser(&pIWebBrowser2, FALSE); if (SUCCEEDED(hr)) { ASSERT(pIWebBrowser2);
NavigateBrowserBarToChannels(pIWebBrowser2);
LPITEMIDLIST pidl; TCHAR szURL[MAX_URL_STRING] = TEXT("");
GetFirstUrl(szURL, SIZEOF(szURL));
if (szURL[0]) { hr = IECreateFromPath(szURL, &pidl);
if (SUCCEEDED(hr)) { ASSERT(pidl);
hr = NavigateToPIDL(pIWebBrowser2, pidl);
ILFree(pidl); } } else { hr = E_FAIL; }
pIWebBrowser2->Release(); }
return hr; }
/////////////////////////////////////
////// Browser only channel band support
// the CProxyWin95Desktop class implements an OleWindow
// to represent the win95 desktop
// the browseronly channel band will use this as its host
class CProxyWin95Desktop : public IOleWindow { public: // *** IUnknown ***
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); virtual STDMETHODIMP_(ULONG) AddRef(void); virtual STDMETHODIMP_(ULONG) Release(void);
// *** IOleWindow methods ***
virtual STDMETHODIMP GetWindow(HWND * lphwnd); virtual STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
CProxyWin95Desktop(HWND hwnd); protected: UINT _cRef; HWND _hwnd; };
CProxyWin95Desktop::CProxyWin95Desktop(HWND hwnd) : _cRef(1), _hwnd(hwnd) { }
ULONG CProxyWin95Desktop::AddRef() { _cRef++; return _cRef; }
ULONG CProxyWin95Desktop::Release() { ASSERT(_cRef > 0); _cRef--;
if (_cRef > 0) return _cRef;
delete this; return 0; }
HRESULT CProxyWin95Desktop::QueryInterface(REFIID riid, LPVOID * ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IOleWindow) || IsEqualIID(riid, SID_SShellDesktop) // private hack for deskbar.cpp
) { *ppvObj = SAFECAST(this, IOleWindow*); } else { *ppvObj = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; }
HRESULT CProxyWin95Desktop::GetWindow(HWND * lphwnd) { *lphwnd = _hwnd; if (_hwnd) return S_OK; return E_FAIL; }
void Channels_InitState(IUnknown* punkBar) { // initialize properties
CDeskBarPropertyBag* ppb = new CDeskBarPropertyBag(); if (ppb) { // Get the default rc
CISSTRUCT cis; DWORD cbSize = sizeof(CISSTRUCT); RECT *prc = &cis.rc;
cis.iVer = 1; // set version number to 1
SystemParametersInfoA(SPI_GETWORKAREA, 0, prc, 0); prc->bottom = min(prc->bottom - 20, prc->top + 12*38 + 28); // 12 icons + caption
if(IS_BIDI_LOCALIZED_SYSTEM()) { prc->right = prc->left + 90; OffsetRect(prc, 20, 10); } else { prc->left = prc->right - 90; OffsetRect(prc, -20, 10); }
// query registry for persisted state
SHRegGetUSValue(SZ_REGKEY_CHANBAR, SZ_REGVALUE_CHANBAR, NULL, (LPVOID)&cis, &cbSize, FALSE, (LPVOID)&cis, cbSize);
// set ppb by prc
ppb->SetDataDWORD(PROPDATA_MODE, WBM_FLOATING | WBMF_BROWSER); ppb->SetDataDWORD(PROPDATA_X, prc->left); ppb->SetDataDWORD(PROPDATA_Y, prc->top); ppb->SetDataDWORD(PROPDATA_CX, RECTWIDTH(*prc)); ppb->SetDataDWORD(PROPDATA_CY, RECTHEIGHT(*prc)); SHLoadFromPropertyBag(punkBar, ppb); ppb->Release(); } }
void Channels_MainLoop(IDockingWindow *pdw) { MSG msg; HWND hwnd; // loop while the window exists
do { GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg); DispatchMessage(&msg); pdw->GetWindow(&hwnd); } while (hwnd); }
void Channels_SetBandInfoSFB(IUnknown* punkBand) { BANDINFOSFB bi;
// Set band startup conditions
bi.dwMask = ISFB_MASK_STATE | ISFB_MASK_VIEWMODE; bi.dwStateMask = ISFB_STATE_CHANNELBAR | ISFB_STATE_NOSHOWTEXT; bi.dwState = ISFB_STATE_CHANNELBAR | ISFB_STATE_NOSHOWTEXT; bi.wViewMode = ISFBVIEWMODE_LOGOS;
IUnknown_SetBandInfoSFB(punkBand, &bi); }
// from isfband.cpp
extern IDeskBand * ChannelBand_Create( LPCITEMIDLIST pidl );
// this does the desktop channel in browser only mode
void DesktopChannel() { _InitComCtl32();
// Don't show channel bar:
// *. in integrated mode with active desktop turned on, or
// *. NoChannelUI restriction is set, or
// *. there is already one on desktop
if (SHRestricted2(REST_NoChannelUI, NULL, 0)) return; if (WhichPlatform() == PLATFORM_INTEGRATED) { SHELLSTATE ss = { 0 };
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE); // Get the setting
if (ss.fDesktopHTML) { return; } } if (FindWindowEx(GetShellWindow(), NULL, TEXT("BaseBar"), TEXT("ChanApp")) || FindWindowEx(NULL, NULL, TEXT("BaseBar"), TEXT("ChanApp"))) // can be a toplevel window
return;
LPITEMIDLIST pidl = Channel_GetFolderPidl(); if (pidl) { IUnknown* punk = (IUnknown *) ChannelBand_Create( pidl ); if (punk) {
Channels_SetBandInfoSFB(punk);
IUnknown* punkBar; IUnknown* punkBandSite;
HRESULT hres = ChannelDeskBarApp_Create(&punkBar, &punkBandSite); if (SUCCEEDED(hres)) { CProxyWin95Desktop* pow = new CProxyWin95Desktop(GetShellWindow()); if (pow) { IBandSite* pbs; IDockingWindow* pdw;
Channels_InitState(punkBar);
// these are always our own guys, so these QI's MUST succeed if the creation succeeded
punkBandSite->QueryInterface(IID_IBandSite, (LPVOID*)&pbs); punkBar->QueryInterface(IID_IDockingWindow, (LPVOID*)&pdw); ASSERT(pbs && pdw);
hres = pbs->AddBand(punk); IUnknown_SetSite(pdw, (IOleWindow*)pow);
pbs->SetBandState((DWORD)-1, BSSF_NOTITLE, BSSF_NOTITLE);
pdw->ShowDW(TRUE);
Channels_MainLoop(pdw);
pdw->Release(); pbs->Release(); pow->Release(); } punkBar->Release(); punkBandSite->Release(); }
punk->Release(); } ILFree(pidl); } }
HRESULT Channels_OpenBrowser(IWebBrowser2 **ppwb, BOOL fInPlace) { HRESULT hres; IWebBrowser2* pwb;
if (fInPlace) { ASSERT(ppwb && *ppwb != NULL); pwb = *ppwb; hres = S_OK; } else { hres = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IWebBrowser2, &pwb)); } if (SUCCEEDED(hres)) { SA_BSTRGUID strGuid; VARIANT vaGuid;
// Don't special case full-screen mode for channels post IE4. Use the
// browser's full screen setting.
//
//BOOL fTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Channels"),
BOOL fTheater = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("FullScreen"), FALSE, FALSE); pwb->put_TheaterMode( fTheater ? VARIANT_TRUE : VARIANT_FALSE); pwb->put_Visible(VARIANT_TRUE);
if (!SHRestricted2(REST_NoChannelUI, NULL, 0)) { #ifdef ENABLE_CHANNELPANE
StringFromGUID2(CLSID_ChannelBand, strGuid.wsz, ARRAYSIZE(strGuid.wsz)); #else
StringFromGUID2(CLSID_FavBand, strGuid.wsz, ARRAYSIZE(strGuid.wsz)); #endif
strGuid.cb = lstrlenW(strGuid.wsz) * SIZEOF(WCHAR);
vaGuid.vt = VT_BSTR; vaGuid.bstrVal = strGuid.wsz;
pwb->ShowBrowserBar(&vaGuid, PVAREMPTY, PVAREMPTY); } // don't release, we're going to return pwb.
} if (ppwb) *ppwb = pwb; else if (pwb) pwb->Release(); return hres; }
BOOL GetFirstUrl(TCHAR szURL[], DWORD cb) { //BOOL fFirst = FALSE;
DWORD dwType;
// Don't special case first channel click post IE4.
/*if (SHRegGetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("ChannelsFirstURL"),
&dwType, szURL, &cb, FALSE, NULL, 0) == ERROR_SUCCESS) { HUSKEY hUSKey; if (SHRegOpenUSKey(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), KEY_WRITE, NULL, &hUSKey, FALSE) == ERROR_SUCCESS) { SHRegDeleteUSValue(hUSKey, TEXT("ChannelsFirstURL"), SHREGDEL_HKCU); SHRegCloseUSKey(hUSKey); } fFirst = TRUE; } else if (SHRegGetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("ChannelsURL"), &dwType, szURL, &cb, FALSE, NULL, 0) == ERROR_SUCCESS) { // nothing
} else { // BUGBUG if code is ever revived, this res:// needs to be
// accessed through MLBuildResURLWrap because of pluggable UI
szURL = lstrcpy(szURL, TEXT("res://ie4tour.dll/channels.htm")); }*/
SHRegGetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("ChannelsURL"), &dwType, szURL, &cb, FALSE, NULL, 0); return FALSE; }
//////////////////////////////////////////////////
//
// ChannelBand
//
// This is a special band that only looks at the channels folder.
// It overrides several functions from CISFBand.
//
#undef SUPERCLASS
#define SUPERCLASS CISFBand
class ChannelBand : public SUPERCLASS { public: virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); virtual STDMETHODIMP OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); virtual HRESULT OnDropDDT (IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect);
protected: ChannelBand(); friend IDeskBand * ChannelBand_Create(LPCITEMIDLIST pidl);
virtual HRESULT _LoadOrderStream();
virtual HWND _CreatePager(HWND hwndParent);
virtual LRESULT _OnCustomDraw(NMCUSTOMDRAW* pnmcd);
virtual void _Dropped(int nIndex, BOOL fDroppedOnSource); virtual HRESULT _AfterLoad(); virtual void _OnDragBegin(int iItem, DWORD dwPreferedEffect); } ;
#define COLORBK RGB(0,0,0)
ChannelBand::ChannelBand() : SUPERCLASS() { _lEvents |= SHCNE_EXTENDED_EVENT; _dwStyle |= TBSTYLE_CUSTOMERASE;
_crBkgnd = COLORBK; // i see a channelband and i want to paint it black
_fHaveBkColor = TRUE; }
HWND ChannelBand::_CreatePager(HWND hwndParent) { // we do want a pager for this band, so
// override isfband's implementation w/ grandpa's
return CSFToolbar::_CreatePager(hwndParent); }
HRESULT ChannelBand::QueryInterface(REFIID riid, void **ppvObj) { *ppvObj = NULL; if (IsEqualIID(riid, IID_IContextMenu)) return E_NOINTERFACE; return SUPERCLASS::QueryInterface(riid, ppvObj); }
IDeskBand * ChannelBand_Create(LPCITEMIDLIST pidlDefault) { ChannelBand * pBand = NULL; LPITEMIDLIST pidl = NULL;
if (!pidlDefault) { pidl = Channel_GetFolderPidl(); pidlDefault = pidl; } if (EVAL(pidlDefault)) { pBand = new ChannelBand;
if (pBand) { if (FAILED(pBand->InitializeSFB(NULL, pidlDefault))) { ATOMICRELEASE(pBand); } }
ILFree(pidl); }
return pBand; }
HRESULT ChannelBand::_AfterLoad() { HRESULT hres = SUPERCLASS::_AfterLoad();
_LoadOrderStream();
return hres; }
HRESULT ChannelBand::_LoadOrderStream() { OrderList_Destroy(&_hdpaOrder);
COrderList_GetOrderList(&_hdpaOrder, _pidl, _psf); return S_OK; }
HRESULT ChannelBand::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { HRESULT hres = E_FAIL;
switch (lEvent) { case SHCNE_EXTENDED_EVENT: { SHChangeMenuAsIDList UNALIGNED * pdwidl = (SHChangeMenuAsIDList UNALIGNED *)pidl1; if ( pdwidl->dwItem1 == SHCNEE_ORDERCHANGED ) { if (SHChangeMenuWasSentByMe(this, pidl1)) { // We sent this order change, ignore it
TraceMsg(TF_BAND, "ChannelBand::OnChange SHCNEE_ORDERCHANGED skipped (we're source)"); hres = S_OK; } else if (EVAL(pidl2) && _pidl) { if (ILIsEqual(_pidl, pidl2)) { TraceMsg(TF_BAND, "ChannelBand::OnChange SHCNEE_ORDERCHANGED accepted");
_LoadOrderStream();
if (_fShow) _FillToolbar();
hres = S_OK; } } break; } // if it wasn't SHCNEE_ORDERCHANGED, then drop through to pass to the base class..
}
default: hres = SUPERCLASS::OnChange(lEvent, pidl1, pidl2); break; }
return hres; }
HRESULT ChannelBand::OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect) { if (_iDragSource >= 0) { return SUPERCLASS::OnDropDDT(pdt, pdtobj, pgrfKeyState, pt, pdwEffect); } else { // we don't call superclass in this case 'cuz we want to undo
// it's "always use shortcut" override.
//
_fDropping = TRUE; return S_OK; } }
LRESULT ChannelBand::_OnCustomDraw(NMCUSTOMDRAW* pnmcd) { NMTBCUSTOMDRAW * ptbcd = (NMTBCUSTOMDRAW *)pnmcd; LRESULT lres;
lres = SUPERCLASS::_OnCustomDraw(pnmcd); switch (pnmcd->dwDrawStage) { case CDDS_PREPAINT: lres |= CDRF_NOTIFYITEMDRAW; break;
case CDDS_PREERASE: // Channel band has a darker background color
{ RECT rc; GetClientRect(_hwndTB, &rc); // BUGBUG perf: use SHFillRectClr not SetBk/ExtText/SetBk
COLORREF old = SetBkColor(pnmcd->hdc, _crBkgnd); ExtTextOut(pnmcd->hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL); SetBkColor(pnmcd->hdc, old); lres = CDRF_SKIPDEFAULT; } break;
case CDDS_ITEMPREPAINT: // Channel band doesn't draw as buttons
lres |= TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | CDRF_NOTIFYPOSTPAINT; break;
case CDDS_ITEMPOSTPAINT: // Channel band draws the hot item (CDIS_HOT)
//
pnmcd->rc.top++; pnmcd->rc.left++; if (pnmcd->uItemState & CDIS_SELECTED) // Mark the selected item
FrameTrack(pnmcd->hdc, &(pnmcd->rc), TRACKNOCHILD); else if (pnmcd->uItemState & CDIS_HOT) // Mark the hot item
FrameTrack(pnmcd->hdc, &(pnmcd->rc), TRACKHOT); break;
} return lres; }
void ChannelBand::_Dropped(int nIndex, BOOL fDroppedOnSource) { ASSERT(_fDropping);
// I'm not changing this to match the other derivatives (ISFBand, mnfolder, quick links),
// because this structure is slightly different
_fDropped = TRUE;
// Persist the new order out to the registry
if (SUCCEEDED(COrderList_SetOrderList(_hdpa, _pidl, _psf))) { // Notify everyone that the order changed
SHSendChangeMenuNotify(this, SHCNEE_ORDERCHANGED, 0, _pidl); } }
void ChannelBand::_OnDragBegin(int iItem, DWORD dwPreferedEffect) { //
// Don't allow drag if REST_NoRemovingChannels is enabled.
//
if (!SHRestricted2(REST_NoRemovingChannels, NULL, 0)) SUPERCLASS::_OnDragBegin(iItem, dwPreferedEffect);
return; }
#endif // ENABLE_CHANNELS
|