Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1114 lines
39 KiB

  1. // Document.cpp : Implementation of CTriEditDocument
  2. // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
  3. #include "stdafx.h"
  4. #include "triedit.h"
  5. #include "Document.h"
  6. #include "util.h"
  7. #ifdef IE5_SPACING
  8. #include "dispatch.h"
  9. #include <mshtmdid.h>
  10. #include <mshtmcid.h>
  11. #endif //IE5_SPACING
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CTriEditDocument
  14. CTriEditDocument::CTriEditDocument()
  15. {
  16. m_pUnkTrident = NULL;
  17. m_pOleObjTrident = NULL;
  18. m_pCmdTgtTrident = NULL;
  19. m_pDropTgtTrident = NULL;
  20. #ifdef IE5_SPACING
  21. m_pTridentPersistStreamInit = NULL;
  22. m_pMapArray = NULL;
  23. m_hgMap = NULL;
  24. m_pspNonDSP = NULL;
  25. m_hgSpacingNonDSP = NULL;
  26. m_ichspNonDSPMax = 0;
  27. m_ichspNonDSP = 0;
  28. #endif //IE5_SPACING
  29. m_pClientSiteHost = NULL;
  30. m_pUIHandlerHost = NULL;
  31. m_pDragDropHandlerHost = NULL;
  32. m_pUIHandler = NULL;
  33. m_pTokenizer = NULL;
  34. m_hwndTrident = NULL;
  35. m_fUIHandlerSet = FALSE;
  36. m_fInContextMenu = FALSE;
  37. m_fDragRectVisible = FALSE;
  38. m_fConstrain = FALSE;
  39. m_f2dDropMode = FALSE;
  40. m_eDirection = CONSTRAIN_NONE;
  41. m_ptAlign.x = 1;
  42. m_ptAlign.y = 1;
  43. m_pihtmlElement = NULL;
  44. m_pihtmlStyle = NULL;
  45. m_hbrDragRect = NULL;
  46. m_fLocked = FALSE;
  47. m_hgDocRestore = NULL;
  48. }
  49. HRESULT CTriEditDocument::FinalConstruct()
  50. {
  51. HRESULT hr;
  52. IUnknown *pUnk = GetControllingUnknown();
  53. hr = CoCreateInstance(CLSID_HTMLDocument, pUnk, CLSCTX_INPROC_SERVER,
  54. IID_IUnknown, (void**)&m_pUnkTrident);
  55. if (SUCCEEDED(hr))
  56. {
  57. _ASSERTE(NULL != m_pUnkTrident);
  58. // When we cache Trident pointers, we do a GetControllingUnknown()->Release()
  59. // since the addref will increment our outer unknown pointer and not Trident
  60. // We compensate for this by doing a corresponding GetControllingUnknown()->AddRef()
  61. // in our FinalRelease. Though these cancel out, it is necessary to do this in order
  62. // to ensure that our FinalRelease will get called.
  63. // Cache Trident's IOleObject pointer
  64. hr = m_pUnkTrident->QueryInterface(IID_IOleObject, (void **)&m_pOleObjTrident);
  65. _ASSERTE(S_OK == hr && NULL != m_pOleObjTrident);
  66. pUnk->Release();
  67. // Cache Trident's IOleCommandTarget pointer
  68. hr = m_pUnkTrident->QueryInterface(IID_IOleCommandTarget, (void **)&m_pCmdTgtTrident);
  69. _ASSERTE(S_OK == hr && NULL != m_pCmdTgtTrident);
  70. pUnk->Release();
  71. // Allocate UI handler sub-object
  72. m_pUIHandler = new CTriEditUIHandler(this);
  73. if (NULL == m_pUIHandler)
  74. hr = E_OUTOFMEMORY;
  75. #ifdef IE5_SPACING
  76. // Get IPersistStreamInit
  77. hr = m_pUnkTrident->QueryInterface(IID_IPersistStreamInit, (void **) &m_pTridentPersistStreamInit);
  78. _ASSERTE(S_OK == hr && NULL != m_pTridentPersistStreamInit);
  79. pUnk->Release(); // PuruK - REVIEW Why do we need to do this?
  80. SetFilterInDone(FALSE);
  81. #endif //IE5_SPACING
  82. // Allocate buffer for saving document's contents before <BODY> tag
  83. // Trident replaces all content before <BODY> tag by its own header
  84. m_hgDocRestore = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbHeader);
  85. if (NULL == m_hgDocRestore)
  86. {
  87. delete m_pUIHandler;
  88. hr = E_OUTOFMEMORY;
  89. }
  90. }
  91. _ASSERTE(SUCCEEDED(hr));
  92. return hr;
  93. }
  94. void CTriEditDocument::FinalRelease()
  95. {
  96. IUnknown *pUnk = GetControllingUnknown();
  97. // Release host interface pointers
  98. SAFERELEASE(m_pClientSiteHost);
  99. SAFERELEASE(m_pUIHandlerHost);
  100. SAFERELEASE(m_pDragDropHandlerHost);
  101. // Release internal interface pointers
  102. SAFERELEASE(m_pTokenizer);
  103. // Release 2d drop related pointers
  104. ReleaseElement();
  105. // Release Trident interface pointers
  106. SAFERELEASE(m_pDropTgtTrident);
  107. pUnk->AddRef();
  108. SAFERELEASE(m_pOleObjTrident);
  109. pUnk->AddRef();
  110. SAFERELEASE(m_pCmdTgtTrident);
  111. #ifdef IE5_SPACING
  112. pUnk->AddRef(); // REVIEW - PuruK - Why do we need to do this?
  113. SAFERELEASE(m_pTridentPersistStreamInit);
  114. #endif //IE5_SPACING
  115. SAFERELEASE(m_pUnkTrident);
  116. // Delete UI handler sub-object
  117. if (m_pUIHandler != NULL)
  118. {
  119. // Assert that the ref count on the sub-object is 1
  120. // If this isn't 1, then Trident is holding on to this pointer
  121. _ASSERTE(m_pUIHandler->m_cRef == 1);
  122. delete m_pUIHandler;
  123. }
  124. if (m_hgDocRestore != NULL)
  125. {
  126. GlobalUnlock(m_hgDocRestore);
  127. GlobalFree(m_hgDocRestore);
  128. }
  129. #ifdef IE5_SPACING
  130. if (m_hgMap != NULL)
  131. {
  132. GlobalUnlock(m_hgMap);
  133. GlobalFree(m_hgMap);
  134. m_hgMap = NULL;
  135. }
  136. if (m_hgSpacingNonDSP != NULL)
  137. {
  138. GlobalUnlock(m_hgSpacingNonDSP);
  139. GlobalFree(m_hgSpacingNonDSP);
  140. m_hgSpacingNonDSP = NULL;
  141. }
  142. #endif
  143. }
  144. #ifdef IE5_SPACING
  145. void CTriEditDocument::FillUniqueID(BSTR bstrUniqueID, BSTR bstrDspVal, int ichNonDSP, MAPSTRUCT *pMap, int iMapCur, BOOL fLowerCase, int iType)
  146. {
  147. memcpy((BYTE *)pMap[iMapCur].szUniqueID, (BYTE *)bstrUniqueID, min(wcslen(bstrUniqueID), cchID)*sizeof(WCHAR));
  148. if (iType == INDEX_DSP)
  149. {
  150. memcpy((BYTE *)pMap[iMapCur].szDspID, (BYTE *)bstrDspVal, min(wcslen(bstrDspVal), cchID)*sizeof(WCHAR));
  151. _ASSERTE(ichNonDSP == -1);
  152. pMap[iMapCur].ichNonDSP = ichNonDSP;
  153. }
  154. else if (iType == INDEX_COMMENT)
  155. {
  156. pMap[iMapCur].ichNonDSP = ichNonDSP;
  157. }
  158. else if (iType == INDEX_AIMGLINK)
  159. {
  160. memcpy((BYTE *)pMap[iMapCur].szDspID, (BYTE *)bstrDspVal, min(wcslen(bstrDspVal), cchID)*sizeof(WCHAR));
  161. pMap[iMapCur].ichNonDSP = ichNonDSP;
  162. }
  163. else if (iType == INDEX_OBJ_COMMENT)
  164. {
  165. pMap[iMapCur].ichNonDSP = ichNonDSP;
  166. }
  167. else
  168. _ASSERTE(FALSE);
  169. pMap[iMapCur].fLowerCase = fLowerCase;
  170. _ASSERTE(iType >= INDEX_NIL && iType < INDEX_MAX);
  171. pMap[iMapCur].iType = iType;
  172. }
  173. BOOL CTriEditDocument::FGetSavedDSP(BSTR bstrUniqueID, BSTR *pbstrDspVal, int *pichNonDSP, MAPSTRUCT *pMap, BOOL *pfLowerCase, int *pIndex)
  174. {
  175. BOOL fRet = FALSE;
  176. int i;
  177. // TODO - find a faster way than this linear search...
  178. for (i = 0; i < m_iMapCur; i++)
  179. {
  180. if (0 == _wcsnicmp(pMap[i].szUniqueID, bstrUniqueID, wcslen(bstrUniqueID)))
  181. {
  182. fRet = TRUE;
  183. if (pMap[i].iType == INDEX_DSP)
  184. {
  185. *pbstrDspVal = SysAllocString(pMap[i].szDspID);
  186. *pichNonDSP = -1;
  187. }
  188. else if (pMap[i].iType == INDEX_COMMENT)
  189. {
  190. *pbstrDspVal = (BSTR)NULL;
  191. *pichNonDSP = pMap[i].ichNonDSP;
  192. }
  193. else if (pMap[i].iType == INDEX_AIMGLINK)
  194. {
  195. *pbstrDspVal = SysAllocString(pMap[i].szDspID);
  196. *pichNonDSP = pMap[i].ichNonDSP;
  197. _ASSERTE(*pichNonDSP != -1);
  198. }
  199. else if (pMap[i].iType == INDEX_OBJ_COMMENT)
  200. {
  201. *pbstrDspVal = (BSTR)NULL;
  202. *pichNonDSP = pMap[i].ichNonDSP;
  203. _ASSERTE(*pichNonDSP != -1);
  204. }
  205. *pfLowerCase = pMap[i].fLowerCase;
  206. *pIndex = pMap[i].iType;
  207. goto LRet;
  208. }
  209. }
  210. LRet:
  211. return(fRet);
  212. }
  213. void
  214. CTriEditDocument::FillNonDSPData(BSTR pOuterTag)
  215. {
  216. int len = 0;
  217. _ASSERTE(m_ichspNonDSPMax != -1);
  218. _ASSERTE(m_ichspNonDSP != -1);
  219. _ASSERTE(m_hgSpacingNonDSP != NULL);
  220. _ASSERTE(m_pspNonDSP != NULL);
  221. // even if pOuterTag is NULL, we still need to store the fact that we have
  222. // zero bytes of data.
  223. if (pOuterTag != NULL)
  224. len = wcslen(pOuterTag);
  225. if ((int)(m_ichspNonDSP + len + sizeof(int)) > m_ichspNonDSPMax)
  226. {
  227. HGLOBAL hgSpacingNonDSP;
  228. //reallocate & set m_ichspNonDSPMax
  229. GlobalUnlock(m_hgSpacingNonDSP);
  230. hgSpacingNonDSP = m_hgSpacingNonDSP;
  231. #pragma prefast(suppress: 308, "noise")
  232. m_hgSpacingNonDSP = GlobalReAlloc(m_hgSpacingNonDSP, (m_ichspNonDSP + len + sizeof(int)+MIN_SP_NONDSP)*sizeof(WCHAR), GMEM_MOVEABLE|GMEM_ZEROINIT);
  233. // if this alloc failed, we may still want to continue
  234. if (m_hgSpacingNonDSP == NULL)
  235. {
  236. GlobalFree(hgSpacingNonDSP);
  237. goto LRet;
  238. }
  239. else
  240. {
  241. m_pspNonDSP = (WCHAR *)GlobalLock(m_hgSpacingNonDSP);
  242. _ASSERTE(m_pspNonDSP != NULL);
  243. m_ichspNonDSPMax = (m_ichspNonDSP + len + sizeof(int)+MIN_SP_NONDSP);
  244. }
  245. _ASSERTE(m_ichspNonDSP < m_ichspNonDSPMax);
  246. }
  247. memcpy((BYTE *)(m_pspNonDSP+m_ichspNonDSP), (BYTE *)&len, sizeof(int));
  248. m_ichspNonDSP += sizeof(int)/sizeof(WCHAR);
  249. memcpy((BYTE *)(m_pspNonDSP+m_ichspNonDSP), (BYTE *)pOuterTag, len*sizeof(WCHAR));
  250. m_ichspNonDSP += len;
  251. LRet:
  252. return;
  253. }
  254. void
  255. CTriEditDocument::ReSetinnerHTMLComment(IHTMLCommentElement *pCommentElement, IHTMLElement* /*pElement*/, int ichspNonDSP)
  256. {
  257. WCHAR *pStrComment = NULL;
  258. //#ifdef DEBUG
  259. // CComBSTR bstrOuter, bstrOuterBefore;
  260. //#endif //DEBUG
  261. int cchComment = 0;
  262. // get the ich, get the saved comment, set it
  263. memcpy((BYTE *)&cchComment, (BYTE *)(m_pspNonDSP+ichspNonDSP), sizeof(int));
  264. _ASSERTE(cchComment > 0);
  265. //#ifdef DEBUG
  266. // pElement->get_outerHTML(&bstrOuterBefore);
  267. //#endif //DEBUG
  268. pStrComment = new WCHAR[cchComment + 1];
  269. if (pStrComment == NULL)
  270. return;
  271. memcpy((BYTE *)pStrComment, (BYTE *)(m_pspNonDSP+ichspNonDSP+sizeof(int)/sizeof(WCHAR)), cchComment*sizeof(WCHAR));
  272. pStrComment[cchComment] = '\0';
  273. pCommentElement->put_text((BSTR)pStrComment);
  274. //#ifdef DEBUG
  275. // pElement->get_outerHTML(&bstrOuter);
  276. //#endif //DEBUG
  277. if (pStrComment)
  278. delete pStrComment;
  279. //#ifdef DEBUG
  280. // bstrOuter.Empty();
  281. // bstrOuterBefore.Empty();
  282. //#endif //DEBUG
  283. }
  284. void
  285. CTriEditDocument::SetinnerHTMLComment(IHTMLCommentElement *pCommentElement, IHTMLElement* /*pElement*/, BSTR pOuterTag)
  286. {
  287. WCHAR *pStr = NULL;
  288. WCHAR *pStrComment = NULL;
  289. LPCWSTR rgComment[] =
  290. {
  291. L"TRIEDITPRECOMMENT-",
  292. L"-->",
  293. L"<!--",
  294. };
  295. //#ifdef DEBUG
  296. // CComBSTR bstrOuter, bstrInnerBefore, bstrInnerAfter, bstrOuterBefore;
  297. //#endif //DEBUG
  298. // special case -
  299. // send pOuterTag as NULL, if we want to get rid of the comment completely
  300. if (pOuterTag == NULL)
  301. {
  302. pCommentElement->put_text((BSTR)pOuterTag);
  303. goto LRet;
  304. }
  305. //remove the TRIEDITCOMMENT stuff from pOuterTag and set the outerHTML properly
  306. pStr = wcsstr(pOuterTag, rgComment[0]);
  307. if (pStr != NULL)
  308. {
  309. pStrComment = new WCHAR[wcslen(pOuterTag)-(SAFE_PTR_DIFF_TO_INT(pStr-pOuterTag)+wcslen(rgComment[0]))+wcslen(rgComment[1])+wcslen(rgComment[2])+1];
  310. if (pStrComment != NULL)
  311. {
  312. memcpy( (BYTE *)pStrComment,
  313. (BYTE *)(rgComment[2]),
  314. (wcslen(rgComment[2]))*sizeof(WCHAR)
  315. );
  316. memcpy( (BYTE *)(pStrComment+wcslen(rgComment[2])),
  317. (BYTE *)(pStr+wcslen(rgComment[0])),
  318. (wcslen(pOuterTag)-(SAFE_PTR_DIFF_TO_INT(pStr-pOuterTag)+wcslen(rgComment[0]))-wcslen(rgComment[1]))*sizeof(WCHAR)
  319. );
  320. memcpy( (BYTE *)(pStrComment+wcslen(rgComment[2])+wcslen(pOuterTag)-(pStr-pOuterTag+wcslen(rgComment[0]))-wcslen(rgComment[1])),
  321. (BYTE *)(rgComment[1]),
  322. (wcslen(rgComment[1]))*sizeof(WCHAR)
  323. );
  324. pStrComment[wcslen(pOuterTag)-(pStr-pOuterTag+wcslen(rgComment[0]))-wcslen(rgComment[1])+wcslen(rgComment[1])+wcslen(rgComment[2])] = '\0';
  325. //#ifdef DEBUG
  326. // pElement->get_innerHTML(&bstrInnerBefore);
  327. // pElement->get_outerHTML(&bstrOuterBefore);
  328. //#endif //DEBUG
  329. pCommentElement->put_text((BSTR)pStrComment);
  330. //#ifdef DEBUG
  331. // pElement->get_outerHTML(&bstrOuter);
  332. // pElement->get_innerHTML(&bstrInnerAfter);
  333. //#endif //DEBUG
  334. delete pStrComment;
  335. }
  336. }
  337. LRet:
  338. //#ifdef DEBUG
  339. // bstrOuter.Empty();
  340. // bstrInnerBefore.Empty();
  341. // bstrInnerAfter.Empty();
  342. // bstrOuterBefore.Empty();
  343. //#endif //DEBUG
  344. return;
  345. }
  346. void
  347. CTriEditDocument::RemoveEPComment(IHTMLObjectElement *pObjectElement, BSTR bstrAlt,
  348. int cch, BSTR *pbstrAltComment, BSTR *pbstrAltNew)
  349. {
  350. int ich = 0;
  351. WCHAR *pAltNew = NULL;
  352. WCHAR *pStrAlt = bstrAlt;
  353. WCHAR *pStr = NULL;
  354. WCHAR *pStrEnd = NULL;
  355. WCHAR *pStrComment = NULL;
  356. LPCWSTR rgComment[] =
  357. {
  358. L"<!--ERRORPARAM",
  359. L"ERRORPARAM-->",
  360. };
  361. if (bstrAlt == (BSTR)NULL || pObjectElement == NULL)
  362. return;
  363. // look for ERRORPARAM
  364. pStr = wcsstr(bstrAlt, rgComment[0]);
  365. pStrEnd = wcsstr(bstrAlt, rgComment[1]);
  366. if (pStr != NULL && pStrEnd != NULL)
  367. {
  368. pStrEnd += wcslen(rgComment[1]);
  369. pStrComment = new WCHAR[SAFE_PTR_DIFF_TO_INT(pStrEnd-pStr)+1];
  370. if (pStrComment == NULL)
  371. goto LRetNull;
  372. memcpy((BYTE *)pStrComment, (BYTE *)pStr, SAFE_PTR_DIFF_TO_INT(pStrEnd-pStr)*sizeof(WCHAR));
  373. pStrComment[pStrEnd-pStr] = '\0';
  374. *pbstrAltComment = SysAllocString(pStrComment);
  375. delete pStrComment;
  376. pAltNew = new WCHAR[cch+1]; // max size
  377. if (pAltNew == NULL)
  378. goto LRetNull;
  379. // remove stuff from pStr till pStrEnd & copy into *pbstrAltNew
  380. if (pStr > pStrAlt)
  381. {
  382. memcpy((BYTE *)pAltNew, (BYTE *)pStrAlt, SAFE_PTR_DIFF_TO_INT(pStr-pStrAlt)*sizeof(WCHAR));
  383. ich += SAFE_PTR_DIFF_TO_INT(pStr-pStrAlt);
  384. }
  385. if ((pStrAlt+cch)-pStrEnd > 0)
  386. {
  387. memcpy((BYTE *)(pAltNew+ich), (BYTE *)pStrEnd, SAFE_PTR_DIFF_TO_INT((pStrAlt+cch)-pStrEnd)*sizeof(WCHAR));
  388. ich += SAFE_PTR_DIFF_TO_INT((pStrAlt+cch)-pStrEnd);
  389. }
  390. pAltNew[ich] = '\0';
  391. *pbstrAltNew = SysAllocString(pAltNew);
  392. delete pAltNew;
  393. }
  394. else
  395. {
  396. LRetNull:
  397. *pbstrAltNew = (bstrAlt) ? SysAllocString(bstrAlt) : (BSTR)NULL;
  398. *pbstrAltComment = (BSTR)NULL;
  399. }
  400. } /* CTriEditDocument::RemoveEPComment() */
  401. HRESULT
  402. CTriEditDocument::SetObjectComment(IHTMLObjectElement *pObjectElement, BSTR bstrAltNew)
  403. {
  404. HRESULT hr;
  405. _ASSERTE(pObjectElement != NULL);
  406. hr = pObjectElement->put_altHtml(bstrAltNew);
  407. return(hr);
  408. } /* CTriEditDocument::SetObjectComment() */
  409. void
  410. CTriEditDocument::AppendEPComment(IHTMLObjectElement *pObjectElement, int ichspNonDSP)
  411. {
  412. CComBSTR bstrAltNew;
  413. int cch;
  414. WCHAR *pStrSaved = NULL;
  415. HRESULT hr;
  416. // get current altHtml from the tree
  417. hr = pObjectElement->get_altHtml(&bstrAltNew);
  418. if (hr != S_OK || bstrAltNew == (BSTR)NULL)
  419. goto LRet;
  420. // get saved altHtml in m_pspNonDSP
  421. memcpy((BYTE *)&cch, (BYTE *)(m_pspNonDSP+ichspNonDSP), sizeof(int));
  422. if (cch <= 0)
  423. goto LRet;
  424. pStrSaved = new WCHAR[cch + 1];
  425. if (pStrSaved == NULL)
  426. goto LRet;
  427. memcpy((BYTE *)pStrSaved, (BYTE *)(m_pspNonDSP+ichspNonDSP+sizeof(int)/sizeof(WCHAR)), cch*sizeof(WCHAR));
  428. pStrSaved[cch] = '\0';
  429. // append saved altHtml
  430. bstrAltNew += pStrSaved;
  431. // save it back in the tree
  432. hr = pObjectElement->put_altHtml(bstrAltNew);
  433. if (pStrSaved)
  434. delete pStrSaved;
  435. LRet:
  436. return;
  437. } /* CTriEditDocument::AppendEPComment() */
  438. void
  439. CTriEditDocument::MapUniqueID(BOOL fGet)
  440. {
  441. CComPtr<IHTMLDocument2> pHTMLDoc;
  442. CComPtr<IHTMLElementCollection> pHTMLCollection;
  443. CComPtr<IDispatch> pDispControl;
  444. CComPtr<IHTMLElement> pElement;
  445. CComPtr<IHTMLUniqueName> pUniqueName;
  446. CComPtr<IHTMLCommentElement> pCommentElement;
  447. CComPtr<IHTMLObjectElement> pObjectElement;
  448. HRESULT hr;
  449. //CComBSTR bstrUniqueID;
  450. WCHAR *pAttr = NULL;
  451. WCHAR *pAttrL = NULL;
  452. WCHAR *pAttrDSU = NULL;
  453. long len;
  454. int i;
  455. LPCWSTR szDSP[] =
  456. {
  457. L"DESIGNTIMESP",
  458. L"designtimesp",
  459. L"DESIGNTIMEURL",
  460. };
  461. LPCWSTR szComment[] =
  462. {
  463. L"<!--TRIEDITCOMMENT",
  464. L"<!--ERRORPARAM",
  465. L"<!--ERROROBJECT",
  466. };
  467. VARIANT var, vaName, vaIndex;
  468. if (!IsIE5OrBetterInstalled())
  469. goto LRet;
  470. pHTMLDoc = NULL;
  471. hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void **) &pHTMLDoc);
  472. if (hr != S_OK)
  473. goto LRet;
  474. pHTMLDoc->get_all(&pHTMLCollection);
  475. if (hr != S_OK)
  476. goto LRet;
  477. pAttr = new WCHAR[wcslen(szDSP[0])+1];
  478. memcpy((BYTE *)pAttr, (BYTE *)szDSP[0], wcslen(szDSP[0])*sizeof(WCHAR));
  479. pAttr[wcslen(szDSP[0])] = '\0';
  480. pAttrL = new WCHAR[wcslen(szDSP[1])+1];
  481. memcpy((BYTE *)pAttrL, (BYTE *)szDSP[1], wcslen(szDSP[1])*sizeof(WCHAR));
  482. pAttrL[wcslen(szDSP[1])] = '\0';
  483. pAttrDSU = new WCHAR[wcslen(szDSP[2])+1];
  484. memcpy((BYTE *)pAttrDSU, (BYTE *)szDSP[2], wcslen(szDSP[2])*sizeof(WCHAR));
  485. pAttrDSU[wcslen(szDSP[2])] = '\0';
  486. pHTMLCollection->get_length(&len);
  487. if (len == 0)
  488. goto LRet;
  489. if (!fGet)
  490. {
  491. // now we know that we atleast have one element, lets allocate space for saving
  492. // UniqueID's & designtimesp's
  493. if (m_pMapArray == NULL) // this is the first time we are here
  494. {
  495. _ASSERTE(m_hgMap == NULL);
  496. m_hgMap = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, MIN_MAP*sizeof(MAPSTRUCT));
  497. if (m_hgMap == NULL)
  498. goto LRet;
  499. m_cMapMax = MIN_MAP;
  500. }
  501. _ASSERTE(m_hgMap != NULL);
  502. m_pMapArray = (MAPSTRUCT *) GlobalLock(m_hgMap);
  503. _ASSERTE(m_pMapArray != NULL);
  504. // even if we allocate the space for m_hgMap here or not, we should start from 0
  505. m_iMapCur = 0;
  506. // zeroise the array
  507. memset((BYTE *)m_pMapArray, 0, m_cMapMax*sizeof(MAPSTRUCT));
  508. if (m_pspNonDSP == NULL) // this is the first time we are here
  509. {
  510. _ASSERTE(m_hgSpacingNonDSP == NULL);
  511. m_hgSpacingNonDSP = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, MIN_SP_NONDSP*sizeof(WCHAR));
  512. if (m_hgSpacingNonDSP == NULL)
  513. goto LRet;
  514. m_ichspNonDSPMax = MIN_SP_NONDSP;
  515. }
  516. _ASSERTE(m_hgSpacingNonDSP != NULL);
  517. m_pspNonDSP = (WCHAR *) GlobalLock(m_hgSpacingNonDSP);
  518. _ASSERTE(m_pspNonDSP != NULL);
  519. // even if we allocate the space for m_hgSpacingNonDSP here or not, we should start from 0
  520. m_ichspNonDSP = 0;
  521. // zeroise the array
  522. memset((BYTE *)m_pspNonDSP, 0, m_ichspNonDSPMax*sizeof(WCHAR));
  523. }
  524. else // if (fGet)
  525. {
  526. if (m_iMapCur < 1) // we don't have any mappings saved
  527. goto LRet;
  528. m_pMapArray = (MAPSTRUCT *)GlobalLock(m_hgMap);
  529. _ASSERTE(m_pMapArray != NULL);
  530. m_pspNonDSP = (WCHAR *)GlobalLock(m_hgSpacingNonDSP);
  531. _ASSERTE(m_pspNonDSP != NULL);
  532. }
  533. // loop through all the elemets and fill m_pMapArray
  534. for (i = 0; i < len; i++)
  535. {
  536. VARIANT_BOOL fSuccess;
  537. if (!fGet)
  538. {
  539. // reallocate m_hgMap if needed
  540. if (m_iMapCur == m_cMapMax - 1)
  541. {
  542. HGLOBAL hgMap;
  543. GlobalUnlock(m_hgMap);
  544. hgMap = m_hgMap;
  545. #pragma prefast(suppress:308, "noise")
  546. m_hgMap = GlobalReAlloc(m_hgMap, (m_cMapMax+MIN_MAP)*sizeof(MAPSTRUCT), GMEM_MOVEABLE|GMEM_ZEROINIT);
  547. // if this alloc failed, we may still want to continue
  548. if (m_hgMap == NULL)
  549. {
  550. GlobalFree(hgMap);
  551. goto LRet;
  552. }
  553. else
  554. {
  555. m_pMapArray = (MAPSTRUCT *)GlobalLock(m_hgMap);
  556. _ASSERTE(m_pMapArray != NULL);
  557. m_cMapMax += MIN_MAP;
  558. }
  559. }
  560. _ASSERTE(m_iMapCur < m_cMapMax);
  561. }
  562. VariantInit(&vaName);
  563. VariantInit(&vaIndex);
  564. V_VT(&vaName) = VT_ERROR;
  565. V_ERROR(&vaName) = DISP_E_PARAMNOTFOUND;
  566. V_VT(&vaIndex) = VT_I4;
  567. V_I4(&vaIndex) = i;
  568. pDispControl = NULL;
  569. hr = pHTMLCollection->item(vaIndex, vaName, &pDispControl);
  570. VariantClear(&vaName);
  571. VariantClear(&vaIndex);
  572. // Trident has a bug that if the object was nested inside <scripts> tags,
  573. // it returns S_OK with pDispControl as NULL. (See VID BUG 11303)
  574. if (hr == S_OK && pDispControl != NULL)
  575. {
  576. pElement = NULL;
  577. hr = pDispControl->QueryInterface(IID_IHTMLElement, (void **) &pElement);
  578. if (hr == S_OK && pElement != NULL)
  579. {
  580. //#ifdef DEBUG
  581. // CComBSTR bstrTagName, bstrClsName;
  582. //
  583. // hr = pElement->get_className(&bstrClsName);
  584. // hr = pElement->get_tagName(&bstrTagName);
  585. //#endif //DEBUG
  586. if (!fGet) // saving the data
  587. {
  588. BOOL fLowerCase = FALSE;
  589. VariantInit(&var);
  590. // KNOWN (and postponed) TRIDENT BUG - ideally, we should be able to look for hr's value here,
  591. // but trident returns S_OK even if it can't get the attribute!!!
  592. hr = pElement->getAttribute(pAttr, 0, &var); // look for DESIGNTIMESP (upper or lower case'd)
  593. if (var.vt == VT_BSTR)
  594. {
  595. CComVariant varT;
  596. hr = pElement->getAttribute(pAttrL, 1, &varT); // look for lowercase designtimesp
  597. if (varT.vt == VT_BSTR)
  598. fLowerCase = TRUE;
  599. }
  600. if (var.vt == VT_BSTR && var.bstrVal != NULL)
  601. {
  602. CComBSTR bstrUniqueID;
  603. CComVariant varDSU;
  604. int iType = INDEX_DSP; // initial value
  605. int ich = -1; // initial value;
  606. //#ifdef DEBUG
  607. // CComBSTR pOuterTag;
  608. //#endif //DEBUG
  609. pUniqueName = NULL;
  610. hr = pDispControl->QueryInterface(IID_IHTMLUniqueName, (void **) &pUniqueName);
  611. if (hr == S_OK && pUniqueName != NULL)
  612. hr = pUniqueName->get_uniqueID(&bstrUniqueID);
  613. if (pUniqueName)
  614. pUniqueName.Release();
  615. //pHTMLDoc3->get_uniqueID(&bstrUniqueID);
  616. //#ifdef DEBUG
  617. // pElement->get_outerHTML(&pOuterTag);
  618. // pOuterTag.Empty();
  619. //#endif //DEBUG
  620. // at this point, we know that this tag had designtimesp.
  621. // It may also have additional triedit attributes like designtimeurl
  622. // lets check for those as well
  623. hr = pElement->getAttribute(pAttrDSU, 0, &varDSU); // look for DESIGNTIMEURL (upper or lower case'd)
  624. if ( hr == S_OK
  625. && varDSU.vt == VT_BSTR
  626. && varDSU.bstrVal != NULL
  627. )
  628. {
  629. // we found 'designtimeurl'
  630. iType = INDEX_AIMGLINK;
  631. ich = m_ichspNonDSP;
  632. FillNonDSPData(varDSU.bstrVal);
  633. //#ifdef DEBUG
  634. // pElement->get_outerHTML(&pOuterTag);
  635. // pOuterTag.Empty();
  636. //#endif //DEBUG
  637. // now remove designtimeurl & its value
  638. hr = pElement->removeAttribute(pAttrDSU, 0, &fSuccess);
  639. //#ifdef DEBUG
  640. // pElement->get_outerHTML(&pOuterTag);
  641. // pOuterTag.Empty();
  642. //#endif //DEBUG
  643. }
  644. // fill ID mapping structure
  645. FillUniqueID(bstrUniqueID, var.bstrVal, ich, m_pMapArray, m_iMapCur, fLowerCase, iType);
  646. bstrUniqueID.Empty();
  647. m_iMapCur++;
  648. //#ifdef DEBUG
  649. // pElement->get_outerHTML(&pOuterTag);
  650. // pOuterTag.Empty();
  651. //#endif //DEBUG
  652. // Now, remove designtimesp and its value
  653. hr = pElement->removeAttribute(pAttr, 0, &fSuccess);
  654. //#ifdef DEBUG
  655. // pElement->get_outerHTML(&pOuterTag);
  656. // pOuterTag.Empty();
  657. //#endif //DEBUG
  658. bstrUniqueID.Empty();
  659. }
  660. else if (var.vt == VT_NULL)
  661. {
  662. CComBSTR bstrUniqueID;
  663. CComBSTR pOuterTag;
  664. //#ifdef DEBUG
  665. // CComBSTR pOuter;
  666. //#endif // DEBUG
  667. // see if this is a comment and save it
  668. pElement->get_outerHTML(&pOuterTag);
  669. if ( pOuterTag != NULL
  670. && 0 == _wcsnicmp(pOuterTag, szComment[0], wcslen(szComment[0]))
  671. )
  672. {
  673. pUniqueName = NULL;
  674. hr = pDispControl->QueryInterface(IID_IHTMLUniqueName, (void **) &pUniqueName);
  675. if (hr == S_OK && pUniqueName != NULL)
  676. hr = pUniqueName->get_uniqueID(&bstrUniqueID);
  677. if (pUniqueName)
  678. pUniqueName.Release();
  679. // fill ID mapping structure
  680. FillUniqueID(bstrUniqueID, NULL, m_ichspNonDSP, m_pMapArray, m_iMapCur, fLowerCase, INDEX_COMMENT);
  681. bstrUniqueID.Empty();
  682. m_iMapCur++;
  683. FillNonDSPData(pOuterTag);
  684. // now, remove the comment spacing stuff and set_outerHTML
  685. hr = pDispControl->QueryInterface(IID_IHTMLCommentElement, (void **) &pCommentElement);
  686. if (hr == S_OK && pCommentElement != NULL)
  687. SetinnerHTMLComment(pCommentElement, pElement, pOuterTag);
  688. //#ifdef DEBUG
  689. // pElement->get_outerHTML(&pOuter);
  690. // pOuter.Empty();
  691. //#endif //DEBUG
  692. if (pCommentElement)
  693. pCommentElement.Release();
  694. }
  695. else if ( S_OK == pDispControl->QueryInterface(IID_IHTMLObjectElement, (void **) &pObjectElement)
  696. && pObjectElement != NULL
  697. )
  698. {
  699. BSTR bstrAlt, bstrAltNew, bstrAltComment;
  700. bstrAlt = bstrAltNew = bstrAltComment = NULL;
  701. pUniqueName = NULL;
  702. hr = pDispControl->QueryInterface(IID_IHTMLUniqueName, (void **) &pUniqueName);
  703. if (hr == S_OK && pUniqueName != NULL)
  704. hr = pUniqueName->get_uniqueID(&bstrUniqueID);
  705. if (pUniqueName)
  706. pUniqueName.Release();
  707. // fill ID mapping structure
  708. FillUniqueID(bstrUniqueID, NULL, m_ichspNonDSP, m_pMapArray, m_iMapCur, FALSE, INDEX_OBJ_COMMENT);
  709. bstrUniqueID.Empty();
  710. m_iMapCur++;
  711. pObjectElement->get_altHtml(&bstrAlt);
  712. // remove <!--ERRORPARAM ...ERRORPARAM-->
  713. // ASSUME (FOR NOW) that we won't see TRIEDITCOMMENT or others here
  714. RemoveEPComment(pObjectElement, bstrAlt, SysStringLen(bstrAlt), &bstrAltComment, &bstrAltNew);
  715. FillNonDSPData(bstrAltComment);
  716. SysFreeString(bstrAltComment);
  717. hr = SetObjectComment(pObjectElement, bstrAltNew);
  718. SysFreeString(bstrAltNew);
  719. SysFreeString(bstrAlt);
  720. //#ifdef DEBUG
  721. // pObjectElement->get_altHtml(&bstrAlt);
  722. // bstrAlt.Empty();
  723. //#endif //DEBUG
  724. }
  725. if (pObjectElement)
  726. pObjectElement.Release();
  727. bstrUniqueID.Empty();
  728. pOuterTag.Empty();
  729. }
  730. VariantClear(&var);
  731. }
  732. else // if (fGet)
  733. {
  734. BOOL fLowerCase = FALSE;
  735. int index, ichNonDSP;
  736. CComBSTR bstrUniqueID;
  737. pUniqueName = NULL;
  738. hr = pDispControl->QueryInterface(IID_IHTMLUniqueName, (void **) &pUniqueName);
  739. if (hr == S_OK && pUniqueName != NULL)
  740. hr = pUniqueName->get_uniqueID(&bstrUniqueID);
  741. if (pUniqueName)
  742. pUniqueName.Release();
  743. // get the uniqueID
  744. //pHTMLDoc3->get_uniqueID(&bstrUniqueID);
  745. // see if we have it in m_hgMap, if we do, get corresponding designtimesp ID
  746. // if we don't have a DSP for this uniqueID, this is newly inserted element
  747. VariantInit(&var);
  748. if (FGetSavedDSP(bstrUniqueID, &(var.bstrVal), &ichNonDSP, m_pMapArray, &fLowerCase, &index))
  749. {
  750. //#ifdef DEBUG
  751. // CComBSTR pOuterTag;
  752. //#endif //DEBUG
  753. // insert (correct case) "designtimesp = xxxx" in the tag by setting attribute/value
  754. var.vt = VT_BSTR;
  755. #ifdef DEBUG
  756. if (index == INDEX_DSP)
  757. _ASSERTE(var.bstrVal != NULL && ichNonDSP == -1);
  758. else if (index == INDEX_COMMENT)
  759. _ASSERTE(var.bstrVal == (BSTR)NULL && ichNonDSP != -1);
  760. else if (index == INDEX_AIMGLINK)
  761. _ASSERTE(var.bstrVal != NULL && ichNonDSP != -1);
  762. // pElement->get_outerHTML(&pOuterTag);
  763. // pOuterTag.Empty();
  764. #endif //DEBUG
  765. if (index == INDEX_DSP)
  766. {
  767. if (fLowerCase)
  768. hr = pElement->setAttribute(pAttrL, var, 1);
  769. else
  770. hr = pElement->setAttribute(pAttr, var, 1);
  771. }
  772. else if (index == INDEX_COMMENT)
  773. {
  774. hr = pDispControl->QueryInterface(IID_IHTMLCommentElement, (void **) &pCommentElement);
  775. if (hr == S_OK && pCommentElement != NULL)
  776. ReSetinnerHTMLComment(pCommentElement, pElement, ichNonDSP);
  777. if (pCommentElement)
  778. pCommentElement.Release();
  779. }
  780. else if (index == INDEX_AIMGLINK)
  781. {
  782. CComVariant varDSU;
  783. WCHAR *pchDSU;
  784. int cchDSU = 0;
  785. if (fLowerCase)
  786. hr = pElement->setAttribute(pAttrL, var, 1);
  787. else
  788. hr = pElement->setAttribute(pAttr, var, 1);
  789. // put designtimeurl as well
  790. // get the data from ichNonDSP and setAttribute
  791. _ASSERTE(ichNonDSP != -1);
  792. memcpy((BYTE *)&cchDSU, (BYTE *)(m_pspNonDSP+ichNonDSP), sizeof(INT));
  793. _ASSERTE(cchDSU > 0);
  794. pchDSU = new WCHAR[cchDSU+1];
  795. memcpy((BYTE *)pchDSU, (BYTE *)(m_pspNonDSP+ichNonDSP+sizeof(int)/sizeof(WCHAR)), cchDSU*sizeof(WCHAR));
  796. pchDSU[cchDSU] = '\0';
  797. varDSU.bstrVal = SysAllocString(pchDSU);
  798. varDSU.vt = VT_BSTR;
  799. hr = pElement->setAttribute(pAttrDSU, varDSU, 1);
  800. delete pchDSU;
  801. } //else if (index == INDEX_AIMGLINK)
  802. else if (index == INDEX_OBJ_COMMENT)
  803. {
  804. hr = pDispControl->QueryInterface(IID_IHTMLObjectElement, (void **) &pObjectElement);
  805. if (pObjectElement != NULL)
  806. {
  807. AppendEPComment(pObjectElement, ichNonDSP);
  808. }
  809. else // something is not right, just ignore
  810. {
  811. _ASSERTE(FALSE);
  812. }
  813. if (pObjectElement)
  814. pObjectElement.Release();
  815. }
  816. //#ifdef DEBUG
  817. // pElement->get_outerHTML(&pOuterTag);
  818. // pOuterTag.Empty();
  819. //#endif //DEBUG
  820. } // if (FGetSavedDSP())
  821. VariantClear(&var);
  822. bstrUniqueID.Empty();
  823. } // end of else case of 'if (!fGet)'
  824. //#ifdef DEBUG
  825. // bstrTagName.Empty();
  826. // bstrClsName.Empty();
  827. //#endif //DEBUG
  828. } // if (hr == S_OK && pElement != NULL)
  829. if (pElement)
  830. pElement.Release();
  831. } // if (hr == S_OK && pDispControl != NULL)
  832. if (pDispControl)
  833. pDispControl.Release();
  834. } // for (i ...)
  835. LRet:
  836. if (pAttr != NULL)
  837. delete pAttr;
  838. if (pAttrL != NULL)
  839. delete pAttrL;
  840. if (pAttrDSU != NULL)
  841. delete pAttrDSU;
  842. if (pHTMLCollection)
  843. pHTMLCollection.Release();
  844. if (pHTMLDoc)
  845. pHTMLDoc.Release();
  846. if (m_hgMap != NULL)
  847. GlobalUnlock(m_hgMap);
  848. if (m_hgSpacingNonDSP != NULL)
  849. GlobalUnlock(m_hgSpacingNonDSP);
  850. return;
  851. }
  852. /////////////////////////////////////////////////////////////////////
  853. //
  854. STDMETHODIMP
  855. CTridentEventSink::Invoke(DISPID dispid, REFIID, LCID, USHORT, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*)
  856. {
  857. switch(dispid)
  858. {
  859. case DISPID_HTMLDOCUMENTEVENTS_ONREADYSTATECHANGE:
  860. {
  861. CComBSTR p;
  862. HRESULT hr;
  863. LPCWSTR szComplete[] =
  864. {
  865. L"complete",
  866. };
  867. //look for READYSTATE_COMPLETE)
  868. hr = m_pHTMLDocument2->get_readyState(&p);
  869. if ( hr == S_OK
  870. && (p != NULL)
  871. && 0 == _wcsnicmp(p, szComplete[0], wcslen(szComplete[0]))
  872. && m_pTriEditDocument->FIsFilterInDone()
  873. )
  874. {
  875. CComVariant varDirty;
  876. // we know that the document is loaded.
  877. // get pointer to DOM and access all tags
  878. // create a table that holds mapping from designtimespID to uniqueID
  879. // save the mapping and remove designtimesp attribute
  880. // at the time of save, fill in the designtimesp's for each uniqueID
  881. m_pTriEditDocument->MapUniqueID(/*fGet*/FALSE);
  882. m_pTriEditDocument->SetFilterInDone(FALSE);
  883. // set the document to be CLEAN (non-DIRTY), we don't care about hr
  884. varDirty.bVal = FALSE;
  885. varDirty.vt = VT_BOOL;
  886. hr = m_pTriEditDocument->Exec(&CGID_MSHTML, IDM_SETDIRTY, MSOCMDEXECOPT_DODEFAULT, &varDirty, NULL);
  887. }
  888. p.Empty();
  889. }
  890. break;
  891. }
  892. return S_OK;
  893. }
  894. /////////////////////////////////////////////////////////////////////
  895. //
  896. HRESULT
  897. CBaseTridentEventSink::Advise(IUnknown* pUnkSource, REFIID riidEventInterface)
  898. {
  899. HRESULT hr = E_FAIL;
  900. if(NULL == pUnkSource)
  901. {
  902. _ASSERTE(FALSE);
  903. return E_INVALIDARG;
  904. }
  905. if(m_dwCookie > 0)
  906. {
  907. _ASSERTE(FALSE);
  908. return E_UNEXPECTED;
  909. }
  910. hr = AtlAdvise(pUnkSource, static_cast<IUnknown*>(this), riidEventInterface, &m_dwCookie);
  911. if(SUCCEEDED(hr) && m_dwCookie > 0)
  912. {
  913. m_iidEventInterface = riidEventInterface;
  914. m_pUnkSource = pUnkSource; // no addref. Advise already addref'ed it
  915. return S_OK;
  916. }
  917. return hr;
  918. }
  919. /////////////////////////////////////////////////////////////////////
  920. //
  921. void
  922. CBaseTridentEventSink::Unadvise(void)
  923. {
  924. if(0 == m_dwCookie)
  925. return;
  926. AtlUnadvise(m_pUnkSource, m_iidEventInterface, m_dwCookie);
  927. m_dwCookie = 0;
  928. m_pUnkSource = NULL;
  929. }
  930. //------------------------------------------------------------------------------
  931. // IPersistStreamInit
  932. //------------------------------------------------------------------------------
  933. STDMETHODIMP CTriEditDocument::Load(LPSTREAM pStm)
  934. {
  935. ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::Load"));
  936. _ASSERTE(m_pTridentPersistStreamInit != NULL);
  937. return m_pTridentPersistStreamInit->Load(pStm);
  938. }
  939. STDMETHODIMP CTriEditDocument::Save(LPSTREAM pStm, BOOL fClearDirty)
  940. {
  941. ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::Save"));
  942. _ASSERTE(m_pTridentPersistStreamInit != NULL);
  943. // before we deligate Save to Trident, do the preFiltering stuff
  944. if (m_hgMap != NULL)
  945. {
  946. MapUniqueID(/*fGet*/TRUE);
  947. }
  948. return m_pTridentPersistStreamInit->Save(pStm, fClearDirty);
  949. }
  950. STDMETHODIMP CTriEditDocument::GetSizeMax(ULARGE_INTEGER *pcbSize)
  951. {
  952. ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::GetSizeMax"));
  953. _ASSERTE(m_pTridentPersistStreamInit != NULL);
  954. return m_pTridentPersistStreamInit->GetSizeMax(pcbSize);
  955. }
  956. STDMETHODIMP CTriEditDocument::IsDirty()
  957. {
  958. //ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::IsDirty\n"));
  959. _ASSERTE(m_pTridentPersistStreamInit != NULL);
  960. return m_pTridentPersistStreamInit->IsDirty();
  961. }
  962. STDMETHODIMP CTriEditDocument::InitNew()
  963. {
  964. ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::InitNew\n"));
  965. _ASSERTE(m_pTridentPersistStreamInit != NULL);
  966. return(m_pTridentPersistStreamInit->InitNew());
  967. }
  968. STDMETHODIMP CTriEditDocument::GetClassID(CLSID *pClassID)
  969. {
  970. ATLTRACE(_T("CTriEditDocument::IPersistStreamInit::GetClassID\n"));
  971. _ASSERTE(m_pTridentPersistStreamInit != NULL);
  972. *pClassID = GetObjectCLSID();
  973. return S_OK;
  974. }
  975. #endif //IE5_SPACING