#include "precomp.h" #define __MARS_INLINE_FAST_IS_EQUAL_GUID #define LIGHTWEIGHT_AUTOPERSIST #define BLOCK_PANEL_RENAVIGATES #include "mcinc.h" #include #include "marswin.h" #include "pandef.h" #include "panel.h" #include "place.h" #include "htiface.h" #include "mimeinfo.h" #include #include "dllload.h" #include #include #include #include // We include this cpp file because the stuff // in pandef needs to be included in another project // namely, parser\comptree #include "pandef.cpp" // CLSID strings passed to ATL to create control static WCHAR wszCLSID_HTMLDocument[] = L"{25336920-03F9-11CF-8FD0-00AA00686F13}"; static WCHAR wszCLSID_WebBrowser[] = L"{8856F961-340A-11D0-A96B-00C04FD705A2}"; static WCHAR wszCLSID_HTADocument[] = L"{3050f5c8-98b5-11cf-bb82-00aa00bdce0b}"; const GUID CLSID_HTADoc = { 0x3050f5c8, 0x98b5, 0x11cf, { 0xbb, 0x82, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x0b } }; // CLASS_CMarsPanel = {EE0462C2-5CD3-11d3-97FA-00C04F45D0B3} const GUID CLASS_CMarsPanel = { 0xee0462c2, 0x5cd3, 0x11d3, { 0x97, 0xfa, 0x0, 0xc0, 0x4f, 0x45, 0xd0, 0xb3 } }; CMarsPanel::CMarsPanel(CPanelCollection *pParent, CMarsWindow *pMarsWindow) : m_MarsExternal(this, pMarsWindow), m_BrowserEvents(this) { m_spPanelCollection = pParent; m_spMarsDocument = m_spPanelCollection->Document(); m_lReadyState = READYSTATE_COMPLETE; } CMarsPanel::~CMarsPanel() { } HRESULT CMarsPanel::Passivate() { return CMarsComObject::Passivate(); } HRESULT CMarsPanel::DoPassivate() { m_spMarsDocument->MarsWindow()->NotifyHost(MARSHOST_ON_PANEL_PASSIVATE, SAFECAST(this, IMarsPanel *), 0); m_spPanelCollection->SetActivePanel(this, FALSE); // First we unload the document so that script can do work in its "onunload" // handler, before we become passive if(IsWebBrowser()) { CComPtr spUnk; if (SUCCEEDED(m_Content.QueryControl(IID_IUnknown, (void **)&spUnk))) { m_BrowserEvents.Connect(spUnk, FALSE); } } else if(IsCustomControl()) { } else { DisconnectCompletionAdviser(); } m_Content.DestroyWindow(); //////////////////////////////////////// m_spMarsDocument->MarsWindow()->ReleaseOwnedObjects(SAFECAST(this, IDispatch *)); m_BrowserEvents.Passivate(); m_MarsExternal.Passivate(); m_spBrowserService.Release(); m_spPanelCollection.Release(); m_spMarsDocument.Release(); return S_OK; } // IUnknown IMPLEMENT_ADDREF_RELEASE(CMarsPanel); STDMETHODIMP CMarsPanel::QueryInterface(REFIID iid, void ** ppvObject) { ATLASSERT(ppvObject); if ((iid == IID_IUnknown) || (iid == IID_IDispatch) || (iid == IID_IMarsPanel)) { *ppvObject = SAFECAST(this, IMarsPanel *); } else if (iid == IID_IHlinkFrame) { *ppvObject = SAFECAST(this, IHlinkFrame *); } else if (iid == IID_IServiceProvider) { *ppvObject = SAFECAST(this, IServiceProvider *); } else if (iid == IID_IInternetSecurityManager) { *ppvObject = SAFECAST(this, IInternetSecurityManager *); } else if ((iid == IID_IOleInPlaceSite) || (iid == IID_IOleWindow)) { *ppvObject = SAFECAST(this, IOleInPlaceSite *); } else if (iid == IID_IOleControlSite) { *ppvObject = SAFECAST(this, IOleControlSite *); } else if (iid == IID_IPropertyNotifySink) { *ppvObject = SAFECAST(this, IPropertyNotifySink *); } else if (iid == IID_IProfferService) { *ppvObject = SAFECAST(this, IProfferService *); } else if (iid == IID_IOleInPlaceUIWindow) { *ppvObject = SAFECAST(this, IOleInPlaceUIWindow *); } else if (iid == CLASS_CMarsPanel) { *ppvObject = SAFECAST(this, CMarsPanel *); } else { *ppvObject = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } HRESULT CMarsPanel::DoEnableModeless(BOOL fEnable) { CComPtr spOleInPlaceActiveObject; HRESULT hr = m_Content.QueryControl(&spOleInPlaceActiveObject); if (SUCCEEDED(hr)) { spOleInPlaceActiveObject->EnableModeless(fEnable); } return hr; } //================================================================== // Automation Object Model //================================================================== //------------------------------------------------------------------------------ // IMarsPanel::get_name // HRESULT CMarsPanel::get_name( BSTR *pbstrName ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( pbstrName )) { *pbstrName = SysAllocString( GetName() ); hr = (NULL != *pbstrName) ? S_OK : E_OUTOFMEMORY; } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_content // HRESULT CMarsPanel::get_content( IDispatch* *ppVal ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( ppVal )) { *ppVal = NULL; if(VerifyNotPassive( &hr )) { CreateControl(); hr = m_Content.QueryControl( ppVal ); } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_visible // HRESULT CMarsPanel::get_visible( VARIANT_BOOL *pbVisible ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( pbVisible )) { if(VerifyNotPassive( &hr )) { *pbVisible = VARIANT_BOOLIFY( m_fVisible ); hr = S_OK; } else { *pbVisible = VARIANT_FALSE; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_visible // HRESULT CMarsPanel::put_visible( VARIANT_BOOL bVisible ) { ATLASSERT(IsValidVariantBoolVal( bVisible )); HRESULT hr = S_OK; if(VerifyNotPassive( &hr )) { if(!!m_fVisible != !!bVisible) { m_fVisible = (bVisible != VARIANT_FALSE); if(!m_fVisible) { m_spPanelCollection->SetActivePanel( this, FALSE ); } // If the theme has changed while the panel was invisible, // now is a good time to automatically update it if(m_fVisible && IsContentInvalid()) { refresh(); } OnLayoutChange(); } else { hr = S_FALSE; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_startUrl // HRESULT CMarsPanel::get_startUrl( BSTR *pVal ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( pVal )) { *pVal = m_bstrStartUrl.Copy(); hr = S_OK; } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_startUrl // HRESULT CMarsPanel::put_startUrl( BSTR newVal ) { HRESULT hr = S_OK; m_bstrStartUrl = newVal; return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_height // HRESULT CMarsPanel::get_height( long *plHeight ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( plHeight )) { if(VerifyNotPassive( &hr )) { hr = S_OK; if(m_Content.IsWindowVisible()) { // Use actual position RECT rc; m_Content.GetWindowRect( &rc ); *plHeight = rc.bottom - rc.top; } else { // Panel's hidden. Return requested position. *plHeight = m_lHeight; } } else { *plHeight = 0; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_height // HRESULT CMarsPanel::put_height( long lHeight ) { ATLASSERT(lHeight >= 0); HRESULT hr = S_OK; if(VerifyNotPassive( &hr )) { if(lHeight >= 0) { if(m_lMinHeight >= 0 && lHeight < m_lMinHeight) lHeight = m_lMinHeight; if(m_lMaxHeight >= 0 && lHeight > m_lMaxHeight) lHeight = m_lMaxHeight; if(m_lHeight != lHeight) { m_lHeight = lHeight; OnLayoutChange(); } } else { hr = S_FALSE; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_width // HRESULT CMarsPanel::get_width( long *plWidth ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( plWidth )) { if(VerifyNotPassive( &hr )) { if(m_Content.IsWindowVisible()) { // Use actual position RECT rc; m_Content.GetWindowRect( &rc ); *plWidth = rc.right - rc.left; } else { // Panel's hidden. Return requested position. *plWidth = m_lWidth; } hr = S_OK; } else { *plWidth = 0; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_width // HRESULT CMarsPanel::put_width( long lWidth ) { ATLASSERT(lWidth >= 0); HRESULT hr = S_OK; if(VerifyNotPassive( &hr )) { if(lWidth >= 0) { if(m_lMinWidth >= 0 && lWidth < m_lMinWidth) lWidth = m_lMinWidth; if(m_lMaxWidth >= 0 && lWidth > m_lMaxWidth) lWidth = m_lMaxWidth; if(m_lWidth != lWidth) { m_lWidth = lWidth; OnLayoutChange(); } } else { hr = S_FALSE; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_x // HRESULT CMarsPanel::get_x( long *plX ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( plX )) { if(VerifyNotPassive( &hr )) { hr = S_OK; if(m_Content.IsWindowVisible()) { // Use actual position RECT rc; GetMyClientRectInParentCoords( &rc ); *plX = rc.left; } else { // Panel's hidden. Return requested position. *plX = m_lX; } } else { *plX = 0; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_x // HRESULT CMarsPanel::put_x( long lX ) { HRESULT hr = S_OK; if(VerifyNotPassive( &hr )) { if(m_lX != lX) { m_lX = lX; if(IsPopup()) { OnLayoutChange(); } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_y // HRESULT CMarsPanel::get_y( long *plY ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( plY )) { if(VerifyNotPassive( &hr )) { hr = S_OK; if(m_Content.IsWindowVisible()) { // Use actual position RECT rc; GetMyClientRectInParentCoords( &rc ); *plY = rc.top; } else { *plY = m_lY; } } else { *plY = 0; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_y // HRESULT CMarsPanel::put_y( long lY ) { HRESULT hr = S_OK; if(VerifyNotPassive( &hr )) { if(m_lY != lY) { m_lY = lY; if(IsPopup()) { OnLayoutChange(); } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_position // HRESULT CMarsPanel::get_position( VARIANT *pvarPosition ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( pvarPosition )) { if(VerifyNotPassive( &hr )) { VariantClear( pvarPosition ); hr = S_FALSE; if(m_Position <= c_iPositionMapSize) { pvarPosition->bstrVal = SysAllocString( s_PositionMap[m_Position].pwszName ); if(pvarPosition->bstrVal) { pvarPosition->vt = VT_BSTR; hr = S_OK; } } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_position // HRESULT CMarsPanel::put_position( VARIANT varPosition ) { HRESULT hr = E_INVALIDARG; if(API_IsValidVariantBstr( varPosition )) { if(VerifyNotPassive( &hr )) { hr = SCRIPT_ERROR; PANEL_POSITION position; if(SUCCEEDED(StringToPanelPosition( varPosition.bstrVal, &position ))) { hr = S_OK; if(m_Position != position) { m_Position = s_PositionMap[position].Position; if(m_Position == PANEL_POPUP) { m_Content.SetWindowPos( HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE ); } OnLayoutChange(); } } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_autoSize // HRESULT CMarsPanel::get_autoSize( VARIANT_BOOL *pbAutoSize ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( pbAutoSize )) { *pbAutoSize = VARIANT_BOOLIFY(IsAutoSizing()); if(VerifyNotPassive( &hr )) { hr = S_OK; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_autoSize // HRESULT CMarsPanel::put_autoSize( VARIANT_BOOL bAutoSize ) { HRESULT hr = S_OK; ATLASSERT(IsValidVariantBoolVal( bAutoSize )); if(VerifyNotPassive( &hr )) { if(bAutoSize) { if(!IsAutoSizing()) { m_dwFlags |= PANEL_FLAG_AUTOSIZE; OnLayoutChange(); } } else { if(IsAutoSizing()) { m_dwFlags &= ~PANEL_FLAG_AUTOSIZE; OnLayoutChange(); } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_contentInvalid // HRESULT CMarsPanel::get_contentInvalid( VARIANT_BOOL *pbInvalid ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( pbInvalid )) { *pbInvalid = VARIANT_BOOLIFY(m_fContentInvalid); hr = S_OK; } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::put_contentInvalid // HRESULT CMarsPanel::put_contentInvalid( VARIANT_BOOL bInvalid ) { ATLASSERT(IsValidVariantBoolVal( bInvalid )); ATLASSERT(!IsPassive()); m_fContentInvalid = BOOLIFY( bInvalid ); return S_OK; } //------------------------------------------------------------------------------ // IMarsPanel::get_layoutIndex // HRESULT CMarsPanel::get_layoutIndex( long *plIndex ) { HRESULT hr = E_INVALIDARG; if(API_IsValidWritePtr( plIndex )) { if(VerifyNotPassive( &hr )) { hr = m_spPanelCollection->FindPanelIndex( this, plIndex ); } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::moveto // HRESULT CMarsPanel::moveto( VARIANT vlX, VARIANT vlY, VARIANT vlWidth, VARIANT vlHeight ) { HRESULT hr = S_OK; ATLASSERT(vlX.vt == VT_NULL || vlX.vt == VT_I4); ATLASSERT(vlY.vt == VT_NULL || vlY.vt == VT_I4); ATLASSERT(vlWidth.vt == VT_NULL || vlWidth.vt == VT_I4); ATLASSERT(vlHeight.vt == VT_NULL || vlHeight.vt == VT_I4); if(VerifyNotPassive( &hr )) { long lX = VariantToI4( vlX ); long lY = VariantToI4( vlY ); long lWidth = VariantToI4( vlWidth ); long lHeight = VariantToI4( vlHeight ); if(( lX != m_lX ) || ( lY != m_lY ) || (lWidth >= 0 && lWidth != m_lWidth ) || (lHeight >= 0 && lHeight != m_lHeight) ) { m_lX = lX; m_lY = lY; if(lWidth >= 0) m_lWidth = lWidth; if(lHeight >= 0) m_lHeight = lHeight; OnLayoutChange(); } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::restrictWidth // HRESULT CMarsPanel::restrictWidth( VARIANT vlMin, VARIANT vlMax, VARIANT vbstrMarker ) { HRESULT hr = S_OK; ATLASSERT(vlMin.vt == VT_EMPTY || vlMin.vt == VT_NULL || vlMin.vt == VT_BSTR || vlMin.vt == VT_I4); ATLASSERT(vlMax.vt == VT_EMPTY || vlMax.vt == VT_NULL || vlMax.vt == VT_BSTR || vlMin.vt == VT_I4); ATLASSERT((vbstrMarker.vt==VT_NULL) || (vbstrMarker.vt == VT_EMPTY)); if(VerifyNotPassive( &hr )) { m_lMaxWidth = m_lMinWidth = -1; if(vlMin.vt != VT_NULL && vlMin.vt != VT_EMPTY ) { CComVariant vlMin2; vlMin2.ChangeType( VT_I4, &vlMin ); m_lMinWidth = VariantToI4( vlMin2 ); } if(vlMax.vt != VT_NULL && vlMax.vt != VT_EMPTY ) { CComVariant vlMax2; vlMax2.ChangeType( VT_I4, &vlMax ); m_lMaxWidth = VariantToI4( vlMax2 ); } if(m_lMaxWidth >= 0 && m_lMaxWidth < m_lMinWidth) { m_lMaxWidth = m_lMinWidth; } OnLayoutChange(); } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::restrictHeight // HRESULT CMarsPanel::restrictHeight( VARIANT vlMin, VARIANT vlMax, VARIANT vbstrMarker ) { HRESULT hr = S_OK; ATLASSERT(vlMin.vt == VT_EMPTY || vlMin.vt == VT_NULL || vlMin.vt == VT_BSTR || vlMin.vt == VT_I4); ATLASSERT(vlMax.vt == VT_EMPTY || vlMax.vt == VT_NULL || vlMax.vt == VT_BSTR || vlMin.vt == VT_I4); ATLASSERT((vbstrMarker.vt==VT_NULL) || (vbstrMarker.vt == VT_EMPTY)); if(VerifyNotPassive( &hr )) { m_lMaxHeight = m_lMinHeight = -1; if(vlMin.vt != VT_NULL && vlMin.vt != VT_EMPTY ) { CComVariant vlMin2; vlMin2.ChangeType( VT_I4, &vlMin ); m_lMinHeight = VariantToI4( vlMin2 ); } if(vlMax.vt != VT_NULL && vlMax.vt != VT_EMPTY ) { CComVariant vlMax2; vlMax2.ChangeType( VT_I4, &vlMax ); m_lMaxHeight = VariantToI4( vlMax2 ); } if(m_lMaxHeight >= 0 && m_lMaxHeight < m_lMinHeight) m_lMaxHeight = m_lMinHeight; OnLayoutChange(); } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::canResize // HRESULT CMarsPanel::canResize( long lDX, long lDY, VARIANT_BOOL *pVal ) { long lWidthOld = m_lWidth; long lHeightOld = m_lHeight; RECT rcClient; m_lWidth += lDX; m_lHeight += lDY; (void)m_spMarsDocument->Window()->GetClientRect( &rcClient ); if(m_spMarsDocument->MarsWindow()->CanLayout( rcClient )) { if(pVal) *pVal = VARIANT_TRUE; } else { if(pVal) *pVal = VARIANT_FALSE; } m_lWidth = lWidthOld; m_lHeight = lHeightOld; return S_OK; } //------------------------------------------------------------------------------ // IMarsPanel::activate // HRESULT CMarsPanel::activate() { m_Content.SendMessage(WM_SETFOCUS, 0, 0); return S_OK; } //------------------------------------------------------------------------------ // IMarsPanel::insertBefore // HRESULT CMarsPanel::insertBefore(VARIANT varInsertBefore) { ATLASSERT(varInsertBefore.vt == VT_I4 || // index to insert before varInsertBefore.vt == VT_BSTR || // panel name to insert before varInsertBefore.vt == VT_DISPATCH); // panel object to insert before HRESULT hr = E_INVALIDARG; if (API_IsValidVariant(varInsertBefore)) { if (VerifyNotPassive(&hr)) { hr = E_FAIL; long lIndex = -668; switch(varInsertBefore.vt) { case VT_I4: lIndex = varInsertBefore.lVal; hr = S_OK; break; case VT_DISPATCH: { CComClassPtr spPanel; varInsertBefore.pdispVal->QueryInterface(CLASS_CMarsPanel, (void **)&spPanel); if (spPanel) { hr = m_spPanelCollection->FindPanelIndex(spPanel, &lIndex); } break; } case VT_BSTR: hr = m_spPanelCollection->FindPanelIndex( m_spPanelCollection->FindPanel(varInsertBefore.bstrVal), &lIndex); break; default: ATLASSERT(0); } if (SUCCEEDED(hr)) { // Successfully got an index to insert before ATLASSERT(lIndex != -668); // Get our current index long lCurrentIndex; if (SUCCEEDED(m_spPanelCollection->FindPanelIndex(this, &lCurrentIndex))) { ATLASSERT(lCurrentIndex != -1); if (lIndex != lCurrentIndex) { m_spPanelCollection->InsertPanelFromTo(lCurrentIndex, lIndex); OnLayoutChange(); } } else { ATLASSERT(!"FindPanelIndex failed!"); } } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::execMshtml // // execMshtml allows script to send a command directly to Trident. This is different from // IWebBrowser2::ExecWB because ExecWB passes a NULL command group, which prevents Trident // from responding to commands like IDM_FIND. Usually, we could accomplish this by calling // the OM method execCommand, but Trident doesn't respond to execCommand("Find") // HRESULT CMarsPanel::execMshtml(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut) { HRESULT hr = E_INVALIDARG; if (VerifyNotPassive(&hr)) { CComPtr spCmdTarget; hr = m_Content.QueryControl(IID_IOleCommandTarget, (void **) &spCmdTarget); if (SUCCEEDED(hr)) { hr = spCmdTarget->Exec(&CGID_MSHTML, nCmdID, nCmdExecOpt, pvaIn, pvaOut); } hr = S_OK; } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::get_isCurrentlyVisible // HRESULT CMarsPanel::get_isCurrentlyVisible(VARIANT_BOOL *pbIsVisible) { HRESULT hr = E_INVALIDARG; if (API_IsValidWritePtr(pbIsVisible)) { if (VerifyNotPassive(&hr)) { *pbIsVisible = VARIANT_BOOLIFY(m_Content.IsWindowVisible()); hr = S_OK; } } return hr; } //------------------------------------------------------------------------------ // IServiceProvider::QueryService // // First, we try to handle guidService, then we go to IProfferServiceImpl, // then we go to the parent window. // HRESULT CMarsPanel::QueryService(REFGUID guidService, REFIID riid, void **ppv) { HRESULT hr = E_FAIL; *ppv = NULL; if (!IsPassive()) { if (guidService == IID_IInternetProtocol) { // Yeah, we don't support this service. Stop asking us for it! } else if ((guidService == SID_SHlinkFrame) || (guidService == SID_SProfferService) || (guidService == SID_SMarsPanel)) { hr = QueryInterface(riid, ppv); } else if (guidService == SID_SInternetSecurityManager) { if (IsTrusted()) { hr = QueryInterface(riid, ppv); } } if (FAILED(hr)) { hr = IProfferServiceImpl::QueryService(guidService, riid, ppv); } } if (FAILED(hr)) { hr = m_spMarsDocument->MarsWindow()->QueryService(guidService, riid, ppv); } return hr; } //------------------------------------------------------------------------------ // IHlinkFrame::Navigate // HRESULT CMarsPanel::Navigate(DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pibsc, IHlink *pihlNavigate) { // BUGBUG: Call ReleasedOwnedObjects for this panel HRESULT hr = E_FAIL; CComPtr spMk; if (VerifyNotPassive()) { pihlNavigate->GetMonikerReference(grfHLNF, &spMk, NULL); if (spMk) { hr = NavigateMk(spMk); } } return hr; } //------------------------------------------------------------------------------ HRESULT CMarsPanel::Create( MarsAppDef_Panel* pLayout) { ATLASSERT(!IsPassive()); m_bstrName = pLayout->szName; m_Position = pLayout->Position; m_lWidth = pLayout->lWidth; m_lHeight = pLayout->lHeight; m_lX = pLayout->lX; m_lY = pLayout->lY; m_dwFlags = pLayout->dwFlags; m_lMinWidth = pLayout->lWidthMin; m_lMinHeight = pLayout->lHeightMin; m_lMaxWidth = pLayout->lWidthMax; m_lMaxHeight = pLayout->lHeightMax; m_fVisible = BOOLIFY(m_dwFlags & PANEL_FLAG_VISIBLE); m_dwCookie = 0; if(!IsAutoSizing()) { switch(m_Position) { case PANEL_BOTTOM: case PANEL_TOP: if(m_lMinHeight < 0 && m_lMaxHeight < 0) { m_lMinHeight = m_lHeight; m_lMaxHeight = m_lHeight; } break; case PANEL_LEFT: case PANEL_RIGHT: if(m_lMinWidth < 0 && m_lMaxWidth < 0) { m_lMinWidth = m_lWidth; m_lMaxWidth = m_lWidth; } break; } } { DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS; RECT rcCreate = { 0, 0, 0, 0 }; m_Content.Create( m_spMarsDocument->Window()->m_hWnd, &rcCreate, _T(""), dwStyle, 0 ); } { CComPtr spObj; m_Content.QueryHost(IID_IObjectWithSite, (void **)&spObj); if (spObj) { spObj->SetSite(SAFECAST(this, IMarsPanel *)); // To connect our QueryService } } m_spMarsDocument->MarsWindow()->NotifyHost(MARSHOST_ON_PANEL_INIT, SAFECAST(this, IMarsPanel *), 0); if(pLayout->szUrl[0]) { m_bstrStartUrl = pLayout->szUrl; } if(!(m_dwFlags & PANEL_FLAG_ONDEMAND)) { CreateControl(); } if(m_dwFlags & PANEL_FLAG_VISIBLE) { OnLayoutChange(); } return S_OK; } //------------------------------------------------------------------------------ DELAY_LOAD_NAME_HRESULT(g_hinstBorg, mshtml, BorgDllGetClassObject, DllGetClassObject, (REFCLSID rclsid, REFIID riid, LPVOID* ppv), (rclsid, riid, ppv)); HRESULT CMarsPanel::CreateControlObject() { ATLASSERT(!m_fControlCreated); CComPtr spHost; HRESULT hr = m_Content.QueryHost(&spHost); if (SUCCEEDED(hr)) { if(IsWebBrowser()) { hr = spHost->CreateControl(wszCLSID_WebBrowser, m_Content, 0); } else if(IsCustomControl()) { hr = spHost->CreateControl(m_bstrStartUrl, m_Content, 0); } else { if (IsTrusted()) { CComPtr spCf; hr = BorgDllGetClassObject(CLSID_HTADoc, IID_IClassFactory, (void **)&spCf); if (SUCCEEDED(hr)) { CComPtr spUnk; hr = spCf->CreateInstance(NULL, IID_IUnknown, (void **)&spUnk); if (SUCCEEDED(hr)) { hr = spHost->AttachControl(spUnk, m_Content); } } } else { hr = spHost->CreateControl(wszCLSID_HTMLDocument, m_Content, 0); } } } return hr; } //------------------------------------------------------------------------------ // Internal function called when panel is first made visible HRESULT CMarsPanel::CreateControl() { HRESULT hr = S_FALSE; if(!m_fControlCreated) { // Create WebBrowser or Trident and navigate to default url if (SUCCEEDED(CreateControlObject())) { m_fControlCreated = TRUE; if(IsWebBrowser()) { CComPtr spUnk; if (SUCCEEDED(m_Content.QueryControl(IID_IUnknown, (void **)&spUnk))) { m_BrowserEvents.Connect(spUnk, TRUE); // get the browserservice that we will intercept to update the travel log // only if this is a WebBrowser and not a Popup if (!m_spBrowserService) { HRESULT hrQS = IUnknown_QueryService(spUnk, SID_STopFrameBrowser, IID_IBrowserService, (void **)&m_spBrowserService); if (FAILED(hrQS)) { ATLASSERT(!m_spBrowserService); } } CComPtr spCommandTarget; if (SUCCEEDED(IUnknown_QueryService(spUnk, SID_STopFrameBrowser, IID_IOleCommandTarget, (void **)&spCommandTarget))) { VARIANT var; var.vt = VT_BOOL; var.boolVal = TRUE; spCommandTarget->Exec(&CGID_InternetExplorer, IECMDID_SET_INVOKE_DEFAULT_BROWSER_ON_NEW_WINDOW, 0, &var, NULL); } } } else if(IsCustomControl()) { } else { ConnectCompletionAdviser(); } if(IsTrusted()) { m_Content.SetExternalDispatch(&m_MarsExternal); } if (m_bstrStartUrl) { ATLASSERT(m_bstrStartUrl[0]); NavigateURL(m_bstrStartUrl, FALSE); m_bstrStartUrl.Empty(); } m_spMarsDocument->MarsWindow()->NotifyHost(MARSHOST_ON_PANEL_CONTROL_CREATE, SAFECAST(this, IMarsPanel *), 0); hr = S_OK; } else { hr = E_FAIL; } } return hr; } //------------------------------------------------------------------------------ // This returns void because it calls a script method that might return // S_FALSE with no URL, so we should force callers to check the BSTR // // rbstrUrl = document.location.href // void CMarsPanel::GetUrl(CComBSTR& rbstrUrl) { CComPtr spDoc2; GetDoc2FromAxWindow(&m_Content, &spDoc2); if (spDoc2) { CComPtr spLoc; spDoc2->get_location(&spLoc); if (spLoc) { spLoc->get_href(&rbstrUrl); } } } //------------------------------------------------------------------------------ HRESULT CMarsPanel::NavigateMk(IMoniker *pmk) { HRESULT hr = E_FAIL; if (VerifyNotPassive()) { CComPtr spPersistMk; if (SUCCEEDED(m_Content.QueryControl(IID_IPersistMoniker, (void **)&spPersistMk))) { m_spMarsDocument->MarsWindow()->ReleaseOwnedObjects((IDispatch *)this); hr = spPersistMk->Load(FALSE, pmk, NULL, 0); } else { // NavigateMk: QueryControl failed -- the most likely reason for this is that // you don't have CLSID_HTADocument registered -- upgrade your IE bits ATLASSERT(FALSE); // Don't just hang the UI m_lReadyState = READYSTATE_COMPLETE; } } return hr; } //------------------------------------------------------------------------------ HRESULT CMarsPanel::NavigateURL(LPCWSTR lpszURL, BOOL fForceLoad) { HRESULT hr = E_FAIL; if (VerifyNotPassive()) { CreateControl(); BOOL fIgnoreNavigate = FALSE; #ifdef BLOCK_PANEL_RENAVIGATES if (!fForceLoad && IsTrusted() && !IsContentInvalid()) { CComBSTR sbstrCurrentUrl; GetUrl(sbstrCurrentUrl); if (sbstrCurrentUrl && (0 == StrCmpIW(sbstrCurrentUrl, lpszURL))) { fIgnoreNavigate = TRUE; hr = S_FALSE; } } #endif if(!fIgnoreNavigate) { if(IsWebBrowser()) { CComPtr spWebBrowser2; if (SUCCEEDED(m_Content.QueryControl(IID_IWebBrowser2, (void **)&spWebBrowser2))) { CComVariant varEmpty; CComVariant varURL(lpszURL); m_spMarsDocument->MarsWindow()->ReleaseOwnedObjects((IDispatch *)this); hr = spWebBrowser2->Navigate2(&varURL, &varEmpty, &varEmpty, &varEmpty, &varEmpty); } } else if(IsCustomControl()) { } else { CComPtr spMkUrl; if (SUCCEEDED(CreateURLMoniker(NULL, lpszURL, &spMkUrl)) && spMkUrl) { hr = NavigateMk(spMkUrl); } } } if (SUCCEEDED(hr)) { m_fContentInvalid = FALSE; } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::navigate // HRESULT CMarsPanel::navigate(VARIANT varTarget, VARIANT varForceLoad) { HRESULT hr = S_FALSE; if (API_IsValidVariant(varTarget) && VerifyNotPassive(&hr)) { CComBSTR strPath; if (SUCCEEDED(MarsVariantToPath(varTarget, strPath))) { if (!PathIsURLW(strPath) && PathIsURLFileW(strPath)) { // handle navigate to .url shortcut CComPtr spDisp; CreateControl(); if (SUCCEEDED(m_Content.QueryControl(&spDisp))) { if (SUCCEEDED(MarsNavigateShortcut(spDisp, strPath))) { m_spMarsDocument->MarsWindow()->ReleaseOwnedObjects((IDispatch *)this); hr = S_OK; } } } else { // handle navigate to URL BOOL fForceLoad; if (varForceLoad.vt == VT_BOOL) { // the optional param was specified fForceLoad = varForceLoad.boolVal; } else { fForceLoad = FALSE; } if (SUCCEEDED(NavigateURL(strPath, fForceLoad))) { hr = S_OK; } } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanel::refresh // HRESULT CMarsPanel::refresh(void) { m_fInRefresh = TRUE; execMshtml(IDM_REFRESH, OLECMDEXECOPT_DODEFAULT, NULL, NULL); m_fInRefresh = FALSE; m_fContentInvalid = FALSE; return S_OK; } //------------------------------------------------------------------------------ void CMarsPanel::OnLayoutChange() { ATLASSERT(!IsPassive()); if (!m_fVisible && !m_Content.IsWindowVisible()) { // We're not even visible. Nothing to do. return; } // Create content if it's not already created CreateControl(); // Redraw entire Mars window m_spPanelCollection->Layout(); } //------------------------------------------------------------------------------ void CMarsPanel::MakeVisible(VARIANT_BOOL bVisible, VARIANT_BOOL bForce) { ATLASSERT(!IsPassive()); BOOL fVisible = m_Content.IsWindowVisible(); if (bForce || (!!fVisible != !!bVisible)) { m_Content.ShowWindow((bVisible) ? SW_SHOW : SW_HIDE); } } //------------------------------------------------------------------------------ void CMarsPanel::OnWindowPosChanging(WINDOWPOS *pWindowPos) { if (!IsPassive() && !m_spPanelCollection->IsLayoutLocked()) { if (pWindowPos->x < 0) { pWindowPos->x = 0; } if (pWindowPos->y < 0) { pWindowPos->y = 0; } } } //------------------------------------------------------------------------------ inline void DimChange(long& lMember, int iVal, BOOL& bChanged) { if (lMember != iVal) { lMember = iVal; bChanged = TRUE; } } //------------------------------------------------------------------------------ void CMarsPanel::OnWindowPosChanged(WINDOWPOS *pWindowPos) { if(!IsPassive() && !m_spPanelCollection->IsLayoutLocked()) { BOOL bChanged = FALSE; switch(m_Position) { case PANEL_POPUP: if(!(pWindowPos->flags & SWP_NOMOVE)) DimChange(m_lX , pWindowPos->x , bChanged); if(!(pWindowPos->flags & SWP_NOMOVE)) DimChange(m_lY , pWindowPos->y , bChanged); if(!(pWindowPos->flags & SWP_NOSIZE)) DimChange(m_lWidth , pWindowPos->cx, bChanged); if(!(pWindowPos->flags & SWP_NOSIZE)) DimChange(m_lHeight, pWindowPos->cy, bChanged); break; case PANEL_BOTTOM: case PANEL_TOP: if(!(pWindowPos->flags & SWP_NOSIZE)) DimChange(m_lHeight, pWindowPos->cy, bChanged); break; case PANEL_LEFT: case PANEL_RIGHT: if(!(pWindowPos->flags & SWP_NOSIZE)) DimChange(m_lWidth, pWindowPos->cx, bChanged); break; } if(bChanged) { OnLayoutChange(); } } } //------------------------------------------------------------------------------ void CMarsPanel::GetMinMaxInfo( POINT& ptMin, POINT& ptMax ) { long lWidth = m_lWidth; long lHeight = m_lHeight; long lMinWidth; long lMinHeight; long lMaxWidth; long lMaxHeight; if(!IsAutoSizing()) { lMinWidth = m_lMinWidth; lMinHeight = m_lMinHeight; lMaxWidth = m_lMaxWidth; lMaxHeight = m_lMaxHeight; } else { ComputeDimensionsOfContent( &lMinWidth, &lMinHeight ); if(m_lMinWidth != -1 && lMinWidth < m_lMinWidth ) lMinWidth = m_lMinWidth; if(m_lMinHeight != -1 && lMinHeight < m_lMinHeight) lMinHeight = m_lMinHeight; lMaxWidth = m_lMaxWidth; lMaxHeight = m_lMaxHeight; if(lMinWidth > lWidth ) lWidth = lMinWidth; if(lMinHeight > lHeight) lHeight = lMinHeight; } switch(m_Position) { case PANEL_BOTTOM: case PANEL_TOP : if(lMinHeight < 0) lMinHeight = lHeight; if(lMaxHeight < 0) lMaxHeight = lHeight; break; case PANEL_LEFT : case PANEL_RIGHT: if(lMinWidth < 0) lMinWidth = lWidth; if(lMaxWidth < 0) lMaxWidth = lWidth; break; } ptMin.x = lMinWidth; ptMin.y = lMinHeight; ptMax.x = lMaxWidth; ptMax.y = lMaxHeight; } bool CMarsPanel::CanLayout( RECT& rcClient, POINT& ptDiff ) { ptDiff.x = 0; ptDiff.y = 0; if(IsVisible()) { RECT rcClient2; POINT ptMin; POINT ptMax; long lWidth; long lHeight; GetRect ( &rcClient, &rcClient2 ); GetMinMaxInfo( ptMin , ptMax ); lWidth = rcClient2.right - rcClient2.left; lHeight = rcClient2.bottom - rcClient2.top; if(ptMin.x >= 0 && lWidth < ptMin.x) ptDiff.x -= (lWidth - ptMin.x); if(ptMax.x >= 0 && lWidth > ptMax.x) ptDiff.x -= (lWidth - ptMax.x); if(ptMin.y >= 0 && lHeight < ptMin.y) ptDiff.y -= (lHeight - ptMin.y); if(ptMax.y >= 0 && lHeight > ptMax.y) ptDiff.y -= (lHeight - ptMax.y); } return ptDiff.x == 0 && ptDiff.y == 0; } //------------------------------------------------------------------------------ // S_FALSE : We used up all remaining client area // E_INVALIDARG : *prcClient was empty, so we are hidden HRESULT CMarsPanel::Layout( RECT *prcClient ) { ATLASSERT(prcClient); ATLASSERT(!IsPassive()); RECT rcMyClient; HRESULT hr = S_OK; if (m_fVisible && !IsRectEmpty(prcClient)) { hr = GetRect(prcClient, &rcMyClient); // Optimize out the case that the rect is the same as we already have. This // is pretty common, and Windows doesn't optimize it out. RECT rcCurrent; GetMyClientRectInParentCoords(&rcCurrent); if(memcmp( &rcCurrent, &rcMyClient, sizeof(RECT) )) { m_Content.MoveWindow( &rcMyClient, TRUE ); } if (IsPopup()) { // Bring popup windows to top m_Content.SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE); } MakeVisible(VARIANT_TRUE, VARIANT_FALSE); } else { if (m_fVisible) { // We wanted to be visible but had no remaining client area hr = E_INVALIDARG; } MakeVisible(VARIANT_FALSE, VARIANT_FALSE); } return hr; } //------------------------------------------------------------------------------ // IPropertyNotifySink::OnChanged // STDMETHODIMP CMarsPanel::OnChanged(DISPID dispID) { if (DISPID_READYSTATE == dispID) { VARIANT vResult = {0}; EXCEPINFO excepInfo; UINT uArgErr; DISPPARAMS dp = {NULL, NULL, 0, 0}; CComPtr spDocument; if (SUCCEEDED(m_Content.QueryControl(IID_IHTMLDocument2, (void **)&spDocument)) && SUCCEEDED(spDocument->Invoke(DISPID_READYSTATE, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dp, &vResult, &excepInfo, &uArgErr))) { m_lReadyState = (READYSTATE)V_I4(&vResult); switch (m_lReadyState) { case READYSTATE_UNINITIALIZED: //= 0, break; case READYSTATE_LOADING: //= 1, break; case READYSTATE_LOADED: //= 2, break; case READYSTATE_INTERACTIVE: //= 3, break; case READYSTATE_COMPLETE: //= 4 if (IsAutoSizing()) { OnLayoutChange(); } m_spMarsDocument->GetPlaces()->OnPanelReady(); break; } } } return NOERROR; } //------------------------------------------------------------------------------ void CMarsPanel::ConnectCompletionAdviser() { if (!m_dwCookie) { CComPtr spICPC; if (SUCCEEDED(m_Content.QueryControl(IID_IConnectionPointContainer, (void **)&spICPC))) { CComPtr spCP; if (spICPC && SUCCEEDED(spICPC->FindConnectionPoint(IID_IPropertyNotifySink, &spCP))) { spCP->Advise((LPUNKNOWN)(IPropertyNotifySink*)this, &m_dwCookie); ATLASSERT(m_dwCookie); } } } } //------------------------------------------------------------------------------ void CMarsPanel::DisconnectCompletionAdviser() { if (m_dwCookie) { CComPtr spICPC; if (SUCCEEDED(m_Content.QueryControl(IID_IConnectionPointContainer, (void **)&spICPC))) { CComPtr spCP; if (spICPC && SUCCEEDED(spICPC->FindConnectionPoint(IID_IPropertyNotifySink, &spCP))) { spCP->Unadvise(m_dwCookie); m_dwCookie = 0; } } } } //------------------------------------------------------------------------------ // Given some content, we're going to compute its dimensions and use those. // void CMarsPanel::ComputeDimensionsOfContent(long *plWidth, long *plHeight) { ATLASSERT(plWidth && plHeight); ATLASSERT(!IsPassive()); *plWidth = -1; *plHeight = -1; if(!IsWebBrowser() && IsAutoSizing()) { CComPtr spDocument; if(SUCCEEDED(m_Content.QueryControl(IID_IHTMLDocument2, (void **)&spDocument))) { CComPtr spBody; if(spDocument) { spDocument->get_body( &spBody ); } BOOL fScrollBar = FALSE; BOOL fHeight = (m_Position == PANEL_BOTTOM) || (m_Position == PANEL_TOP ) || (m_Position == PANEL_POPUP ); BOOL fWidth = (m_Position == PANEL_LEFT ) || (m_Position == PANEL_RIGHT) || (m_Position == PANEL_POPUP); CComQIPtr spBody2(spBody); if(spBody2 && fHeight) { LONG lScrollHeight = 0; spBody2->get_scrollHeight( &lScrollHeight ); if(m_lMaxHeight >= 0 && lScrollHeight > m_lMaxHeight) { *plHeight = m_lMaxHeight; fScrollBar = TRUE; } else { *plHeight = lScrollHeight; } } if(spBody2 && fWidth) { LONG lScrollWidth = 0; spBody2->get_scrollWidth( &lScrollWidth ); if(m_lMaxWidth >= 0 && lScrollWidth > m_lMaxWidth) { *plWidth = m_lMaxWidth; fScrollBar = TRUE; } else { *plWidth = lScrollWidth; } } CComQIPtr spBody3(spBody); if(spBody3) { spBody3->put_scroll( CComBSTR( fScrollBar ? L"yes" : L"no" ) ); } } } } //------------------------------------------------------------------------------ // Given the remaining client rect that we are allowed to use, calculate our // own position in client coordinates, and return the remaining empty client // rectangle // // S_OK : Remaining client area // S_FALSE : No client area remaining HRESULT CMarsPanel::GetRect(RECT *prcClient, RECT *prcMyClient) { ATLASSERT(!IsPassive()); HRESULT hr = S_OK; if (!m_fVisible) { memset(prcMyClient, 0, sizeof(*prcMyClient)); return S_OK; } *prcMyClient = *prcClient; long lWidth = m_lWidth; long lHeight = m_lHeight; if (IsAutoSizing()) { long lMinWidth; long lMinHeight; ComputeDimensionsOfContent(&lMinWidth, &lMinHeight); if(lMinWidth > lWidth ) lWidth = lMinWidth; if(lMinHeight > lHeight) lHeight = lMinHeight; } if(m_lMinWidth >= 0 && lWidth < m_lMinWidth ) lWidth = m_lMinWidth; if(m_lMinHeight >= 0 && lHeight < m_lMinHeight) lHeight = m_lMinHeight; switch (m_Position) { case PANEL_POPUP: // Special case: we exist on top of the other panels. if (m_lX < 0) { prcMyClient->right = prcClient->right + 1 + m_lX; prcMyClient->left = prcMyClient->right - lWidth; } else { prcMyClient->left = prcClient->left + m_lX; prcMyClient->right = prcMyClient->left + lWidth; } if (m_lY < 0) { prcMyClient->bottom = prcClient->bottom + 1 + m_lY; prcMyClient->top = prcMyClient->bottom - lHeight; } else { prcMyClient->top = prcClient->top + m_lY; prcMyClient->bottom = prcMyClient->top + lHeight; } break; case PANEL_LEFT: prcClient->left = prcMyClient->right = prcClient->left + lWidth; if (prcClient->left > prcClient->right) { prcClient->left = prcMyClient->right = prcClient->right; hr = S_FALSE; } break; case PANEL_RIGHT: prcClient->right = prcMyClient->left = prcClient->right - lWidth; if (prcClient->right < prcClient->left) { prcClient->right = prcMyClient->left = prcClient->left; hr = S_FALSE; } break; case PANEL_TOP: prcClient->top = prcMyClient->bottom = prcClient->top + lHeight; if (prcClient->top > prcClient->bottom) { prcClient->top = prcMyClient->bottom = prcClient->bottom; hr = S_FALSE; } break; case PANEL_BOTTOM: prcClient->bottom = prcMyClient->top = prcClient->bottom - lHeight; if (prcClient->bottom < prcClient->top) { prcClient->bottom = prcMyClient->top = prcClient->top; hr = S_FALSE; } break; case PANEL_WINDOW: hr = S_FALSE; break; default: ATLASSERT(FALSE); // Invalid panel position. break; } return hr; } // ========================================================= // CBrowserEvents // ========================================================= CMarsPanel::CBrowserEvents::CBrowserEvents(CMarsPanel *pParent) : CMarsPanelSubObject(pParent) { ATLASSERT(m_dwCookie == 0); ATLASSERT(m_dwCookie2 == 0); } IMPLEMENT_ADDREF_RELEASE(CMarsPanel::CBrowserEvents); //------------------------------------------------------------------------------ void CMarsPanel::CBrowserEvents::Connect(IUnknown *punk, BOOL bConnect) { CComPtr spCpc; if (SUCCEEDED(punk->QueryInterface(IID_IConnectionPointContainer, (void **)&spCpc))) { CComPtr spCp; if (SUCCEEDED(spCpc->FindConnectionPoint(DIID_DWebBrowserEvents, &spCp))) { if (bConnect) { spCp->Advise(this, &m_dwCookie); } else if (m_dwCookie) { spCp->Unadvise(m_dwCookie); m_dwCookie = 0; } } spCp.Release(); if (SUCCEEDED(spCpc->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCp))) { if (bConnect) { spCp->Advise(this, &m_dwCookie2); } else if (m_dwCookie2) { spCp->Unadvise(m_dwCookie2); m_dwCookie2 = 0; } } } } //------------------------------------------------------------------------------ // IUnknown::QueryInterface // HRESULT CMarsPanel::CBrowserEvents::QueryInterface(REFIID iid, void **ppvObject) { HRESULT hr; if ((iid == IID_IUnknown) || (iid == IID_IDispatch)) { AddRef(); *ppvObject = SAFECAST(this, IDispatch *); hr = S_OK; } else { *ppvObject = NULL; hr = E_NOINTERFACE; } return hr; } //------------------------------------------------------------------------------ // IDispatch::Invoke // HRESULT CMarsPanel::CBrowserEvents::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { HRESULT hr = S_OK; if (VerifyNotPassive(&hr)) { switch (dispidMember) { case DISPID_BEFORENAVIGATE: case DISPID_FRAMEBEFORENAVIGATE: case DISPID_BEFORENAVIGATE2: { VARIANT *pVarCancel = &pdispparams->rgvarg[0]; if (pVarCancel->vt == (VT_BOOL | VT_BYREF)) { if (VARIANT_TRUE == *pVarCancel->pboolVal) { CComPtr spDoc2; GetDoc2FromAxWindow(&Parent()->m_Content, &spDoc2); if (spDoc2) { VARIANT vResult = {0}; EXCEPINFO excepInfo; UINT uArgErr; DISPPARAMS dp = {NULL, NULL, 0, 0}; if (SUCCEEDED(spDoc2->Invoke(DISPID_READYSTATE, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dp, &vResult, &excepInfo, &uArgErr))) { Parent()->m_lReadyState = (READYSTATE)V_I4(&vResult); } } } else { Parent()->m_lReadyState = READYSTATE_LOADING; } if (READYSTATE_COMPLETE == Parent()->m_lReadyState) { Parent()->m_spMarsDocument->GetPlaces()->OnPanelReady(); } } break; } case DISPID_DOCUMENTCOMPLETE: { Parent()->m_lReadyState = READYSTATE_COMPLETE; Parent()->m_spMarsDocument->GetPlaces()->OnPanelReady(); break; } } // switch(dispidMember) } return hr; } //------------------------------------------------------------------------------ STDMETHODIMP CMarsPanel::TranslateAccelerator(MSG *pMsg, DWORD grfModifiers) { HRESULT hr; ATLASSERT(!m_fTabCycle); if (IsVK_TABCycler(pMsg)) { m_fTabCycle = TRUE; hr = S_OK; } else { hr = S_FALSE; } return hr; } //------------------------------------------------------------------------------ STDMETHODIMP CMarsPanel::OnUIActivate() { ATLASSERT(!IsPassive()); m_spPanelCollection->SetActivePanel(this, TRUE); return S_OK; } //------------------------------------------------------------------------------ HRESULT CMarsPanel::UIDeactivate() { HRESULT hr; CComPtr spOleInPlaceObject; if (SUCCEEDED(m_Content.QueryControl(&spOleInPlaceObject))) { hr = spOleInPlaceObject->UIDeactivate(); } else { // What the heck else can we do? hr = S_FALSE; } return hr; } //------------------------------------------------------------------------------ // Forwards the message to the hosted control. void CMarsPanel::ForwardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { HWND hwnd; CComPtr spOleWindow; // Note that we send the message directly to the window rather than use // WM_FORWARDMSG which calls TranslateAccelerator if (SUCCEEDED(m_Content.QueryControl(&spOleWindow)) && SUCCEEDED(spOleWindow->GetWindow(&hwnd))) { SendMessage(hwnd, uMsg, wParam, lParam); } } //------------------------------------------------------------------------------ HRESULT CMarsPanel::TranslateAccelerator(MSG *pMsg) { ATLASSERT(!IsPassive()); HRESULT hr = S_FALSE; BOOL fGlobal = IsGlobalKeyMessage( pMsg ); if((S_OK == SHIsChildOrSelf(m_Content.m_hWnd, pMsg->hwnd)) || fGlobal) { if(m_spActiveObject && (this == m_spPanelCollection->ActivePanel())) { hr = m_spActiveObject->TranslateAccelerator(pMsg); } else { CComPtr obj; if(SUCCEEDED(m_Content.QueryControl( IID_IOleInPlaceActiveObject, (void **)&obj ))) { hr = obj->TranslateAccelerator(pMsg); } // // If it's a WebBrowser, forward the accelerator directly to the Document object, otherwise accesskeys won't be resolved. // if(hr == S_FALSE && fGlobal) { CComPtr obj2; if(SUCCEEDED(m_Content.QueryControl( IID_IWebBrowser2, (void **)&obj2 ))) { CComPtr disp; if(SUCCEEDED(obj2->get_Document( &disp )) && disp) { CComPtr obj3; if(SUCCEEDED(disp.QueryInterface( &obj3 ))) { hr = obj3->TranslateAccelerator(pMsg); } } } } } } return hr; } //---------------------------------------------------------------------------- // Returns the Screen coordinates of this panel //---------------------------------------------------------------------------- void CMarsPanel::GetMyClientRectInParentCoords(RECT *prc) { ATLASSERT(!IsPassive()); POINT ptParent = {0, 0}, ptMe = {0, 0}, ptOffset; m_Content.ClientToScreen(&ptMe); m_spMarsDocument->Window()->ClientToScreen(&ptParent); ptOffset.x = ptMe.x - ptParent.x; ptOffset.y = ptMe.y - ptParent.y; m_Content.GetClientRect(prc); OffsetRect(prc, ptOffset.x, ptOffset.y); } // IInternetSecurityManager // This interface is used to override default security settings for our panels. // These panels are trusted. //------------------------------------------------------------------------------ // IInternetSecurityManager::SetSecuritySite // HRESULT CMarsPanel::SetSecuritySite(IInternetSecurityMgrSite *pSite) { return E_NOTIMPL; } //------------------------------------------------------------------------------ // IInternetSecurityManager::GetSecuritySite // HRESULT CMarsPanel::GetSecuritySite(IInternetSecurityMgrSite **ppSite) { return E_NOTIMPL; } //------------------------------------------------------------------------------ // IInternetSecurityManager::MapUrlToZone // HRESULT CMarsPanel::MapUrlToZone(LPCWSTR pwszUrl, DWORD *pdwZone, DWORD dwFlags) { return INET_E_DEFAULT_ACTION; } //------------------------------------------------------------------------------ // IInternetSecurityManager::GetSecurityId // HRESULT CMarsPanel::GetSecurityId(LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved) { return INET_E_DEFAULT_ACTION; } //------------------------------------------------------------------------------ // IInternetSecurityManager::ProcessUrlAction // // Be as permissive as we can // HRESULT CMarsPanel::ProcessUrlAction(LPCWSTR pwszUrl, DWORD dwAction, BYTE __RPC_FAR *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved) { ATLASSERT(IsTrusted()); if (cbPolicy >= sizeof(DWORD)) { *((DWORD *)pPolicy) = URLPOLICY_ALLOW; } return S_OK; } //------------------------------------------------------------------------------ // IInternetSecurityManager::QueryCustomPolicy // // Be as permissive as we can // HRESULT CMarsPanel::QueryCustomPolicy(LPCWSTR pwszUrl, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwReserved) { ATLASSERT(IsTrusted()); ATLASSERT(ppPolicy && !*ppPolicy); ATLASSERT(pcbPolicy); if (ppPolicy && pcbPolicy) { *ppPolicy = (BYTE *)CoTaskMemAlloc(sizeof(DWORD)); if (*ppPolicy) { *pcbPolicy = sizeof(DWORD); *(DWORD *)*ppPolicy = URLPOLICY_ALLOW; return S_OK; } } return INET_E_DEFAULT_ACTION; } //------------------------------------------------------------------------------ // IInternetSecurityManager::SetZoneMapping // HRESULT CMarsPanel::SetZoneMapping(DWORD dwZone, LPCWSTR lpszPattern, DWORD dwFlags) { return INET_E_DEFAULT_ACTION; } //------------------------------------------------------------------------------ // IInternetSecurityManager::GetZoneMappings // HRESULT CMarsPanel::GetZoneMappings(DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags) { return INET_E_DEFAULT_ACTION; } //------------------------------------------------------------------------------ // OnDocHostUIExec // // When we get an Exec from Trident on CGID_DocHostCommandHandler, we can return S_OK // to indicate that we handled the command and Trident should take no further action // We'll delegate the processing to script by firing events // // TODO: once Mars accelerators are implemented, we should just block Trident from // taking action, and not fire any events. // HRESULT CMarsPanel::OnDocHostUIExec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { // HACK: Shdocvw/Trident sometimes tests specifically for a value like // OLECMDERR_E_NOTSUPPORTED and will not perform an essential action // if we return something more generic like E_FAIL. HRESULT hr = OLECMDERR_E_NOTSUPPORTED; if(!IsPassive() && pguidCmdGroup && (*pguidCmdGroup == CGID_DocHostCommandHandler)) { switch (nCmdID) { case OLECMDID_SHOWFIND: hr = S_OK; break; case IDM_NEW_TOPLEVELWINDOW: // Shdocvw gives us this command when Ctrl+N or the localized equivalent // is translated. We return S_OK to stop it from opening an IE window. hr = S_OK; break; case IDM_REFRESH: case IDM_REFRESH_TOP: case IDM_REFRESH_TOP_FULL: case IDM_REFRESH_THIS: case IDM_REFRESH_THIS_FULL: if(!m_fInRefresh) { hr = S_OK; } break; case OLECMDID_SHOWSCRIPTERROR: if(SUCCEEDED(m_spMarsDocument->MarsWindow()->NotifyHost( MARSHOST_ON_SCRIPT_ERROR, V_VT(pvarargIn) == VT_UNKNOWN ? V_UNKNOWN(pvarargIn) : NULL, 0 ))) { V_VT (pvarargOut) = VT_BOOL; V_BOOL(pvarargOut) = VARIANT_FALSE; hr = S_OK; } break; } } return hr; } // // CPanelCollection implementation // //------------------------------------------------------------------------------ CPanelCollection::CPanelCollection(CMarsDocument *pMarsDocument) { m_spMarsDocument = pMarsDocument; } //------------------------------------------------------------------------------ CPanelCollection::~CPanelCollection() { ATLASSERT(GetSize() == 0); FreePanels(); } //------------------------------------------------------------------------------ void CPanelCollection::FreePanels() { for (int i=0; iDoEnableModeless(fEnable); } return S_OK; } ////////////////////////////// // IMarsPanelCollection //------------------------------------------------------------------------------ // IMarsPanelCollection::get_panel // // TODO: (PaulNash, 9/19/99) This method is outdated. // Remove once content is switched over. // STDMETHODIMP CPanelCollection::get_panel(LPWSTR pwszName, IMarsPanel **ppPanel) { CComVariant var(pwszName); return get_item(var, ppPanel); } //------------------------------------------------------------------------------ // IMarsPanelCollection::addPanel // STDMETHODIMP CPanelCollection::addPanel( BSTR bstrName, VARIANT varType, BSTR bstrStartUrl, VARIANT varCreate, long lFlags, IMarsPanel **ppPanel) { HRESULT hr = E_INVALIDARG; if (API_IsValidString(bstrName) && (VT_NULL == varType.vt || API_IsValidVariantBstr(varType)) && (NULL == bstrStartUrl || API_IsValidString(bstrStartUrl)) && (VT_NULL == varCreate.vt || API_IsValidVariantBstr(varCreate)) && API_IsValidFlag(lFlags, PANEL_FLAG_ALL) && API_IsValidWritePtr(ppPanel) ) { *ppPanel = NULL; if (VerifyNotPassive(&hr)) { MarsAppDef_Panel Layout; BSTR bstrType = VariantToBSTR( varType ); BSTR bstrCreate = VariantToBSTR( varCreate ); DWORD dwFlags = DEFAULT_PANEL_FLAGS | (DWORD)lFlags; StringToPanelFlags( bstrType , dwFlags ); StringToPanelFlags( bstrCreate, dwFlags ); StringCchCopyW ( Layout.szName, ARRAYSIZE(Layout.szName), bstrName ); ExpandEnvironmentStringsW( bstrStartUrl , Layout.szUrl, ARRAYSIZE(Layout.szUrl ) ); Layout.dwFlags = dwFlags; AddPanel(&Layout, NULL); hr = get_item( CComVariant( bstrName ), ppPanel ); } } return hr; } //------------------------------------------------------------------------------ // IMarsPanelCollection::removePanel // STDMETHODIMP CPanelCollection::removePanel(LPWSTR pwszName) { HRESULT hr = E_INVALIDARG; if(API_IsValidString(pwszName)) { if(VerifyNotPassive(&hr)) { hr = S_FALSE; for(int i=0; iGetName())) { BOOL fVisible = (*this)[i]->IsVisible(); (*this)[i].PassivateAndRelease(); RemoveAt(i); if(fVisible) { Layout(); } hr = S_OK; break; } } } } return hr; } //------------------------------------------------------------------------------ // IMarsPanelCollection::lockLayout // STDMETHODIMP CPanelCollection::lockLayout() { HRESULT hr = S_OK; if (VerifyNotPassive(&hr)) { m_iLockLayout++; } return hr; } //------------------------------------------------------------------------------ // IMarsPanelCollection::unlockLayout // STDMETHODIMP CPanelCollection::unlockLayout() { HRESULT hr = S_OK; if (VerifyNotPassive(&hr)) { if (IsLayoutLocked()) { if (0 == --m_iLockLayout) { // TODO: clear lock timeout if (m_fPendingLayout) { m_fPendingLayout = FALSE; Layout(); } } } } return hr; } //------------------------------------------------------------------------------ void CPanelCollection::Layout() { if(!IsPassive()) { if(!IsLayoutLocked()) { RECT rcClient; lockLayout(); m_spMarsDocument->Window()->GetClientRect( &rcClient ); if(m_spMarsDocument->MarsWindow()->CanLayout( rcClient ) == false) { m_spMarsDocument->MarsWindow()->FixLayout( rcClient ); } m_fPendingLayout = FALSE; for (int i=0; iLayout( &rcClient )) { // We're out of client area; won't be able to show all panels. // Keep calling Layout for remaining panels so they can hide themselves. } } ATLASSERT(!m_fPendingLayout); unlockLayout(); } else { // We'll do the layout once we get unlocked m_fPendingLayout = TRUE; } } } //------------------------------------------------------------------------------ void CPanelCollection::SetActivePanel(CMarsPanel *pPanel, BOOL bActive) { if (bActive) { if (m_spActivePanel != pPanel) { if (m_spActivePanel) { m_spActivePanel->UIDeactivate(); m_spActivePanel.Release(); } m_spActivePanel = pPanel; } } else { // A panel is telling us it doesn't want to be the active // panel anymore. if (pPanel == m_spActivePanel) { m_spActivePanel->UIDeactivate(); m_spActivePanel.Release(); } } } //------------------------------------------------------------------------------ // IMarsPanelCollection::get_activePanel // STDMETHODIMP CPanelCollection::get_activePanel(IMarsPanel **ppPanel) { HRESULT hr = E_INVALIDARG; if (API_IsValidWritePtr(ppPanel)) { *ppPanel = NULL; if (VerifyNotPassive(&hr)) { hr = S_OK; *ppPanel = ActivePanel(); if (*ppPanel) { (*ppPanel)->AddRef(); } } } return hr; } //------------------------------------------------------------------------------ HRESULT CPanelCollection::AddPanel( MarsAppDef_Panel* pLayout, /*optional*/ IMarsPanel **ppPanel) { ATLASSERT(pLayout); ATLASSERT(!IsPassive()); HRESULT hr = E_FAIL; if (ppPanel) { *ppPanel = NULL; } // If it's a duplicate panel name, just fail. if (!FindPanel(pLayout->szName)) { CComClassPtr spPanel; spPanel.Attach(new CMarsPanel(this, m_spMarsDocument->MarsWindow())); if (spPanel) { if (Add(spPanel)) { spPanel->Create(pLayout); if (ppPanel) { hr = spPanel->QueryInterface(IID_IMarsPanel, (void **)ppPanel); } hr = S_OK; } else { hr = E_OUTOFMEMORY; } } else { hr = E_OUTOFMEMORY; } } return hr; } //------------------------------------------------------------------------------ CMarsPanel *CPanelCollection::FindPanel(LPCWSTR pwszName) { ATLASSERT(!IsPassive()); CMarsPanel *pPanel = NULL; int iLen = GetSize(); for (int i = 0; i < iLen; ++i) { if (!StrCmpIW(pwszName, (*this)[i]->GetName())) { pPanel = (*this)[i]; break; } } return pPanel; } //------------------------------------------------------------------------------ HRESULT CPanelCollection::FindPanelIndex(CMarsPanel *pPanel, long *plIndex) { ATLASSERT(plIndex); ATLASSERT(!IsPassive()); HRESULT hr = E_FAIL; *plIndex = -1; if (pPanel) { long lSize = GetSize(); for (long i = 0; i < lSize; ++i) { if (pPanel == (*this)[i]) { *plIndex = i; hr = S_OK; break; } } } return hr; } //------------------------------------------------------------------------------ HRESULT CPanelCollection::InsertPanelFromTo(long lOldIndex, long lNewIndex) { ATLASSERT((lOldIndex >= 0) && (lOldIndex < GetSize())); ATLASSERT(!IsPassive()); HRESULT hr = S_FALSE; if (lNewIndex < 0) { lNewIndex = 0; } if (lNewIndex > GetSize() - 1) { lNewIndex = GetSize() - 1; } // If this is something that is done very often, we should optimize this better // and probably not use an array if (lOldIndex != lNewIndex) { CComClassPtr spPanel = (*this)[lOldIndex]; RemoveAt(lOldIndex); InsertAt(lNewIndex, spPanel); hr = S_OK; } return hr; } //------------------------------------------------------------------------------ // Sets the dirty bit on all panels after a theme switch // void CPanelCollection::InvalidatePanels() { for (int i=0; i < GetSize(); i++) { (*this)[i]->put_contentInvalid(VARIANT_TRUE); } } //------------------------------------------------------------------------------ // Called after the theme switch event has fired, to refresh any panels // that are visible but still haven't been updated with the new theme // void CPanelCollection::RefreshInvalidVisiblePanels() { for (int i=0; i < GetSize(); i++) { CMarsPanel *pPanel = (*this)[i]; if (pPanel->IsVisible() && pPanel->IsContentInvalid()) { pPanel->refresh(); } } } //------------------------------------------------------------------------------ // IMarsPanelCollection::get_length // // standard collection method (gets instantaneous length of coll) // STDMETHODIMP CPanelCollection::get_length(LONG *plNumPanels) { HRESULT hr = E_INVALIDARG; if (API_IsValidWritePtr(plNumPanels)) { (*plNumPanels) = GetSize(); hr = S_OK; } return hr; } //------------------------------------------------------------------------------ // IMarsPanelCollection::get_item // // standard collection method (gets an theme given index or name) // STDMETHODIMP CPanelCollection::get_item(/*[in]*/ VARIANT varIndexOrName, /*[out, retval]*/ IMarsPanel **ppPanel) { ATLASSERT(VT_BSTR == varIndexOrName.vt || VT_I4 == varIndexOrName.vt); HRESULT hr = E_INVALIDARG; // // We can't use the API_IsValid varieties because they rip, and we actually don't want that. // It's only valid to RIP on IsValidFailure if only a single type is allowed, but here we // allow two types in the Variant, so we would only want to RIP if both are false (already // handled by above RIP). // if ((IsValidVariantI4(varIndexOrName) || IsValidVariantBstr(varIndexOrName)) && API_IsValidWritePtr(ppPanel)) { *ppPanel= NULL; if (VerifyNotPassive(&hr)) { CMarsPanel *pPanel = NULL; if (VT_BSTR == varIndexOrName.vt) { pPanel = FindPanel(V_BSTR(&varIndexOrName)); if (pPanel) { hr = pPanel->QueryInterface(IID_IMarsPanel, (void **)ppPanel); } else { hr = S_FALSE; } } else if (VT_I4 == varIndexOrName.vt) { long idxPanel = V_I4(&varIndexOrName); if (idxPanel >= 0 && idxPanel < GetSize()) { pPanel = (*this)[idxPanel]; if (pPanel) { hr = pPanel->QueryInterface(IID_IMarsPanel, (void **)ppPanel); } else { hr = S_FALSE; } } } else { // We only accept VT_BSTR and VT_I4 and we should have already // detected any other invalid params higher up in the function. ATLASSERT(false); } } } return hr; } // get_item //------------------------------------------------------------------------------ // IMarsPanelCollection::get__newEnum // standard collection method (gets a new IEnumVARIANT) // STDMETHODIMP CPanelCollection::get__newEnum(/*[out, retval]*/ IUnknown **ppEnumPanels) { HRESULT hr = E_INVALIDARG; if (API_IsValidWritePtr(ppEnumPanels)) { *ppEnumPanels = NULL; if (VerifyNotPassive(&hr)) { // This helper takes a CMarsSimpleArray and does all // the work of creating a CComEnum for us. Neat! hr = CMarsComEnumVariant< CMarsPanel >::CreateFromMarsSimpleArray(*this, ppEnumPanels); } } return hr; } // get__newEnum