|
|
// Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
// Notes on m_bfModeSwitched and m_bfReloadAttempted.
// IE5 bug 52818 was punted; pages containing IFrames don't refresh when changing
// browse/edit modes, because the stream is seen as dirty (because the IFrame
// considers itself dirty.) In response, we set m_bfModeSwitched when changing mode,
// m_bfReloadAttempted when and ATTEMPT is made to reload the page, and check for BOTH
// in OnReadyStateChanged. If the mode was changed but the page wasn't reloaded,
// we have to reload it manually.
#include "stdafx.h"
#include "DHTMLEd.h"
#include "DHTMLEdit.h"
#include "site.h"
#include "proxyframe.h"
#include <TRIEDIID.h>
#include <mshtmdid.h>
#include "dispexa.h"
#include <wchar.h>
#include <string.h>
// HTML to initialize Trident with if the host didn't supply any
// The <P> </P> works around a nasty Trident bug.
// Change: now there is one with paragraphs, one with DIVs.
//
static WCHAR* g_initialHTMLwithP = \ L"<HTML>\r\n\
<HEAD>\r\n\ <META NAME=\"GENERATOR\" Content=\"Microsoft DHTML Editing Control\">\r\n\
<TITLE></TITLE>\r\n\ </HEAD>\r\n\ <BODY>\r\n\ <P> </P>\r\n\ </BODY>\r\n\ </HTML>\r\n";
static WCHAR* g_initialHTMLwithDIV = \ L"<HTML>\r\n\
<HEAD>\r\n\ <META NAME=\"GENERATOR\" Content=\"Microsoft DHTML Editing Control\">\r\n\
<TITLE></TITLE>\r\n\ </HEAD>\r\n\ <BODY>\r\n\ <DIV> </DIV>\r\n\ </BODY>\r\n\ </HTML>\r\n";
// Text, numbers and constants used to construct a unique-per-process protocol ID
//
static WCHAR* g_wszProtocolPrefix = L"DHTMLEd"; static int s_iProtocolSuffix = 0; #define MAX_PROTOCOL_SUFFIX 999999
// Name of the Title property which we get from the IHtmlDocument2 interface.
static WCHAR* g_wszHTMLTitlePropName = L"title";
// Maps private DHTMLEdit command IDs to Triedit command IDs.
// The third field is true if the command includes an out parameter.
//
static CommandMap cmdMap[] = { {DECMD_BOLD, IDM_TRIED_BOLD, FALSE}, {DECMD_COPY, IDM_TRIED_COPY, FALSE}, {DECMD_CUT, IDM_TRIED_CUT, FALSE}, {DECMD_DELETE, IDM_TRIED_DELETE, FALSE}, {DECMD_DELETECELLS, IDM_TRIED_DELETECELLS, FALSE}, {DECMD_DELETECOLS, IDM_TRIED_DELETECOLS, FALSE}, {DECMD_DELETEROWS, IDM_TRIED_DELETEROWS, FALSE}, {DECMD_FINDTEXT, IDM_TRIED_FIND, FALSE}, {DECMD_FONT, IDM_TRIED_FONT, FALSE}, {DECMD_GETBACKCOLOR, IDM_TRIED_BACKCOLOR, TRUE}, {DECMD_GETBLOCKFMT, IDM_TRIED_BLOCKFMT, TRUE}, {DECMD_GETBLOCKFMTNAMES, IDM_TRIED_GETBLOCKFMTS, TRUE}, {DECMD_GETFONTNAME, IDM_TRIED_FONTNAME, TRUE}, {DECMD_GETFONTSIZE, IDM_TRIED_FONTSIZE, TRUE}, {DECMD_GETFORECOLOR, IDM_TRIED_FORECOLOR, TRUE}, {DECMD_HYPERLINK, IDM_TRIED_HYPERLINK, FALSE}, {DECMD_IMAGE, IDM_TRIED_IMAGE, FALSE}, {DECMD_INDENT, IDM_TRIED_INDENT, FALSE}, {DECMD_INSERTCELL, IDM_TRIED_INSERTCELL, FALSE}, {DECMD_INSERTCOL, IDM_TRIED_INSERTCOL, FALSE}, {DECMD_INSERTROW, IDM_TRIED_INSERTROW, FALSE}, {DECMD_INSERTTABLE, IDM_TRIED_INSERTTABLE, FALSE}, {DECMD_ITALIC, IDM_TRIED_ITALIC, FALSE}, {DECMD_JUSTIFYLEFT, IDM_TRIED_JUSTIFYLEFT, FALSE}, {DECMD_JUSTIFYRIGHT, IDM_TRIED_JUSTIFYRIGHT, FALSE}, {DECMD_JUSTIFYCENTER, IDM_TRIED_JUSTIFYCENTER, FALSE}, {DECMD_LOCK_ELEMENT, IDM_TRIED_LOCK_ELEMENT, FALSE}, {DECMD_MAKE_ABSOLUTE, IDM_TRIED_MAKE_ABSOLUTE, FALSE}, {DECMD_MERGECELLS, IDM_TRIED_MERGECELLS, FALSE}, {DECMD_ORDERLIST, IDM_TRIED_ORDERLIST, FALSE}, {DECMD_OUTDENT, IDM_TRIED_OUTDENT, FALSE}, {DECMD_PASTE, IDM_TRIED_PASTE, FALSE}, {DECMD_REDO, IDM_TRIED_REDO, FALSE}, {DECMD_REMOVEFORMAT, IDM_TRIED_REMOVEFORMAT, FALSE}, {DECMD_SELECTALL, IDM_TRIED_SELECTALL, FALSE}, {DECMD_SEND_BACKWARD, IDM_TRIED_SEND_BACKWARD, FALSE}, {DECMD_BRING_FORWARD, IDM_TRIED_SEND_FORWARD, FALSE}, {DECMD_SEND_BELOW_TEXT, IDM_TRIED_SEND_BEHIND_1D, FALSE}, {DECMD_BRING_ABOVE_TEXT, IDM_TRIED_SEND_FRONT_1D, FALSE}, {DECMD_SEND_TO_BACK, IDM_TRIED_SEND_TO_BACK, FALSE}, {DECMD_BRING_TO_FRONT, IDM_TRIED_SEND_TO_FRONT, FALSE}, {DECMD_SETBACKCOLOR, IDM_TRIED_BACKCOLOR, FALSE}, {DECMD_SETBLOCKFMT, IDM_TRIED_BLOCKFMT, FALSE}, {DECMD_SETFONTNAME, IDM_TRIED_FONTNAME, FALSE}, {DECMD_SETFONTSIZE, IDM_TRIED_FONTSIZE, FALSE}, {DECMD_SETFORECOLOR, IDM_TRIED_FORECOLOR, FALSE}, {DECMD_SPLITCELL, IDM_TRIED_SPLITCELL, FALSE}, {DECMD_UNDERLINE, IDM_TRIED_UNDERLINE, FALSE}, {DECMD_UNDO, IDM_TRIED_UNDO, FALSE}, {DECMD_UNLINK, IDM_TRIED_UNLINK, FALSE}, {DECMD_UNORDERLIST, IDM_TRIED_UNORDERLIST, FALSE}, {DECMD_PROPERTIES, IDM_TRIED_DOVERB, FALSE} };
CProxyFrame::CProxyFrame(CDHTMLSafe* pCtl) { SAFEARRAYBOUND rgsabound[1] = {0};
_ASSERTE(pCtl);
m_cRef = 1;
m_pUnkTriEdit = NULL; m_hWndObj = NULL; m_pIOleIPActiveObject = NULL; m_pSite = NULL; m_pCtl = pCtl;
m_fCreated = FALSE; m_fActivated = FALSE; m_state = ESTATE_NOTCREATED; m_readyState = READYSTATE_UNINITIALIZED; m_dwFilterFlags = m_dwFilterOutFlags = filterAll;
m_fActivateApplets = FALSE; m_fActivateControls = FALSE; m_fActivateDTCs = TRUE; m_fShowAllTags = FALSE; m_fShowBorders = FALSE;
m_fDialogEditing = TRUE; m_fDisplay3D = TRUE; m_fScrollbars = TRUE; m_fDisplayFlatScrollbars = FALSE; m_fContextMenu = TRUE;
m_fPreserveSource = TRUE;
m_fAbsoluteDropMode = FALSE; m_fSnapToGrid = FALSE; m_ulSnapToGridX = 50; m_ulSnapToGridY = 50;
rgsabound[0].lLbound = 0; rgsabound[0].cElements = 0;
m_pMenuStrings = NULL; m_pMenuStates = NULL;
m_vbBrowseMode = VARIANT_FALSE;
m_vbUseDivOnCr = VARIANT_FALSE; m_bfIsLoading = FALSE; m_bfBaseURLFromBASETag = FALSE; m_bfPreserveDirtyFlagAcrossBrowseMode = FALSE; m_bstrInitialDoc.Empty ();
m_bstrCurDocPath.Empty ();
wcscpy ( m_wszProtocol, g_wszProtocolPrefix ); WCHAR wszSuffix[8]; _itow ( s_iProtocolSuffix++, wszSuffix, 10 ); if ( MAX_PROTOCOL_SUFFIX <= s_iProtocolSuffix ) { s_iProtocolSuffix = 0; // Roll over.
} wcscat ( m_wszProtocol, wszSuffix ); wcscpy ( m_wszProtocolPrefix, m_wszProtocol ); wcscat ( m_wszProtocolPrefix, L":" );
m_pProtInfo = NULL; m_bfIsURL = FALSE; m_bstrBaseURL = L""; m_hwndRestoreFocus = NULL;
#ifdef LATE_BIND_URLMON_WININET
m_hUlrMon = NULL; m_hWinINet = NULL; m_pfnCoInternetCombineUrl = NULL; m_pfnCoInternetParseUrl = NULL; m_pfnCreateURLMoniker = NULL; m_pfnCoInternetGetSession = NULL; m_pfnURLOpenBlockingStream = NULL;
m_pfnDeleteUrlCacheEntry = NULL; m_pfnInternetCreateUrl = NULL; m_pfnInternetCrackUrl = NULL; #endif // LATE_BIND_URLMON_WININET
m_bfModeSwitched = FALSE; m_bfReloadAttempted = FALSE; m_bfSFSRedirect = FALSE; }
CProxyFrame::~CProxyFrame() { _ASSERTE(FALSE == m_fCreated); _ASSERTE(FALSE == m_fActivated); _ASSERTE( m_cRef == 0 );
if (m_pMenuStrings) { SafeArrayDestroy(m_pMenuStrings); m_pMenuStrings = NULL; }
if (m_pMenuStates) { SafeArrayDestroy(m_pMenuStates); m_pMenuStates = NULL; }
// This should never happen: SetActiveObject should take care of it.
_ASSERTE ( NULL == m_pIOleIPActiveObject ); if (m_pIOleIPActiveObject) { m_pIOleIPActiveObject->Release(); m_pIOleIPActiveObject = NULL; }
UnRegisterPluggableProtocol (); #ifdef LATE_BIND_URLMON_WININET
DynUnloadLibraries (); #endif // LATE_BIND_URLMON_WININET
}
// Create the TriEdit object and host it.
// Clean up and return an error if there was any problem.
//
HRESULT CProxyFrame::Init(IUnknown* pUnk, IUnknown** ppUnkTriEdit) { HRESULT hr = S_OK;
#ifdef LATE_BIND_URLMON_WININET
if ( ! DynLoadLibraries () ) { return E_FAIL; } #endif // LATE_BIND_URLMON_WININET
hr = RegisterPluggableProtocol (); if ( FAILED ( hr ) ) { return hr; }
_ASSERTE(NULL == m_pSite); _ASSERTE(GetState() == ESTATE_NOTCREATED);
InitializeDocString ();
if (m_pSite) return E_UNEXPECTED;
if (GetState() != ESTATE_NOTCREATED) return E_UNEXPECTED;
// Create and initialize the site for TriEdit
m_pSite = new CSite(this);
if (NULL == m_pSite) { return E_OUTOFMEMORY; }
m_pSite->AddRef(); // So we can free with Release
// Ask the site to create TriEdit
if (SUCCEEDED(hr = m_pSite->HrCreate(pUnk, &m_pUnkTriEdit))) { ChangeState(ESTATE_CREATED); m_fCreated = TRUE; if (ppUnkTriEdit) { m_pUnkTriEdit->AddRef(); *ppUnkTriEdit = m_pUnkTriEdit; } } else { m_pSite->Release(); m_pSite = NULL; }
return hr; }
// Destroy the site and the TriEdit object.
//
HRESULT CProxyFrame::Close() { HRESULT hr = S_OK;
_ASSERTE(m_pUnkTriEdit); _ASSERTE(m_pSite); _ASSERTE(GetState() != ESTATE_NOTCREATED);
m_bstrCurDocPath.Empty ();
// triedit must be created
// any state from created to activated is ok
if (GetState() == ESTATE_NOTCREATED) return E_UNEXPECTED;
if (m_fActivated) { hr = HrExecCommand(&CGID_MSHTML, IDM_STOP, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL); _ASSERTE(SUCCEEDED(hr)); }
ChangeState(ESTATE_NOTCREATED); m_fCreated = FALSE; m_fActivated = FALSE; if (m_pSite != NULL) { CSite* pSite = m_pSite; // prevents reentry;
m_pSite = NULL;
pSite->Close(FALSE); ReleaseInterface(pSite) pSite = NULL; }
if (m_pUnkTriEdit != NULL) { LPUNKNOWN pUnkTriEdit = m_pUnkTriEdit; m_pUnkTriEdit = NULL;
ReleaseInterface(pUnkTriEdit); pUnkTriEdit = NULL; }
m_hwndRestoreFocus = NULL;
return S_OK; }
// Determine which string constant to use and return a pointer to it.
//
WCHAR* CProxyFrame::GetInitialHTML () { if ( m_vbUseDivOnCr ) { return g_initialHTMLwithDIV; } else { return g_initialHTMLwithP; } }
// Perform these steps before loading TriEdit's contents
//
HRESULT CProxyFrame::PreActivate() { HRESULT hr = S_OK; _ASSERTE(m_pSite); _ASSERTE(m_pCtl);
_ASSERTE(ESTATE_CREATED == GetState());
if (GetState() != ESTATE_CREATED) return E_UNEXPECTED;
if (FAILED(hr = m_pSite->HrObjectInitialize())) { _ASSERTE(SUCCEEDED(hr)); goto error; }
m_fActivated = TRUE; ChangeState(ESTATE_PREACTIVATING);
if (FAILED(hr = HrSetRuntimeProperties())) { _ASSERTE(SUCCEEDED(hr)); goto error; }
ChangeState(ESTATE_ACTIVATING);
error:
return hr; }
void CProxyFrame::UIDeactivate() { // This was m_pSite->GetIPObject()->UIDeactivate(),
// but the QA teams VB app using this version of the control crashed
// with a NULL pointer dereference.
if ( NULL != m_pSite ) { LPOLEINPLACEOBJECT pipObj = m_pSite->GetIPObject(); if ( NULL != pipObj ) { pipObj->UIDeactivate(); } } }
// Perform these steps after loading TriEdits contents to go UI active.
//
HRESULT CProxyFrame::Activate() { HRESULT hr = S_OK;
_ASSERTE(m_pSite); _ASSERTE(m_pCtl); _ASSERTE(m_pCtl->m_hWndCD);
_ASSERTE(GetState() == ESTATE_ACTIVATING);
if (GetState() != ESTATE_ACTIVATING) return E_UNEXPECTED;
// UI-activate the control
if ( ! m_pCtl->m_bUIActive ) { // Used to be UIActivate, until MohanB fixed OnSetFocus and activation/deactivation linkage.
m_pCtl->DoVerbInPlaceActivate ( NULL, NULL ); }
// activate Trident with "Show"
m_pSite->InitialActivate(OLEIVERB_SHOW, m_pCtl->m_hWndCD);
ChangeState(ESTATE_ACTIVATED);
// This may have been deferred, because the site's command target did not yet exist...
SetBrowseMode ( m_vbBrowseMode );
return hr; }
// Load and activate the control with a minimal, empty page.
//
HRESULT CProxyFrame::LoadInitialDoc() { HRESULT hr = S_OK;
_ASSERTE(GetState() == ESTATE_CREATED);
if (GetState() != ESTATE_CREATED) return E_UNEXPECTED; if (FAILED(hr = PreActivate())) goto error;
if (FAILED(hr = LoadBSTRDeferred ( m_bstrInitialDoc ))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = Activate())) goto error;
error:
return hr; }
// Before getting or setting a property or calling a method on the docobject,
// assure that it's been properly activated.
//
void CProxyFrame::AssureActivated () { if ( ! m_fActivated ) { if ( m_pCtl->IsUserMode() ) { if ( !m_pCtl->m_bInPlaceActive ) { m_pCtl->DoVerbInPlaceActivate ( NULL, NULL ); } LoadInitialDoc (); } } }
// Loading MSHTML shifts the focus to its document window.
// This is not desirable in a control. Experimentation has demonstrated
// that the focus shifts between various QIs from MSHTML (probably in response
// to posted messages.) There is no routine in DHTMLEdit which enters with the
// focus outside the control and exits with the focus within the control.
// Therefore, a member variable is used to preserve the appropriate focus
// across calls to OnReadyStateChanged, which are called in response to events
// fired by the control. m_hwndRestoreFocus is used to preserve the appropriate
// window to receive the focus. Note that NULL may be appropriate, but is not honored.
// If no window had focus, the document will gain focus.
//
void CProxyFrame::OnReadyStateChanged(READYSTATE readyState) { _ASSERTE(m_pCtl);
m_readyState = readyState;
switch (m_readyState) { case READYSTATE_UNINITIALIZED: { m_hwndRestoreFocus = NULL; } break;
case READYSTATE_LOADING: { m_hwndRestoreFocus = ::GetFocus (); } break; case READYSTATE_LOADED: { } break;
case READYSTATE_INTERACTIVE: { if ( NULL != m_hwndRestoreFocus ) { _ASSERTE ( ::IsWindow ( m_hwndRestoreFocus ) ); if ( ::IsWindow ( m_hwndRestoreFocus ) ) { ::SetFocus ( m_hwndRestoreFocus ); } }
// See if we failed to get a refresh on a mode change. This happens if
// there are IFrames on the page, perhaps in other cases as well.
if ( m_bfModeSwitched && !m_bfReloadAttempted ) { HRESULT hr = S_OK;
CComPtr<IMoniker> srpMoniker; CComPtr<IBindCtx> srpBindCtx; CComQIPtr<IPersistMoniker, &IID_IPersistMoniker> srpPM (m_pUnkTriEdit); _ASSERTE ( srpPM );
if ( srpPM ) { CComBSTR bstrProtocol = m_wszProtocolPrefix;
#ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnCreateURLMoniker ); hr = (*m_pfnCreateURLMoniker)( NULL, bstrProtocol, &srpMoniker ); #else
hr = CreateURLMoniker ( NULL, bstrProtocol, &srpMoniker ); #endif // LATE_BIND_URLMON_WININET
_ASSERTE ( SUCCEEDED( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = ::CreateBindCtx(NULL, &srpBindCtx); _ASSERTE ( SUCCEEDED( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = srpPM->Load(FALSE, srpMoniker, srpBindCtx, STGM_READ); } } } } m_bfModeSwitched = FALSE; m_bfReloadAttempted = FALSE; } break;
case READYSTATE_COMPLETE: { HRESULT hr = S_OK;
m_hwndRestoreFocus = NULL; if ( ! m_vbBrowseMode ) { hr = HrSetDocLoadedProperties(); _ASSERTE(SUCCEEDED(hr)); }
_ASSERTE ( m_pCtl->m_hWnd ); _ASSERTE ( ::IsWindow ( m_pCtl->m_hWnd ) );
if ( m_bfPreserveDirtyFlagAcrossBrowseMode && !m_vbBrowseMode ) { m_bfPreserveDirtyFlagAcrossBrowseMode = FALSE; SetDirtyFlag ( TRUE ); } // Post a user message to fire the DocumentComplete event.
// Otherwise, calling things like LoadURL from DocumentComplete behaves strangely.
::PostMessage ( m_pCtl->m_hWnd, DOCUMENT_COMPETE_MESSAGE, DOCUMENT_COMPETE_SIGNATURE, 0L ); HrSetRuntimeProperties (); //m_bfIsLoading = FALSE; // This has been moved the the DOCUMENT_COMPETE_MESSAGE handler.
SetBaseURLFromBaseHref (); // Must be called after clearing m_bfIsLoading
} break; } }
/*
* IUnknown implementation */ /*
* CProxyFrame::QueryInterface * CProxyFrame::AddRef * CProxyFrame::Release */ STDMETHODIMP CProxyFrame::QueryInterface( REFIID riid, void **ppv ) { /*
* We provide IOleInPlaceFrame and IOleCommandTarget * interfaces here for the ActiveX Document hosting */ *ppv = NULL;
if ( IID_IUnknown == riid || IID_IOleInPlaceUIWindow == riid || IID_IOleWindow == riid || IID_IOleInPlaceFrame == riid ) { *ppv = static_cast<IOleInPlaceFrame *>(this); }
else if ( IID_IOleCommandTarget == riid ) { *ppv = static_cast<IOleCommandTarget *>(this); } else if ( IID_IBindStatusCallback == riid ) { *ppv = static_cast<IBindStatusCallback *>(this); } else if ( IID_IAuthenticate == riid ) { *ppv = static_cast<IAuthenticate *>(this); } else if ( IID_IServiceProvider == riid ) { // Ask the control for a security manager IF in edit mode:
if ( ! m_vbBrowseMode ) { return m_pCtl->GetUnknown()->QueryInterface ( riid, ppv ); } }
if ( NULL != *ppv ) { ((LPUNKNOWN)*ppv)->AddRef(); return S_OK; }
return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CProxyFrame::AddRef( void ) { return ++m_cRef; }
STDMETHODIMP_(ULONG) CProxyFrame::Release( void ) { //Nothing special happening here-- life if user-controlled.
// Debug check to see we don't fall below 0
_ASSERTE( m_cRef != 0 );
ULONG ulRefCount = --m_cRef; if ( 0 == ulRefCount ) { delete this; // Do not refer to any member variables after this.
} return ulRefCount; }
/*
* IOleInPlaceFrame implementation */ /*
* CProxyFrame::GetWindow * * Purpose: * Retrieves the handle of the window associated with the object * on which this interface is implemented. * * Parameters: * phWnd HWND * in which to store the window handle. * * Return Value: * HRESULT S_OK if successful, E_FAIL if there is no * window. */ STDMETHODIMP CProxyFrame::GetWindow( HWND* phWnd ) { if ( m_pCtl != NULL ) { *phWnd = m_pCtl->m_hWnd; } return S_OK; }
/*
* CProxyFrame::ContextSensitiveHelp * * Purpose: * Instructs the object on which this interface is implemented to * enter or leave a context-sensitive help mode. * * Parameters: * fEnterMode BOOL TRUE to enter the mode, FALSE otherwise. * * Return Value: * HRESULT S_OK */ STDMETHODIMP CProxyFrame::ContextSensitiveHelp( BOOL /*fEnterMode*/ ) { return S_OK; }
/*
* CProxyFrame::GetBorder * * Purpose: * Returns the rectangle in which the container is willing to * negotiate about an object's adornments. * * Parameters: * prcBorder LPRECT in which to store the rectangle. * * Return Value: * HRESULT S_OK if all is well, INPLACE_E_NOTOOLSPACE * if there is no negotiable space. */ STDMETHODIMP CProxyFrame::GetBorder( LPRECT prcBorder ) { if ( NULL == prcBorder ) { return E_INVALIDARG; }
//We return all the client area space
m_pCtl->GetClientRect( prcBorder ); return S_OK; }
/*
* CProxyFrame::RequestBorderSpace * * Purpose: * Asks the container if it can surrender the amount of space * in pBW that the object would like for it's adornments. The * container does nothing but validate the spaces on this call. * * Parameters: * pBW LPCBORDERWIDTHS containing the requested space. * The values are the amount of space requested * from each side of the relevant window. * * Return Value: * HRESULT S_OK if we can give up space, * INPLACE_E_NOTOOLSPACE otherwise. */ STDMETHODIMP CProxyFrame::RequestBorderSpace( LPCBORDERWIDTHS /*pBW*/ ) { // We have no border space restrictions
return S_OK; }
/*
* CProxyFrame::SetBorderSpace * * Purpose: * Called when the object now officially requests that the * container surrender border space it previously allowed * in RequestBorderSpace. The container should resize windows * appropriately to surrender this space. * * Parameters: * pBW LPCBORDERWIDTHS containing the amount of space * from each side of the relevant window that the * object is now reserving. * * Return Value: * HRESULT S_OK */ STDMETHODIMP CProxyFrame::SetBorderSpace( LPCBORDERWIDTHS /*pBW*/ ) { // We turn off the MSHTML.DLL UI so we ignore all of this.
return S_OK; }
/*
* CProxyFrame::SetActiveObject * * Purpose: * Provides the container with the object's IOleInPlaceActiveObject * pointer * * Parameters: * pIIPActiveObj LPOLEINPLACEACTIVEOBJECT of interest. * pszObj LPCOLESTR naming the object. Not used. * * Return Value: * HRESULT S_OK */ STDMETHODIMP CProxyFrame::SetActiveObject( LPOLEINPLACEACTIVEOBJECT pIIPActiveObj, LPCOLESTR /*pszObj*/) { // If we already have an active Object then release it.
if ( NULL != m_pIOleIPActiveObject ) { m_pIOleIPActiveObject->Release(); }
//NULLs m_pIOleIPActiveObject if pIIPActiveObj is NULL
m_pIOleIPActiveObject = pIIPActiveObj;
if ( NULL != m_pIOleIPActiveObject ) { m_pIOleIPActiveObject->AddRef(); m_pIOleIPActiveObject->GetWindow( &m_hWndObj ); } return S_OK; }
/*
* CProxyFrame::InsertMenus * * Purpose: * Instructs the container to place its in-place menu items where * necessary in the given menu and to fill in elements 0, 2, and 4 * of the OLEMENUGROUPWIDTHS array to indicate how many top-level * items are in each group. * * Parameters: * hMenu HMENU in which to add popups. * pMGW LPOLEMENUGROUPWIDTHS in which to store the * width of each container menu group. * * Return Value: * HRESULT E_NOTIMPL */ STDMETHODIMP CProxyFrame::InsertMenus( HMENU /*hMenu*/, LPOLEMENUGROUPWIDTHS /*pMGW*/ ) { // We've turned off the MSHTML.DLL Menus so we don't expect any merging to go on!
return E_NOTIMPL; }
/*
* CProxyFrame::SetMenu * * Purpose: * Instructs the container to replace whatever menu it's currently * using with the given menu and to call OleSetMenuDescritor so OLE * knows to whom to dispatch messages. * * Parameters: * hMenu HMENU to show. * hOLEMenu HOLEMENU to the menu descriptor. * hWndObj HWND of the active object to which messages are * dispatched. * * Return Value: * HRESULT NOERROR */ STDMETHODIMP CProxyFrame::SetMenu( HMENU /*hMenu*/, HOLEMENU /*hOLEMenu*/, HWND /*hWndObj*/ ) { // We've turned off the MSHTML.DLL Menus so we don't expect any merging to go on!
return E_NOTIMPL; }
/*
* CProxyFrame::RemoveMenus * * Purpose: * Asks the container to remove any menus it put into hMenu in * InsertMenus. * * Parameters: * hMenu HMENU from which to remove the container's * items. * * Return Value: * HRESULT NOERROR */ STDMETHODIMP CProxyFrame::RemoveMenus( HMENU /*hMenu*/ ) { // We've turned off the MSHTML.DLL Menus so we don't expect any merging to go on!
return E_NOTIMPL; }
/*
* CProxyFrame::SetStatusText * * Purpose: * Asks the container to place some text in a status line, if one * exists. If the container does not have a status line it * should return E_FAIL here in which case the object could * display its own. * * Parameters: * pszText LPCOLESTR to display. * * Return Value: * HRESULT S_OK if successful, S_TRUNCATED if not all * of the text could be displayed, or E_FAIL if * the container has no status line. */ STDMETHODIMP CProxyFrame::SetStatusText( LPCOLESTR /*pszText*/ ) { return S_OK; }
/*
* CProxyFrame::EnableModeless * * Purpose: * Instructs the container to show or hide any modeless popup * windows that it may be using. * * Parameters: * fEnable BOOL indicating to enable/show the windows * (TRUE) or to hide them (FALSE). * * Return Value: * HRESULT S_OK */
STDMETHODIMP CProxyFrame::EnableModeless( BOOL /*fEnable*/ ) { return S_OK; }
/*
* CProxyFrame::TranslateAccelerator * * Purpose: * When dealing with an in-place object from an EXE server, this * is called to give the container a chance to process accelerators * after the server has looked at the message. * * Parameters: * pMSG LPMSG for the container to examine. * wID WORD the identifier in the container's * accelerator table (from IOleInPlaceSite * ::GetWindowContext) for this message (OLE does * some translation before calling). * * Return Value: * HRESULT NOERROR if the keystroke was used, * S_FALSE otherwise. */ STDMETHODIMP CProxyFrame::TranslateAccelerator( LPMSG /*pMSG*/, WORD /*wID*/ ) { return S_FALSE; }
/*
* IOleCommandTarget::QueryStatus */ STDMETHODIMP CProxyFrame::QueryStatus( const GUID* pguidCmdGroup, ULONG cCmds, OLECMD* prgCmds, OLECMDTEXT* pCmdText ) { if ( pguidCmdGroup != NULL ) { // It's a nonstandard group!!
return OLECMDERR_E_UNKNOWNGROUP; }
MSOCMD* pCmd; INT c; HRESULT hr = S_OK;
// By default command text is NOT SUPPORTED.
if ( pCmdText && ( pCmdText->cmdtextf != OLECMDTEXTF_NONE ) ) { pCmdText->cwActual = 0; }
// Loop through each command in the array, setting the status of each.
for ( pCmd = prgCmds, c = cCmds; --c >= 0; pCmd++ ) { // By default command status is NOT SUPPORTED.
pCmd->cmdf = 0;
switch ( pCmd->cmdID ) { case OLECMDID_UPDATECOMMANDS: pCmd->cmdf = OLECMDF_SUPPORTED; break;
case OLECMDID_NEW: case OLECMDID_OPEN: case OLECMDID_SAVE: pCmd->cmdf = (MSOCMDF_SUPPORTED | MSOCMDF_ENABLED); break; } }
return (hr); }
/*
* IOleCommandTarget::Exec */
STDMETHODIMP CProxyFrame::Exec( const GUID* pguidCmdGroup, DWORD nCmdID, DWORD /*nCmdexecopt*/, VARIANTARG* /*pvaIn*/, VARIANTARG* /*pvaOut*/ ) { HRESULT hr = S_OK;
if ( pguidCmdGroup == NULL ) { switch (nCmdID) {
case OLECMDID_UPDATECOMMANDS: { // Fires event to container.
m_pCtl->Fire_DisplayChanged(); hr = S_OK; } break;
default: hr = OLECMDERR_E_NOTSUPPORTED; break; } } else { hr = OLECMDERR_E_UNKNOWNGROUP; } return (hr); }
// Connector from control to site.
//
void CProxyFrame::UpdateObjectRects() { _ASSERTE ( m_pSite ); if ( NULL != m_pSite ) { m_pSite->UpdateObjectRects(); } }
// Called from the control's TranslateAccelerator.
// Try our own (VID-like) acclerators first, and if not handled pass them along to TriEdit.
//
HRESULT CProxyFrame::HrTranslateAccelerator(LPMSG lpmsg) { HRESULT hr = S_OK;
if (NULL != m_pIOleIPActiveObject) { _ASSERTE(lpmsg);
hr = HrHandleAccelerator(lpmsg);
if (hr != S_OK) { _ASSERTE(SUCCEEDED(hr)); hr = m_pIOleIPActiveObject->TranslateAccelerator(lpmsg); } }
return hr; }
// A lot of time was lost here in scenarios like clicking on/tabbing to a control
// embedded in a VB OCX, tabbing to a control on a page, etc.
// Exercise great caution and perform a lot of testing if this is changed.
//
LRESULT CProxyFrame::OnSetFocus(UINT /*nMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if ( ! m_pCtl->m_bUIActive ) { m_pCtl->DoVerbUIActivate ( NULL, NULL ); }
// Give the focus to the ActiveX Document window
if ( m_hWndObj != NULL ) { ::SetFocus( m_hWndObj ); bHandled = TRUE; }
// activate Trident with "Show"
m_pSite->Activate(OLEIVERB_SHOW);
return 0; }
// Sets the Trident window's parent correctly when created and destroyed.
//
void CProxyFrame::SetParent ( HWND hwndParent ) { // This may be called before the control has been drawn.
if ( NULL != m_hWndObj ) { if( hwndParent ) { HWND hwndOldParent = ::SetParent ( m_hWndObj, hwndParent ); if ( NULL == hwndOldParent ) { DWORD dwErr = 0; dwErr = GetLastError (); } _ASSERTE ( m_pSite ); m_pSite->SetWindow ( hwndParent ); } } }
// Handles WM_SHOWWINDOW messages directed to the control.
//
void CProxyFrame::Show ( WPARAM nCmdShow ) { // This may be called before the control has been drawn.
// Hide or show the hosted Trident
if ( NULL != m_hWndObj ) { ::ShowWindow ( m_hWndObj, (int)nCmdShow ); } }
///////////////////////////////////////////////////////////////////////////////////////////
//
// ExecCommand mechanism
//
///////////////////////////////////////////////////////////////////////////////////////////
// Convert a command ID into a TriEdit command ID.
// Some commands used to represent other command groups as well, thus the ppguidCmdGroup parameter.
// While this does little now, it may be useful again in the future.
//
HRESULT CProxyFrame::HrMapCommand(DHTMLEDITCMDID typeLibCmdID, ULONG* cmdID, const GUID** ppguidCmdGroup, BOOL* pbOutParam) {
_ASSERTE(cmdID); _ASSERTE(ppguidCmdGroup); _ASSERTE(pbOutParam);
*cmdID = 0; *ppguidCmdGroup = NULL; *pbOutParam = FALSE;
for (UINT i=0; i < sizeof(cmdMap)/sizeof(CommandMap); ++i) { if (typeLibCmdID == cmdMap[i].typeLibCmdID) { *cmdID = cmdMap[i].cmdID; *ppguidCmdGroup = &GUID_TriEditCommandGroup; *pbOutParam = cmdMap[i].bOutParam;
return S_OK; } }
return OLECMDERR_E_NOTSUPPORTED ; }
// Helper routine for calling Exec.
//
HRESULT CProxyFrame::HrExecCommand(const GUID* pguidCmdGroup, ULONG ucmdID, OLECMDEXECOPT cmdexecopt, VARIANT* pVarIn, VARIANT* pVarOut) { HRESULT hr = E_FAIL; LPOLECOMMANDTARGET pCommandTarget = NULL;
// note that it is valid for pguidCmdGroup to be NULL
_ASSERTE(m_pSite);
if (NULL == m_pSite) return E_UNEXPECTED;
pCommandTarget = m_pSite->GetCommandTarget();
_ASSERTE(pCommandTarget);
if (pCommandTarget != NULL) { hr = pCommandTarget->Exec(pguidCmdGroup, ucmdID, cmdexecopt, pVarIn, pVarOut); }
return hr; }
// Main command dispatcher; called from the control's ExecCommand method.
// Handle our unique commands here, pass the rest onto HrExecGenericCommands.
//
HRESULT CProxyFrame::HrMapExecCommand(DHTMLEDITCMDID deCommand, OLECMDEXECOPT cmdexecopt, VARIANT* pVarInput, VARIANT* pVarOutput) { HRESULT hr = S_OK; LPOLECOMMANDTARGET pCmdTgt = NULL; ULONG ulMappedCommand = 0; const GUID* pguidCmdGroup = NULL; BOOL bOutParam = FALSE;
if (FALSE == m_fActivated) return E_UNEXPECTED;
_ASSERTE(m_pSite); if (NULL == m_pSite) return E_UNEXPECTED;
pCmdTgt = m_pSite->GetCommandTarget(); _ASSERTE(pCmdTgt);
if (NULL == pCmdTgt) return E_UNEXPECTED;
// Its valid for pVarInput to be NULL
if (FAILED(hr = HrMapCommand(deCommand, &ulMappedCommand, &pguidCmdGroup, &bOutParam))) return hr;
AssureActivated();
switch ( deCommand ) { case DECMD_GETBLOCKFMTNAMES: hr = HrExecGetBlockFmtNames(pVarInput); break;
case DECMD_INSERTTABLE: hr = HrExecInsertTable(pVarInput); break;
case DECMD_GETFORECOLOR: case DECMD_GETBACKCOLOR: hr = HrExecGetColor(deCommand, ulMappedCommand, pVarOutput); break;
case DECMD_SETFONTSIZE: hr = HrExecSetFontSize(pVarInput); break;
case DECMD_GETBLOCKFMT: // Trident inconsistancy: GetBlockFmt fails if outparam isn't a BSTR. GetFontName is OK with VT_EMPTY
VariantChangeType ( pVarOutput, pVarOutput, 0, VT_BSTR ); // Fall through; do not break!
case DECMD_GETFONTNAME: case DECMD_GETFONTSIZE: hr = HrExecGenericCommands(pguidCmdGroup, ulMappedCommand, cmdexecopt, pVarOutput, TRUE ); break;
// Because our QueryStatus on DECMD_PROPERTIES returns TRUE for anything with IOleObject, executing the properties
// verb can return an unexpected error. Therefore, we ALWAYS return S_OK from this command to avoid causing VB and
// script to terminate.
case DECMD_PROPERTIES: { CComVariant varParam; varParam.vt = VT_I4; varParam.lVal = OLEIVERB_PROPERTIES; hr = HrExecGenericCommands(pguidCmdGroup, ulMappedCommand, cmdexecopt, &varParam, FALSE ); hr = S_OK; } break;
default: hr = HrExecGenericCommands(pguidCmdGroup, ulMappedCommand, cmdexecopt, pVarInput, bOutParam); break; }
if (FAILED(hr)) { if (DISP_E_BADVARTYPE == hr || DISP_E_MEMBERNOTFOUND == hr) { // Map these Trident errors to something more general.
// These errors can occur if Trident expected the element
// it was trying to operate on to support certain interfaces.
// The caller was trying to perform an operation not valid
// for the current selection. Probably didn't call QueryStatus
// first.
hr = OLECMDERR_E_NOTSUPPORTED; } }
return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// ExecCommand handler implementations
//
///////////////////////////////////////////////////////////////////////////////////////////
// Helper routine for calling Exec and dealing with results.
//
HRESULT CProxyFrame::HrExecGenericCommands(const GUID* pguidCmdGroup, ULONG cmdID, OLECMDEXECOPT cmdexecopt, LPVARIANT pVarInput, BOOL bOutParam) { HRESULT hr = S_OK; LPOLECOMMANDTARGET pCmdTgt = NULL; LPVARIANT _pVar = NULL; VARIANT varCopy;
pCmdTgt = m_pSite->GetCommandTarget();
if (pVarInput && V_VT(pVarInput) & VT_BYREF) { // convert VARIANTARGs to Variant for use by Trident
// this occurs in VB if the user specified a basic type
// as an arg, i.e., String or Long, instead of Variant
VariantInit(&varCopy); if (FAILED(hr = VariantCopyInd(&varCopy, pVarInput))) { _ASSERTE(SUCCEEDED(hr)); return hr; }
_pVar = &varCopy; } else if (pVarInput) _pVar = pVarInput;
if (bOutParam) { hr = pCmdTgt->Exec(pguidCmdGroup, cmdID, cmdexecopt, NULL, _pVar); } else { hr = pCmdTgt->Exec(pguidCmdGroup, cmdID, cmdexecopt, _pVar, NULL); }
if (FAILED(hr)) goto cleanup;
// if a VARIANTARG was passed in for a command with output then
// fill it in with the result from the Exec
if (bOutParam && pVarInput && (V_VT(pVarInput) & VT_BYREF)) { _ASSERTE(_pVar); // _pVar should always be non NULL here
// if there was an input arg that was byref,
// then it should have been mapped to _pVar
if (NULL == _pVar) return E_UNEXPECTED; // the catch all error return for "we are in a weird state"
// if the type of return is different that the type the caller
// passed in then do nothing and return
if (V_VT(_pVar) != (V_VT(pVarInput) ^ VT_BYREF)) return hr;
switch(V_VT(_pVar)) { case VT_BSTR: _ASSERTE(V_VT(pVarInput) == (VT_BSTR|VT_BYREF));
if (V_BSTRREF(pVarInput)) hr = SysReAllocString(V_BSTRREF(pVarInput), V_BSTR(_pVar)); break;
case VT_BOOL: _ASSERTE(V_VT(pVarInput) == (VT_BOOL|VT_BYREF));
if (V_BOOLREF(pVarInput)) *(V_BOOLREF(pVarInput)) = V_BOOL(_pVar); break;
case VT_I4: _ASSERTE(V_VT(pVarInput) == (VT_I4|VT_BYREF));
if (V_I4REF(pVarInput)) *(V_I4REF(pVarInput)) = V_I4(_pVar); break;
default: _ASSERTE(0); break; } }
cleanup: // Our documentation replaces E_FAIL with DE_E_UNEXPECTED: different values.
if ( E_FAIL == hr ) { hr = DE_E_UNEXPECTED; }
return hr; }
// Handler for command DECMD_GETBLOCKFMTNAMES.
// There are plenty of possible types of arrays to be handled.
//
HRESULT CProxyFrame::HrExecGetBlockFmtNames(LPVARIANT pVarInput) { HRESULT hr = S_OK; LPOLECOMMANDTARGET pCmdTgt = NULL; VARIANT varArray; LPUNKNOWN pUnk = NULL; CComPtr<IDEGetBlockFmtNamesParam> piNamesParam;
pCmdTgt = m_pSite->GetCommandTarget();
if (NULL == pVarInput) return E_INVALIDARG;
if (V_VT(pVarInput) == (VT_BYREF|VT_DISPATCH)) { if (V_DISPATCHREF(pVarInput)) pUnk = *(V_DISPATCHREF(pVarInput)); else return E_INVALIDARG; } else if (V_VT(pVarInput) == VT_DISPATCH) { if (V_DISPATCH(pVarInput)) pUnk = V_DISPATCH(pVarInput); else return E_INVALIDARG; } else if (V_VT(pVarInput) == (VT_BYREF|VT_UNKNOWN)) { if (V_UNKNOWNREF(pVarInput)) pUnk = *(V_UNKNOWNREF(pVarInput)); else return E_INVALIDARG; } else if (V_VT(pVarInput) == VT_UNKNOWN) { if (V_UNKNOWN(pVarInput)) pUnk = V_UNKNOWN(pVarInput); else return E_INVALIDARG; } else return E_INVALIDARG;
// This can happen in VB if an object that has not
// been set with CreateObject has been passed in
if (NULL == pUnk) return E_INVALIDARG;
// Try to get the names object before
// performing the command
if (FAILED(hr = pUnk->QueryInterface(IID_IDEGetBlockFmtNamesParam, (LPVOID*) &piNamesParam))) return E_INVALIDARG;
_ASSERTE((!piNamesParam) == FALSE);
// Trident wants the vt to be specifically VT_ARRAY with
// no type qualifer -- if you give one it fails even though
// an array of BSTRs is returned
VariantInit(&varArray); V_VT(&varArray) = VT_ARRAY;
hr = pCmdTgt->Exec(&GUID_TriEditCommandGroup, IDM_TRIED_GETBLOCKFMTS, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, &varArray);
if (FAILED(hr)) goto cleanup;
piNamesParam->put_Names(&varArray);
cleanup:
return hr; }
// Handler for command DECMD_INSERTTABLE.
//
HRESULT CProxyFrame::HrExecInsertTable(LPVARIANT pVarInput) { HRESULT hr = S_OK; LPOLECOMMANDTARGET pCmdTgt = NULL; VARIANT varTableArray; LPUNKNOWN pUnk = NULL; CComPtr<IDEInsertTableParam> piTableParam;
pCmdTgt = m_pSite->GetCommandTarget();
VariantInit(&varTableArray);
if (NULL == pVarInput) return E_INVALIDARG;
if (V_VT(pVarInput) == (VT_BYREF|VT_DISPATCH)) { if (V_DISPATCHREF(pVarInput)) pUnk = *(V_DISPATCHREF(pVarInput)); else return E_INVALIDARG; } else if (V_VT(pVarInput) == VT_DISPATCH) { if (V_DISPATCH(pVarInput)) pUnk = V_DISPATCH(pVarInput); else return E_INVALIDARG; } else if (V_VT(pVarInput) == (VT_BYREF|VT_UNKNOWN)) { if (V_UNKNOWNREF(pVarInput)) pUnk = *(V_UNKNOWNREF(pVarInput)); else return E_INVALIDARG; } else if (V_VT(pVarInput) == VT_UNKNOWN) { if (V_UNKNOWN(pVarInput)) pUnk = V_UNKNOWN(pVarInput); else return E_INVALIDARG; } else return E_INVALIDARG;
// This can happen in VB if an object that has not
// been set with CreateObject has been passed in
if (NULL == pUnk) return E_INVALIDARG;
if (FAILED(hr = pUnk->QueryInterface(IID_IDEInsertTableParam, (LPVOID*) &piTableParam))) return E_INVALIDARG;
_ASSERTE((!piTableParam) == FALSE);
if (FAILED(hr = HrGetTableSafeArray(piTableParam, &varTableArray))) { _ASSERTE(SUCCEEDED(hr)); return hr; }
hr = pCmdTgt->Exec(&GUID_TriEditCommandGroup, IDM_TRIED_INSERTTABLE, MSOCMDEXECOPT_DONTPROMPTUSER, &varTableArray, NULL);
return hr; }
// Hanlder for commands DECMD_GETFORECOLOR and DECMD_GETBACKCOLOR.
// Reply with a string in the format #RRGGBB or an empty string.
//
HRESULT CProxyFrame::HrExecGetColor(DHTMLEDITCMDID deCommand, ULONG ulMappedCommand, LPVARIANT pVarOutput) { USES_CONVERSION; HRESULT hr = S_OK; LPOLECOMMANDTARGET pCmdTgt = NULL; VARIANT varColorOut; TCHAR buf[32]; WCHAR* oleStr = NULL;
pCmdTgt = m_pSite->GetCommandTarget();
if (NULL == pVarOutput) return E_INVALIDARG;
// validate the command
if (DECMD_GETFORECOLOR != deCommand && DECMD_GETBACKCOLOR != deCommand) return E_INVALIDARG;
// validate the args
if (V_VT(pVarOutput) == (VT_BYREF|VT_BSTR)) { if (NULL == V_BSTRREF(pVarOutput)) return E_INVALIDARG; } else if (V_VT(pVarOutput) == VT_BSTR) { if (NULL == V_BSTR(pVarOutput)) return E_INVALIDARG; } else if (V_VT(pVarOutput) != (VT_EMPTY) && V_VT(pVarOutput) != (VT_NULL)) return E_INVALIDARG;
VariantInit(&varColorOut); V_VT(&varColorOut) = VT_I4;
hr = pCmdTgt->Exec(&GUID_TriEditCommandGroup, ulMappedCommand, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, &varColorOut);
// Trident will return VT_NULL if color selection
// was mixed or no text is selected, we return empty
// string ("") in that case.
buf[0] = 0;
if (VT_I4 == V_VT(&varColorOut)) { ULONG ulColor = 0; ULONG r=0; ULONG g=0; ULONG b=0;
ulColor = V_I4(&varColorOut); r = 0x000000ff & ulColor; g = (0x0000ff00 & ulColor) >> 8; b = (0x00ff0000 & ulColor) >> 16;
wsprintf(buf, TEXT("#%02X%02X%02X"), r, g, b); } oleStr = T2OLE(buf);
if (V_VT(pVarOutput) == (VT_BSTR|VT_BYREF)) hr = SysReAllocString(V_BSTRREF(pVarOutput), oleStr); else if (V_VT(pVarOutput) == (VT_BSTR)) hr = SysReAllocString(&(V_BSTR(pVarOutput)), oleStr); else if (V_VT(pVarOutput) == (VT_EMPTY) || V_VT(pVarOutput) == (VT_NULL)) { V_VT(pVarOutput) = VT_BSTR; V_BSTR(pVarOutput) = SysAllocString(oleStr); }
return hr; }
// Handler for command DECMD_SETFONTSIZE.
//
HRESULT CProxyFrame::HrExecSetFontSize(LPVARIANT pVarInput) { HRESULT hr = S_OK; LPOLECOMMANDTARGET pCmdTgt = NULL; VARIANT varSizeIn;
pCmdTgt = m_pSite->GetCommandTarget();
if (NULL == pVarInput) return E_INVALIDARG;
VariantInit(&varSizeIn);
if (FAILED(hr = VariantChangeType(&varSizeIn, pVarInput, 0, VT_I4))) return E_INVALIDARG;
if (varSizeIn.lVal < 0 || varSizeIn.lVal > 7) return E_INVALIDARG;
if (0 == varSizeIn.lVal) varSizeIn.lVal = varSizeIn.lVal + 1;
hr = pCmdTgt->Exec(&GUID_TriEditCommandGroup, IDM_TRIED_FONTSIZE, MSOCMDEXECOPT_DONTPROMPTUSER, &varSizeIn, NULL);
return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// QueryStatus mechanism
//
///////////////////////////////////////////////////////////////////////////////////////////
// Map the control specific command ID to a TriEdit command ID and call QueryStatus.
//
HRESULT CProxyFrame::HrMapQueryStatus( DHTMLEDITCMDID ucmdID, DHTMLEDITCMDF* cmdf) { LPOLECOMMANDTARGET pCommandTarget = NULL;
_ASSERTE(cmdf);
HRESULT hr = E_FAIL;
if (FALSE == m_fActivated) return E_UNEXPECTED;
if (NULL == cmdf) return E_INVALIDARG;
*cmdf = (DHTMLEDITCMDF) 0;
_ASSERTE(m_pSite);
if (NULL == m_pSite) return E_UNEXPECTED;
pCommandTarget = m_pSite->GetCommandTarget(); _ASSERTE(pCommandTarget);
if ( pCommandTarget != NULL ) {
AssureActivated ();
ULONG cmdID = 0; const GUID* pguidCmdGroup = NULL; BOOL bOutParam = FALSE;
if (SUCCEEDED(hr = HrMapCommand(ucmdID, &cmdID, &pguidCmdGroup, &bOutParam))) { MSOCMD msocmd; msocmd.cmdID = cmdID; msocmd.cmdf = 0;
hr = pCommandTarget->QueryStatus(pguidCmdGroup, 1, &msocmd, NULL);
*cmdf = (DHTMLEDITCMDF) msocmd.cmdf; } }
return hr; }
// General routine for determining the status of a command.
// Should resolve to not supported, disabled, enabled, latched or ninched.
//
HRESULT CProxyFrame::HrQueryStatus(const GUID* pguidCmdGroup, ULONG ucmdID, OLECMDF* cmdf) { HRESULT hr = E_FAIL;
_ASSERTE(cmdf);
// Note that it is valid for pguidCmdGroup to be NULL
if (NULL == cmdf) return E_INVALIDARG;
*cmdf = (OLECMDF) 0;
_ASSERTE(m_pSite);
if ( m_pSite != NULL ) // m_pSite should always be set
{ LPOLECOMMANDTARGET pCommandTarget = m_pSite->GetCommandTarget();
if ( pCommandTarget != NULL ) { MSOCMD msocmd; msocmd.cmdID = ucmdID; msocmd.cmdf = 0;
hr = pCommandTarget->QueryStatus(pguidCmdGroup, 1, &msocmd, NULL);
*cmdf = (OLECMDF) msocmd.cmdf; } }
return hr; }
// A tragic FAT16 compatibility problem: file names in the specific form:
// [a-zA-z]\:[^\\].+ cause various, severe problems. NTFS "forgives".
// We must detect these, both in file names and file:// URL and return an error.
//
BOOL CProxyFrame::IsMissingBackSlash ( BSTR path, BOOL bfIsURL ) { BOOL bfMissing = FALSE;
if ( bfIsURL ) { WCHAR wszFileProtocol[] = L"file://"; int cchProtocol = wcslen ( wszFileProtocol );
if ( 0 == _wcsnicmp ( path, wszFileProtocol, cchProtocol ) ) { if ( OLECHAR(':') == path[cchProtocol+1] ) { if ( OLECHAR('\\') != path[cchProtocol+2] ) { bfMissing = TRUE; } } } } else { // Path name. chec for drive letter, colon, non-backslash.
if ( OLECHAR(':') == path[1] ) { if ( OLECHAR('\\') != path[2] ) { bfMissing = TRUE; } } } return bfMissing; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// Control methods and properties
//
///////////////////////////////////////////////////////////////////////////////////////////
// Handles NewDocument, LoadURL and LoadDocument control methods.
// The document is loaded indirectly via the pluggable protocol handler.
// If "path" is NULL, do NewDocument. TestbfURL to see if it's a URL or UNC path.
//
HRESULT CProxyFrame::LoadDocument(BSTR path, BOOL bfIsURL ) { USES_CONVERSION;
HRESULT hr = S_OK; UINT pathLen = 0;
AssureActivated (); // This can set m_bstrLoadText as a side effect in unactivated controls! Be careful!
if (FALSE == m_fActivated) return E_UNEXPECTED;
m_bstrLoadText.Empty (); // Clear the text to be added directly, or it will be used instead!
m_bstrCurDocPath = L""; m_bstrBaseURL = L"";
if (path) pathLen = ::SysStringLen(path); else pathLen = 0;
// We've resetting the contents of the control. Go back to default save mechanism.
// If we load Unicode it will be reset.
m_pSite->SetSaveAsUnicode ( FALSE );
if (path && pathLen) { _ASSERTE(path); _ASSERTE(pathLen > 0);
// First, look out for a wicked error: X:FileName with no '\' is BAD on FAT16.
if ( IsMissingBackSlash ( path, bfIsURL ) ) { hr = DE_E_PATH_NOT_FOUND; LoadBSTRDeferred ( m_bstrInitialDoc ); goto error; }
// Try to open the file -- stop the sequence
// if its bogus or we don't have access
if ( !bfIsURL ) { if (FAILED(hr = m_pSite->HrTestFileOpen(path))) { LoadBSTRDeferred ( m_bstrInitialDoc ); goto error; } } m_bfIsURL = bfIsURL;
m_bstrCurDocPath = path; // This needs to be set before loading, because base url is needed durring load.
SetBaseURLFromCurDocPath ( bfIsURL ); m_bfPreserveDirtyFlagAcrossBrowseMode = FALSE;
CComPtr<IMoniker> srpMoniker; CComPtr<IBindCtx> srpBindCtx; CComQIPtr<IPersistMoniker, &IID_IPersistMoniker> srpPM (m_pUnkTriEdit); _ASSERTE ( srpPM );
if ( srpPM ) { CComBSTR bstrProtocol = m_wszProtocolPrefix; bstrProtocol += L"("; bstrProtocol += path; bstrProtocol += L")";
#ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnCreateURLMoniker ); hr = (*m_pfnCreateURLMoniker)( NULL, bstrProtocol, &srpMoniker ); #else
hr = CreateURLMoniker ( NULL, bstrProtocol, &srpMoniker ); #endif // LATE_BIND_URLMON_WININET
_ASSERTE ( SUCCEEDED( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = ::CreateBindCtx(NULL, &srpBindCtx); _ASSERTE ( SUCCEEDED( hr ) ); if ( SUCCEEDED ( hr ) ) { // Delete the cache entry before downloading.
// This assures that loading, posting, and reloading works.
// Bug 18544.
// NOTE: Inexact match fails! http://www.microsoft.com fails,
// because this actually loads/caches a specific default page.
if ( bfIsURL ) { LPTSTR szURL = OLE2T ( m_bstrCurDocPath ); #ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnDeleteUrlCacheEntry ); (*m_pfnDeleteUrlCacheEntry)( szURL ); #else
DeleteUrlCacheEntry ( szURL ); #endif // LATE_BIND_URLMON_WININET
} m_bfIsLoading = TRUE; m_hrDeferredLoadError = S_OK; // URLs: don't let Trident get the error!
hr = srpPM->Load(FALSE, srpMoniker, srpBindCtx, STGM_READ);
if ( SUCCEEDED ( hr ) && FAILED ( m_hrDeferredLoadError ) ) { hr = m_hrDeferredLoadError; // In case we stashed a result
} if ( FAILED ( hr ) ) { m_bfIsLoading = FALSE; } } } } } else { if (FAILED(hr = LoadBSTRDeferred ( m_bstrInitialDoc ))) { _ASSERTE(SUCCEEDED(hr)); goto error; } }
error: return hr; }
// Implements FilterSourceCode control method
// Used to restore filtered content extracted directly from DOM.
//
HRESULT CProxyFrame::FilterSourceCode ( BSTR bsSourceIn, BSTR* pbsSourceOut ) { HRESULT hr; CComPtr<IStream> spStreamIn; IStream* piStreamOut;
hr = m_pSite->HrBstrToStream(bsSourceIn, &spStreamIn); if ( SUCCEEDED ( hr ) ) { if ( m_vbBrowseMode ) { spStreamIn.p->AddRef (); piStreamOut = spStreamIn; } else { hr = m_pSite->HrFilter ( FALSE, spStreamIn, &piStreamOut, m_dwFilterOutFlags | dwFilterSourceCode); } if ( SUCCEEDED ( hr ) ) { hr = m_pSite->HrStreamToBstr ( piStreamOut, pbsSourceOut ); piStreamOut->Release (); } } return hr; }
// Implements the control's Print method
//
HRESULT CProxyFrame::Print ( BOOL bfWithUI ) { AssureActivated ();
if (FALSE == m_fActivated) return E_UNEXPECTED; return HrExecCommand ( &GUID_TriEditCommandGroup, IDM_TRIED_PRINT, bfWithUI ? MSOCMDEXECOPT_PROMPTUSER : MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL ); }
// Implements the control's Refresh method
//
HRESULT CProxyFrame::RefreshDoc () { if ( NULL != m_hWndObj ) { if ( ::IsWindow ( m_hWndObj ) ) { ::InvalidateRect ( m_hWndObj, NULL, TRUE ); return S_OK; } } return S_FALSE; }
// Implements the control's SaveDocument method
//
HRESULT CProxyFrame::SaveDocument(BSTR path) { HRESULT hr = S_OK; ULONG pathLen = 0;
if (FALSE == m_fActivated) return E_UNEXPECTED;
_ASSERTE(GetState() == ESTATE_ACTIVATED);
AssureActivated ();
if (GetState() != ESTATE_ACTIVATED) return E_UNEXPECTED;
_ASSERTE(path);
if (path) pathLen = ::SysStringLen(path); else pathLen = 0;
if (0 == pathLen) return E_INVALIDARG;
_ASSERTE(pathLen);
// First, look out for a wicked error: X:FileName with no '\' is BAD on FAT16.
if ( IsMissingBackSlash ( path, FALSE ) ) { return DE_E_PATH_NOT_FOUND; }
hr = m_pSite->HrSaveToFile(path, m_dwFilterOutFlags);
if ( SUCCEEDED ( hr ) ) { m_bstrCurDocPath = path; }
return hr; }
// Implements the control's SetContextMenu method
// One routine handles javascript arrays, the other simple arrays.
//
HRESULT CProxyFrame::SetContextMenu(LPVARIANT pVarMenuStrings, LPVARIANT pVarMenuStates) { if (V_VT(pVarMenuStrings) == VT_DISPATCH || V_VT(pVarMenuStates) == VT_DISPATCH) return SetContextMenuDispEx(pVarMenuStrings, pVarMenuStates); else return SetContextMenuSA(pVarMenuStrings, pVarMenuStates); }
// Get menu strings from SafeArray
//
HRESULT CProxyFrame::SetContextMenuSA(LPVARIANT pVarMenuStrings, LPVARIANT pVarMenuStates) { HRESULT hr = S_OK; SAFEARRAY* psaStrings = NULL; SAFEARRAY* psaStates = NULL; LONG lLBound, lUBound, lLBoundState, lUBoundState;
if (NULL == pVarMenuStrings || NULL == pVarMenuStates) return E_INVALIDARG;
if ((VT_ARRAY|VT_BSTR) != V_VT(pVarMenuStrings) && ((VT_ARRAY|VT_BSTR)|VT_BYREF) != V_VT(pVarMenuStrings) && ((VT_ARRAY|VT_VARIANT)|VT_BYREF) != V_VT(pVarMenuStrings) && (VT_ARRAY|VT_VARIANT) != V_VT(pVarMenuStrings)) return E_INVALIDARG;
if ((VT_ARRAY|VT_I4) != V_VT(pVarMenuStates) && ((VT_ARRAY|VT_I4)|VT_BYREF) != V_VT(pVarMenuStates) && ((VT_ARRAY|VT_VARIANT)|VT_BYREF) != V_VT(pVarMenuStates) && (VT_ARRAY|VT_VARIANT) != V_VT(pVarMenuStates)) return E_INVALIDARG;
if ((VT_ARRAY|VT_BSTR) == V_VT(pVarMenuStrings)) { psaStrings = V_ARRAY(pVarMenuStrings); } if ((VT_ARRAY|VT_VARIANT) == V_VT(pVarMenuStrings)) { psaStrings = V_ARRAY(pVarMenuStrings); } else if ((VT_ARRAY|VT_BSTR|VT_BYREF) == V_VT(pVarMenuStrings)) { if (NULL == V_ARRAYREF(pVarMenuStrings)) return E_INVALIDARG;
psaStrings = *(V_ARRAYREF(pVarMenuStrings)); } else if ((VT_ARRAY|VT_VARIANT|VT_BYREF) == V_VT(pVarMenuStrings)) { if (NULL == V_ARRAYREF(pVarMenuStrings)) return E_INVALIDARG; psaStrings = *(V_ARRAYREF(pVarMenuStrings)); }
if ((VT_ARRAY|VT_I4) == V_VT(pVarMenuStates)) { psaStates = V_ARRAY(pVarMenuStates); } if ((VT_ARRAY|VT_VARIANT) == V_VT(pVarMenuStates)) { psaStates = V_ARRAY(pVarMenuStates); } else if ((VT_ARRAY|VT_I4|VT_BYREF) == V_VT(pVarMenuStates)) { if (NULL == V_ARRAYREF(pVarMenuStates)) return E_INVALIDARG;
psaStates = *(V_ARRAYREF(pVarMenuStates)); } else if ((VT_ARRAY|VT_VARIANT|VT_BYREF) == V_VT(pVarMenuStates)) { if (NULL == V_ARRAYREF(pVarMenuStates)) return E_INVALIDARG;
psaStates = *(V_ARRAYREF(pVarMenuStates)); }
if (NULL == psaStrings || NULL == psaStates) return E_INVALIDARG;
SafeArrayGetLBound(psaStrings, 1, &lLBound); SafeArrayGetUBound(psaStrings, 1, &lUBound);
SafeArrayGetLBound(psaStates, 1, &lLBoundState); SafeArrayGetUBound(psaStates, 1, &lUBoundState);
if (lLBound != lLBoundState || lUBound != lUBoundState) return E_INVALIDARG;
if (m_pMenuStrings) { SafeArrayDestroy(m_pMenuStrings); m_pMenuStrings = NULL; }
if (m_pMenuStates) { SafeArrayDestroy(m_pMenuStates); m_pMenuStates = NULL; }
// An empty array was passed in
// The context menu has been cleared
if (lLBound ==lUBound ) goto cleanup;
if (FAILED(hr = SafeArrayCopy(psaStrings, &m_pMenuStrings))) goto cleanup;
if (FAILED(hr = SafeArrayCopy(psaStates, &m_pMenuStates))) goto cleanup;
cleanup:
if (FAILED(hr)) { if (m_pMenuStrings) { SafeArrayDestroy(m_pMenuStrings); m_pMenuStrings = NULL; }
if (m_pMenuStates) { SafeArrayDestroy(m_pMenuStates); m_pMenuStates = NULL; } }
return hr; }
// Get menu strings from JScript array, or object that supports IDispatchEx
// For iterating through JScript arrays, we expect the elements
// to be accessable by ordinals starting at 0, i.e., a 0 based array
//
HRESULT CProxyFrame::SetContextMenuDispEx(LPVARIANT pVarMenuStrings, LPVARIANT pVarMenuStates) { HRESULT hr = S_OK; ULONG i=0; ULONG ulStringsLen = 0; ULONG ulStatesLen = 0; IDispatch* pdStrings = NULL; IDispatch* pdStates = NULL; IDispatchEx* pdexStrings = NULL; IDispatchEx* pdexStates = NULL; CDispExArray dispStrings; CDispExArray dispStates; VARIANT varString; VARIANT varState; SAFEARRAYBOUND rgsabound[1] = {0}; LONG ix[1] = {0};
if (VT_DISPATCH != V_VT(pVarMenuStrings) || VT_DISPATCH != V_VT(pVarMenuStates)) return E_INVALIDARG;
VariantInit(&varString); VariantInit(&varState);
pdStrings = V_DISPATCH(pVarMenuStrings); pdStates = V_DISPATCH(pVarMenuStates);
_ASSERTE(pdStrings); _ASSERTE(pdStates);
if (FAILED(hr = pdStrings->QueryInterface(IID_IDispatchEx, (LPVOID*) &pdexStrings))) { return E_INVALIDARG; } dispStrings.Attach(pdexStrings);
if (FAILED(hr = pdStates->QueryInterface(IID_IDispatchEx, (LPVOID*) &pdexStates))) { return E_INVALIDARG; } dispStates.Attach(pdexStates);
if (FAILED(dispStrings.HrGetLength(&ulStringsLen))) goto cleanup;
if (FAILED(dispStates.HrGetLength(&ulStatesLen))) goto cleanup;
// Make sure that arrays are equal length
if (ulStringsLen != ulStatesLen) return E_INVALIDARG;
if (m_pMenuStrings) { SafeArrayDestroy(m_pMenuStrings); m_pMenuStrings = NULL; }
if (m_pMenuStates) { SafeArrayDestroy(m_pMenuStates); m_pMenuStates = NULL; }
// An empty array was passed in
// The context menu has been cleared
if (ulStringsLen <= 0) goto cleanup;
rgsabound[0].lLbound = 0; rgsabound[0].cElements = ulStringsLen;
m_pMenuStrings = SafeArrayCreate(VT_BSTR, 1, rgsabound); _ASSERTE(m_pMenuStrings); if (NULL == m_pMenuStrings) { hr = E_OUTOFMEMORY; goto cleanup; }
m_pMenuStates = SafeArrayCreate(VT_I4, 1, rgsabound); _ASSERTE(m_pMenuStates); if (NULL == m_pMenuStates) { hr = E_OUTOFMEMORY; goto cleanup; }
// For iterating through JScript arrays, we expect the elements
// to be accessable by ordinals starting at 0, i.e., a 0 based array
hr = S_OK; for (i=0; i < ulStringsLen && hr != S_FALSE; i++) { if (FAILED(hr = dispStrings.HrGetElement(i, &varString))) goto cleanup;
if (FAILED(hr = dispStates.HrGetElement(i, &varState))) goto cleanup;
if (VT_BSTR != V_VT(&varString) || VT_I4 != V_VT(&varState)) { hr = E_INVALIDARG; goto cleanup; }
ix[0] = i; if (FAILED(hr = SafeArrayPutElement(m_pMenuStrings, ix, (LPVOID) V_BSTR(&varString)))) goto cleanup;
if (FAILED(hr = SafeArrayPutElement(m_pMenuStates, ix, (LPVOID) &(V_I4(&varState))))) goto cleanup;
VariantClear ( &varString ); VariantClear ( &varState ); }
cleanup:
if (FAILED(hr)) { if (m_pMenuStrings) { SafeArrayDestroy(m_pMenuStrings); m_pMenuStrings = NULL; }
if (m_pMenuStates) { SafeArrayDestroy(m_pMenuStates); m_pMenuStates = NULL; } }
return hr; }
// DocumentTitle property implementation; read only.
// Get the property from the HTML document.
//
HRESULT CProxyFrame::GetDocumentTitle ( CComBSTR& bstrTitle ) { HRESULT hr = S_OK; DISPID dispid; DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; CComVariant varResult;
CComPtr<IHTMLDocument2> piHtmlDoc = NULL; hr = HrGetDoc( &piHtmlDoc );
if ( SUCCEEDED ( hr ) ) { AssureActivated();
hr = piHtmlDoc->GetIDsOfNames ( IID_NULL, &g_wszHTMLTitlePropName, 1, LOCALE_SYSTEM_DEFAULT, &dispid ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( FAILED ( hr ) ) { return hr; }
hr = piHtmlDoc->Invoke ( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparamsNoArgs, &varResult, NULL, NULL ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( FAILED ( hr ) ) { return hr; } hr = varResult.ChangeType ( VT_BSTR ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( FAILED ( hr ) ) { return hr; }
bstrTitle = varResult.bstrVal; }
return hr; }
// Implements getting the control's BrowseMode property
//
HRESULT CProxyFrame::GetBrowseMode ( VARIANT_BOOL *pVal ) { *pVal = m_vbBrowseMode; return S_OK; }
// Implements setting the control's BrowseMode property
//
HRESULT CProxyFrame::SetBrowseMode ( VARIANT_BOOL newVal ) { HRESULT hr = S_FALSE; // Indicates value was set, but actual mode was not changed.
_ASSERTE ( m_pSite );
// If we're still reading the property bag, just set the value, don't change the text;
// it hasn't been loaded yet.
if ( NULL == m_pSite->GetCommandTarget() ) { m_vbBrowseMode = newVal; hr = S_OK; } else { if ( m_vbBrowseMode != newVal ) { AssureActivated ();
m_bfModeSwitched = TRUE;
if ( newVal && m_pCtl->IsUserMode () ) // newVal means "switching to browse mode"
{ CComPtr<IStream> spStream = NULL;
HrGetIsDirty ( m_bfPreserveDirtyFlagAcrossBrowseMode ); hr = m_pSite->HrSaveToStreamAndFilter ( &spStream, m_dwFilterOutFlags ); if ( SUCCEEDED ( hr ) ) { m_bstrLoadText.Empty (); // Preserve the byte order mark, or else it will not be reloaded properly
hr = m_pSite->HrStreamToBstr ( spStream, &m_bstrLoadText, TRUE ); } }
m_vbBrowseMode = newVal;
// Let Trident know the ambient property has changed.
CComQIPtr<IOleControl,&IID_IOleControl>spioc ( m_pSite->GetObjectUnknown() ); if ( spioc ) { m_bfIsLoading = TRUE; spioc->OnAmbientPropertyChange ( DISPID_AMBIENT_USERMODE ); } } } return hr; }
// Implements getting the control's UseDivOnCarriageReturn property
//
HRESULT CProxyFrame::GetDivOnCr ( VARIANT_BOOL *pVal ) { *pVal = m_vbUseDivOnCr; return S_OK; }
// Implements setting the control's UseDivOnCarriageReturn property
//
HRESULT CProxyFrame::SetDivOnCr ( VARIANT_BOOL newVal ) { HRESULT hr = S_OK; CComVariant varDefBlock;
m_vbUseDivOnCr = newVal;
// Reinitialize if we haven't loaded our properties before this point.
if ( READYSTATE_UNINITIALIZED == m_readyState ) { // InitializeDocString takes m_vbUseDivOnCr into account
InitializeDocString (); } return hr; }
// Implements getting the control's read-only Busy property
//
HRESULT CProxyFrame::GetBusy ( VARIANT_BOOL *pVal ) { #pragma warning(disable: 4310) // cast truncates constant value
*pVal = ( m_bfIsLoading ) ? VARIANT_TRUE : VARIANT_FALSE; #pragma warning(default: 4310) // cast truncates constant value
return S_OK; }
// Implements setting the control's ActivateActiveXControls property
//
HRESULT CProxyFrame::HrSetPropActivateControls(BOOL activateControls) { HRESULT hr = S_OK;
if (m_fActivated) { if (SUCCEEDED(hr = HrTridentSetPropBool(IDM_NOACTIVATENORMALOLECONTROLS, !activateControls))) m_fActivateControls = activateControls; } else m_fActivateControls = activateControls;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's ActivateActiveXControls property
//
HRESULT CProxyFrame::HrGetPropActivateControls(BOOL& activateControls) { HRESULT hr = S_OK;
activateControls = m_fActivateControls;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements setting the control's ActivateApplets property
//
HRESULT CProxyFrame::HrSetPropActivateApplets(BOOL activateApplets) { HRESULT hr = S_OK;
if (m_fActivated) { if (SUCCEEDED(hr = HrTridentSetPropBool(IDM_NOACTIVATEJAVAAPPLETS, !activateApplets))) m_fActivateApplets = activateApplets; } else m_fActivateApplets = activateApplets;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's ActivateApplets property
//
HRESULT CProxyFrame::HrGetPropActivateApplets(BOOL& activateApplets) { HRESULT hr = S_OK;
activateApplets = m_fActivateApplets;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements setting the control's ActivateDTCs property
//
HRESULT CProxyFrame::HrSetPropActivateDTCs(BOOL activateDTCs) { HRESULT hr = S_OK;
if (m_fActivated) { if (SUCCEEDED(hr = HrTridentSetPropBool(IDM_NOACTIVATEDESIGNTIMECONTROLS, !activateDTCs))) m_fActivateDTCs = activateDTCs; } else m_fActivateDTCs = activateDTCs;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's ActivateDTCs property
//
HRESULT CProxyFrame::HrGetPropActivateDTCs(BOOL& activateDTCs) { HRESULT hr = S_OK;
activateDTCs = m_fActivateDTCs;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements setting the control's ShowDetails property
//
HRESULT CProxyFrame::HrSetPropShowAllTags(BOOL showAllTags) { HRESULT hr = S_OK;
if (m_fActivated) { if (SUCCEEDED(hr = HrTridentSetPropBool(IDM_SHOWALLTAGS, showAllTags))) m_fShowAllTags = showAllTags; } else m_fShowAllTags = showAllTags;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's ShowDetails property
//
HRESULT CProxyFrame::HrGetPropShowAllTags(BOOL& showAllTags) { HRESULT hr = S_OK;
showAllTags = m_fShowAllTags;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements setting the control's ShowBorders property
//
HRESULT CProxyFrame::HrSetPropShowBorders(BOOL showBorders) { HRESULT hr = S_OK;
if (m_fActivated) { if (SUCCEEDED(hr = HrTridentSetPropBool(IDM_SHOWZEROBORDERATDESIGNTIME, showBorders))) m_fShowBorders = showBorders; } else m_fShowBorders = showBorders;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's ShowBorders property
//
HRESULT CProxyFrame::HrGetPropShowBorders(BOOL& showBorders) { HRESULT hr = S_OK;
showBorders = m_fShowBorders;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements setting the control's Appearance property
//
HRESULT CProxyFrame::HrSetDisplay3D(BOOL bVal) { m_fDisplay3D = bVal; return S_OK; }
// Implements getting the control's Appearance property
//
HRESULT CProxyFrame::HrGetDisplay3D(BOOL& bVal) { bVal = m_fDisplay3D; return S_OK; }
// Implements setting the control's Scrollbars property
//
HRESULT CProxyFrame::HrSetScrollbars(BOOL bVal) { m_fScrollbars = bVal; return S_OK; }
// Implements getting the control's Scrollbars property
//
HRESULT CProxyFrame::HrGetScrollbars(BOOL& bVal) { bVal = m_fScrollbars; return S_OK; }
// Implements setting the control's ScrollbarAppearance property
//
HRESULT CProxyFrame::HrSetDisplayFlatScrollbars(BOOL bVal) { m_fDisplayFlatScrollbars = bVal; return S_OK; }
// Implements getting the control's ScrollbarAppearance property
//
HRESULT CProxyFrame::HrGetDisplayFlatScrollbars(BOOL& bVal) { bVal = m_fDisplayFlatScrollbars; return S_OK; }
// Implements setting the control's AbsoluteDropMode property
//
HRESULT CProxyFrame::HrSetAbsoluteDropMode(BOOL dropMode) { HRESULT hr = S_OK;
if (m_fActivated) { VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_BOOL; #pragma warning(disable: 4310) // cast truncates constant value
V_BOOL(&var) = (dropMode) ? VARIANT_TRUE : VARIANT_FALSE; #pragma warning(default: 4310) // cast truncates constant value
if (SUCCEEDED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_SET_2D_DROP_MODE, MSOCMDEXECOPT_DONTPROMPTUSER, &var, NULL))) m_fAbsoluteDropMode = dropMode; } else m_fAbsoluteDropMode = dropMode;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's AbsoluteDropMode property
//
HRESULT CProxyFrame::HrGetAbsoluteDropMode(BOOL& dropMode) { HRESULT hr = S_OK;
dropMode = m_fAbsoluteDropMode; return hr; }
// Implements setting the control's SnapToGrid property
//
HRESULT CProxyFrame::HrSetSnapToGrid(BOOL snapToGrid) { HRESULT hr = S_OK;
if (m_fActivated) { VARIANT var; POINT pt = {0};
VariantInit(&var); if ( snapToGrid ) { pt.y = m_ulSnapToGridY; pt.x = m_ulSnapToGridX; } else { pt.y = 0; pt.x = 0; }
V_VT(&var) = VT_BYREF; V_BYREF(&var) = &pt;
if (SUCCEEDED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_SET_ALIGNMENT, MSOCMDEXECOPT_DONTPROMPTUSER, &var, NULL))) m_fSnapToGrid = snapToGrid;
} else m_fSnapToGrid = snapToGrid;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's SnapToGrid property
//
HRESULT CProxyFrame::HrGetSnapToGrid(BOOL& snapToGrid) { HRESULT hr = S_OK;
snapToGrid = m_fSnapToGrid; return hr; }
// Implements setting the control's SnapToGridX property
//
HRESULT CProxyFrame::HrSetSnapToGridX(LONG snapToGridX) { HRESULT hr = S_OK;
if ( 0 >= snapToGridX ) { return DE_E_INVALIDARG; }
if (m_fActivated) { VARIANT var; POINT pt = {0};
VariantInit(&var);
pt.x = snapToGridX; pt.y = m_ulSnapToGridY;
V_VT(&var) = VT_BYREF; V_BYREF(&var) = &pt;
if (SUCCEEDED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_SET_ALIGNMENT, MSOCMDEXECOPT_DONTPROMPTUSER, &var, NULL))) m_ulSnapToGridX = snapToGridX; } else m_ulSnapToGridX = snapToGridX;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's SnapToGridX property
//
HRESULT CProxyFrame::HrGetSnapToGridX(LONG& snapToGridX) { HRESULT hr = S_OK;
snapToGridX = m_ulSnapToGridX; return hr; }
// Implements setting the control's SnapToGridY property
//
HRESULT CProxyFrame::HrSetSnapToGridY(LONG snapToGridY) { HRESULT hr = S_OK;
if ( 0 >= snapToGridY ) { return DE_E_INVALIDARG; }
if (m_fActivated) { VARIANT var; POINT pt = {0};
VariantInit(&var); pt.y = snapToGridY; pt.x = m_ulSnapToGridX;
V_VT(&var) = VT_BYREF; V_BYREF(&var) = &pt;
if (SUCCEEDED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_SET_ALIGNMENT, MSOCMDEXECOPT_DONTPROMPTUSER, &var, NULL))) m_ulSnapToGridY = snapToGridY; } else m_ulSnapToGridY = snapToGridY;
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Implements getting the control's SnapToGridY property
//
HRESULT CProxyFrame::HrGetSnapToGridY(LONG& snapToGridY) { HRESULT hr = S_OK;
snapToGridY = m_ulSnapToGridY; return hr; }
// Implements setting the control's DocumentHTML property
//
HRESULT CProxyFrame::HrSetDocumentHTML(BSTR bVal) { HRESULT hr = S_OK;
_ASSERTE(bVal);
if (NULL == bVal) return E_INVALIDARG;
if (m_pCtl->IsUserMode ()) { hr = DE_E_UNEXPECTED;
AssureActivated (); if ( m_fActivated ) { m_bstrBaseURL = L""; m_bfPreserveDirtyFlagAcrossBrowseMode = FALSE; if ( 0 == SysStringLen ( bVal ) ) { CComBSTR bstrMT = GetInitialHTML (); hr = LoadBSTRDeferred ( bstrMT ); } else { hr = LoadBSTRDeferred ( bVal ); }
if ( FAILED ( hr ) ) { goto error; }
// We've reset the contents of the control. Go back to default save mechanism.
m_pSite->SetSaveAsUnicode ( FALSE ); } }
error:
return hr; }
// Implements getting the control's DocumentHTML property
//
HRESULT CProxyFrame::HrGetDocumentHTML(BSTR* bVal) { HRESULT hr = S_OK; BOOL bfWasDirty = FALSE;
_ASSERTE(bVal);
if (NULL == bVal) return E_INVALIDARG;
if ( m_bfIsLoading ) return DE_E_UNEXPECTED; // This is invalid while document is still loading.
if ( FAILED ( hr = m_pSite->HrIsDirtyIPersistStreamInit(bfWasDirty) ) ) { _ASSERTE ( SUCCEEDED ( hr ) ); bfWasDirty = FALSE; // what else can we do in a situation like this?
}
AssureActivated ();
if (m_fActivated) { _ASSERTE(m_pSite);
hr = m_pSite->HrSaveToBstr(bVal, m_dwFilterOutFlags );
// Preserve original dirty state.
if ( bfWasDirty ) { SetDirtyFlag ( TRUE ); } }
return hr; }
// Implements setting the control's SourceCodePreservation property
//
HRESULT CProxyFrame::HrSetPreserveSource(BOOL bVal) { m_fPreserveSource = bVal; if (m_fPreserveSource) m_dwFilterFlags = filterAll; else m_dwFilterFlags = filterDTCs | filterASP;
return S_OK; }
// Implements getting the control's SourceCodePreservation property
//
HRESULT CProxyFrame::HrGetPreserveSource(BOOL& bVal) { bVal = m_fPreserveSource; return S_OK; }
// Implements getting the control's read-only IsDirty property
//
HRESULT CProxyFrame::HrGetIsDirty(BOOL& bVal) { HRESULT hr = S_OK;
bVal = FALSE;
AssureActivated ();
if (m_fActivated) { hr = m_pSite->HrIsDirtyIPersistStreamInit(bVal); }
return hr; }
// Implements getting the BaseURL property
//
HRESULT CProxyFrame::GetBaseURL ( CComBSTR& bstrBaseURL ) { AssureActivated ();
if ( NULL == m_bstrBaseURL.m_str ) { bstrBaseURL = L""; } else { bstrBaseURL = m_bstrBaseURL; } return S_OK; }
// Implements setting the BaseURL property.
// NOTE:
// The BaseURL can't be (effectively) changed if there's a <BASE HREF=XXX> tag in
// the document. Our pluggable Protocol's CombineURL is never called in this case,
// so don't misguide the user by changing the property.
//
// Pay attention to m_bfBaseURLFromBASETag before calling to set the value from
// the routine parsing the <BASE> tag!
//
HRESULT CProxyFrame::SetBaseURL ( CComBSTR& bstrBaseURL ) { HRESULT hr = S_OK;
_ASSERTE ( bstrBaseURL );
// Non-persisted property. Ignore if not in UserMode.
if ( m_pCtl->IsUserMode () ) { if ( m_bfBaseURLFromBASETag ) { return S_FALSE; } else { if ( NULL == m_bstrBaseURL.m_str ) { m_bstrBaseURL = L""; }
// If this test succeedes, the user has done something like x.BaseURL = x.DOM.url or
// x.BaseURL = y.DOM.url.
// Response: bstrBaseURL may be the bare protocol prefix, or a prefix with a URL attached
// for example: dhtmled0:(http://www.microsoft.com).
// Strip off the prefix and parens (if they exist) and use the interior URL.
if ( 0 == _wcsnicmp ( bstrBaseURL.m_str, g_wszProtocolPrefix, wcslen ( g_wszProtocolPrefix ) ) ) { CComBSTR bstrNew = bstrBaseURL.m_str;
// There must be a colon; it would be possibe to have a legitimate base url beginning with g_wszProtocolPrefix
WCHAR* pwcURL = wcschr ( bstrNew, (WCHAR)':' ); if ( NULL != pwcURL ) { // Find the first open paren:
pwcURL = wcschr ( pwcURL, (WCHAR)'(' ); if ( NULL == pwcURL ) { bstrBaseURL = L""; // No (...)? Set the Base to empty. Input must have been bare protocol ID.
} else { pwcURL++; // Step past the paren.
// Strip of dhtmledXXX:( ...to... ) and set the BaseURL to what remains.
_ASSERTE ( (WCHAR)')' == pwcURL[wcslen(pwcURL)-1] ); if ( (WCHAR)')' == pwcURL[wcslen(pwcURL)-1] ) { pwcURL[wcslen(pwcURL)-1] = (WCHAR)'\0'; bstrBaseURL = pwcURL; } else { // Unexpected: ill formed pluggable protocol id:
// starts with dhtml[n[n]]:( but does not end with ).
// If we skipped it, we would crash. Best to use an empty base URL.
bstrBaseURL = L""; } } } }
if ( 0 != wcscmp ( m_bstrBaseURL.m_str, bstrBaseURL.m_str ) ) { m_bstrBaseURL = bstrBaseURL; m_bfIsLoading = TRUE;
// Can't Exec without a command target:
if ( NULL != m_pSite->GetCommandTarget() ) { // Reload the page, revaluating relative links.
hr = HrExecCommand(&CGID_MSHTML, IDM_REFRESH, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL); } } } } return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// Accelerator handler implementations
//
///////////////////////////////////////////////////////////////////////////////////////////
// Nudge accelerator handler
// Nudge the selection in the given direction by one pixle if SnaptoGrid is off, or by
// the SnaptoGridX/Y quantity if SnapToGrid is on.
//
HRESULT CProxyFrame::HrNudge(DENudgeDirection dir) { HRESULT hr = S_FALSE; OLECMDF cmdf = (OLECMDF) 0; VARIANT var; LPVARIANT pVarIn = &var; LONG lXDelta = m_fSnapToGrid ? m_ulSnapToGridX : 1; LONG lYDelta = m_fSnapToGrid ? m_ulSnapToGridY : 1;
if (FAILED(hr = HrQueryStatus(&GUID_TriEditCommandGroup, IDM_TRIED_NUDGE_ELEMENT, &cmdf))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
if (cmdf & OLECMDF_SUPPORTED && cmdf & OLECMDF_ENABLED) { LPPOINT lpPoint = new POINT;
if (NULL == lpPoint) { hr = E_OUTOFMEMORY; goto cleanup; } _ASSERTE(lpPoint);
lpPoint->x = 0; lpPoint->y = 0;
// Set increment to snap to absolute grid, not relative grid.
// Find the selections current position and set increment modulo that position.
// This assures the first nudge snaps to a grid corner.
if ( m_fSnapToGrid ) { POINT ptSelPos; if ( SUCCEEDED ( GetSelectionPos ( &ptSelPos ) ) ) { LONG lXNorm = ptSelPos.x % lXDelta; LONG lYNorm = ptSelPos.y % lYDelta; lXDelta = lXNorm ? lXNorm : lXDelta; lYDelta = lYNorm ? lYNorm : lYDelta; } }
switch(dir) { case deNudgeUp: { lpPoint->x = 0; lpPoint->y = -lYDelta; } break;
case deNudgeDown: { lpPoint->x = 0; lpPoint->y = lYDelta; } break;
case deNudgeLeft: { lpPoint->x = -lXDelta; lpPoint->y = 0; } break;
case deNudgeRight: { lpPoint->x = lXDelta; lpPoint->y = 0; } break;
default: // move right by default
{ lpPoint->x = lXDelta; lpPoint->y = 0; } break; }
VariantInit(pVarIn); V_VT(pVarIn) = VT_BYREF; V_BYREF(pVarIn) = lpPoint;
if (FAILED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_NUDGE_ELEMENT, MSOCMDEXECOPT_DONTPROMPTUSER, pVarIn, NULL))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
hr = S_OK; } else hr = S_FALSE;
cleanup: return hr; }
// Accelerator handler
// Toggle the absolute positioned property of the selected object
//
HRESULT CProxyFrame::HrToggleAbsolutePositioned() { HRESULT hr = S_FALSE; OLECMDF cmdf = (OLECMDF) 0;
if (FAILED(hr = HrQueryStatus(&GUID_TriEditCommandGroup, IDM_TRIED_MAKE_ABSOLUTE, &cmdf))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
if (cmdf & OLECMDF_SUPPORTED && cmdf & OLECMDF_ENABLED) { if (FAILED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_MAKE_ABSOLUTE, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
hr = S_OK; }
cleanup: return hr; }
// Accelerator handler
// Make a link out of the current selection (with UI.)
//
HRESULT CProxyFrame::HrHyperLink() { HRESULT hr = S_FALSE; OLECMDF cmdf = (OLECMDF) 0;
if (FAILED(hr = HrQueryStatus(&GUID_TriEditCommandGroup, IDM_TRIED_HYPERLINK, &cmdf))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
if (cmdf & OLECMDF_SUPPORTED && cmdf & OLECMDF_ENABLED) { if (FAILED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_HYPERLINK, MSOCMDEXECOPT_PROMPTUSER, NULL, NULL))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
hr = S_OK; }
cleanup: return hr; }
// Accelerator handler
// Increase the indent of the current selection.
//
HRESULT CProxyFrame::HrIncreaseIndent() { HRESULT hr = S_FALSE; OLECMDF cmdf = (OLECMDF) 0;
if (FAILED(hr = HrQueryStatus(&GUID_TriEditCommandGroup, IDM_TRIED_INDENT, &cmdf))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
if (cmdf & OLECMDF_SUPPORTED && cmdf & OLECMDF_ENABLED) { if (FAILED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_INDENT, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
hr = S_OK; }
cleanup: return hr; }
// Accelerator handler
// Decrease the indent of the current selection.
//
HRESULT CProxyFrame::HrDecreaseIndent() { HRESULT hr = S_FALSE; OLECMDF cmdf = (OLECMDF) 0;
if (FAILED(hr = HrQueryStatus(&GUID_TriEditCommandGroup, IDM_TRIED_OUTDENT, &cmdf))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
if (cmdf & OLECMDF_SUPPORTED && cmdf & OLECMDF_ENABLED) { if (FAILED(hr = HrExecCommand(&GUID_TriEditCommandGroup, IDM_TRIED_OUTDENT, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL))) { _ASSERTE(SUCCEEDED(hr)); goto cleanup; }
hr = S_OK; }
cleanup: return hr; }
// Check for and handle control-specific accelerators. If none is found, call TriEdit to handle it.
//
HRESULT CProxyFrame::HrHandleAccelerator(LPMSG lpmsg) { HRESULT hr = S_FALSE; BOOL fControl = (0x8000 & GetKeyState(VK_CONTROL)); BOOL fShift = (0x8000 & GetKeyState(VK_SHIFT)); BOOL fAlt = (0x8000 & GetKeyState(VK_MENU));
if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_UP) { hr = HrNudge(deNudgeUp); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_DOWN) { hr = HrNudge(deNudgeDown); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_LEFT) { hr = HrNudge(deNudgeLeft); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_RIGHT) { hr = HrNudge(deNudgeRight); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == 'K' && fControl) { hr = HrToggleAbsolutePositioned(); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == 'L' && fControl && !fAlt) { hr = HrHyperLink(); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == 'T' && !fShift && fControl) { hr = HrIncreaseIndent(); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == 'T' && fShift && fControl) { hr = HrDecreaseIndent(); } else if (lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_TAB && fControl) { // Process control-tab keys as belonging to the container; this allows the user
// to tab out of the control in non-MDI apps. MDI uses control-tab to switch
// windows, thus these apps (like VID) do not pass them to us.
IOleControlSite* piControlSite = m_pCtl->GetControlSite (); _ASSERTE ( piControlSite ); if ( NULL != piControlSite ) { // Eat the control key, but preserve shift to perform reverse tabbing.
// KEYMOD_SHIFT = 0x00000001, but isn't defined in any header...
DWORD dwModifiers = fShift ? 1 : 0;
hr = piControlSite->TranslateAccelerator ( lpmsg, dwModifiers ); } }
return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// BaseURL helper routines
//
///////////////////////////////////////////////////////////////////////////////////////////
// Override the default BaseURL if there is one or more <BASE HREF=...> tags
// in the document. If successful, set m_bfBaseURLFromBASETag to TRUE
// If multiple BASE tags exist, simply use the last one.
// Equivilent script: baseurl = document.all.tags("BASE")[<LAST>].href,
// where <LAST> is derived.
//
HRESULT CProxyFrame::SetBaseURLFromBaseHref () { HRESULT hr = S_OK; CComBSTR bstrBase;
if ( !m_bfBaseURLFromBASETag ) { if ( SUCCEEDED ( hr ) ) { CComPtr<IHTMLDocument2> spHtmlDoc = NULL; hr = HrGetDoc( &spHtmlDoc ); if ( spHtmlDoc && SUCCEEDED ( hr ) ) { CComPtr<IHTMLElementCollection> spAll = NULL; hr = spHtmlDoc->get_all ( &spAll ); if ( spAll && SUCCEEDED ( hr ) ) { CComVariant varTag = L"BASE"; IDispatch* piDispTags = NULL;
hr = spAll->tags ( varTag, &piDispTags ); if ( piDispTags && SUCCEEDED ( hr ) ) { CComQIPtr<IHTMLElementCollection, &IID_IHTMLElementCollection> spBases (piDispTags); piDispTags->Release (); piDispTags = NULL; if ( spBases ) { long cBases = 0; hr = spBases->get_length ( &cBases ); if ( SUCCEEDED ( hr ) && ( 0 != cBases ) ) { CComVariant varName; varName.vt = VT_I2;
for ( varName.iVal = 0; varName.iVal < cBases; varName.iVal++ ) { IDispatch* piDispBase = NULL; CComVariant varValue;
hr = spBases->item ( varName, varName, &piDispBase ); if ( piDispBase && SUCCEEDED ( hr ) ) { CComQIPtr<IHTMLElement, &IID_IHTMLElement> spElem ( piDispBase ); piDispBase->Release (); piDispBase = NULL;
if ( spElem ) { varValue.Clear (); hr = spElem->getAttribute ( L"HREF", FALSE, &varValue ); if ( SUCCEEDED ( hr ) ) { hr = varValue.ChangeType ( VT_BSTR ); if ( SUCCEEDED ( hr ) ) { if ( 0 != SysStringLen ( varValue.bstrVal ) ) { bstrBase = varValue.bstrVal; } } } } } } if ( 0 != bstrBase.Length () ) { hr = SetBaseURL ( bstrBase ); // This clears m_bfBaseURLIsDefault
m_bfBaseURLFromBASETag = TRUE; } } } } } } } } return hr; }
// Set the m_bstrBaseURL value using m_bstrCurDocPath.
// With URLs, it may be impossible to be certain about the correct BaseURL,
// so make an intellegent guess. With files, it should be deterministic.
//
HRESULT CProxyFrame::SetBaseURLFromCurDocPath ( BOOL bfIsURL ) { m_bfBaseURLFromBASETag = FALSE; // We're reloading: whipe this out.
if ( bfIsURL ) { return SetBaseURLFromURL ( m_bstrCurDocPath ); } else { return SetBaseURLFromFileName ( m_bstrCurDocPath ); } }
// Given a URL_COMPONENTS with nScheme set to INTERNET_SCHEME_FILE,
// modify the path part to reflect the base path, reconstruct the URL,
// and set m_bstrBaseURL.
// Separators may be \ or /.
//
HRESULT CProxyFrame::SetBaseUrlFromFileUrlComponents ( URL_COMPONENTS & urlc ) { TCHAR* pszPath; BOOL bfBackSlash = TRUE; HRESULT hr = S_OK;
_ASSERTE ( INTERNET_SCHEME_FILE == urlc.nScheme ); _ASSERTE ( urlc.dwUrlPathLength ); if ( urlc.dwUrlPathLength <= 0) { return E_UNEXPECTED; } pszPath = new TCHAR [urlc.dwUrlPathLength + 3]; // Extra room for \0, dot, and /.
if ( NULL != pszPath ) { TCHAR c = 0; int iPos = 0;
// Scan backwards and modify in copy (never in BSTR, please) for beginning, '/' or '\'
memcpy ( pszPath, urlc.lpszUrlPath, ( urlc.dwUrlPathLength + 1 ) * sizeof(TCHAR) ); for ( iPos = urlc.dwUrlPathLength - 1; iPos >= 0; iPos-- ) { c = pszPath[iPos]; pszPath[iPos] = '\0'; // Delete first, ask questions later. '\' must go.
if ( '\\' == c ) { break; } if ( '/' == c ) { bfBackSlash = FALSE; break; } }
// Space was reserved for an additional two characters, if needed.
// If empty, add a dot.
if ( 0 == _tcslen ( pszPath ) ) { _tcscat ( pszPath, TEXT(".") ); } // Add a / or \.
if ( bfBackSlash ) { _tcscat ( pszPath, TEXT("\\") ); } else { _tcscat ( pszPath, TEXT("/") ); }
urlc.lpszUrlPath = pszPath; urlc.dwUrlPathLength = _tcslen ( pszPath );
DWORD dwLen = 0; #ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnInternetCreateUrl ); (*m_pfnInternetCreateUrl)( &urlc, 0, NULL, &dwLen ); // Get the size required.
#else
InternetCreateUrl ( &urlc, 0, NULL, &dwLen ); // Get the size required.
#endif // LATE_BIND_URLMON_WININET
_ASSERTE ( 0 != dwLen ); TCHAR* pszURL = new TCHAR [ dwLen + 1 ]; _ASSERTE ( pszURL ); if ( NULL != pszURL ) { // Incredibly, on Win98, the URL is terminated with a single byte \0.
// Intializing this buffer to zero assures full termination of the string.
dwLen += 1; memset ( pszURL, 0, sizeof(TCHAR) * dwLen ); #ifdef LATE_BIND_URLMON_WININET
if ( (*m_pfnInternetCreateUrl)( &urlc, 0, pszURL, &dwLen ) ) #else
if ( InternetCreateUrl ( &urlc, 0, pszURL, &dwLen ) ) #endif // LATE_BIND_URLMON_WININET
{ m_bstrBaseURL = pszURL; } else { hr = HRESULT_FROM_WIN32 ( GetLastError () ); } delete [] pszURL; }
delete [] pszPath; } else { return E_FAIL; }
return hr; }
// The most complicated scenario for "guessing" at the base URL.
// URLs like http://www.x.com/stuff could be either a file or a directory;
// a default page might actually be loaded. We guess based on whether or
// not the last item in the path contains a period. If so, we eliminate it.
// We make sure the path ends with a '/'.
//
HRESULT CProxyFrame::SetBaseUrlFromUrlComponents ( URL_COMPONENTS & urlc ) { _ASSERTE ( INTERNET_SCHEME_FILE != urlc.nScheme );
BOOL bfPeriodIncluded = FALSE; HRESULT hr = S_OK;
if ( 0 == urlc.dwSchemeLength ) { m_bstrBaseURL = L""; return S_FALSE; }
// Scan backwards over path for beginning, '/'
TCHAR c = 0; int iPos = 0;
for ( iPos = urlc.dwUrlPathLength - 1; iPos >= 0; iPos-- ) { c = urlc.lpszUrlPath[iPos]; if ( '/' == c ) { break; } if ( '.' == c ) { bfPeriodIncluded = TRUE; } }
if ( bfPeriodIncluded ) { if ( 0 > iPos ) iPos = 0; urlc.lpszUrlPath[iPos] = '\0'; // Truncate at the '/', or beginning
urlc.dwUrlPathLength = _tcslen ( urlc.lpszUrlPath ); }
// Recreate the URL:
DWORD dwLen = 0; #ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnInternetCreateUrl ); (*m_pfnInternetCreateUrl)( &urlc, 0, NULL, &dwLen ); // Get the size required.
#else
InternetCreateUrl ( &urlc, 0, NULL, &dwLen ); // Get the size required.
#endif // LATE_BIND_URLMON_WININET
_ASSERTE ( 0 != dwLen ); TCHAR* pszURL = new TCHAR [ dwLen + 1 ]; _ASSERTE ( pszURL ); if ( NULL != pszURL ) { dwLen += 1; memset ( pszURL, 0, sizeof(TCHAR) * dwLen ); #ifdef LATE_BIND_URLMON_WININET
if ( (*m_pfnInternetCreateUrl)( &urlc, 0, pszURL, &dwLen ) ) #else
if ( InternetCreateUrl ( &urlc, 0, pszURL, &dwLen ) ) #endif
{ m_bstrBaseURL = pszURL;
// Append a '/' if needed.
WCHAR wc = m_bstrBaseURL.m_str[m_bstrBaseURL.Length () - 1]; if ( ( WCHAR('/') != wc ) && ( NULL != urlc.lpszHostName ) ) // hostname: special case for user pluggable protocols
{ m_bstrBaseURL += L"/"; } } else { hr = HRESULT_FROM_WIN32 ( GetLastError () ); } delete [] pszURL; } return hr; }
// Crack the URL, determine if it's a file scheme or other, and call the appropriate handler.
//
HRESULT CProxyFrame::SetBaseURLFromURL ( const CComBSTR& bstrURL ) { USES_CONVERSION;
HRESULT hr = S_OK; URL_COMPONENTS urlc; TCHAR *ptszScheme = NULL; TCHAR *ptszHostName = NULL; TCHAR *ptszUrlPath = NULL; BOOL fSuccess = FALSE; TCHAR* tszURL = NULL;
_ASSERTE ( 0 != bstrURL.Length () );
tszURL = OLE2T ( bstrURL ); _ASSERTE ( tszURL ); if ( NULL == tszURL ) { return E_OUTOFMEMORY; }
memset ( &urlc, 0, sizeof ( urlc ) ); urlc.dwStructSize = sizeof ( urlc ); urlc.dwSchemeLength = 1; urlc.dwHostNameLength = 1; urlc.dwUrlPathLength = 1;
#ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnInternetCrackUrl ); fSuccess = (*m_pfnInternetCrackUrl)( tszURL, 0, 0, &urlc ); #else
fSuccess = InternetCrackUrl ( tszURL, 0, 0, &urlc ); #endif // LATE_BIND_URLMON_WININET
if ( !fSuccess ) { return E_FAIL; }
if ( 0 != urlc.dwSchemeLength ) { urlc.dwSchemeLength++; ptszScheme = new TCHAR[urlc.dwSchemeLength]; urlc.lpszScheme = ptszScheme; if ( NULL == ptszScheme ) goto ONERROR; } if ( 0 != urlc.dwHostNameLength ) { urlc.dwHostNameLength++; ptszHostName = new TCHAR[urlc.dwHostNameLength]; urlc.lpszHostName = ptszHostName; if ( NULL == ptszHostName ) goto ONERROR; } if ( 0 != urlc.dwUrlPathLength ) { urlc.dwUrlPathLength++; ptszUrlPath = new TCHAR[urlc.dwUrlPathLength]; urlc.lpszUrlPath = ptszUrlPath; if ( NULL == ptszUrlPath ) goto ONERROR; }
#ifdef LATE_BIND_URLMON_WININET
fSuccess = (*m_pfnInternetCrackUrl)( tszURL, 0, 0, &urlc ); #else
fSuccess = InternetCrackUrl ( tszURL, 0, 0, &urlc ); #endif
if ( fSuccess ) { if ( INTERNET_SCHEME_FILE == urlc.nScheme ) { hr = SetBaseUrlFromFileUrlComponents ( urlc ); } else { hr = SetBaseUrlFromUrlComponents ( urlc ); } }
ONERROR: if ( ptszScheme ) delete [] ptszScheme; if ( ptszHostName ) delete [] ptszHostName; if ( ptszUrlPath ) delete [] ptszUrlPath;
return hr; }
// Given a UNC file name, set the m_bstrBaseURL member variable.
// if bstrFName is empty, set m_bstrBaseURL to empty.
// Else, scan backward to the first "\" or the beginning of the string.
// Truncate the string at this point. If the resultant string is empty,
// add ".". Then, add "\".
//
HRESULT CProxyFrame::SetBaseURLFromFileName ( const CComBSTR& bstrFName ) { if ( 0 == bstrFName.Length () ) { m_bstrBaseURL = L""; } else { WCHAR* pwzstr = new WCHAR[bstrFName.Length () + 1]; _ASSERTE ( pwzstr ); if ( NULL != pwzstr ) { WCHAR wc = 0; int iPos = 0;
// Scan backwards and modify in copy (never in BSTR, please) for beginning or '\'
memcpy ( pwzstr, bstrFName.m_str, sizeof(WCHAR) * (bstrFName.Length () + 1) ); for ( iPos = wcslen ( pwzstr ) - 1; iPos >= 0; iPos-- ) { wc = pwzstr[iPos]; pwzstr[iPos] = WCHAR('\0'); // Delete first, ask questions later. '\' must go.
if ( WCHAR('\\') == wc ) { break; } } m_bstrBaseURL = pwzstr; delete [] pwzstr;
// If empty, add a '.'
if ( 0 == m_bstrBaseURL.Length () ) { m_bstrBaseURL += L"."; } m_bstrBaseURL += L"\\"; } else { return E_FAIL; } } return S_OK; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// Security oriented routines
//
///////////////////////////////////////////////////////////////////////////////////////////
// This is a critical security issue:
// The pluggable protocol's ParseURL is called with PARSE_SECURITY_URL in the SFS control.
// If the BaseURL is empty, and if we're hosted in Trident, we should return the
// URL of the hosting page.
// If there is no Trident host, say we're hosted in VB, return the bootdrive + : + /.
// Bootdrive is not always C.
//
HRESULT CProxyFrame::GetSecurityURL (CComBSTR& bstrSecurityURL ) { HRESULT hr = S_OK; IOleClientSite *piClientSiteUnreffed = NULL;
bstrSecurityURL = L""; piClientSiteUnreffed = m_pCtl->m_spClientSite; if ( NULL != piClientSiteUnreffed ) { CComPtr<IOleContainer> spContainer = NULL; hr = piClientSiteUnreffed->GetContainer ( &spContainer ); if ( SUCCEEDED ( hr ) && spContainer ) { CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHostDoc ( spContainer ); if ( spHostDoc ) { CComPtr<IHTMLLocation> spHostLoc = NULL;
spHostDoc->get_location ( &spHostLoc ); if ( spHostLoc ) { BSTR bsOut; hr = spHostLoc->get_href ( &bsOut ); if ( SUCCEEDED ( hr ) ) { bstrSecurityURL.Empty (); bstrSecurityURL.Attach ( bsOut ); } } } else { // If we are not hosted in Trident, use local machine access:
TCHAR tszDrive[4]; GetModuleFileName ( _Module.m_hInst, tszDrive, 3 ); // Get X:\.
_ASSERTE ( TCHAR(':') == tszDrive[1] ); _ASSERTE ( TCHAR('\\') == tszDrive[2] ); bstrSecurityURL = tszDrive; hr = S_OK; } } } return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// Pluggable protocol oriented routines
//
///////////////////////////////////////////////////////////////////////////////////////////
// Register our pluggable protocol handler so dhtmledN[N...] is loaded by our code.
//
HRESULT CProxyFrame::RegisterPluggableProtocol() { HRESULT hr;
// Get InternetSession
CComPtr<IInternetSession> srpSession; #ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnCoInternetGetSession ); hr = (*m_pfnCoInternetGetSession)(0, &srpSession, 0); #else
hr = CoInternetGetSession (0, &srpSession, 0); #endif // LATE_BIND_URLMON_WININET
if ( FAILED ( hr ) ) { return hr; }
if(m_pProtInfo == NULL) { hr = CComObject<CDHTMLEdProtocolInfo>::CreateInstance(&m_pProtInfo); if ( FAILED ( hr ) ) { return hr; }
// CreateInstance - doesnt AddRef
m_pProtInfo->GetUnknown()->AddRef(); }
hr = srpSession->RegisterNameSpace( static_cast<IClassFactory*>(m_pProtInfo), CLSID_DHTMLEdProtocol, m_wszProtocol, 0, NULL, 0);
if ( FAILED ( hr ) ) { return hr; }
CComQIPtr <IProtocolInfoConnector, &IID_IProtocolInfoConnector> piPic ( m_pProtInfo ); _ASSERTE ( piPic ); piPic->SetProxyFrame ( (SIZE_T*)this );
ATLTRACE( _T("CProxyFrame::Registered ProtocolInfo\n"));
return NOERROR; }
// Unregister the pluggable protocol handler installed in RegisterPluggableProtocol
//
HRESULT CProxyFrame::UnRegisterPluggableProtocol() { if(m_pProtInfo == NULL) return E_UNEXPECTED;
// Get InternetSession
HRESULT hr; CComPtr<IInternetSession> srpSession;
#ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnCoInternetGetSession ); hr = (*m_pfnCoInternetGetSession)(0, &srpSession, 0); #else
hr = CoInternetGetSession (0, &srpSession, 0); #endif // LATE_BIND_URLMON_WININET
if(SUCCEEDED(hr)) { // UnRegister Protocol
srpSession->UnregisterNameSpace( static_cast<IClassFactory*>(m_pProtInfo), m_wszProtocol);
}
m_pProtInfo->GetUnknown()->Release(); m_pProtInfo = NULL;
ATLTRACE(_T("CProxyFrame::UnRegistered ProtocolInfo\n"));
return NOERROR; }
// Workhorse routine that actually performs the loading of the control, including filtering.
// ParseAndBind calls this to retrieve the data to be displayed in the control.
//
HRESULT CProxyFrame::GetFilteredStream ( IStream** ppStream ) { USES_CONVERSION; HRESULT hr = S_OK; LPTSTR pFileName = NULL; CComPtr<IStream> piStream; BOOL bfLoadingFromBSTR = ( 0 != m_bstrLoadText.Length () );
*ppStream = NULL; m_bfReloadAttempted = TRUE;
if ( !bfLoadingFromBSTR ) { _ASSERTE(m_bstrCurDocPath);
pFileName = OLE2T(m_bstrCurDocPath);
_ASSERTE(pFileName);
if (NULL == pFileName) return E_OUTOFMEMORY; }
if ( bfLoadingFromBSTR ) { hr = m_pSite->HrBstrToStream(m_bstrLoadText, &piStream); } else if ( m_bfIsURL ) { hr = m_pSite->HrURLToStream(pFileName, &piStream); } else { hr = m_pSite->HrFileToStream(pFileName, &piStream); }
if (FAILED( hr )) { m_bstrCurDocPath.Empty (); m_bstrBaseURL.Empty ();
// Get TriEdit into a reasonable state by loading an empty document
// If we reinstanced successfully, this should never fail
// Also, this will make ignoring the above assert benign
if (FAILED(m_pSite->HrBstrToStream(m_bstrInitialDoc, ppStream))) { _ASSERTE(SUCCEEDED(hr)); }
} else { if ( m_vbBrowseMode ) { piStream.p->AddRef (); *ppStream = piStream; } else { hr = m_pSite->HrFilter(TRUE, piStream, ppStream, m_dwFilterFlags); }
if (FAILED(hr)) { m_pSite->HrBstrToStream(m_bstrInitialDoc, ppStream); } else { m_dwFilterOutFlags = m_dwFilterFlags; } }
// Store the result to return from the (indirectly) called routine,
// but don't return an error to ParseAndBind!
if ( FAILED(hr) && ( ! bfLoadingFromBSTR ) ) { m_hrDeferredLoadError = hr; // Stash this away, we'll pic it up in LoadDocument
hr = S_OK; }
return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// Document event handling routines
//
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT CProxyFrame::OnTriEditEvent ( const GUID& iidEventInterface, DISPID dispid ) { HRESULT hr = S_OK;
if ( DIID_HTMLDocumentEvents == iidEventInterface ) { switch ( dispid ) { case DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS: case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN: if ( DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN == dispid ) { m_pCtl->Fire_onmousedown(); } else if ( DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS == dispid ) { m_pCtl->Fire_onkeypress(); }
// Make the control UIActive if it was clicked in. Since the DocObject swallows the clicks,
// the control isn't activated automatically.
// Not needed in browse mode.
if ( !m_pCtl->m_bUIActive && ! m_vbBrowseMode ) { m_pCtl->DoVerbUIActivate ( NULL, NULL ); if ( m_hWndObj != NULL ) { ::SetFocus( m_hWndObj ); } } break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE: m_pCtl->Fire_onmousemove(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP: m_pCtl->Fire_onmouseup(); // onclick is not delivered in edit mode. First one lost in broswe mode.
m_pCtl->Fire_onclick(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT: m_pCtl->Fire_onmouseout(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER: m_pCtl->Fire_onmouseover(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONCLICK: // We do not fire the onclick event in response.
// It is only delivered in browse mode, and in addition,
// the first onclick is lost. We fire on onmouseup.
//m_pCtl->Fire_onclick();
// The addition of the DesignMode property, in addition to <BASE TARGET="_top">
// makes links exploitable for cross-zone access in the SFS control.
// We must disable clicks (user and script) in the SFS control to prevent this.
if ( m_pCtl->IsSafeForScripting ()) { CComPtr<IHTMLDocument2> spHtmlDoc; hr = HrGetDoc ( &spHtmlDoc ); if ( SUCCEEDED ( hr ) && spHtmlDoc ) { CComPtr<IHTMLWindow2> spWindow;
hr = spHtmlDoc->get_parentWindow ( &spWindow ); if ( SUCCEEDED ( hr ) && spWindow ) { CComPtr<IHTMLEventObj> spEvt; hr = spWindow->get_event ( &spEvt ); if ( SUCCEEDED ( hr ) && spEvt ) { CComVariant varFalse(VARIANT_FALSE);
spEvt->put_cancelBubble ( VARIANT_TRUE ); spEvt->put_returnValue ( varFalse ); } } } }
break;
case DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK: m_pCtl->Fire_ondblclick(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN: m_pCtl->Fire_onkeydown(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONKEYUP: m_pCtl->Fire_onkeyup(); break;
case DISPID_HTMLDOCUMENTEVENTS_ONREADYSTATECHANGE: m_pCtl->Fire_onreadystatechange(); break;
default: _ASSERTE ( TRUE ); break; } } else if ( DIID_HTMLWindowEvents == iidEventInterface ) { // I expected to get these, but I'm not...
switch ( dispid ) { case DISPID_HTMLWINDOWEVENTS_ONLOAD: case DISPID_HTMLWINDOWEVENTS_ONUNLOAD: case DISPID_HTMLWINDOWEVENTS_ONHELP: case DISPID_HTMLWINDOWEVENTS_ONFOCUS: case DISPID_HTMLWINDOWEVENTS_ONBLUR: case DISPID_HTMLWINDOWEVENTS_ONERROR: case DISPID_HTMLWINDOWEVENTS_ONRESIZE: case DISPID_HTMLWINDOWEVENTS_ONSCROLL: case DISPID_HTMLWINDOWEVENTS_ONBEFOREUNLOAD: hr = S_OK; break; default: _ASSERTE ( TRUE ); break; } } return hr; }
///////////////////////////////////////////////////////////////////////////////////////////
//
// Dynamic loading routines, used in 4.0 versions
//
///////////////////////////////////////////////////////////////////////////////////////////
#ifdef LATE_BIND_URLMON_WININET
// Load Urlmon and Wininet and get the proc addresses of every routine we use.
// We must be able to register the control, even if these libraries are not installed.
// NOTE:
// This routine loads ANSI versions. Needs addaptation for UNICODE.
//
BOOL CProxyFrame::DynLoadLibraries () { m_hUlrMon = LoadLibrary ( TEXT("URLMON.DLL") ); m_hWinINet = LoadLibrary ( TEXT("WININET.DLL") ); if ( ( NULL == m_hUlrMon ) || ( NULL == m_hWinINet ) ) { DynUnloadLibraries (); return FALSE; }
m_pfnCoInternetCombineUrl = (PFNCoInternetCombineUrl)GetProcAddress ( m_hUlrMon, "CoInternetCombineUrl" ); _ASSERTE ( m_pfnCoInternetCombineUrl ); m_pfnCoInternetParseUrl = (PFNCoInternetParseUrl)GetProcAddress ( m_hUlrMon, "CoInternetParseUrl" ); _ASSERTE ( m_pfnCoInternetParseUrl ); m_pfnCreateURLMoniker = (PFNCreateURLMoniker)GetProcAddress ( m_hUlrMon, "CreateURLMoniker" ); _ASSERTE ( m_pfnCreateURLMoniker ); m_pfnCoInternetGetSession = (PFNCoInternetGetSession)GetProcAddress ( m_hUlrMon, "CoInternetGetSession" ); _ASSERTE ( m_pfnCoInternetGetSession ); m_pfnURLOpenBlockingStream = (PFNURLOpenBlockingStream)GetProcAddress ( m_hUlrMon, "URLOpenBlockingStreamA" ); _ASSERTE ( m_pfnURLOpenBlockingStream );
m_pfnDeleteUrlCacheEntry = (PFNDeleteUrlCacheEntry)GetProcAddress ( m_hWinINet, "DeleteUrlCacheEntry" ); _ASSERTE ( m_pfnDeleteUrlCacheEntry ); m_pfnInternetCreateUrl = (PFNInternetCreateUrl)GetProcAddress ( m_hWinINet, "InternetCreateUrlA" ); _ASSERTE ( m_pfnInternetCreateUrl ); m_pfnInternetCrackUrl = (PFNInternetCrackURL)GetProcAddress ( m_hWinINet, "InternetCrackUrlA" ); _ASSERTE ( m_pfnInternetCrackUrl );
return ( m_pfnCoInternetCombineUrl && m_pfnCoInternetParseUrl && m_pfnCreateURLMoniker && m_pfnCoInternetGetSession && m_pfnURLOpenBlockingStream && m_pfnDeleteUrlCacheEntry && m_pfnInternetCreateUrl && m_pfnInternetCrackUrl ); }
// Release the libraries loaded by DynLoadLibraries
//
void CProxyFrame::DynUnloadLibraries () { if ( NULL != m_hUlrMon ) { FreeLibrary ( m_hUlrMon ); m_hUlrMon = NULL; } if ( NULL != m_hWinINet ) { FreeLibrary ( m_hWinINet ); m_hWinINet = NULL; }
m_pfnCoInternetCombineUrl = NULL; m_pfnCoInternetParseUrl = NULL; m_pfnCreateURLMoniker = NULL; m_pfnCoInternetGetSession = NULL; m_pfnURLOpenBlockingStream = NULL;
m_pfnDeleteUrlCacheEntry = NULL; m_pfnInternetCreateUrl = NULL; m_pfnInternetCrackUrl = NULL; } #endif // LATE_BIND_URLMON_WININET
///////////////////////////////////////////////////////////////////////////////////////////
//
// Utility routines
//
///////////////////////////////////////////////////////////////////////////////////////////
// Return the IHTMLDocument2 pointer from the hosted doc.
//
HRESULT CProxyFrame::HrGetDoc(IHTMLDocument2 **ppDoc) { HRESULT hr = E_FAIL; IUnknown* lpUnk = m_pSite->GetObjectUnknown();
if (FALSE == m_fActivated) return DE_E_UNEXPECTED;
_ASSERTE(ppDoc);
if (NULL == ppDoc) return DE_E_INVALIDARG;
_ASSERTE(lpUnk);
if ( m_bfIsLoading ) return DE_E_UNEXPECTED; // This is invalid while document is still loading.
if (lpUnk != NULL) { // Request the "document" object from the MSHTML
*ppDoc = NULL; hr = lpUnk->QueryInterface(IID_IHTMLDocument2, (void **)ppDoc); }
_ASSERTE(SUCCEEDED(hr)); // this should always succeed
return hr; }
// Helper routine to set any Boolean Trident property
//
HRESULT CProxyFrame::HrTridentSetPropBool(ULONG cmd, BOOL bVal) { HRESULT hr = S_OK; VARIANT varIn;
VariantInit(&varIn); V_VT(&varIn) = VT_BOOL;
#pragma warning(disable: 4310) // cast truncates constant value
bVal ? V_BOOL(&varIn) = VARIANT_TRUE : V_BOOL(&varIn) = VARIANT_FALSE; #pragma warning(default: 4310) // cast truncates constant value
hr = HrExecCommand(&CGID_MSHTML, cmd, MSOCMDEXECOPT_DONTPROMPTUSER, &varIn, NULL);
// this should always succeed since all props
// should be set in correct phases of Trident creation
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Helper routine to get any Boolean Trident property
//
HRESULT CProxyFrame::HrTridentGetPropBool(ULONG cmd, BOOL& bVal) { HRESULT hr = S_OK; OLECMDF cmdf = (OLECMDF) 0;
if (SUCCEEDED(HrQueryStatus(&CGID_MSHTML, cmd, &cmdf))) { bVal = (cmdf & OLECMDF_ENABLED) == OLECMDF_ENABLED ? TRUE : FALSE; }
// this should always succeed since all props
// should be set in correct phases of Trident creation
_ASSERTE(SUCCEEDED(hr)); return hr; }
// Store the BSTR so LoadFilteredStream can access it, and load a URL with our protocol
// to kick off the load/resolve/display through the pluggable protocol handler.
//
// Clear the BaseURL, and mark the control "Loading..."
//
HRESULT CProxyFrame::LoadBSTRDeferred ( BSTR bVal ) { HRESULT hr = E_FAIL;
_ASSERTE ( m_pUnkTriEdit );
m_bstrLoadText = bVal;
CComPtr<IMoniker> srpMoniker; CComPtr<IBindCtx> srpBindCtx; CComQIPtr<IPersistMoniker, &IID_IPersistMoniker> srpPM (m_pUnkTriEdit); _ASSERTE ( srpPM );
if ( srpPM ) { #ifdef LATE_BIND_URLMON_WININET
_ASSERTE ( m_pfnCreateURLMoniker ); hr = (*m_pfnCreateURLMoniker)( NULL, m_wszProtocolPrefix, &srpMoniker ); #else
hr = CreateURLMoniker ( NULL, m_wszProtocolPrefix, &srpMoniker ); #endif // LATE_BIND_URLMON_WININET
_ASSERTE ( SUCCEEDED( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = ::CreateBindCtx(NULL, &srpBindCtx); _ASSERTE ( SUCCEEDED( hr ) ); if ( SUCCEEDED ( hr ) ) { m_bfIsLoading = TRUE; m_bfBaseURLFromBASETag = FALSE;
hr = srpPM->Load(FALSE, srpMoniker, srpBindCtx, STGM_READ);
_ASSERTE ( SUCCEEDED( hr ) ); } } } return hr; }
// Set the document stream's dirty flag
//
HRESULT CProxyFrame::SetDirtyFlag ( BOOL bfMakeDirty ) { CComVariant varDirty;
varDirty = bfMakeDirty ? true : false;
return HrExecCommand(&CGID_MSHTML, IDM_SETDIRTY, MSOCMDEXECOPT_DONTPROMPTUSER, &varDirty, NULL); }
// properties that can be set only after TriEdit is in running state
HRESULT CProxyFrame::HrSetRuntimeProperties() { HRESULT hr = S_OK;
if (FAILED(hr = HrSetPropActivateControls(m_fActivateControls))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetPropActivateApplets(m_fActivateApplets))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetPropActivateDTCs(m_fActivateDTCs))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
// toggle properties
if (FAILED(hr = HrSetPropShowAllTags(m_fShowAllTags))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetPropShowBorders(m_fShowBorders))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
error:
return hr; }
HRESULT CProxyFrame::HrGetCurrentDocumentPath(BSTR* bVal) { HRESULT hr = S_OK;
_ASSERTE(bVal);
if (NULL == bVal) return E_INVALIDARG;
*bVal = m_bstrCurDocPath.Copy (); return hr; }
// properties that can only be set after UIActivation
HRESULT CProxyFrame::HrSetDocLoadedProperties() { HRESULT hr = S_OK; BOOL bGoodUndoBehavior = TRUE;
bGoodUndoBehavior = TRUE; if (FAILED(HrTridentGetPropBool(IDM_GOOD_UNDO_BEHAVIOR, bGoodUndoBehavior))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetAbsoluteDropMode(m_fAbsoluteDropMode))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetSnapToGridX(m_ulSnapToGridX))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetSnapToGridY(m_ulSnapToGridY))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
if (FAILED(hr = HrSetSnapToGrid(m_fSnapToGrid))) { _ASSERTE(SUCCEEDED(hr)); goto error; }
error:
return hr; }
// HrExecInsertTable helper. Extract the safearrys
//
HRESULT CProxyFrame::HrGetTableSafeArray(IDEInsertTableParam* pTable, LPVARIANT pVarIn) { HRESULT hr = S_OK; UINT i = 0; SAFEARRAY FAR* psa = NULL; SAFEARRAYBOUND rgsabound[1] = {0}; LONG ix[1] = {0}; VARIANT varElem; LONG nNumRows = 0; LONG nNumCols = 0; BSTR bstrTableAttrs = NULL; BSTR bstrCellAttrs = NULL; BSTR bstrCaption = NULL;
_ASSERTE(pTable);
if (FAILED(hr = pTable->get_NumRows(&nNumRows))) { _ASSERTE(SUCCEEDED(hr)); return hr; }
if (FAILED(hr = pTable->get_NumCols(&nNumCols))) { _ASSERTE(SUCCEEDED(hr)); return hr; }
if (FAILED(hr = pTable->get_TableAttrs(&bstrTableAttrs))) { _ASSERTE(SUCCEEDED(hr)); return hr; } _ASSERTE(bstrTableAttrs);
if (FAILED(hr = pTable->get_CellAttrs(&bstrCellAttrs))) { _ASSERTE(SUCCEEDED(hr)); return hr; } _ASSERTE(bstrCellAttrs);
if (FAILED(hr = pTable->get_Caption(&bstrCaption))) { _ASSERTE(SUCCEEDED(hr)); return hr; } _ASSERTE(bstrCaption);
rgsabound[0].lLbound = 0; rgsabound[0].cElements = 5;
psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound); _ASSERTE(psa);
if(NULL == psa) return E_OUTOFMEMORY;
VariantInit(pVarIn); V_VT(pVarIn) = VT_ARRAY; V_ARRAY(pVarIn) = psa;
i=0;
// elmement 1: number of rows
ix[0] = i; VariantInit(&varElem); V_VT(&varElem) = VT_I4; V_I4(&varElem) = nNumRows; hr = SafeArrayPutElement(psa, ix, &varElem); VariantClear(&varElem); ++i;
// elmement 2: number of columns
ix[0] = i; VariantInit(&varElem); V_VT(&varElem) = VT_I4; V_I4(&varElem) = nNumCols; hr = SafeArrayPutElement(psa, ix, &varElem); VariantClear(&varElem); ++i;
// elmement 3: table tag attributes
ix[0] = i; VariantInit(&varElem); V_VT(&varElem) = VT_BSTR; V_BSTR(&varElem) = bstrTableAttrs; hr = SafeArrayPutElement(psa, ix, &varElem); VariantClear(&varElem); ++i;
// elmement 4: cell attributes
ix[0] = i; VariantInit(&varElem); V_VT(&varElem) = VT_BSTR; V_BSTR(&varElem) = bstrCellAttrs; hr = SafeArrayPutElement(psa, ix, &varElem); VariantClear(&varElem); ++i;
// elmement 5: table caption
// VK bug 15857: don't include caption if it's empty.
if ( 0 != SysStringLen ( bstrCaption ) ) { ix[0] = i; VariantInit(&varElem); V_VT(&varElem) = VT_BSTR; V_BSTR(&varElem) = bstrCaption; hr = SafeArrayPutElement(psa, ix, &varElem); VariantClear(&varElem); ++i; }
return hr; }
// Determine which object is selected, and return its position
//
HRESULT CProxyFrame::GetSelectionPos ( LPPOINT lpWhere ) { HRESULT hr = E_FAIL; CComPtr<IHTMLDocument2> spHtmlDoc = NULL; CComPtr<IHTMLSelectionObject> spSelectionObj = NULL; CComPtr<IDispatch> spRangeDisp = NULL; CComPtr<IHTMLElement> spElement = NULL; lpWhere->x = 0; lpWhere->y = 0;
hr = HrGetDoc ( &spHtmlDoc ); if ( SUCCEEDED ( hr ) ) { hr = spHtmlDoc->get_selection ( &spSelectionObj ); if ( SUCCEEDED ( hr ) ) { hr = spSelectionObj->createRange ( &spRangeDisp ); if (SUCCEEDED ( hr ) ) { CComQIPtr<IHTMLTxtRange, &IID_IHTMLTxtRange> spTextRange ( spRangeDisp ); if ( spTextRange ) { hr = spTextRange->parentElement(&spElement); } else { CComQIPtr<IHTMLControlRange, &IID_IHTMLControlRange> spControlRange ( spRangeDisp ); if ( spControlRange ) { hr = spControlRange->commonParentElement(&spElement); } } if ( spElement ) { CComPtr<IHTMLStyle> spStyle = NULL; hr = spElement->get_style ( &spStyle ); if ( spStyle ) { spStyle->get_pixelTop ( &( lpWhere->y ) ); spStyle->get_pixelLeft ( &( lpWhere->x ) ); } } } } } return hr; }
// If the current document is loaded from a URL, return the empty string.
// If it's loaded from a file, strip the path part off and return just the file name.
// Return S_FALSE for a URL or no file name. S_OK if a file name is supplied.
//
HRESULT CProxyFrame::GetCurDocNameWOPath ( CComBSTR& bstrDocName ) { bstrDocName = L"";
if ( m_bfIsURL ) { return S_FALSE; } if ( 0 == m_bstrCurDocPath.Length () ) { return S_FALSE; }
bstrDocName = m_bstrCurDocPath;
// Truncate at first backslash:
_wcsrev ( bstrDocName ); wcstok ( bstrDocName, OLESTR( "\\" ) ); _wcsrev ( bstrDocName );
return S_OK; }
// Used by ShowContextMenu to properly offset the position of the click
//
HRESULT CProxyFrame::GetScrollPos ( LPPOINT lpPos ) { HRESULT hr = E_FAIL; CComPtr<IHTMLDocument2> spHtmlDoc = NULL; CComPtr<IHTMLElement> spBodyElem = NULL;
_ASSERTE ( lpPos ); hr = HrGetDoc ( &spHtmlDoc ); // It's possible that the user clicked while the doc was still loading.
// If so, just return 0, 0.
if ( DE_E_UNEXPECTED == hr ) { lpPos->x = lpPos->y = 0; return S_FALSE; }
_ASSERTE ( spHtmlDoc ); if ( SUCCEEDED ( hr ) ) { hr = spHtmlDoc->get_body ( &spBodyElem ); _ASSERTE ( spBodyElem ); if ( SUCCEEDED ( hr ) ) { CComQIPtr<IHTMLTextContainer, &IID_IHTMLTextContainer> spHtmlTextCont ( spBodyElem ); if ( spHtmlTextCont ) { LONG lxPos = 0; LONG lyPos = 0;
hr = spHtmlTextCont->get_scrollLeft ( &lxPos ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = spHtmlTextCont->get_scrollTop ( &lyPos ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( SUCCEEDED ( hr ) ) { lpPos->x = lxPos; lpPos->y = lyPos; } } } else { hr = E_NOINTERFACE; _ASSERTE ( SUCCEEDED ( hr ) ); } } } return hr; }
HRESULT CProxyFrame::GetContainer ( LPOLECONTAINER* ppContainer ) { _ASSERTE ( m_pCtl ); _ASSERTE ( m_pCtl->m_spClientSite ); if ( m_pCtl->m_spClientSite ) { return m_pCtl->m_spClientSite->GetContainer ( ppContainer ); } return E_NOTIMPL; }
// For the Safe for Scripting control, make sure the URL specified comes from
// the same host as the SecurityURL, the URL of the hosting container..
// Note that this makes the SFS control virtually useless in VB, which returns
// the Boot Drive Root Folder as the Security URL.
//
HRESULT CProxyFrame::CheckCrossZoneSecurity ( BSTR urlToLoad ) { HRESULT hr = S_OK;
CComPtr<IInternetSecurityManager> srpSec; CComBSTR bstrSecURL;
hr = GetSecurityURL ( bstrSecURL ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( SUCCEEDED ( hr ) ) { #ifdef LATE_BIND_URLMON_WININET
hr = (m_pfnCoInternetCreateSecurityManager)( NULL, &srpSec, 0 ); #else
hr = CoInternetCreateSecurityManager( NULL, &srpSec, 0 ); #endif // LATE_BIND_URLMON_WININET
if ( SUCCEEDED ( hr ) && srpSec ) { BYTE* pbSidToLoad = NULL; BYTE* pbDSidSecURL = NULL; DWORD dwSizeToLoad = INTERNET_MAX_URL_LENGTH; DWORD dwSizeSecURL = INTERNET_MAX_URL_LENGTH;
pbSidToLoad = new BYTE [INTERNET_MAX_URL_LENGTH]; pbDSidSecURL = new BYTE [INTERNET_MAX_URL_LENGTH];
hr = srpSec->GetSecurityId ( urlToLoad, pbSidToLoad, &dwSizeToLoad, 0 ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = srpSec->GetSecurityId ( bstrSecURL, pbDSidSecURL, &dwSizeSecURL, 0 ); _ASSERTE ( SUCCEEDED ( hr ) ); if ( SUCCEEDED ( hr ) ) { hr = DE_E_ACCESS_DENIED;
if ( ( dwSizeToLoad == dwSizeSecURL ) && ( 0 == memcmp ( pbSidToLoad, pbDSidSecURL, dwSizeToLoad ) ) ) { hr = S_OK; } } }
delete [] pbSidToLoad; delete [] pbDSidSecURL; } else { // BUG 597887: If CoInternetCreateSecurityManager returns NULL and success, return error:
if ( !srpSec ) { hr = E_UNEXPECTED; } } } return hr; }
// A specialization of CheckCrossZoneSecurity which works on the current selection.
// Bug 547802 indicated a regression in execCommand, so we will assure safety ourselves.
//
HRESULT CProxyFrame::CheckCrossZoneSecurityOfSelection () { HRESULT hr = S_OK; CComPtr<IHTMLDocument2> spDOM; CComPtr<IServiceProvider> srpSP; CComPtr<IHTMLEditServices> srpEditor; CComPtr<ISelectionServices> srpSelSvc; CComPtr<IMarkupContainer> sprMarkupCont; CComPtr<IHTMLDocument2> spSelDoc; CComPtr<IHTMLLocation> spHostLoc; CComBSTR bstrHref;
hr = HrGetDoc( &spDOM ); if ( FAILED(hr) ) goto ONERROR;
hr = spDOM->QueryInterface(IID_IServiceProvider, (LPVOID *)&srpSP); if ( FAILED(hr) ) goto ONERROR; hr = srpSP->QueryService(SID_SHTMLEditServices, IID_IHTMLEditServices, (void **)&srpEditor); if ( FAILED(hr) ) goto ONERROR; hr = srpEditor->GetSelectionServices(NULL, &srpSelSvc); if ( FAILED(hr) ) goto ONERROR; if ( !srpSelSvc ) goto ONERROR; hr = srpSelSvc->GetMarkupContainer(&sprMarkupCont); if ( FAILED(hr) ) goto ONERROR; if ( !sprMarkupCont ) goto ONERROR; hr = sprMarkupCont->QueryInterface(&spSelDoc); if ( FAILED(hr) ) goto ONERROR; hr = spSelDoc->get_location ( &spHostLoc ); if ( FAILED(hr) ) goto ONERROR; if ( !spHostLoc ) goto ONERROR; hr = spHostLoc->get_href ( &bstrHref ); if ( FAILED(hr) ) goto ONERROR; if ( !bstrHref ) goto ONERROR;
hr = CheckCrossZoneSecurity ( bstrHref );
return hr;
ONERROR: return DE_E_ACCESS_DENIED; }
HRESULT CProxyFrame::OnProgress(ULONG, ULONG, ULONG ulStatusCode, LPCWSTR) { if ( BINDSTATUS_REDIRECTING == ulStatusCode ) { // If we're the SFS control, cancel on Redirect. Otherwise, ignore it.
if ( m_pCtl->IsSafeForScripting ()) { m_bfSFSRedirect = TRUE; } } return E_NOTIMPL; }
|