// Document.cpp : Implementation of CTriEditDocument // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved #include "stdafx.h" #include "triedit.h" #include "Document.h" #include "util.h" #ifdef IE5_SPACING #include "dispatch.h" #include #include #endif //IE5_SPACING ///////////////////////////////////////////////////////////////////////////// // CTriEditDocument CTriEditDocument::CTriEditDocument() { m_pUnkTrident = NULL; m_pOleObjTrident = NULL; m_pCmdTgtTrident = NULL; m_pDropTgtTrident = NULL; #ifdef IE5_SPACING m_pTridentPersistStreamInit = NULL; m_pMapArray = NULL; m_hgMap = NULL; m_pspNonDSP = NULL; m_hgSpacingNonDSP = NULL; m_ichspNonDSPMax = 0; m_ichspNonDSP = 0; #endif //IE5_SPACING m_pClientSiteHost = NULL; m_pUIHandlerHost = NULL; m_pDragDropHandlerHost = NULL; m_pUIHandler = NULL; m_pTokenizer = NULL; m_hwndTrident = NULL; m_fUIHandlerSet = FALSE; m_fInContextMenu = FALSE; m_fDragRectVisible = FALSE; m_fConstrain = FALSE; m_f2dDropMode = FALSE; m_eDirection = CONSTRAIN_NONE; m_ptAlign.x = 1; m_ptAlign.y = 1; m_pihtmlElement = NULL; m_pihtmlStyle = NULL; m_hbrDragRect = NULL; m_fLocked = FALSE; m_hgDocRestore = NULL; } HRESULT CTriEditDocument::FinalConstruct() { HRESULT hr; IUnknown *pUnk = GetControllingUnknown(); hr = CoCreateInstance(CLSID_HTMLDocument, pUnk, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&m_pUnkTrident); if (SUCCEEDED(hr)) { _ASSERTE(NULL != m_pUnkTrident); // When we cache Trident pointers, we do a GetControllingUnknown()->Release() // since the addref will increment our outer unknown pointer and not Trident // We compensate for this by doing a corresponding GetControllingUnknown()->AddRef() // in our FinalRelease. Though these cancel out, it is necessary to do this in order // to ensure that our FinalRelease will get called. // Cache Trident's IOleObject pointer hr = m_pUnkTrident->QueryInterface(IID_IOleObject, (void **)&m_pOleObjTrident); _ASSERTE(S_OK == hr && NULL != m_pOleObjTrident); pUnk->Release(); // Cache Trident's IOleCommandTarget pointer hr = m_pUnkTrident->QueryInterface(IID_IOleCommandTarget, (void **)&m_pCmdTgtTrident); _ASSERTE(S_OK == hr && NULL != m_pCmdTgtTrident); pUnk->Release(); // Allocate UI handler sub-object m_pUIHandler = new CTriEditUIHandler(this); if (NULL == m_pUIHandler) hr = E_OUTOFMEMORY; #ifdef IE5_SPACING // Get IPersistStreamInit hr = m_pUnkTrident->QueryInterface(IID_IPersistStreamInit, (void **) &m_pTridentPersistStreamInit); _ASSERTE(S_OK == hr && NULL != m_pTridentPersistStreamInit); pUnk->Release(); // PuruK - REVIEW Why do we need to do this? SetFilterInDone(FALSE); #endif //IE5_SPACING // Allocate buffer for saving document's contents before tag // Trident replaces all content before tag by its own header m_hgDocRestore = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbHeader); if (NULL == m_hgDocRestore) { delete m_pUIHandler; hr = E_OUTOFMEMORY; } } _ASSERTE(SUCCEEDED(hr)); return hr; } void CTriEditDocument::FinalRelease() { IUnknown *pUnk = GetControllingUnknown(); // Release host interface pointers SAFERELEASE(m_pClientSiteHost); SAFERELEASE(m_pUIHandlerHost); SAFERELEASE(m_pDragDropHandlerHost); // Release internal interface pointers SAFERELEASE(m_pTokenizer); // Release 2d drop related pointers ReleaseElement(); // Release Trident interface pointers SAFERELEASE(m_pDropTgtTrident); pUnk->AddRef(); SAFERELEASE(m_pOleObjTrident); pUnk->AddRef(); SAFERELEASE(m_pCmdTgtTrident); #ifdef IE5_SPACING pUnk->AddRef(); // REVIEW - PuruK - Why do we need to do this? SAFERELEASE(m_pTridentPersistStreamInit); #endif //IE5_SPACING SAFERELEASE(m_pUnkTrident); // Delete UI handler sub-object if (m_pUIHandler != NULL) { // Assert that the ref count on the sub-object is 1 // If this isn't 1, then Trident is holding on to this pointer _ASSERTE(m_pUIHandler->m_cRef == 1); delete m_pUIHandler; } if (m_hgDocRestore != NULL) { GlobalUnlock(m_hgDocRestore); GlobalFree(m_hgDocRestore); } #ifdef IE5_SPACING if (m_hgMap != NULL) { GlobalUnlock(m_hgMap); GlobalFree(m_hgMap); m_hgMap = NULL; } if (m_hgSpacingNonDSP != NULL) { GlobalUnlock(m_hgSpacingNonDSP); GlobalFree(m_hgSpacingNonDSP); m_hgSpacingNonDSP = NULL; } #endif } #ifdef IE5_SPACING void CTriEditDocument::FillUniqueID(BSTR bstrUniqueID, BSTR bstrDspVal, int ichNonDSP, MAPSTRUCT *pMap, int iMapCur, BOOL fLowerCase, int iType) { memcpy((BYTE *)pMap[iMapCur].szUniqueID, (BYTE *)bstrUniqueID, min(wcslen(bstrUniqueID), cchID)*sizeof(WCHAR)); if (iType == INDEX_DSP) { memcpy((BYTE *)pMap[iMapCur].szDspID, (BYTE *)bstrDspVal, min(wcslen(bstrDspVal), cchID)*sizeof(WCHAR)); _ASSERTE(ichNonDSP == -1); pMap[iMapCur].ichNonDSP = ichNonDSP; } else if (iType == INDEX_COMMENT) { pMap[iMapCur].ichNonDSP = ichNonDSP; } else if (iType == INDEX_AIMGLINK) { memcpy((BYTE *)pMap[iMapCur].szDspID, (BYTE *)bstrDspVal, min(wcslen(bstrDspVal), cchID)*sizeof(WCHAR)); pMap[iMapCur].ichNonDSP = ichNonDSP; } else if (iType == INDEX_OBJ_COMMENT) { pMap[iMapCur].ichNonDSP = ichNonDSP; } else _ASSERTE(FALSE); pMap[iMapCur].fLowerCase = fLowerCase; _ASSERTE(iType >= INDEX_NIL && iType < INDEX_MAX); pMap[iMapCur].iType = iType; } BOOL CTriEditDocument::FGetSavedDSP(BSTR bstrUniqueID, BSTR *pbstrDspVal, int *pichNonDSP, MAPSTRUCT *pMap, BOOL *pfLowerCase, int *pIndex) { BOOL fRet = FALSE; int i; // TODO - find a faster way than this linear search... for (i = 0; i < m_iMapCur; i++) { if (0 == _wcsnicmp(pMap[i].szUniqueID, bstrUniqueID, wcslen(bstrUniqueID))) { fRet = TRUE; if (pMap[i].iType == INDEX_DSP) { *pbstrDspVal = SysAllocString(pMap[i].szDspID); *pichNonDSP = -1; } else if (pMap[i].iType == INDEX_COMMENT) { *pbstrDspVal = (BSTR)NULL; *pichNonDSP = pMap[i].ichNonDSP; } else if (pMap[i].iType == INDEX_AIMGLINK) { *pbstrDspVal = SysAllocString(pMap[i].szDspID); *pichNonDSP = pMap[i].ichNonDSP; _ASSERTE(*pichNonDSP != -1); } else if (pMap[i].iType == INDEX_OBJ_COMMENT) { *pbstrDspVal = (BSTR)NULL; *pichNonDSP = pMap[i].ichNonDSP; _ASSERTE(*pichNonDSP != -1); } *pfLowerCase = pMap[i].fLowerCase; *pIndex = pMap[i].iType; goto LRet; } } LRet: return(fRet); } void CTriEditDocument::FillNonDSPData(BSTR pOuterTag) { int len = 0; _ASSERTE(m_ichspNonDSPMax != -1); _ASSERTE(m_ichspNonDSP != -1); _ASSERTE(m_hgSpacingNonDSP != NULL); _ASSERTE(m_pspNonDSP != NULL); // even if pOuterTag is NULL, we still need to store the fact that we have // zero bytes of data. if (pOuterTag != NULL) len = wcslen(pOuterTag); if ((int)(m_ichspNonDSP + len + sizeof(int)) > m_ichspNonDSPMax) { HGLOBAL hgSpacingNonDSP; //reallocate & set m_ichspNonDSPMax GlobalUnlock(m_hgSpacingNonDSP); hgSpacingNonDSP = m_hgSpacingNonDSP; #pragma prefast(suppress: 308, "noise") m_hgSpacingNonDSP = GlobalReAlloc(m_hgSpacingNonDSP, (m_ichspNonDSP + len + sizeof(int)+MIN_SP_NONDSP)*sizeof(WCHAR), GMEM_MOVEABLE|GMEM_ZEROINIT); // if this alloc failed, we may still want to continue if (m_hgSpacingNonDSP == NULL) { GlobalFree(hgSpacingNonDSP); goto LRet; } else { m_pspNonDSP = (WCHAR *)GlobalLock(m_hgSpacingNonDSP); _ASSERTE(m_pspNonDSP != NULL); m_ichspNonDSPMax = (m_ichspNonDSP + len + sizeof(int)+MIN_SP_NONDSP); } _ASSERTE(m_ichspNonDSP < m_ichspNonDSPMax); } memcpy((BYTE *)(m_pspNonDSP+m_ichspNonDSP), (BYTE *)&len, sizeof(int)); m_ichspNonDSP += sizeof(int)/sizeof(WCHAR); memcpy((BYTE *)(m_pspNonDSP+m_ichspNonDSP), (BYTE *)pOuterTag, len*sizeof(WCHAR)); m_ichspNonDSP += len; LRet: return; } void CTriEditDocument::ReSetinnerHTMLComment(IHTMLCommentElement *pCommentElement, IHTMLElement* /*pElement*/, int ichspNonDSP) { WCHAR *pStrComment = NULL; //#ifdef DEBUG // CComBSTR bstrOuter, bstrOuterBefore; //#endif //DEBUG int cchComment = 0; // get the ich, get the saved comment, set it memcpy((BYTE *)&cchComment, (BYTE *)(m_pspNonDSP+ichspNonDSP), sizeof(int)); _ASSERTE(cchComment > 0); //#ifdef DEBUG // pElement->get_outerHTML(&bstrOuterBefore); //#endif //DEBUG pStrComment = new WCHAR[cchComment + 1]; if (pStrComment == NULL) return; memcpy((BYTE *)pStrComment, (BYTE *)(m_pspNonDSP+ichspNonDSP+sizeof(int)/sizeof(WCHAR)), cchComment*sizeof(WCHAR)); pStrComment[cchComment] = '\0'; pCommentElement->put_text((BSTR)pStrComment); //#ifdef DEBUG // pElement->get_outerHTML(&bstrOuter); //#endif //DEBUG if (pStrComment) delete pStrComment; //#ifdef DEBUG // bstrOuter.Empty(); // bstrOuterBefore.Empty(); //#endif //DEBUG } void CTriEditDocument::SetinnerHTMLComment(IHTMLCommentElement *pCommentElement, IHTMLElement* /*pElement*/, BSTR pOuterTag) { WCHAR *pStr = NULL; WCHAR *pStrComment = NULL; LPCWSTR rgComment[] = { L"TRIEDITPRECOMMENT-", L"-->", L"", }; if (bstrAlt == (BSTR)NULL || pObjectElement == NULL) return; // look for ERRORPARAM pStr = wcsstr(bstrAlt, rgComment[0]); pStrEnd = wcsstr(bstrAlt, rgComment[1]); if (pStr != NULL && pStrEnd != NULL) { pStrEnd += wcslen(rgComment[1]); pStrComment = new WCHAR[SAFE_PTR_DIFF_TO_INT(pStrEnd-pStr)+1]; if (pStrComment == NULL) goto LRetNull; memcpy((BYTE *)pStrComment, (BYTE *)pStr, SAFE_PTR_DIFF_TO_INT(pStrEnd-pStr)*sizeof(WCHAR)); pStrComment[pStrEnd-pStr] = '\0'; *pbstrAltComment = SysAllocString(pStrComment); delete pStrComment; pAltNew = new WCHAR[cch+1]; // max size if (pAltNew == NULL) goto LRetNull; // remove stuff from pStr till pStrEnd & copy into *pbstrAltNew if (pStr > pStrAlt) { memcpy((BYTE *)pAltNew, (BYTE *)pStrAlt, SAFE_PTR_DIFF_TO_INT(pStr-pStrAlt)*sizeof(WCHAR)); ich += SAFE_PTR_DIFF_TO_INT(pStr-pStrAlt); } if ((pStrAlt+cch)-pStrEnd > 0) { memcpy((BYTE *)(pAltNew+ich), (BYTE *)pStrEnd, SAFE_PTR_DIFF_TO_INT((pStrAlt+cch)-pStrEnd)*sizeof(WCHAR)); ich += SAFE_PTR_DIFF_TO_INT((pStrAlt+cch)-pStrEnd); } pAltNew[ich] = '\0'; *pbstrAltNew = SysAllocString(pAltNew); delete pAltNew; } else { LRetNull: *pbstrAltNew = (bstrAlt) ? SysAllocString(bstrAlt) : (BSTR)NULL; *pbstrAltComment = (BSTR)NULL; } } /* CTriEditDocument::RemoveEPComment() */ HRESULT CTriEditDocument::SetObjectComment(IHTMLObjectElement *pObjectElement, BSTR bstrAltNew) { HRESULT hr; _ASSERTE(pObjectElement != NULL); hr = pObjectElement->put_altHtml(bstrAltNew); return(hr); } /* CTriEditDocument::SetObjectComment() */ void CTriEditDocument::AppendEPComment(IHTMLObjectElement *pObjectElement, int ichspNonDSP) { CComBSTR bstrAltNew; int cch; WCHAR *pStrSaved = NULL; HRESULT hr; // get current altHtml from the tree hr = pObjectElement->get_altHtml(&bstrAltNew); if (hr != S_OK || bstrAltNew == (BSTR)NULL) goto LRet; // get saved altHtml in m_pspNonDSP memcpy((BYTE *)&cch, (BYTE *)(m_pspNonDSP+ichspNonDSP), sizeof(int)); if (cch <= 0) goto LRet; pStrSaved = new WCHAR[cch + 1]; if (pStrSaved == NULL) goto LRet; memcpy((BYTE *)pStrSaved, (BYTE *)(m_pspNonDSP+ichspNonDSP+sizeof(int)/sizeof(WCHAR)), cch*sizeof(WCHAR)); pStrSaved[cch] = '\0'; // append saved altHtml bstrAltNew += pStrSaved; // save it back in the tree hr = pObjectElement->put_altHtml(bstrAltNew); if (pStrSaved) delete pStrSaved; LRet: return; } /* CTriEditDocument::AppendEPComment() */ void CTriEditDocument::MapUniqueID(BOOL fGet) { CComPtr pHTMLDoc; CComPtr pHTMLCollection; CComPtr pDispControl; CComPtr pElement; CComPtr pUniqueName; CComPtr pCommentElement; CComPtr pObjectElement; HRESULT hr; //CComBSTR bstrUniqueID; WCHAR *pAttr = NULL; WCHAR *pAttrL = NULL; WCHAR *pAttrDSU = NULL; long len; int i; LPCWSTR szDSP[] = { L"DESIGNTIMESP", L"designtimesp", L"DESIGNTIMEURL", }; LPCWSTR szComment[] = { L" // ASSUME (FOR NOW) that we won't see TRIEDITCOMMENT or others here RemoveEPComment(pObjectElement, bstrAlt, SysStringLen(bstrAlt), &bstrAltComment, &bstrAltNew); FillNonDSPData(bstrAltComment); SysFreeString(bstrAltComment); hr = SetObjectComment(pObjectElement, bstrAltNew); SysFreeString(bstrAltNew); SysFreeString(bstrAlt); //#ifdef DEBUG // pObjectElement->get_altHtml(&bstrAlt); // bstrAlt.Empty(); //#endif //DEBUG } if (pObjectElement) pObjectElement.Release(); bstrUniqueID.Empty(); pOuterTag.Empty(); } VariantClear(&var); } else // if (fGet) { BOOL fLowerCase = FALSE; int index, ichNonDSP; CComBSTR bstrUniqueID; pUniqueName = NULL; hr = pDispControl->QueryInterface(IID_IHTMLUniqueName, (void **) &pUniqueName); if (hr == S_OK && pUniqueName != NULL) hr = pUniqueName->get_uniqueID(&bstrUniqueID); if (pUniqueName) pUniqueName.Release(); // get the uniqueID //pHTMLDoc3->get_uniqueID(&bstrUniqueID); // see if we have it in m_hgMap, if we do, get corresponding designtimesp ID // if we don't have a DSP for this uniqueID, this is newly inserted element VariantInit(&var); if (FGetSavedDSP(bstrUniqueID, &(var.bstrVal), &ichNonDSP, m_pMapArray, &fLowerCase, &index)) { //#ifdef DEBUG // CComBSTR pOuterTag; //#endif //DEBUG // insert (correct case) "designtimesp = xxxx" in the tag by setting attribute/value var.vt = VT_BSTR; #ifdef DEBUG if (index == INDEX_DSP) _ASSERTE(var.bstrVal != NULL && ichNonDSP == -1); else if (index == INDEX_COMMENT) _ASSERTE(var.bstrVal == (BSTR)NULL && ichNonDSP != -1); else if (index == INDEX_AIMGLINK) _ASSERTE(var.bstrVal != NULL && ichNonDSP != -1); // pElement->get_outerHTML(&pOuterTag); // pOuterTag.Empty(); #endif //DEBUG if (index == INDEX_DSP) { if (fLowerCase) hr = pElement->setAttribute(pAttrL, var, 1); else hr = pElement->setAttribute(pAttr, var, 1); } else if (index == INDEX_COMMENT) { hr = pDispControl->QueryInterface(IID_IHTMLCommentElement, (void **) &pCommentElement); if (hr == S_OK && pCommentElement != NULL) ReSetinnerHTMLComment(pCommentElement, pElement, ichNonDSP); if (pCommentElement) pCommentElement.Release(); } else if (index == INDEX_AIMGLINK) { CComVariant varDSU; WCHAR *pchDSU; int cchDSU = 0; if (fLowerCase) hr = pElement->setAttribute(pAttrL, var, 1); else hr = pElement->setAttribute(pAttr, var, 1); // put designtimeurl as well // get the data from ichNonDSP and setAttribute _ASSERTE(ichNonDSP != -1); memcpy((BYTE *)&cchDSU, (BYTE *)(m_pspNonDSP+ichNonDSP), sizeof(INT)); _ASSERTE(cchDSU > 0); pchDSU = new WCHAR[cchDSU+1]; memcpy((BYTE *)pchDSU, (BYTE *)(m_pspNonDSP+ichNonDSP+sizeof(int)/sizeof(WCHAR)), cchDSU*sizeof(WCHAR)); pchDSU[cchDSU] = '\0'; varDSU.bstrVal = SysAllocString(pchDSU); varDSU.vt = VT_BSTR; hr = pElement->setAttribute(pAttrDSU, varDSU, 1); delete pchDSU; } //else if (index == INDEX_AIMGLINK) else if (index == INDEX_OBJ_COMMENT) { hr = pDispControl->QueryInterface(IID_IHTMLObjectElement, (void **) &pObjectElement); if (pObjectElement != NULL) { AppendEPComment(pObjectElement, ichNonDSP); } else // something is not right, just ignore { _ASSERTE(FALSE); } if (pObjectElement) pObjectElement.Release(); } //#ifdef DEBUG // pElement->get_outerHTML(&pOuterTag); // pOuterTag.Empty(); //#endif //DEBUG } // if (FGetSavedDSP()) VariantClear(&var); bstrUniqueID.Empty(); } // end of else case of 'if (!fGet)' //#ifdef DEBUG // bstrTagName.Empty(); // bstrClsName.Empty(); //#endif //DEBUG } // if (hr == S_OK && pElement != NULL) if (pElement) pElement.Release(); } // if (hr == S_OK && pDispControl != NULL) if (pDispControl) pDispControl.Release(); } // for (i ...) LRet: if (pAttr != NULL) delete pAttr; if (pAttrL != NULL) delete pAttrL; if (pAttrDSU != NULL) delete pAttrDSU; if (pHTMLCollection) pHTMLCollection.Release(); if (pHTMLDoc) pHTMLDoc.Release(); if (m_hgMap != NULL) GlobalUnlock(m_hgMap); if (m_hgSpacingNonDSP != NULL) GlobalUnlock(m_hgSpacingNonDSP); return; } ///////////////////////////////////////////////////////////////////// // STDMETHODIMP CTridentEventSink::Invoke(DISPID dispid, REFIID, LCID, USHORT, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*) { switch(dispid) { case DISPID_HTMLDOCUMENTEVENTS_ONREADYSTATECHANGE: { CComBSTR p; HRESULT hr; LPCWSTR szComplete[] = { L"complete", }; //look for READYSTATE_COMPLETE) hr = m_pHTMLDocument2->get_readyState(&p); if ( hr == S_OK && (p != NULL) && 0 == _wcsnicmp(p, szComplete[0], wcslen(szComplete[0])) && m_pTriEditDocument->FIsFilterInDone() ) { CComVariant varDirty; // we know that the document is loaded. // get pointer to DOM and access all tags // create a table that holds mapping from designtimespID to uniqueID // save the mapping and remove designtimesp attribute // at the time of save, fill in the designtimesp's for each uniqueID m_pTriEditDocument->MapUniqueID(/*fGet*/FALSE); m_pTriEditDocument->SetFilterInDone(FALSE); // set the document to be CLEAN (non-DIRTY), we don't care about hr varDirty.bVal = FALSE; varDirty.vt = VT_BOOL; hr = m_pTriEditDocument->Exec(&CGID_MSHTML, IDM_SETDIRTY, MSOCMDEXECOPT_DODEFAULT, &varDirty, NULL); } p.Empty(); } break; } return S_OK; } ///////////////////////////////////////////////////////////////////// // HRESULT CBaseTridentEventSink::Advise(IUnknown* pUnkSource, REFIID riidEventInterface) { HRESULT hr = E_FAIL; if(NULL == pUnkSource) { _ASSERTE(FALSE); return E_INVALIDARG; } if(m_dwCookie > 0) { _ASSERTE(FALSE); return E_UNEXPECTED; } hr = AtlAdvise(pUnkSource, static_cast(this), riidEventInterface, &m_dwCookie); if(SUCCEEDED(hr) && m_dwCookie > 0) { m_iidEventInterface = riidEventInterface; m_pUnkSource = pUnkSource; // no addref. Advise already addref'ed it return S_OK; } return hr; } ///////////////////////////////////////////////////////////////////// // void CBaseTridentEventSink::Unadvise(void) { if(0 == m_dwCookie) return; AtlUnadvise(m_pUnkSource, m_iidEventInterface, m_dwCookie); m_dwCookie = 0; m_pUnkSource = NULL; } //------------------------------------------------------------------------------ // IPersistStreamInit //------------------------------------------------------------------------------ STDMETHODIMP CTriEditDocument::Load(LPSTREAM pStm) { ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::Load")); _ASSERTE(m_pTridentPersistStreamInit != NULL); return m_pTridentPersistStreamInit->Load(pStm); } STDMETHODIMP CTriEditDocument::Save(LPSTREAM pStm, BOOL fClearDirty) { ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::Save")); _ASSERTE(m_pTridentPersistStreamInit != NULL); // before we deligate Save to Trident, do the preFiltering stuff if (m_hgMap != NULL) { MapUniqueID(/*fGet*/TRUE); } return m_pTridentPersistStreamInit->Save(pStm, fClearDirty); } STDMETHODIMP CTriEditDocument::GetSizeMax(ULARGE_INTEGER *pcbSize) { ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::GetSizeMax")); _ASSERTE(m_pTridentPersistStreamInit != NULL); return m_pTridentPersistStreamInit->GetSizeMax(pcbSize); } STDMETHODIMP CTriEditDocument::IsDirty() { //ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::IsDirty\n")); _ASSERTE(m_pTridentPersistStreamInit != NULL); return m_pTridentPersistStreamInit->IsDirty(); } STDMETHODIMP CTriEditDocument::InitNew() { ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::InitNew\n")); _ASSERTE(m_pTridentPersistStreamInit != NULL); return(m_pTridentPersistStreamInit->InitNew()); } STDMETHODIMP CTriEditDocument::GetClassID(CLSID *pClassID) { ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::GetClassID\n")); _ASSERTE(m_pTridentPersistStreamInit != NULL); *pClassID = GetObjectCLSID(); return S_OK; } #endif //IE5_SPACING