|
|
#include "priv.h"
#include "basesb.h"
#define DISPID_ONTRANSITIONFINISH 1
const GUID DIID_ICSSTransitionEvents = {0x8E64AA50L,0xDC42,0x11D0,0x99,0x49,0x00,0xA0,0xC9,0x0A,0x8F,0xF2};
//
// Notes:
// - CTransitionSite object is always contained in a CBaseBrowser object,
// therefore, it does not have its own reference count.
// - The macro CONTAINERMAP maps the pointer to this object up to the
// containing object.
// - CTransitionSite is a friend class of CBaseBrowser class.
//
// Notes:
// - Having anything be a friend of CBaseBrowser is not good.
// - This object is completely contained by it's parent object,
// so to avoid a reference loop we keep our pContainer pointer
// with no reference. Do not QI off it or we will leak!
//
#define TF_TRSITE 0
#define TF_TRDRAW TF_ALWAYS
#define TF_TREXTDRAW 0
#define TF_TRLIFE 0
#define TF_ADDREFRELEASE 0
#define TF_TRSPB 0
#define TF_DEBUGQI 0
/////////////////////////////////////////////////////////////////////////////
// Design constants
/////////////////////////////////////////////////////////////////////////////
#define MIN_TRANSITION_DURATION 0.0
#define MAX_TRANSITION_DURATION 100.0
#define MIN_ONVIEWCHANGE_DURATION 1500 // ms
#define TSPB_CREATE_INCR 4
// CTransitionSitePropertyBag property list create size
/////////////////////////////////////////////////////////////////////////////
// Module variables
/////////////////////////////////////////////////////////////////////////////
static const TCHAR c_szTransitionsKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CSSFilters"); static const OLECHAR c_szDurationProp[] = OLESTR("Duration"); static OLECHAR * s_szApplyMethod = OLESTR("Apply"); static OLECHAR * s_szPlayMethod = OLESTR("Play"); static OLECHAR * s_szStopMethod = OLESTR("Stop");
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite
/////////////////////////////////////////////////////////////////////////////
#undef THISCLASS
CTransitionSite::CTransitionSite ( IShellBrowser * pcont ) : _pContainer(pcont) // DO NOT ADDREF
{ TraceMsg(TF_TRLIFE, "TRS::ctor called");
ASSERT(pcont != NULL);
_uState = TRSTATE_NONE; _ptiCurrent = NULL; }
CTransitionSite::~CTransitionSite ( ) { TraceMsg(TF_TRLIFE, "TRS::dtor called");
#ifdef DEBUG
ASSERT(_pSite == NULL); ASSERT(_psvNew == NULL); ASSERT(_pvoNew == NULL); ASSERT(_hwndViewNew == NULL); ASSERT(_pTransition == NULL); ASSERT(_pDispTransition == NULL); ASSERT(_dwTransitionSink == NULL); #endif // DEBUG
for (int te = teFirstEvent; te < teNumEvents; te++) SAFERELEASE(_tiEventInfo[te].pPropBag); }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_ApplyTransition
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_ApplyTransition ( BOOL bSiteChanging ) { HRESULT hrResult = S_OK;
TraceMsg(TF_TRSITE, "TRS::_ApplyTransition(%d) called", bSiteChanging);
if (_ptiCurrent != NULL) _OnComplete();
ASSERT(_ptiCurrent == NULL);
if (bSiteChanging && (_tiEventInfo[teSiteEnter].clsid != CLSID_NULL)) _ptiCurrent = &_tiEventInfo[teSiteEnter]; else if (_tiEventInfo[tePageEnter].clsid != CLSID_NULL) _ptiCurrent = &_tiEventInfo[tePageEnter]; else _ptiCurrent = NULL;
// Allow the contatiner a chance to set a transition if we don't have one.
if (_ptiCurrent == NULL) { // vaIn.vt = VT_BOOL; vaIn.boolVal = Site is changing;
VARIANTARG vaIn = { VT_BOOL, bSiteChanging };
// vaOut[0].vt = VT_I4; vaOut[0].lVal = TransitionEvent
// vaOut[1].vt = VT_BSTR; vaOut[1].bstrVal = Transition String.
VARIANTARG vaOut[2] = { 0 };
if (SUCCEEDED(hrResult = IUnknown_Exec(_pContainer, &CGID_ShellDocView, SHDVID_GETTRANSITION, OLECMDEXECOPT_DODEFAULT, &vaIn, vaOut))) { TRANSITIONINFO ti = { 0 };
if ( (vaOut[0].vt == VT_I4) && ((vaOut[0].lVal >= teFirstEvent) && (vaOut[0].lVal < teNumEvents)) && (vaOut[1].vt == VT_BSTR) && (vaOut[1].bstrVal != NULL) && ParseTransitionInfo((LPWSTR)vaOut[1].bstrVal, &ti) ) { hrResult = _SetTransitionInfo((TransitionEvent)vaOut[0].lVal, &ti); _ptiCurrent = &_tiEventInfo[vaOut[0].lVal]; } else hrResult = E_UNEXPECTED;
SAFERELEASE(ti.pPropBag); }
TraceMsg(TF_TRSITE, "hrResult = 0x%.8X after _pContainer->Exec()", hrResult);
VariantClear(&vaOut[0]); VariantClear(&vaOut[1]); }
if (SUCCEEDED(hrResult)) { if (SUCCEEDED(hrResult = _LoadTransition())) { ASSERT(_hwndViewNew != NULL);
// We need to hide the view window to draw on our own DC.
_fViewIsVisible = ::IsWindowVisible(_hwndViewNew); if (_fViewIsVisible) ::ShowWindow(_hwndViewNew, SW_HIDE);
_pContainer->EnableModelessSB(FALSE); } } else { // Make sure we don't fiddle with the window visibility
// in _OnComplete if we didn't succeed.
_hwndViewNew = NULL;
_OnComplete(); }
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_LoadTransition
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_LoadTransition ( ) { HRESULT hrResult;
TraceMsg(TF_TRSITE, "TRS::_LoadTransition called");
if ((_ptiCurrent == NULL) || (_ptiCurrent->clsid == CLSID_NULL)) return E_INVALIDARG;
// Create the transition.
for (;;) { ASSERT(_pTransition == NULL); if (FAILED(hrResult = CoCreateInstance( _ptiCurrent->clsid, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLViewFilter, (void **)&_pTransition))) { TraceMsg(TF_ERROR, "TRS::_LoadTransition CoCreateInstance failed 0x%X", hrResult); break; }
ASSERT(_pDispTransition == NULL); if (FAILED(hrResult = _pTransition->QueryInterface( IID_IDispatch, (void **)&_pDispTransition))) { TraceMsg(TF_ERROR, "TRS::_LoadTransition QI::IDispatch failed 0x%X", hrResult); break; }
ASSERT(_dwTransitionSink == 0); if (FAILED(hrResult = ConnectToConnectionPoint( SAFECAST(this, IDispatch *), DIID_ICSSTransitionEvents, TRUE, _pTransition, &_dwTransitionSink, NULL))) { TraceMsg(TF_ERROR, "TRS::_LoadTransition ConnectToConnectionPoint failed 0x%X", hrResult); break; }
// Supply the property bag to the transition (if needed)
IPersistPropertyBag * pPersistPropBag; if ( (_ptiCurrent->pPropBag != NULL) && SUCCEEDED(_pTransition->QueryInterface(IID_IPersistPropertyBag, (void **)&pPersistPropBag)) ) { EVAL(SUCCEEDED(pPersistPropBag->InitNew())); EVAL(SUCCEEDED(pPersistPropBag->Load(SAFECAST(_ptiCurrent->pPropBag, IPropertyBag *), NULL))); ATOMICRELEASE(pPersistPropBag); }
if (FAILED(hrResult = _pTransition->SetSite(SAFECAST(this, IHTMLViewFilterSite *)))) { TraceMsg(TF_ERROR, "TRS::_LoadTransition _pT->SetSite failed 0x%X", hrResult); break; }
if (FAILED(hrResult = _pTransition->SetSource(SAFECAST(this, IHTMLViewFilter *)))) { TraceMsg(TF_ERROR, "TRS::_LoadTransition _pT->SetSource failed 0x%X", hrResult); break; }
if (FAILED(hrResult = _InitWait())) { TraceMsg(TF_ERROR, "TRS::_LoadTransition _InitWait failed 0x%X", hrResult); break; }
hrResult = S_OK; break; }
if (FAILED(hrResult)) _OnComplete();
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_SetTransitionInfo
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_SetTransitionInfo ( TransitionEvent te, TRANSITIONINFO * pti ) { TraceMsg(TF_TRSITE, "TRS::_SetTransitionInfo(%d)", te); ASSERT((te >= teFirstEvent) && (te < teNumEvents));
SAFERELEASE(_tiEventInfo[te].pPropBag);
_tiEventInfo[te] = *pti;
if (_tiEventInfo[te].pPropBag != NULL) _tiEventInfo[te].pPropBag->AddRef();
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_InitWait
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_InitWait() { HRESULT hrResult;
TraceMsg(TF_TRSITE, "TRS::_InitWait called");
ASSERT(_pTransition != NULL); ASSERT(_pDispTransition != NULL); ASSERT(_uState == TRSTATE_NONE);
for (;;) { RECT rc; IBrowserService2 *pbs2; if (SUCCEEDED(_pContainer->QueryInterface(IID_IBrowserService2, (void **)&pbs2))) { pbs2->GetViewRect(&rc); pbs2->Release(); }
EVAL(SUCCEEDED(hrResult = _pTransition->SetPosition(&rc))); TraceMsg(TF_TRSITE, "TRS::_InitWait called _pTransition->SetPosition 0x%X", hrResult);
DISPID dispid; if (FAILED(hrResult = _pDispTransition->GetIDsOfNames( IID_NULL, &s_szApplyMethod, 1, LOCALE_USER_DEFAULT, &dispid))) { TraceMsg(TF_ERROR, "TRS::_InitWait _pDispTransition->GetIDsOfNames(Apply) failed 0x%X", hrResult); break; }
unsigned int uArgError = (unsigned int)-1; DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 }; if (FAILED(hrResult = _pDispTransition->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, NULL, NULL, &uArgError))) { TraceMsg(TF_ERROR, "TRS::_InitWait _pDispTransition->Invoke(Apply) failed 0x%X", hrResult); break; }
break; }
if (SUCCEEDED(hrResult)) _uState = TRSTATE_INITIALIZING;
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_StartTransition
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_StartTransition ( ) { HRESULT hrResult; TraceMsg(TF_TRSITE, "TRS::_StartTransition");
ASSERT(_uState == TRSTATE_INITIALIZING);
for (;;) { if (_pDispTransition == NULL) { hrResult = E_UNEXPECTED; break; }
if ( FAILED(hrResult = _psvNew->QueryInterface(IID_IViewObject, (void **)&_pvoNew)) || FAILED(hrResult = _pvoNew->SetAdvise( DVASPECT_CONTENT, 0, SAFECAST(this, IAdviseSink *))) ) { TraceMsg(TF_ERROR, "TRS::_StartTransition QI for IViewObject failed 0x%X", hrResult); break; }
_uState = TRSTATE_STARTPAINTING;
DISPID dispid; if (FAILED(hrResult = _pDispTransition->GetIDsOfNames( IID_NULL, &s_szPlayMethod, 1, LOCALE_USER_DEFAULT, &dispid))) { TraceMsg(TF_ERROR, "TRS::_StartTransition _pDispTransition->GetIDsOfNames(Play) failed 0x%X", hrResult); break; }
unsigned int uArgError = (unsigned int)-1; DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 }; if (FAILED(hrResult = _pDispTransition->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, NULL, NULL, &uArgError))) { TraceMsg(TF_ERROR, "TRS::_StartTransition _pDispTransition->Invoke(Play) failed 0x%X", hrResult); break; }
_uState = TRSTATE_PAINTING; break; }
if (FAILED(hrResult)) _OnComplete();
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_StopTransition
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_StopTransition ( ) { HRESULT hrResult;
for (;;) { if (_pDispTransition == NULL) { hrResult = E_UNEXPECTED; break; }
DISPID dispid; if (FAILED(hrResult = _pDispTransition->GetIDsOfNames( IID_NULL, &s_szStopMethod, 1, LOCALE_USER_DEFAULT, &dispid))) { TraceMsg(TF_ERROR, "TRS::_StopTransition _pDispTransition->GetIDsOfNames(Stop) failed 0x%X", hrResult); break; }
unsigned int uArgError = (unsigned int)-1; DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 }; if (FAILED(hrResult = _pDispTransition->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, NULL, NULL, &uArgError))) { TraceMsg(TF_ERROR, "TRS::_StopTransition _pDispTransition->Invoke(Stop) failed 0x%X", hrResult); break; }
break; }
_OnComplete();
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_UpdateEventList
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_UpdateEventList ( ) { SAFERELEASE(_tiEventInfo[teSiteEnter].pPropBag); _tiEventInfo[teSiteEnter] = _tiEventInfo[teSiteExit]; _tiEventInfo[teSiteExit].clsid = CLSID_NULL; _tiEventInfo[teSiteExit].pPropBag = NULL;
SAFERELEASE(_tiEventInfo[tePageEnter].pPropBag); _tiEventInfo[tePageEnter] = _tiEventInfo[tePageExit]; _tiEventInfo[tePageExit].clsid = CLSID_NULL; _tiEventInfo[tePageExit].pPropBag = NULL;
_uState = TRSTATE_NONE; _ptiCurrent = NULL;
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::_OnComplete
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::_OnComplete ( ) { TraceMsg(TF_TRSITE, "TRS::_OnComplete() called");
if (_dwTransitionSink != 0) { EVAL(SUCCEEDED(ConnectToConnectionPoint(SAFECAST(this, IDispatch *), DIID_ICSSTransitionEvents, FALSE, _pTransition, &_dwTransitionSink, NULL))); _dwTransitionSink = 0; } if (_pvoNew != NULL) { _pvoNew->SetAdvise(DVASPECT_CONTENT, 0, 0); ATOMICRELEASE(_pvoNew); }
ATOMICRELEASE(_pDispTransition);
if (_pTransition != NULL) { _pTransition->SetSource(NULL); _pTransition->SetSite(NULL);
ASSERT(_pSite == NULL);
ATOMICRELEASE(_pTransition); }
if (_hwndViewNew != NULL) { if (_fViewIsVisible) ::ShowWindow(_hwndViewNew, SW_SHOW);
_pContainer->EnableModelessSB(TRUE); }
ATOMICRELEASE(_psvNew); _hwndViewNew = NULL;
return _UpdateEventList(); }
/////////////////////////////////////////////////////////////////////////////
// IUnknown interface
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::QueryInterface(REFIID riid, void **ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IHTMLViewFilter)) { *ppvObj = SAFECAST(this, IHTMLViewFilter *); } else if (IsEqualIID(riid, IID_IHTMLViewFilterSite)) { *ppvObj = SAFECAST(this, IHTMLViewFilterSite *); } else if (IsEqualIID(riid, DIID_ICSSTransitionEvents) || IsEqualIID(riid, IID_IDispatch)) { *ppvObj = SAFECAST(this, IDispatch *); } else if (IsEqualIID(riid, IID_IServiceProvider)) { return _pContainer->QueryInterface(IID_IServiceProvider, ppvObj); } else { *ppvObj = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; }
ULONG CTransitionSite::AddRef() { TraceMsg(TF_ADDREFRELEASE, "TRS::AddRef()"); return _pContainer->AddRef(); }
ULONG CTransitionSite::Release() { TraceMsg(TF_ADDREFRELEASE, "TRS::Release()"); return _pContainer->Release(); }
/////////////////////////////////////////////////////////////////////////////
// IHTMLViewFilter interface
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::SetSource(IHTMLViewFilter * pFilter) { ASSERT(0); return E_FAIL; }
HRESULT CTransitionSite::GetSource ( IHTMLViewFilter ** ppFilter ) { ASSERT(0); return E_FAIL; }
HRESULT CTransitionSite::SetSite ( IHTMLViewFilterSite * pFilterSite ) { TraceMsg(TF_TRSITE, "TRS::SetSite called with %x", pFilterSite);
ATOMICRELEASE(_pSite);
_pSite = pFilterSite; if (pFilterSite != NULL) pFilterSite->AddRef();
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::GetSite
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::GetSite ( IHTMLViewFilterSite ** ppFilterSite ) { TraceMsg(TF_TRSITE, "TRS::GetSite called _pSite=%x", _pSite); *ppFilterSite = _pSite;
if (_pSite != NULL) { _pSite->AddRef(); return S_OK; }
return S_FALSE; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::SetPosition
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::SetPosition ( LPCRECT prc ) { return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::Draw
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::Draw ( HDC hDC, LPCRECT prc ) { HRESULT hrResult; HWND hwndView = NULL; // init to suppress bogus C4701 warning
TraceMsg(TF_TREXTDRAW, "TRS::Draw called with hdc=%x (%d,%d)-(%d,%d)", hDC, prc->left, prc->top, prc->right, prc->bottom);
if ((_uState == TRSTATE_STARTPAINTING) || (_uState == TRSTATE_PAINTING)) { ASSERT(_pvoNew != NULL);
RECTL rcl = { prc->left, prc->top, prc->right, prc->bottom };
if (FAILED(hrResult = _pvoNew->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, hDC, &rcl, NULL, NULL, 0))) { TraceMsg(TF_ERROR, "TRS::Draw IVO::Draw failed 0x%X", hrResult); hwndView = _hwndViewNew; } } else { IShellView * psv; hrResult = _pContainer->QueryActiveShellView(&psv); if (SUCCEEDED(hrResult)) { hrResult = OleDraw(psv, DVASPECT_CONTENT, hDC, prc); psv->Release(); } if (FAILED(hrResult)) { IBrowserService2 *pbs; TraceMsg(TF_WARNING, "TRS:Draw OleDraw failed 0x%X", hrResult); if (SUCCEEDED(_pContainer->QueryInterface(IID_IBrowserService2, (void **)&pbs))) { pbs->GetViewWindow(&hwndView); pbs->Release(); } } }
// As a last resort, if IViewObject::Draw fails, try WM_PRINT
if (FAILED(hrResult)) { ASSERT((hwndView != NULL) && IsWindow(hwndView));
// DrawEdge(..., EDGE_SUNKEN, BF_ADJUST|BF_RECT|BF_SOFT);
::SendMessage(hwndView, WM_PRINT, (WPARAM)hDC, PRF_NONCLIENT | PRF_CLIENT | PRF_CHILDREN | PRF_ERASEBKGND); hrResult = S_OK; }
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::GetStatusBits
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::GetStatusBits ( DWORD * pdwFlags ) { *pdwFlags = FILTER_STATUS_OPAQUE; return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// IHTMLViewFilterSite interface
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::GetDC
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::GetDC ( LPCRECT prc, DWORD dwFlags, HDC * phDC ) { HWND hwnd; _pContainer->GetWindow(&hwnd); *phDC = ::GetDC(hwnd); TraceMsg(TF_TRSITE, "TRS::GetDC returning *phDC=%x", *phDC);
return ((*phDC != NULL) ? S_OK : E_FAIL); }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::ReleaseDC
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::ReleaseDC ( HDC hDC ) { TraceMsg(TF_TRSITE, "TRS::ReleaseDC called with %x", hDC); HWND hwnd; _pContainer->GetWindow(&hwnd); ::ReleaseDC(hwnd, hDC);
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::InvalidateRect
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::InvalidateRect ( LPCRECT prc, BOOL fErase ) { #ifdef DEBUG
if (prc) { TraceMsg(TF_TREXTDRAW, "TRS::InvalidateRect called with (%x, %x)-(%x, %x) fErase=%d", prc->left, prc->top, prc->right, prc->bottom, fErase); } else { TraceMsg(TF_TREXTDRAW, "TRS::InvalidateRect called prc=NULL, fErase=%d", fErase); } #endif
DWORD dwFlags = RDW_INVALIDATE | RDW_UPDATENOW; dwFlags |= (fErase ? RDW_ERASE : 0);
HWND hwnd; _pContainer->GetWindow(&hwnd); ::RedrawWindow(hwnd, prc, NULL, dwFlags);
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::InvalidateRgn
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::InvalidateRgn ( HRGN hrgn, BOOL fErase ) { TraceMsg(TF_TRSITE, "TRS::InvalidateRgn called");
DWORD dwFlags = RDW_INVALIDATE | RDW_UPDATENOW; dwFlags |= (fErase ? RDW_ERASE : 0);
HWND hwnd; _pContainer->GetWindow(&hwnd); ::RedrawWindow(hwnd, NULL, hrgn, dwFlags);
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::OnStatusBitsChange
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::OnStatusBitsChange ( DWORD dwFlags ) { return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// IAdviseSink interface
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::OnViewChange
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(void) CTransitionSite::OnViewChange(DWORD dwAspect, LONG lindex) { static DWORD dwLastUpdate = 0;
if ( ((GetTickCount() - dwLastUpdate) > MIN_ONVIEWCHANGE_DURATION) && (_uState == TRSTATE_PAINTING) && (dwAspect & DVASPECT_CONTENT) ) { TraceMsg(TF_TRDRAW, "TRS::OnViewChange(%d)", lindex);
_pSite->InvalidateRect(NULL, FALSE); }
dwLastUpdate = GetTickCount(); }
/////////////////////////////////////////////////////////////////////////////
// IDispatch interface
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CTransitionSite::Invoke
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSite::Invoke ( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr ) { ASSERT(pdispparams != NULL); if (pdispparams == NULL) return E_INVALIDARG;
if (!(wFlags & DISPATCH_METHOD)) return E_INVALIDARG;
switch(dispidMember) { case DISPID_ONTRANSITIONFINISH: { _OnComplete(); break; }
default: return E_INVALIDARG; }
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// CTransitionSitePropertyBag
/////////////////////////////////////////////////////////////////////////////
#undef CTransitionSite
CTransitionSitePropertyBag::CTransitionSitePropertyBag ( ) : _cRef(1) { TraceMsg(TF_TRLIFE, "TRSPropBag::ctor called");
// Implicit: _hdpaProperties = NULL;
}
CTransitionSitePropertyBag::~CTransitionSitePropertyBag() { TraceMsg(TF_TRLIFE, "TRSPropBag::dtor called");
if (_hdpaProperties != NULL) { DPA_DestroyCallback(_hdpaProperties, _DPA_FreeProperties, 0); _hdpaProperties = NULL; } }
/////////////////////////////////////////////////////////////////////////////
// _DPA_FreeProperties
/////////////////////////////////////////////////////////////////////////////
int CTransitionSitePropertyBag::_DPA_FreeProperties(void *pv, void *pData) { NAMEVALUE * pnv = (NAMEVALUE *)pv;
ASSERT(pnv != NULL); ASSERT(pnv->pwszName != NULL);
LocalFree(pnv->pwszName); pnv->pwszName = NULL;
VariantClear(&pnv->varValue);
LocalFree(pnv); pnv = NULL;
return 1; }
/////////////////////////////////////////////////////////////////////////////
// _AddProperty
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSitePropertyBag::_AddProperty(WCHAR *wszPropName, VARIANT *pvarValue) { NAMEVALUE * pnv = NULL; HRESULT hrResult = E_FAIL;
// Create the list if needed
if (_hdpaProperties == NULL) _hdpaProperties = DPA_Create(TSPB_CREATE_INCR);
for (;;) { if (_hdpaProperties == NULL) break;
// Alloc a new name value pair
pnv = (NAMEVALUE *)LocalAlloc(LPTR, SIZEOF(NAMEVALUE)); if (pnv == NULL) { TraceMsg(TF_WARNING, "TRSPB Unable to alloc memory for property"); break; }
// Copy the name
UINT cb = (lstrlenW(wszPropName)+1) * SIZEOF(wszPropName[0]); pnv->pwszName = (LPWSTR)LocalAlloc(LPTR, cb); if (pnv->pwszName == NULL) { TraceMsg(TF_WARNING, "TRSPB Unable to alloc memory for property"); break; }
StrCpyNW(pnv->pwszName, wszPropName, cb / sizeof(wszPropName[0]));
// Copy the value
if (FAILED(hrResult = VariantCopy(&pnv->varValue, pvarValue))) { TraceMsg(TF_WARNING, "TRSPB VariantCopy failed"); break; }
// Add the name value pair to the list
if (DPA_AppendPtr(_hdpaProperties, pnv) == DPA_ERR) break;
#ifdef DEBUG
TCHAR szPropName[80]; SHUnicodeToTChar(wszPropName, szPropName, SIZEOF(szPropName));
VARIANT vVal = { 0 }; TCHAR szPropVal[80];
EVAL(SUCCEEDED(VariantChangeType(&vVal, pvarValue, 0, VT_BSTR))); SHUnicodeToTChar(V_BSTR(&vVal), szPropVal, SIZEOF(szPropVal)); EVAL(SUCCEEDED(VariantClear(&vVal)));
TraceMsg(TF_TRSPB, "TRSPB::_AddProperty added '%s = %s'", szPropName, szPropVal); #endif // DEBUG
hrResult = S_OK; break; }
// Cleanup on error
if (FAILED(hrResult)) { if (pnv != NULL) { if (pnv->pwszName != NULL) { LocalFree(pnv->pwszName); pnv->pwszName = NULL; }
VariantClear(&pnv->varValue);
LocalFree(pnv); pnv = NULL; } }
return hrResult; }
ULONG CTransitionSitePropertyBag::AddRef() { _cRef++; return _cRef; }
ULONG CTransitionSitePropertyBag::Release() { ASSERT(_cRef > 0); _cRef--;
if (_cRef > 0) return _cRef;
delete this; return 0; }
HRESULT CTransitionSitePropertyBag::QueryInterface(REFIID riid, void **ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IPropertyBag)) { *ppvObj = SAFECAST(this, IPropertyBag *); } else { *ppvObj = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; }
/////////////////////////////////////////////////////////////////////////////
// IPropertyBag interface
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CTransitionSitePropertyBag::Read
/////////////////////////////////////////////////////////////////////////////
HRESULT CTransitionSitePropertyBag::Read ( LPCOLESTR pszPropName, VARIANT * pVar, IErrorLog * pErrorLog ) { HRESULT hrResult = E_INVALIDARG;
if ((pszPropName == NULL) || (pVar == NULL)) return E_POINTER;
#ifdef DEBUG
TCHAR szPropName[80]; SHUnicodeToTChar(pszPropName, szPropName, SIZEOF(szPropName)); TraceMsg(TF_TRSPB, "TRSPB::Read(%s)", szPropName); #endif // DEBUG
if (_hdpaProperties != NULL) { // Search for the property in the list.
for (int i = 0; i < DPA_GetPtrCount(_hdpaProperties); i++) { NAMEVALUE * pnv = (NAMEVALUE *)DPA_GetPtr(_hdpaProperties, i);
if (StrCmpIW(pszPropName, pnv->pwszName) == 0) { // Copy the variant property.
hrResult = VariantChangeType(pVar, &pnv->varValue, 0, pVar->vt); break; } } }
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// Helper functions
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CLSIDFromTransitionName
/////////////////////////////////////////////////////////////////////////////
HRESULT CLSIDFromTransitionName ( LPCTSTR pszName, LPCLSID clsidName ) { HKEY hkeyTransitions = NULL; HRESULT hrResult;
for (;;) { // Check for "{...CLSID...}"
if (*pszName == TEXT('{')) { hrResult = SHCLSIDFromString(pszName, clsidName); break; }
// Check for Transition Name
if (RegCreateKey( HKEY_LOCAL_MACHINE, c_szTransitionsKey, &hkeyTransitions) == ERROR_SUCCESS) { TCHAR szCLSID[GUIDSTR_MAX]; DWORD cbBytes = SIZEOF(szCLSID); DWORD dwType;
if ( (RegQueryValueEx( hkeyTransitions, pszName, NULL, &dwType, (BYTE *)szCLSID, &cbBytes) == ERROR_SUCCESS) && (dwType == REG_SZ) ) { hrResult = SHCLSIDFromString(szCLSID, clsidName); break; } }
hrResult = E_FAIL; break; }
if (hkeyTransitions != NULL) RegCloseKey(hkeyTransitions);
return hrResult; }
/////////////////////////////////////////////////////////////////////////////
// ParseTransitionInfo
//
// Purpose: Parse <META HTTP-EQUIV...> of the form:
//
// <META
// HTTP-EQUIV = transition-event
// CONTENT = transition-description
// >
//
// where:
//
// transition-event -> PAGE-ENTER
// | PAGE-EXIT
// | SITE-ENTER
// | SITE-EXIT
//
// transition-description -> transition-name ( transition-properties )
//
// transition-name -> IDENTIFIER
// | CLSID
// | PROGID
//
// transition-properties -> transition-property , transition-property
// transition-properties -> transition-property
//
// name-value-assignment -> = | :
//
// transition-property -> NAME name-value-assignment VALUE
//
// examples:
//
// <META
// HTTP-EQUIV = "Page-Enter"
// CONTENT = "Reveal(duration=500)"
// >
//
// <META
// HTTP-EQUIV = "Page-Leave"
// CONTENT = "Reveal(duration=500, type=checkerboard, size=10)"
// >
//
/////////////////////////////////////////////////////////////////////////////
BOOL ParseTransitionInfo ( WCHAR * pwz, TRANSITIONINFO * pti ) { enum { PTE_PARSE_TRANSITION_NAME, PTE_PARSE_NAME, PTE_PARSE_VALUE, PTE_FINISHED };
#define MAX_TRANSITION_NAME_LEN GUIDSTR_MAX
WCHAR wszTransitionName[MAX_TRANSITION_NAME_LEN]; WCHAR * pwzTransitionName = wszTransitionName;
#define MAX_PTINAME_LEN 32
WCHAR wszName[MAX_PTINAME_LEN]; WCHAR * pwzName = wszName;
#define MAX_PTIVALUE_LEN 32
WCHAR wszValue[MAX_PTIVALUE_LEN]; WCHAR * pwzValue = wszValue;
WCHAR wch; UINT cch = 0; UINT uiState = PTE_PARSE_TRANSITION_NAME; BOOL bSucceeded = FALSE;
ASSERT(pti != NULL);
do { wch = *pwz;
switch (uiState) { case PTE_PARSE_TRANSITION_NAME: { if (wch == TEXT('(')) // Open paren
{ cch = 0; uiState = PTE_PARSE_NAME;
*pwzTransitionName = '\0'; pwzTransitionName = wszTransitionName;
TCHAR szTransitionName[MAX_TRANSITION_NAME_LEN]; SHUnicodeToTChar(wszTransitionName, szTransitionName, ARRAYSIZE(szTransitionName));
TraceMsg(DM_TRACE, "ParseTransitionInfo(%s)", szTransitionName);
// Resolve the Transition Name
EVAL(SUCCEEDED(CLSIDFromTransitionName(szTransitionName, &(pti->clsid)))); } else if ( !ISSPACE(wch) && (cch++ < (MAX_TRANSITION_NAME_LEN-1)) ) { *pwzTransitionName++ = wch; } else ; // Ignore
break; }
case PTE_PARSE_NAME: { if ( (wch == TEXT('=')) // Equal
|| (wch == TEXT(':')) // Semicolon
) { cch = 0; uiState = PTE_PARSE_VALUE;
*pwzName = '\0'; pwzName = wszName; } else if ( !ISSPACE(wch) && (cch++ < (MAX_PTINAME_LEN-1)) ) { *pwzName++ = wch; } else ; // Ignore
break; }
case PTE_PARSE_VALUE: { if ( (wch == TEXT(',')) // Comma
|| (wch == TEXT(')')) // Close paren
) { cch = 0; if (wch == TEXT(',')) uiState = PTE_PARSE_NAME; else uiState = PTE_FINISHED;
*pwzValue = '\0'; pwzValue = wszValue;
// Initialize the property bag class
if (pti->pPropBag == NULL) pti->pPropBag = new CTransitionSitePropertyBag;
if (pti->pPropBag) { VARIANT v; if (SUCCEEDED(InitVariantFromStr(&v, wszValue))) { VARIANT vDuration = { 0 }; VARIANT* pvarToAdd = &v;
// Limit the duration of the transition.
if (StrCmpIW(wszName, c_szDurationProp) == 0) { if (SUCCEEDED(VariantChangeTypeEx(&vDuration, &v, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, VT_R4))) { ASSERT(V_VT(&vDuration) == VT_R4);
if (V_R4(&vDuration) < MIN_TRANSITION_DURATION) V_R4(&vDuration) = MIN_TRANSITION_DURATION; else if (V_R4(&vDuration) > MAX_TRANSITION_DURATION) V_R4(&vDuration) = MAX_TRANSITION_DURATION;
// don't need to VariantClear() vDuration since it's VT_R4 by the above ASSERT
pvarToAdd = &vDuration; } }
// Add the property to the property bag
pti->pPropBag->_AddProperty(wszName, pvarToAdd);
VariantClear(&v); // vDuration is VT_EMPTY or VT_R4, neither of which nead VariantClear
} } } else if ( !ISSPACE(wch) && (cch++ < (MAX_PTIVALUE_LEN-1)) ) { *pwzValue++ = wch; } else ; // Ignore
break; }
case PTE_FINISHED: { bSucceeded = TRUE; break; }
default: break; }
pwz++; } while (wch && !bSucceeded);
return bSucceeded; } // ParseTransitionInfo
|