Windows2003-3790/inetcore/mshtml/iextag/persist.cxx
2020-09-30 16:53:55 +02:00

1972 lines
54 KiB
C++

//+=============================================================================
//
// File : persist.cxx
//
// contents : implementation of CPersistData xtag
//
//=============================================================================
#include "headers.h"
#pragma MARK_DATA(__FILE__)
#pragma MARK_CODE(__FILE__)
#pragma MARK_CONST(__FILE__)
#ifndef X_MSHTML_H_
#define X_MSHTML_H_
#include "mshtml.h" // for IHTML*ELement*
#endif
#ifndef X_PERHIST_H_
#define X_PERHIST_H_
#include "perhist.h" // For IPersistHistory
#endif
#ifndef X_DISPEX_H_
#define X_DISPEX_H_
#include "dispex.h" // For IDispatchEx
#endif
#ifndef X_PERSIST_HXX_
#define X_PERSIST_HXX_
#include "persist.hxx"
#endif
#ifndef __X_IEXTAG_H_
#define __X_IEXTAG_H_
#include "iextag.h"
#endif
#ifndef __X_UTILS_HXX_
#define __X_UTILS_HXX_
#include "utils.hxx"
#endif
//+----------------------------------------------------------------------------
//
// Member : Init
//
// Synopsis : this method is called by MSHTML.dll to initialize peer object
//
//-----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::Init(IElementBehaviorSite * pPeerSite)
{
_pPeerSite = pPeerSite;
_pPeerSite->AddRef();
_pPeerSite->QueryInterface(IID_IElementBehaviorSiteOM, (void**)&_pPeerSiteOM);
// now register our 2 events
if (_pPeerSiteOM)
{
_pPeerSiteOM->RegisterEvent (_T("onload"), 0, NULL);
_pPeerSiteOM->RegisterEvent (_T("onsave"), 0, NULL);
}
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member : Notify
//
// Synopsis : when document is ready for modifications, setup timer calls
//
//-----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::Notify(LONG lEvent, VARIANT *)
{
return S_OK;
}
//+----------------------------------------------------------------------------
//
// member : queryType
//
// Synopsis : IPersistData method, this is used by the calling routines in order
// to avoid cocreating the XML object. This way they can query any of the
// persist Tags, and find out what persist behaiors it supprots.
//-----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::queryType(long lType, VARIANT_BOOL * pfSupportsType)
{
if (!pfSupportsType)
return E_POINTER;
*pfSupportsType = (lType == (long)_eState) ? VB_TRUE : VB_FALSE;
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member : Save
//
// Synopsis : Implementation of the IHTMLPersistData method
//
//-----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::save(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfBroadcast)
{
HRESULT hr;
BSTR bstrEvent;
if (!pfBroadcast)
{
hr = E_POINTER;
goto Cleanup;
}
*pfBroadcast = VB_TRUE;
// cache the OM pointers
InitOM(pUnk, lType);
bstrEvent = SysAllocString(L"onsave");
if (!bstrEvent)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
// allow script to save data
hr = (FireEvent(bstrEvent, pfBroadcast, TRUE));
SysFreeString(bstrEvent);
Cleanup:
return( hr );
}
//+----------------------------------------------------------------------------
//
// Member : Load
//
// Synopsis : Implementation of the IHTMLPersistData method
//
//-----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::load(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfContinue)
{
HRESULT hr;
BSTR bstrEvent;
if (!pfContinue)
{
hr = E_POINTER;
goto Cleanup;
}
*pfContinue = VB_TRUE;
// cache the OM pointers
InitOM(pUnk, lType, INIT_USE_CACHED);
bstrEvent = SysAllocString(L"onload");
if (!bstrEvent)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
// allow event handlers the chance to load from the cach
hr = (FireEvent(bstrEvent, pfContinue, FALSE));
SysFreeString(bstrEvent);
Cleanup:
return( hr );
}
//+--------------------------------------------------------------------------------
//
// Member : FireEvent
//
// Synopsis : helper method to fire the persistence events
//
//---------------------------------------------------------------------------------
HRESULT
CPersistDataPeer::FireEvent(BSTR bstrEvent, VARIANT_BOOL * pfContinue, BOOL fIsSaveEvent)
{
IHTMLEventObj * pEventObj = NULL;
IHTMLEventObj2 * pEO2 = NULL;
LONG lCookie;
HRESULT hr = E_PENDING;
VARIANT varRet;
if (!_pPeerSiteOM)
goto Cleanup;
VariantInit(&varRet);
// create an event object
hr = _pPeerSiteOM->CreateEventObject(&pEventObj);
if (hr || !pEventObj)
goto Cleanup;
// Now populate the event object with whatever properties are
// appropriate for this event:
hr = pEventObj->QueryInterface(IID_IHTMLEventObj2, (void**)&pEO2);
if (hr==S_OK)
{
BSTR bstrEventType = SysAllocString( (fIsSaveEvent) ? L"save" : L"load" );
// we need to set the event type, the event type is either
// "load" or "save".
if (bstrEventType)
{
pEO2->put_type( bstrEventType );
SysFreeString(bstrEventType);
}
}
// get the event cookie to fire the event
hr = _pPeerSiteOM->GetEventCookie (bstrEvent, &lCookie);
if (hr)
goto Cleanup;
hr = _pPeerSiteOM->FireEvent (lCookie, pEventObj);
if (pfContinue)
{
hr = pEventObj->get_returnValue(&varRet);
if (!hr)
*pfContinue = ((V_VT(&varRet) == VT_BOOL) &&
(V_BOOL(&varRet) == VB_FALSE))? VB_FALSE : VB_TRUE;
}
Cleanup:
VariantClear(&varRet);
ReleaseInterface(pEventObj);
ReleaseInterface(pEO2);
return ( hr );
}
//+-----------------------------------------------------------------------
//
// Member : ClearOMInterfaces ()
//
// Synopsis : this helper function is called after the Save/Load persistenceCache
// operations are finished, and is responsible for freeing up any of hte OM
// interfaces that were cached.
//
//------------------------------------------------------------------------
void
CPersistDataPeer::ClearOMInterfaces()
{
ClearInterface(&_pRoot);
ClearInterface(&_pInnerXMLDoc);
}
//---------------------------------------------------------------------------
//
// Member: CPersistDataPeer::InitOM
//
// Synopsis: IHTMLPersistData OM method implementation
//
//---------------------------------------------------------------------------
HRESULT
CPersistDataPeer::InitOM(IUnknown * pUnk, long lType, DWORD dwFlags /* ==0*/)
{
HRESULT hr = S_OK;
IHTMLElement * pPeerElement = NULL;
long lElemID = -1;
BSTR bstrTag =NULL;
CBufferedStr cbsID;
IXMLDOMNodeList * pChildren = NULL;
IXMLDOMElement * pNewChild = NULL;
IXMLDOMNode * pSubTree = NULL;
if (!pUnk)
return E_INVALIDARG;
if (_pInnerXMLDoc)
{
if (dwFlags & INIT_USE_CACHED)
goto Cleanup;
else
ClearOMInterfaces();
}
// make sure we know what we have been given.
hr = (pUnk->QueryInterface(IID_IXMLDOMDocument, (void**)&_pInnerXMLDoc));
if (hr)
goto Cleanup;
// find the data value...
hr = _pInnerXMLDoc->get_documentElement( &_pRoot );
if (hr)
goto Cleanup;
// but in most cases the xmlObject is a big bucket, and we would like
// to set the _pRoot to the subtree associated with our own _pPeerElement.
// if this root doesn't exist, create it. we try to find an ID first, if
// if it is not there, then create a unique name for this child subtree
// but appending the srcID to the tagName.
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
goto Cleanup;
hr = pPeerElement->get_id(&bstrTag);
if (hr || !bstrTag || !SysStringLen(bstrTag))
{
SysFreeString(bstrTag);
hr = pPeerElement->get_sourceIndex(&lElemID);
if (hr)
goto Cleanup;
hr = pPeerElement->get_tagName(&bstrTag);
if (hr)
goto Cleanup;
hr = cbsID.QuickAppend(bstrTag);
SysFreeString(bstrTag);
if (hr)
goto Cleanup;
hr = cbsID.QuickAppend(lElemID);
if (hr)
goto Cleanup;
bstrTag = SysAllocString(cbsID);
}
if (!bstrTag)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
// now we can actually see if there is a child of this name
// We need to do this by looping over the childNode collection
// and looking for one with our name.
//--------------------------------------------------------------
hr = _pRoot->get_childNodes(&pChildren);
if (FAILED(hr))
goto Cleanup;
if (hr == S_OK)
{
long i, iLen;
hr = pChildren->get_length(&iLen);
if (FAILED(hr))
goto Cleanup;
for (i=0; i < iLen; i++)
{
IXMLDOMNode * pTemp = NULL;
BSTR bstrNodeName = NULL;
BOOL fEqual = FALSE;
hr= pChildren->get_item(i, &pTemp);
if (FAILED(hr))
break;
hr = pTemp->get_nodeName( &bstrNodeName );
if (FAILED(hr))
break;
fEqual = ! _wcsicmp(bstrTag, bstrNodeName);
SysFreeString(bstrNodeName);
if (fEqual)
{
// transfer ownership
pSubTree = pTemp;
break;
}
ClearInterface( &pTemp );
}
}
if(pSubTree)
{
// yes there's a child so use it, we have a domnode so we need to
// qi for the element
ClearInterface(&_pRoot);
hr = pSubTree->QueryInterface(IID_IXMLDOMElement, (void**)&_pRoot);
}
else
{
// no child yet so lets create one.
hr = _pInnerXMLDoc->createElement(bstrTag, &pNewChild);
if (hr || ! pNewChild)
goto Cleanup;
hr = _pRoot->appendChild(pNewChild, NULL);
if (hr)
goto Cleanup;
ClearInterface(&_pRoot);
_pRoot=pNewChild;
pNewChild = NULL; // transfer ownership
}
Cleanup:
ReleaseInterface(pPeerElement);
SysFreeString(bstrTag);
ReleaseInterface(pChildren);
ReleaseInterface(pSubTree);
ReleaseInterface(pNewChild);
return( hr );
}
//---------------------------------------------------------------------------
//
// Member: CPersistDataPeer::getAttribute
//
// Synopsis: IHTMLPersistData OM method implementation
//
//---------------------------------------------------------------------------
HRESULT
CPersistDataPeer::getAttribute (BSTR strName, VARIANT * pvarValue )
{
HRESULT hr = S_OK;
if (!pvarValue)
{
hr = E_POINTER;
goto Cleanup;
}
VariantClear(pvarValue);
if (!strName)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hr = InitOM();
if (hr)
{
// no OM pointers so fail silently
hr = S_OK;
goto Cleanup;
}
// get the child of the root that has the name strName
if (_pRoot)
{
hr = _pRoot->getAttribute(strName, pvarValue);
if (hr ==S_FALSE)
hr = S_OK;
}
Cleanup:
return hr ;
}
//---------------------------------------------------------------------------
//
// Member: CPersistDataPeer::setAttribute
//
// Synopsis: IHTMLPersistData OM method implementation
//
//---------------------------------------------------------------------------
HRESULT
CPersistDataPeer::setAttribute (BSTR strName, VARIANT varValue)
{
HRESULT hr = S_OK;
if (!strName)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hr = InitOM();
if (hr)
{
// no OM pointers so fail silently
hr = S_OK;
goto Cleanup;
}
// save this value as an attribute on the root.
if (_pRoot)
{
// TODO - look into just passing the variant into the xml object
// and let them worry about all the types... We do the processing below
// to be safe for now.
VARIANT * pvar = NULL;
CVariant cvarTemp;
if ((V_VT(&varValue)==VT_BSTR) ||
V_VT(&varValue)==(VT_BYREF|VT_BSTR))
{
pvar = (V_VT(&varValue) & VT_BYREF) ?
V_VARIANTREF(&varValue) : &varValue;
}
else if ((V_VT(&varValue)==VT_BOOL ||
V_VT(&varValue)==(VT_BYREF|VT_BOOL)))
{
// sadly, do our own bool conversion...
VARIANT_BOOL vbFlag = (V_VT(&varValue)==VT_BOOL) ?
V_BOOL(&varValue) :
V_BOOL( V_VARIANTREF(&varValue) );
V_VT(&cvarTemp) = VT_BSTR;
V_BSTR(&cvarTemp) = vbFlag ? SysAllocString(L"true") :
SysAllocString(L"false");
pvar = & cvarTemp;
}
else
{
pvar = &varValue;
hr = VariantChangeTypeEx(pvar, pvar, LCID_SCRIPTING, 0, VT_BSTR);
if (hr)
goto Cleanup;
}
hr = _pRoot->setAttribute(strName, *pvar);
if (hr ==S_FALSE)
hr = S_OK;
}
Cleanup:
return hr;
}
//---------------------------------------------------------------------------
//
// Member: CPersistDataPeer::removeDataValue
//
// Synopsis: IHTMLPersistData OM method implementation
//
//---------------------------------------------------------------------------
HRESULT
CPersistDataPeer::removeAttribute (BSTR strName)
{
HRESULT hr = S_OK;
if (!strName)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hr = InitOM();
if (hr)
{
// no OM pointers so fail silently
hr = S_OK;
goto Cleanup;
}
// get the child of the root that has the name strName
if (_pRoot)
{
hr = _pRoot->removeAttribute(strName);
if (hr ==S_FALSE)
hr = S_OK;
}
Cleanup:
return hr ;
}
//---------------------------------------------------------------------------
//
// Member: CPersistDataPeer::get_XMLDocument
//
// Synopsis: IHTMLPersistData OM proeprty implementation. this is the default
// property for this object, and as such it exposes the XMLOM
// of the user data.
//
//---------------------------------------------------------------------------
HRESULT
CPersistDataPeer::get_XMLDocument (IDispatch ** ppDisp)
{
HRESULT hr = S_OK;
if (!ppDisp)
{
hr = E_POINTER;
goto Cleanup;
}
*ppDisp = NULL;
hr = InitOM();
if (hr)
{
// no OM pointers so fail silently
hr = S_OK;
goto Cleanup;
}
if (_pInnerXMLDoc)
{
hr = _pInnerXMLDoc->QueryInterface(IID_IDispatch,
(void**)ppDisp);
}
Cleanup:
return hr;
}
//+-----------------------------------------------------------
//
// Member : GetSaveCategory
//
// Synopsis : this helper function turns the tagName fo the
// pPeerElement, into the category for its save operations.
//
//+-----------------------------------------------------------
ENUM_SAVE_CATEGORY
CPersistDataPeer::GetSaveCategory()
{
HRESULT hr = S_OK;
CVariant cvarTag;
IHTMLElement * pPeerElement = NULL;
ENUM_SAVE_CATEGORY escRet = ESC_UNKNOWN;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
goto Cleanup;
V_VT(&cvarTag) = VT_BSTR;
hr = pPeerElement->get_tagName(&V_BSTR(&cvarTag));
if (hr)
goto Cleanup;
// there's got to be a better way to do this, but for
// now I will try to put the most common ones in front.
if (0==_wcsicmp(V_BSTR(&cvarTag), L"input"))
{
// but wait!!!! don't save password type inputs
BSTR bstrType = SysAllocString(L"type");
CVariant cvarVal;
escRet = ESC_INTRINSIC;
if (!bstrType)
goto Cleanup;
hr = (pPeerElement->getAttribute(bstrType, 0, &cvarVal));
SysFreeString(bstrType);
if (hr)
goto Cleanup;
if (V_VT(&cvarVal) == VT_BSTR &&
0==_wcsicmp(V_BSTR(&cvarVal), L"password"))
{
escRet = ESC_PASSWORD;
goto Cleanup;
}
}
else if (0==_wcsicmp(V_BSTR(&cvarTag), L"script"))
{
escRet = ESC_SCRIPT;
}
else if (0==_wcsicmp(V_BSTR(&cvarTag), L"select") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"textarea") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"richtext") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"button") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"fieldset")
)
{
escRet = ESC_INTRINSIC;
}
else if (0==_wcsicmp(V_BSTR(&cvarTag), L"object") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"embed") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"applet")
)
{
escRet = ESC_CONTROL;
}
Cleanup:
ReleaseInterface(pPeerElement);
return escRet;
}
//+-----------------------------------------------------------
//
// member : GetEngineClsidForLanguage ()
//
// synopsis : another helper method that returns the CLSID of the
// scripdEngine associated with the language progID.
//
//+-----------------------------------------------------------
HRESULT
CPersistDataPeer::GetEngineClsidForLanguage(CLSID * pclsid,
IHTMLDocument2 * pBrowseDoc)
{
HRESULT hr = S_OK;
BSTR bstrLanguage = NULL;
IHTMLElement * pPeerElement = NULL;
if (!pclsid)
return E_POINTER;
*pclsid = IID_NULL;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
// what language script engine to instantiate?
hr = (pPeerElement->get_language(&bstrLanguage));
if (hr)
goto Cleanup;
if (!bstrLanguage || !SysStringLen(bstrLanguage))
{
IHTMLElementCollection * pCollection = NULL;
hr = E_FAIL;
if (bstrLanguage)
{
SysFreeString(bstrLanguage);
bstrLanguage = NULL;
}
// use the default language, we get this from the language of
// first script block in the document.
if (!FAILED(pBrowseDoc->get_scripts(&pCollection)))
{
CVariant cvarID;
CVariant cvarEmpty;
IDispatch * pDisp;
V_VT(&cvarID) = VT_I4;
V_I4(&cvarID) = 0;
if (!FAILED(pCollection->item(cvarID, cvarEmpty, &pDisp)))
{
IHTMLElement * pFirstScript = NULL;
if (pDisp &&
!FAILED(pDisp->QueryInterface(IID_IHTMLElement,
(void**)&pFirstScript)))
{
pFirstScript->get_language(&bstrLanguage);
if (bstrLanguage && SysStringLen(bstrLanguage))
hr = CLSIDFromProgID ( bstrLanguage, pclsid );
ReleaseInterface(pFirstScript);
}
ReleaseInterface(pDisp);
}
ReleaseInterface(pCollection);
}
if (hr)
{
hr = CLSIDFromProgID ( L"JScript", pclsid );
}
}
else
{
hr = CLSIDFromProgID ( bstrLanguage, pclsid );
}
Cleanup:
SysFreeString(bstrLanguage);
ReleaseInterface(pPeerElement);
return ( hr );
}
//+-----------------------------------------------------------
//
// Member GetScriptEngine
//
// Synopsis : helper method - this creates the appropriate script
// engine, and parses in the text of hte script block that we
// are interested in.
//
//+-----------------------------------------------------------
IActiveScript *
CPersistDataPeer::GetScriptEngine(IHTMLDocument2 * pBrowseDoc, ULONG * puFlags)
{
HRESULT hr = S_OK;
BSTR bstrCode = NULL;
CLSID clsID;
CLSID clsIDTarget;
IActiveScript * pScriptEngine = NULL;
IActiveScriptSite * pScriptSite = NULL;
IActiveScriptParse * pASP = NULL;
IHTMLScriptElement * pScriptElem = NULL;
IHTMLElement * pPeerElement = NULL;
hr = (GetEngineClsidForLanguage(&clsID, pBrowseDoc));
if (hr)
goto Cleanup;
// set the return flags, so that these tests only need to be done once
// some callers need to know if the script block is jscript, vbscript,
// of something else
if (!FAILED(CLSIDFromProgID ( _T("JScript"), &clsIDTarget )) &&
(clsID == clsIDTarget))
{
*puFlags = SCRIPT_ENGINE_JSCRIPT;
}
else if (!FAILED(CLSIDFromProgID ( _T("VBScript"), &clsIDTarget )) &&
(clsID == clsIDTarget))
{
*puFlags = SCRIPT_ENGINE_VBSCRIPT;
}
else
*puFlags = SCRIPT_ENGINE_OTHER;
// create the script engine
hr = CoCreateInstance( clsID, NULL, CLSCTX_INPROC_SERVER,
IID_IActiveScript,(void **)&pScriptEngine);
if ( hr )
goto Cleanup;
// get the scriptSite interface from ourselves.
hr = (QueryInterface(IID_IActiveScriptSite, (void**) &pScriptSite));
if (hr)
goto Cleanup;
hr = pScriptEngine->SetScriptSite(pScriptSite);
ReleaseInterface(pScriptSite); // engine should have addref'd
if ( FAILED(hr) )
goto Error;
// prepare to load out text
hr = (pScriptEngine->QueryInterface (IID_IActiveScriptParse, (void**)&pASP));
if ( hr )
goto Error;
hr = (pASP->InitNew());
if ( hr )
goto Error;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
// get the text of the script element
hr = (pPeerElement->QueryInterface(IID_IHTMLScriptElement, (void**)&pScriptElem));
if ( hr )
goto Error;
hr = (pScriptElem->get_text(&bstrCode));
if ( hr || !bstrCode)
goto Error;
hr = pASP->ParseScriptText( bstrCode,
NULL, // Item Name (Namespace)
NULL, // context
NULL, // delimiter
0, // srcContext Cookie
0, // ulStarting Line
SCRIPTTEXT_ISVISIBLE, //dwFlags
NULL, // pVarResult
NULL ); // pException Info
if ( hr )
goto Error;
hr = pScriptEngine->SetScriptState(SCRIPTSTATE_CONNECTED);
if ( FAILED(hr) )
goto Error;
Cleanup:
SysFreeString(bstrCode);
ReleaseInterface(pPeerElement);
ReleaseInterface(pScriptElem);
ReleaseInterface(pASP);
return pScriptEngine;
Error:
ClearInterface(&pScriptEngine);
goto Cleanup;
}
//+-----------------------------------------------------------
//
// Member BuildNewScriptBlock
//
// Synopsis : helper method, this does the real work of snapshotting a
// script block. IF the script is VBSCRIPT or JSCRIPT the appropriate
// syntax is used. for any other language, we convert to JScript.
//
//+-----------------------------------------------------------
HRESULT
CPersistDataPeer::BuildNewScriptBlock(CBufferedStr * pstrBuffer, ULONG *puFlags)
{
HRESULT hr = S_OK;
IDispatch * pScriptNameSpace = NULL;
IDispatchEx * pDispScript = NULL;
IDispatchEx * pBrowseWin = NULL;
DISPID dispidName;
BSTR bstrName = NULL;
IHTMLWindow2 * pWin = NULL;
IActiveScript * pScriptEngine = NULL;
IDispatch * pdispBrowseDoc = NULL;
IHTMLDocument2 * pBrowseDoc = NULL;
IHTMLElement * pPeerElement = NULL;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
hr = (pPeerElement->get_document(&pdispBrowseDoc));
if (hr)
goto Cleanup;
hr = (pdispBrowseDoc->QueryInterface(IID_IHTMLDocument2,
(void**)&pBrowseDoc));
if (hr)
goto Cleanup;
pScriptEngine = GetScriptEngine(pBrowseDoc, puFlags);
if (!pScriptEngine)
goto Cleanup; // fail silently
// loop over all the dispatches in the script engine's name
// space and get thier values.from..pSrcDoc
hr = pScriptEngine->GetScriptDispatch( NULL, &pScriptNameSpace );
if ( hr )
goto Cleanup;
hr = (pScriptNameSpace->QueryInterface( IID_IDispatchEx, (void**)&pDispScript));
if ( hr )
goto Cleanup;
// inorder to derefernce the script variables we need the browse
// documents window.
hr = (pBrowseDoc->get_parentWindow(&pWin));
if(hr)
goto Cleanup;
hr = (pWin->QueryInterface(IID_IDispatchEx, (void**)&pBrowseWin));
if (hr)
goto Cleanup;
// now run through all the objects in this script engine and
// find their values
hr = (pDispScript->GetNextDispID(0, DISPID_STARTENUM, &dispidName));
if (hr)
goto Cleanup;
while (dispidName)
{
hr = (pDispScript->GetMemberName(dispidName, &bstrName));
if (!hr && bstrName)
{
DISPID dispidBrowser;
if (!FAILED(pBrowseWin->GetDispID(bstrName, fdexNameCaseSensitive, &dispidBrowser)))
{
DISPPARAMS dp;
CVariant cvarRes;
BOOL fNeedsQuotesInScript = FALSE;
dp.rgvarg = NULL;
dp.rgdispidNamedArgs = NULL;
dp.cArgs = 0;
dp.cNamedArgs = 0;
hr = (pBrowseWin->Invoke(dispidBrowser,
IID_NULL,
LCID_SCRIPTING,
DISPATCH_PROPERTYGET,
&dp,
&cvarRes,
NULL,
NULL));
fNeedsQuotesInScript = (V_VT(&cvarRes) == VT_BSTR);
// Filter out VT_IDISPATCH & VT_UNKNOWN
if (!hr &&
V_VT(&cvarRes) != VT_DISPATCH &&
V_VT(&cvarRes) != VT_UNKNOWN &&
!FAILED(cvarRes.CoerceVariantArg(VT_BSTR)))
{
// assume JSCript if not VBScript
LPTSTR pstrAssign = (*puFlags & SCRIPT_ENGINE_VBSCRIPT) ?
_T("\n\r dim ") :
_T("\n\r var ");
// concatenate on the end of the buffer.
// "\n\r var <name> = " <value>"; "
hr = pstrBuffer->QuickAppend(pstrAssign);
if (hr)
goto Cleanup;
hr = pstrBuffer->QuickAppend(bstrName);
if (hr)
goto Cleanup;
// if vbscript, put assignment on its own line.
if (*puFlags & SCRIPT_ENGINE_VBSCRIPT)
{
hr = pstrBuffer->QuickAppend(_T("\n\r "));
if (hr)
goto Cleanup;
hr = pstrBuffer->QuickAppend(bstrName);
if (hr)
goto Cleanup;
}
// now handle outputing the assignment itself, careful
// to only put quotes around things that were strings.
hr = pstrBuffer->QuickAppend(_T(" = "));
if (hr)
goto Cleanup;
if (fNeedsQuotesInScript )
{
hr = pstrBuffer->QuickAppend(_T("\""));
if (hr)
goto Cleanup;
}
if (V_VT(&cvarRes) != VT_EMPTY)
{
hr = pstrBuffer->QuickAppend(V_BSTR(&cvarRes));
}
else
{
// someone had dim x = Empty in their script
// or var x = document.expando
// and this doesn't coerc to a bstr (returned S_FALSE)
// don't reset the use quotes flag,
// for jscript convert to null, for vb
if (!(*puFlags & SCRIPT_ENGINE_VBSCRIPT))
{
hr = pstrBuffer->QuickAppend(_T("null"));
}
else
hr = pstrBuffer->QuickAppend(_T("Empty"));
}
if (hr)
goto Cleanup;
if (fNeedsQuotesInScript )
{
hr = pstrBuffer->QuickAppend(_T("\""));
if (hr)
goto Cleanup;
}
// VBSCRIPT doesn need ';' at the eol
if (!(*puFlags & SCRIPT_ENGINE_VBSCRIPT))
{
hr = pstrBuffer->QuickAppend(_T(";"));
}
if (hr)
goto Cleanup;
}
}
SysFreeString(bstrName);
bstrName = NULL;
}
hr = (pDispScript->GetNextDispID(0, dispidName, &dispidName));
if (hr==S_FALSE)
{
hr = S_OK;
break;
}
else if (hr)
goto Cleanup;
}
Cleanup:
if (pScriptEngine)
pScriptEngine->Close();
if (bstrName)
SysFreeString(bstrName);
ReleaseInterface(pPeerElement);
ReleaseInterface(pBrowseDoc);
ReleaseInterface(pScriptEngine);
ReleaseInterface(pdispBrowseDoc);
ReleaseInterface(pWin);
ReleaseInterface(pBrowseWin);
ReleaseInterface(pDispScript);
ReleaseInterface(pScriptNameSpace);
// no partial string in an error case...
if (hr)
pstrBuffer->Set();
return( hr );
}
//+-----------------------------------------------------------
//
// member : SaveHandler_GenericTag
//
// synopsis : this does the generic handling when a tag has the
// persistence peer. It simply gets the outerHTML and saves that
// in the XML object. on the load the element will be hit
// with a put_outerHTML of this string.
//
//+-----------------------------------------------------------
HRESULT
CPersistDataPeer::SaveHandler_GenericTag()
{
HRESULT hr = S_OK;
CVariant cvarOuter;
IHTMLElement * pPeerParent = NULL;
IHTMLElement * pPeerElement = NULL;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
// for elements in the head, we don't want to do this since
// there is a tree limitation that doesn't allow the outerHTML
// to be set.
hr = pPeerElement->get_parentElement(&pPeerParent);
if (hr)
goto Cleanup;
// the right way to do this is to ask the question:
// are we in the body/frameset, NOT is our parent the
// head, so...
while (pPeerParent)
{
CVariant cvarTag;
IHTMLElement * pTemp = NULL;
V_VT(&cvarTag) = VT_BSTR;
hr = pPeerParent->get_tagName(&V_BSTR(&cvarTag));
if (hr)
goto Cleanup;
if (0==_wcsicmp(V_BSTR(&cvarTag), L"body") ||
0==_wcsicmp(V_BSTR(&cvarTag), L"frameset"))
break;
hr = pPeerParent->get_parentElement(&pTemp);
if (hr)
goto Cleanup;
ClearInterface(&pPeerParent);
pPeerParent = pTemp;
}
if (!pPeerParent)
goto Cleanup;
hr = pPeerElement->get_outerHTML(&V_BSTR(&cvarOuter));
if (hr)
goto Cleanup;
V_VT(&cvarOuter) = VT_BSTR;
// now save the outerHTML string
hr = _pRoot->setAttribute(_T("__NEW_TAG_OUTER"), cvarOuter);
if (hr)
goto Cleanup;
Cleanup:
ReleaseInterface(pPeerElement);
ReleaseInterface(pPeerParent);
return( hr );
}
//+----------------------------------------------------------------------------
//
// Member : LoadHandler_GenericTag()
//
// Synopsis : this restores the outerHTML of the tag as it is loaded
//
//+----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::LoadHandler_GenericTag()
{
HRESULT hr = S_OK;
CVariant cvarOuter;
IHTMLElement * pPeerElement = NULL;
if (!_pRoot)
goto Cleanup;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
// now get the outerHTML string
hr = _pRoot->getAttribute(_T("__NEW_TAG_OUTER"), &cvarOuter);
if (hr)
goto Cleanup;
hr = cvarOuter.CoerceVariantArg(VT_BSTR);
if (hr)
goto Cleanup;
hr = pPeerElement->put_outerHTML(V_BSTR(&cvarOuter));
if (hr)
goto Cleanup;
Cleanup:
ReleaseInterface(pPeerElement);
return( hr );
}
//+------------------------------------------------------------------------------
//
// Member : SaveHandler_ScriptTag()
//
// Synopsis : saves the script into the xml store. We do this in the standard way:
// 1- create a private script engin,
// 2- load it with the text of the peer's script block
// 3 - walk through its namespace pulling out the variables
// 4 - create a list of name value pairs as the new script block
// 5 - save this block in the appropriate place
//
//+------------------------------------------------------------------------------
HRESULT
CPersistDataPeer::SaveHandler_ScriptTag()
{
HRESULT hr = S_OK;
CVariant cvarText;
BSTR bstrLanguage = NULL;
CLSID clsIDTarget;
CLSID clsIDLang;
CBufferedStr cbsNewScript;
IDispatch * pdispBrowseDoc = NULL;
IHTMLDocument2 * pBrowseDoc = NULL;
IHTMLElement * pPeerElement = NULL;
ULONG uFlags = 0;
if (!_pRoot)
goto Cleanup;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
hr = pPeerElement->get_document(&pdispBrowseDoc);
if (hr)
goto Cleanup;
hr = pdispBrowseDoc->QueryInterface(IID_IHTMLDocument2,
(void**)&pBrowseDoc);
if (hr)
goto Cleanup;
// get the new script block, and the language that it
// originated from
hr = BuildNewScriptBlock(&cbsNewScript, &uFlags);
if (hr)
goto Cleanup;
// Language can only be set in design mode, as a result
// we can't change the script block since we don't know the
// syntax for an arbitrary script engine. so, only save
// script if this is javascript or vbscript.
if (uFlags & SCRIPT_ENGINE_OTHER)
goto Cleanup;
V_VT(&cvarText) = VT_BSTR;
V_BSTR(&cvarText) = SysAllocString((LPTSTR)cbsNewScript);
if (!V_BSTR(&cvarText))
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
hr = _pRoot->setAttribute(_T("__NEW_SCRIPT_TEXT"), cvarText);
if (hr)
goto Cleanup;
Cleanup:
SysFreeString(bstrLanguage);
ReleaseInterface(pPeerElement);
ReleaseInterface(pBrowseDoc);
ReleaseInterface(pdispBrowseDoc);
return( hr );
}
//+----------------------------------------------------------------------------
//
// Member : LoadHandler_ScriptTag()
//
// Synopsis : does the load - but wait...
// NYI - put_text is design time only, so the peer needs a different way
// of sliding this in.
//
//+----------------------------------------------------------------------------
HRESULT
CPersistDataPeer::LoadHandler_ScriptTag()
{
HRESULT hr = S_OK;
CVariant cvarText;
if (!_pRoot)
goto Cleanup;
// try to get the new text from the saved XML
hr = _pRoot->getAttribute(_T("__NEW_SCRIPT_TEXT"), &cvarText);
if (hr)
goto Cleanup;
// if there is script text, then we need to set this into the
// browse window's namespace
Cleanup:
if (hr == S_FALSE) hr = S_OK;
return( hr );
}
//===============================================================
//
// Class : CPersistShortcut
//
// synopsis : derives from CPersistDataPeer and does the special handling
// related to the shortcut functionality
//
//===============================================================
//+----------------------------------------------------------------
//
// Member : save
//
// synopsis: over ride of parent functionality to deal with shortcut
// specific stuff...
//
//-----------------------------------------------------------------
HRESULT
CPersistShortcut::save(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfContinue)
{
HRESULT hr;
if (lType != (long)htmlPersistStateFavorite)
{
hr = S_OK;
goto Cleanup;
}
hr = super::save(pUnk, lType, pfContinue);
if (hr || (*pfContinue == VB_FALSE))
goto Cleanup;
// do the particular tag handling related to shortcuts
switch (GetSaveCategory())
{
case ESC_UNKNOWN:
case ESC_INTRINSIC:
case ESC_CONTROL:
hr = SaveHandler_GenericTag();
break;
// case ESC_SCRIPT:
// hr = SaveHandler_ScriptTag();
// break;
default:
break;
}
Cleanup:
return hr;
}
//+----------------------------------------------------------------------------
//
// Member : Load
//
// Synopsis : Implementation of the IHTMLPersistenceCache method
//
//-----------------------------------------------------------------------------
HRESULT
CPersistShortcut::load(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfDoDefault)
{
HRESULT hr;
if (lType != (long)htmlPersistStateFavorite)
{
hr = S_OK;
goto Cleanup;
}
// fire the event first, since the pPeerElement is about to be
// removed from the tree entirely. Of course, if the user sets
// expandoes on this, they will get lost, but the alternative is to
// loose access to the xmlcache. So, if you think about it, they get
// outerHTML behaviour, and using XMLCache behavior means
// that you better cancel default behavior.
hr = super::load(pUnk, lType, pfDoDefault);
// is default load behavior canceled ?
if (hr || (*pfDoDefault == VB_FALSE))
goto Cleanup;
switch (GetSaveCategory())
{
case ESC_UNKNOWN:
case ESC_INTRINSIC:
case ESC_CONTROL:
hr = LoadHandler_GenericTag();
break;
// case ESC_SCRIPT:
// hr = LoadHandler_ScriptTag();
// break;
default:
break;
}
Cleanup:
return hr;
}
//===============================================================
//
// Class : CPersistHistory
//
// synopsis : derives from CPersistDataPeer and does the special handling
// related to the History functionality
//
//===============================================================
//+----------------------------------------------------------------
//
// Member : save
//
// synopsis: over ride of parent functionality to deal with shortcut
// specific stuff...
//
//-----------------------------------------------------------------
HRESULT
CPersistHistory::save(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfContinue)
{
HRESULT hr;
if (lType != (long)htmlPersistStateHistory)
{
hr = S_OK;
goto Cleanup;
}
hr = super::save(pUnk, lType, pfContinue);
if (hr || (*pfContinue == VB_FALSE))
goto Cleanup;
// do any tag specific handling that history needs
switch (GetSaveCategory())
{
// if we don't know anything special to do with this tag, just
// transfer over its outerHTML on the assumption that the author
// knows what they are doing
case ESC_UNKNOWN:
case ESC_INTRINSIC:
hr = SaveHandler_GenericTag();
break;
// case ESC_SCRIPT:
// hr = SaveHandler_ScriptTag();
// break;
default :
break;
}
Cleanup:
return hr;
}
//+----------------------------------------------------------------------------
//
// Member : Load
//
// Synopsis : Implementation of the IHTMLPersistenceCache method
//
//-----------------------------------------------------------------------------
HRESULT
CPersistHistory::load(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfDoDefault)
{
HRESULT hr;
if (lType != (long)htmlPersistStateHistory)
{
hr = S_OK;
goto Cleanup;
}
// cache the OM pointers
hr = InitOM(pUnk, lType);
if (hr)
goto Cleanup;
hr = super::load(pUnk, lType, pfDoDefault);
// is default load behavior canceled ?
if (hr || (*pfDoDefault == VB_FALSE))
goto Cleanup;
// ISSUE (carled) NYI - script retoration presents a unique challenge
// because this needs to execute inline instead of the original
// script block text.
switch(GetSaveCategory())
{
// case ESC_SCRIPT:
// hr = LoadHandler_ScriptTag();
// break;
case ESC_UNKNOWN:
case ESC_INTRINSIC:
hr = LoadHandler_GenericTag();
break;
default:
break;
}
Cleanup:
return hr;
}
//===============================================================
//
// Class : CPersistSnapshot
//
// synopsis : derives from CPersistDataPeer and does the special handling
// related to the run-time same (snapshot) functionality
//
//===============================================================
//+----------------------------------------------------------------
//
// Member : CPersistSnapshot::save
//
// synopsis: over ride of parent functionality to deal with shortcut
// specific stuff...
// Since it doesn't make much sense to allow theXMLOM to be acccessed
// in this case, calling super:: pretty much only fires the event.
//
//-----------------------------------------------------------------
HRESULT
CPersistSnapshot::save(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfContinue)
{
HRESULT hr;
CVariant cvarTag;
IHTMLDocument2 * pDesignDoc = NULL;
if (lType != (long)htmlPersistStateSnapshot)
{
hr = S_OK;
goto Cleanup;
}
if (!pUnk)
{
hr = E_POINTER;
goto Cleanup;
}
hr = pUnk->QueryInterface(IID_IHTMLDocument2, (void**)&pDesignDoc);
if (hr)
goto Cleanup;
// allow the onsave event to be fired.
hr = super::save(NULL, lType, pfContinue);
if (hr || (*pfContinue == VB_FALSE))
goto Cleanup;
// now that the author has had the oppurtunity to set expandoes,
// and value properties, we start the real work of snapshot saveing.
switch (GetSaveCategory())
{
case ESC_CONTROL:
hr = TransferControlValues(pDesignDoc);
break;
case ESC_SCRIPT:
hr = TransferScriptValues(pDesignDoc);
break;
case ESC_UNKNOWN:
// if we don't know anything special to do with this tag, just
// transfer over its outerHTML on the assumption that the author
// knows what they are doing
case ESC_INTRINSIC:
hr = TransferIntrinsicValues(pDesignDoc);
break;
default:
break;
}
Cleanup:
ReleaseInterface(pDesignDoc);
return hr;
}
//+----------------------------------------------------------------------------
//
// Member : CPersistSnapshot::Load
//
// Synopsis : Implementation of the IHTMLPersistenceCache method
// Since it doesn't make much sense to allow theXMLOM to be acccessed
// in this case, calling super:: pretty much only fires the event.
//
//-----------------------------------------------------------------------------
HRESULT
CPersistSnapshot::load(IUnknown * pUnk,
long lType,
VARIANT_BOOL *pfDoDefault)
{
HRESULT hr;
if (lType != (long)htmlPersistStateSnapshot)
{
hr = S_OK;
goto Cleanup;
}
hr = super::load(pUnk, lType, pfDoDefault);
Cleanup:
return hr;
}
//+-----------------------------------------------------------
//
// member : GetDesignElem
//
// Synposis : this helper function is responsible for finding the
// design document's element counterpart to our pPeerElement.
//
//+-----------------------------------------------------------
IHTMLElement *
CPersistSnapshot::GetDesignElem(IHTMLDocument2 * pDesignDoc)
{
HRESULT hr = S_OK;
CVariant cvarID;
CVariant cvarEmpty;
IDispatch * pDisp = NULL;
IHTMLElement * pRetElem = NULL;
IHTMLElement * pPeerElement = NULL;
IHTMLElementCollection * pCollection = NULL;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
V_VT(&cvarID) = VT_BSTR;
hr = pPeerElement->get_id(&V_BSTR(&cvarID));
if (hr)
goto Cleanup;
// first get the documents all collection.
hr = pDesignDoc->get_all(&pCollection);
if (hr)
goto Cleanup;
// now find out elements coutner part inthe design document,
// if it exits. Elements that were created by inline scripts,
// or other script driven means, may not be found.
hr = pCollection->item(cvarID, cvarEmpty, &pDisp);
if (hr || !pDisp)
goto Cleanup;
// make sure that we do not have a collection...
hr = pDisp->QueryInterface(IID_IHTMLElement, (void**)&pRetElem);
Cleanup:
ReleaseInterface(pPeerElement);
ReleaseInterface(pDisp);
ReleaseInterface(pCollection);
return pRetElem;
}
//+-----------------------------------------------------------
//
// member : TransferIntrinsicValues
//
// synopsis : this transfers the value of the browse-control to the
// design control by setting the outerHTML of the design control
// to that of the browseControl
//
//+-----------------------------------------------------------
HRESULT
CPersistSnapshot::TransferIntrinsicValues (IHTMLDocument2 *pDesignDoc)
{
HRESULT hr = S_OK;
BSTR bstrOuter = NULL;
IHTMLElement * pDesignElem = NULL;
IHTMLElement * pPeerElement = NULL;
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
hr = pPeerElement->get_outerHTML(&bstrOuter);
if (hr)
goto Cleanup;
pDesignElem = GetDesignElem(pDesignDoc);
if (!pDesignElem)
goto Cleanup;
hr = pDesignElem->put_outerHTML(bstrOuter);
Cleanup:
SysFreeString(bstrOuter);
ReleaseInterface(pPeerElement);
ReleaseInterface(pDesignElem);
return( hr );
}
//+-----------------------------------------------------------
//
// Member : TransferControlValues
//
// Synopsis : Transfers the values of the control by cooking up a
// stream and calling IPersitHistory::Save on the browse-control
// and then feeding that stream into IPersistHistory::Load on
// the design-control, Then when the design document is saved,
// IPersistPropertyBag::save will get called (it is this that finally
// allows the controls state to be written out as the altHTML attribute.
//
//+-----------------------------------------------------------
HRESULT
CPersistSnapshot::TransferControlValues (IHTMLDocument2 *pDesignDoc)
{
HRESULT hr = S_OK;
IHTMLElement * pDesignElem = NULL;
IHTMLElement * pPeerElement = NULL;
IPersistHistory * pSrcPH = NULL;
IPersistHistory * pDesignPH = NULL;
IStream * pStream = NULL;
HGLOBAL hg = NULL;
static LARGE_INTEGER i64Zero = {0, 0};
_pPeerSite->GetElement(&pPeerElement);
if (!pPeerElement)
{
hr = E_FAIL;
goto Cleanup;
}
pDesignElem = GetDesignElem(pDesignDoc);
if (!pDesignElem)
goto Cleanup;
// step 1. get the appropriate IPersistHistory interfaces.
hr = pPeerElement->QueryInterface(IID_IPersistHistory, (void**)&pSrcPH);
if (hr)
goto Cleanup;
hr = (pDesignElem->QueryInterface(IID_IPersistHistory, (void**)&pDesignPH));
if (hr)
goto Cleanup;
// step 2. create a temporary stream
hg = GlobalAlloc(GMEM_MOVEABLE, 0);
if (!hg)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
hr = (CreateStreamOnHGlobal(hg, TRUE, &pStream));
if (hr)
goto Cleanup;
// Step 3. save the browse object
hr = (pSrcPH->SaveHistory(pStream));
if (hr)
goto Cleanup;
// Step 4. reset the stream
hr = (pStream->Seek(i64Zero, STREAM_SEEK_SET, NULL));
if (hr)
goto Cleanup;
// Stpe 5. Load the design object.
hr = (pDesignPH->LoadHistory(pStream, NULL));
if (hr)
goto Cleanup;
Cleanup:
// ISSUE (carled) is there a memory leak here? the hGlobal was allocated,
// a stream was created, and freed but where does the memory get freed?
ReleaseInterface(pPeerElement);
ReleaseInterface(pStream);
ReleaseInterface(pSrcPH);
ReleaseInterface(pDesignPH);
ReleaseInterface(pDesignElem);
return( (hr == E_NOINTERFACE)? S_OK : hr );
}
//+-----------------------------------------------------------
//
// Member : TransferScriptValues
//
// Synopsis: transfers the values of script blocks, by loading this
// script into a private script engine, and then iterating over all
// the values and getting the current values from the browse document.
// These (Variable, Value) pairs are then spit out as the new innerHTML
// of the design-script element.
//
//+-----------------------------------------------------------
HRESULT
CPersistSnapshot::TransferScriptValues (IHTMLDocument2 *pDesignDoc)
{
HRESULT hr = S_OK;
IHTMLElement * pDesignElem = NULL;
BSTR bstrNewBlock = NULL;
CBufferedStr cbsNewScript;
ULONG uFlags = 0;
IHTMLScriptElement * pScriptElem = NULL;
pDesignElem = GetDesignElem(pDesignDoc);
if (!pDesignElem)
goto Cleanup;
// get the text of the new script block
hr = (BuildNewScriptBlock(&cbsNewScript, &uFlags));
if (hr)
goto Cleanup;
bstrNewBlock = SysAllocString((LPTSTR)cbsNewScript);
if (!bstrNewBlock)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
// Set the new script assignments
hr = (pDesignElem->QueryInterface(IID_IHTMLScriptElement, (void**)&pScriptElem));
if ( hr )
goto Cleanup;
hr = (pScriptElem->put_text(bstrNewBlock));
if ( hr )
goto Cleanup;
// since all the namespaces exist on the "window"
// we need to make sure that the script block we
// write out is in a language whose syntax we know. As
// a result a script block from any ActiveScript language
// will get persisted, but unless it is VBScript or JScript,
// in the saveing, it is translated into JScript.
if (uFlags & SCRIPT_ENGINE_OTHER)
{
BSTR bstrForceLanguage = SysAllocString(L"JScript");
if (!bstrForceLanguage)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
hr = (pDesignElem->put_language(bstrForceLanguage));
SysFreeString(bstrForceLanguage);
if (hr)
goto Cleanup;
}
Cleanup:
SysFreeString(bstrNewBlock);
ReleaseInterface(pScriptElem);
ReleaseInterface(pDesignElem);
return( hr );
}