#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 of the form: // // // // 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: // // // // // ///////////////////////////////////////////////////////////////////////////// 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