Source code of Windows XP (NT5)
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.

612 lines
16 KiB

  1. /*==============================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. File: dbgcxt.cpp
  6. Maintained by: DGottner
  7. Component: Implementation of IDebugDocumentContext for CTemplates
  8. ==============================================================================*/
  9. #include "denpre.h"
  10. #pragma hdrstop
  11. #include "dbgcxt.h"
  12. #include "perfdata.h"
  13. #include "memchk.h"
  14. // {5FA45A6C-AB8A-11d0-8EBA-00C04FC34DCC}
  15. const GUID IID_IDenaliTemplateDocumentContext =
  16. { 0x5fa45a6c, 0xab8a, 0x11d0, { 0x8e, 0xba, 0x0, 0xc0, 0x4f, 0xc3, 0x4d, 0xcc } };
  17. // {3AED94BE-ED79-11d0-8F34-00C04FC34DCC}
  18. static const GUID IID_IDenaliIncFileDocumentContext =
  19. { 0x3aed94be, 0xed79, 0x11d0, { 0x8f, 0x34, 0x0, 0xc0, 0x4f, 0xc3, 0x4d, 0xcc } };
  20. /*
  21. *
  22. * C T e m p l a t e D o c u m e n t C o n t e x t
  23. *
  24. */
  25. /* ============================================================================
  26. CTemplateDocumentContext::CTemplateDocumentContext
  27. Constructor
  28. */
  29. CTemplateDocumentContext::CTemplateDocumentContext
  30. (
  31. CTemplate *pTemplate,
  32. ULONG cchSourceOffset,
  33. ULONG cchText,
  34. IActiveScriptDebug *pDebugScript,
  35. ULONG idEngine,
  36. ULONG cchTargetOffset
  37. )
  38. {
  39. Assert (pTemplate != NULL);
  40. m_pTemplate = pTemplate;
  41. m_idEngine = idEngine;
  42. m_pDebugScript = pDebugScript;
  43. m_cchSourceOffset = cchSourceOffset;
  44. m_cchTargetOffset = cchTargetOffset;
  45. m_cchText = cchText;
  46. m_cRefs = 1;
  47. m_pTemplate->AddRef();
  48. if (m_pDebugScript)
  49. {
  50. m_pDebugScript->AddRef();
  51. // If they passed in a script, then they must also pass in target offset & engine ID
  52. Assert (m_idEngine != -1);
  53. Assert (m_cchTargetOffset != -1);
  54. }
  55. }
  56. /* ============================================================================
  57. CTemplateDocumentContext::~CTemplateDocumentContext
  58. Destructor
  59. */
  60. CTemplateDocumentContext::~CTemplateDocumentContext
  61. (
  62. )
  63. {
  64. m_pTemplate->Release();
  65. if (m_pDebugScript)
  66. m_pDebugScript->Release();
  67. }
  68. /* ============================================================================
  69. CTemplateDocumentContext::QueryInterface
  70. NOTE: QueryInterface here is also used by CTemplate to determine if an
  71. arbitrary document context is ours.
  72. */
  73. HRESULT CTemplateDocumentContext::QueryInterface
  74. (
  75. const GUID & guid,
  76. void ** ppvObj
  77. )
  78. {
  79. if (guid == IID_IUnknown ||
  80. guid == IID_IDebugDocumentContext ||
  81. guid == IID_IDenaliTemplateDocumentContext)
  82. {
  83. *ppvObj = this;
  84. AddRef();
  85. return S_OK;
  86. }
  87. else
  88. {
  89. *ppvObj = NULL;
  90. return E_NOINTERFACE;
  91. }
  92. }
  93. /* ============================================================================
  94. CTemplateDocumentContext::AddRef
  95. CTemplateDocumentContext::Release
  96. NOTE: Don't know if these need to be protected with Interlocked(In|De)crement.
  97. */
  98. ULONG CTemplateDocumentContext::AddRef()
  99. {
  100. InterlockedIncrement(&m_cRefs);
  101. return m_cRefs;
  102. }
  103. ULONG CTemplateDocumentContext::Release()
  104. {
  105. if (InterlockedDecrement(&m_cRefs) == 0)
  106. {
  107. delete this;
  108. return 0;
  109. }
  110. return m_cRefs;
  111. }
  112. /* ============================================================================
  113. CTemplateDocumentContext::GetDocument
  114. Return the document.
  115. */
  116. HRESULT CTemplateDocumentContext::GetDocument
  117. (
  118. /* [out] */ IDebugDocument **ppDebugDocument
  119. )
  120. {
  121. #ifndef PERF_DISABLE
  122. g_PerfData.Incr_DEBUGDOCREQ();
  123. #endif
  124. return m_pTemplate->QueryInterface(IID_IDebugDocument, reinterpret_cast<void **>(ppDebugDocument));
  125. }
  126. /* ============================================================================
  127. CTemplateDocumentContext::EnumCodeContexts
  128. Convert document offset to script offset and enumerate code contexts
  129. */
  130. HRESULT CTemplateDocumentContext::EnumCodeContexts
  131. (
  132. /* [out] */ IEnumDebugCodeContexts **ppEnumerator
  133. )
  134. {
  135. if (! m_pTemplate->FIsValid())
  136. return E_FAIL;
  137. if (m_pDebugScript == NULL)
  138. {
  139. // Convert offset
  140. m_pTemplate->GetTargetOffset(m_pTemplate->GetSourceFileName(), m_cchSourceOffset, &m_idEngine, &m_cchTargetOffset);
  141. // See if the script ran and template is holding onto it
  142. CActiveScriptEngine *pScriptEngine = m_pTemplate->GetActiveScript(m_idEngine);
  143. if (pScriptEngine)
  144. {
  145. if (FAILED(pScriptEngine->GetActiveScript()->QueryInterface(IID_IActiveScriptDebug, reinterpret_cast<void **>(&m_pDebugScript))))
  146. {
  147. pScriptEngine->Release();
  148. return E_FAIL;
  149. }
  150. pScriptEngine->IsBeingDebugged();
  151. pScriptEngine->Release();
  152. }
  153. // Script may be still running ("stop" statement case)
  154. if (m_pDebugScript == NULL)
  155. m_pDebugScript = g_ScriptManager.GetDebugScript(m_pTemplate, m_idEngine);
  156. // This is probably a bug...
  157. if (m_pDebugScript == NULL) // don't have a running script to match this
  158. return E_FAIL;
  159. // No need for AddRef(); m_pDebugScript called funtions that AddRef'ed
  160. }
  161. return m_pDebugScript->EnumCodeContextsOfPosition(
  162. m_idEngine,
  163. m_cchTargetOffset,
  164. m_cchText,
  165. ppEnumerator);
  166. }
  167. /*
  168. *
  169. * C I n c F i l e E n u m C o d e C o n t e x t s
  170. *
  171. *
  172. * For an include file, the corresponding code contexts are the union
  173. * of all appropriate code contexts in all template objects that are using
  174. * the include file. This special enumerator implements the union.
  175. */
  176. class CIncFileEnumCodeContexts : public IEnumDebugCodeContexts
  177. {
  178. private:
  179. CIncFileDocumentContext * m_pContext; // context we are providing enumeration for
  180. IEnumDebugCodeContexts * m_pEnumCodeContexts; // Current code context enumerator
  181. LONG m_cRefs; // reference count
  182. int m_iTemplate; // index of current template
  183. IEnumDebugCodeContexts *GetEnumerator(int *piTemplate); // Get enumerator for a template
  184. public:
  185. CIncFileEnumCodeContexts(CIncFileDocumentContext *pIncFileDocumentContext);
  186. ~CIncFileEnumCodeContexts();
  187. // IUnknown methods
  188. virtual HRESULT STDMETHODCALLTYPE QueryInterface(const GUID &guid, void **ppvObj);
  189. virtual ULONG STDMETHODCALLTYPE AddRef();
  190. virtual ULONG STDMETHODCALLTYPE Release();
  191. // IEnumDebugCodeContexts methods
  192. virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, IDebugCodeContext **pscc, ULONG *pceltFetched);
  193. virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
  194. virtual HRESULT STDMETHODCALLTYPE Reset(void);
  195. virtual HRESULT STDMETHODCALLTYPE Clone(IEnumDebugCodeContexts **ppescc);
  196. };
  197. /* ============================================================================
  198. CIncFileEnumCodeContexts::CIncFileEnumCodeContexts
  199. Constructor
  200. */
  201. CIncFileEnumCodeContexts::CIncFileEnumCodeContexts
  202. (
  203. CIncFileDocumentContext *pDocumentContext
  204. )
  205. {
  206. m_pContext = pDocumentContext;
  207. m_pContext->AddRef();
  208. m_cRefs = 1;
  209. Reset();
  210. }
  211. /* ============================================================================
  212. CIncFileEnumCodeContexts::~CIncFileEnumCodeContexts
  213. Destructor
  214. */
  215. CIncFileEnumCodeContexts::~CIncFileEnumCodeContexts()
  216. {
  217. m_pContext->Release();
  218. if (m_pEnumCodeContexts)
  219. m_pEnumCodeContexts->Release();
  220. }
  221. /* ============================================================================
  222. CIncFileEnumCodeContexts::GetEnumerator
  223. Get a code context enumerator for the current script engine
  224. Side Effects:
  225. piTemplate is incremented to point to the next available template
  226. (piTemplate is really an "iteration cookie" -- don't think of it as an index)
  227. */
  228. IEnumDebugCodeContexts *CIncFileEnumCodeContexts::GetEnumerator
  229. (
  230. int *piTemplate
  231. )
  232. {
  233. // Get a template from the array - may need to retry if template contains compiler errors
  234. CTemplate *pTemplate;
  235. do
  236. {
  237. // GetTemplate returns NULL when array index is out of range (which is when iteration is exhaused)
  238. pTemplate = m_pContext->m_pIncFile->GetTemplate((*piTemplate)++);
  239. if (pTemplate == NULL)
  240. return NULL;
  241. }
  242. while (! pTemplate->FIsValid());
  243. // If we got this far, we got one of the users of this include file. Convert the offset
  244. ULONG idEngine, cchTargetOffset;
  245. pTemplate->GetTargetOffset(m_pContext->m_pIncFile->GetIncFileName(), m_pContext->m_cchSourceOffset, &idEngine, &cchTargetOffset);
  246. // Now we have the engine ID, see if template is holding onto corresponding engine
  247. IActiveScriptDebug *pDebugScriptEngine = NULL;
  248. CActiveScriptEngine *pScriptEngine = pTemplate->GetActiveScript(idEngine);
  249. if (pScriptEngine)
  250. {
  251. if (FAILED(pScriptEngine->GetActiveScript()->QueryInterface(IID_IActiveScriptDebug, reinterpret_cast<void **>(&pDebugScriptEngine))))
  252. {
  253. pScriptEngine->Release();
  254. return NULL;
  255. }
  256. pScriptEngine->IsBeingDebugged();
  257. pScriptEngine->Release();
  258. }
  259. // If we could not get the engine that way, the script is likely still in the running state
  260. if (pDebugScriptEngine == NULL)
  261. pDebugScriptEngine = g_ScriptManager.GetDebugScript(pTemplate, idEngine);
  262. // This is probably a bug...
  263. if (pDebugScriptEngine == NULL) // don't have a running script to match this
  264. return NULL;
  265. IEnumDebugCodeContexts *pEnumerator;
  266. HRESULT hrGotEnum = pDebugScriptEngine->EnumCodeContextsOfPosition(
  267. idEngine,
  268. cchTargetOffset,
  269. m_pContext->m_cchText,
  270. &pEnumerator);
  271. pDebugScriptEngine->Release();
  272. return SUCCEEDED(hrGotEnum)? pEnumerator : NULL;
  273. }
  274. /* ============================================================================
  275. CIncFileEnumCodeContexts::QueryInterface
  276. */
  277. HRESULT CIncFileEnumCodeContexts::QueryInterface
  278. (
  279. const GUID & guid,
  280. void ** ppvObj
  281. )
  282. {
  283. if (guid == IID_IUnknown || guid == IID_IEnumDebugCodeContexts)
  284. {
  285. *ppvObj = this;
  286. AddRef();
  287. return S_OK;
  288. }
  289. else
  290. {
  291. *ppvObj = NULL;
  292. return E_NOINTERFACE;
  293. }
  294. }
  295. /* ============================================================================
  296. CIncFileEnumCodeContexts::AddRef
  297. CIncFileEnumCodeContexts::Release
  298. NOTE: Don't know if these need to be protected with Interlocked(In|De)crement.
  299. */
  300. ULONG CIncFileEnumCodeContexts::AddRef()
  301. {
  302. InterlockedIncrement(&m_cRefs);
  303. return m_cRefs;
  304. }
  305. ULONG CIncFileEnumCodeContexts::Release()
  306. {
  307. if (InterlockedDecrement(&m_cRefs) == 0)
  308. {
  309. delete this;
  310. return 0;
  311. }
  312. return m_cRefs;
  313. }
  314. /* ============================================================================
  315. CIncFileEnumCodeContexts::Clone
  316. Clone this iterator (standard method)
  317. */
  318. HRESULT CIncFileEnumCodeContexts::Clone
  319. (
  320. IEnumDebugCodeContexts **ppEnumClone
  321. )
  322. {
  323. CIncFileEnumCodeContexts *pClone = new CIncFileEnumCodeContexts(m_pContext);
  324. if (pClone == NULL)
  325. return E_OUTOFMEMORY;
  326. // new iterator should point to same location as this.
  327. pClone->m_iTemplate = m_iTemplate;
  328. pClone->m_pEnumCodeContexts = m_pEnumCodeContexts;
  329. if (m_pEnumCodeContexts)
  330. m_pEnumCodeContexts->AddRef();
  331. *ppEnumClone = pClone;
  332. return S_OK;
  333. }
  334. /* ============================================================================
  335. CIncFileEnumCodeContexts::Next
  336. Get next value (standard method)
  337. To rehash standard OLE semantics:
  338. We get the next "cElements" from the collection and store them
  339. in "rgVariant" which holds at least "cElements" items. On
  340. return "*pcElementsFetched" contains the actual number of elements
  341. stored. Returns S_FALSE if less than "cElements" were stored, S_OK
  342. otherwise.
  343. */
  344. HRESULT CIncFileEnumCodeContexts::Next
  345. (
  346. unsigned long cElementsRequested,
  347. IDebugCodeContext **ppCodeContexts,
  348. unsigned long *pcElementsFetched
  349. )
  350. {
  351. // give a valid pointer value to 'pcElementsFetched'
  352. //
  353. unsigned long cLocalElementsFetched;
  354. if (pcElementsFetched == NULL)
  355. pcElementsFetched = &cLocalElementsFetched;
  356. // Initialize things
  357. //
  358. unsigned long cElements = cElementsRequested;
  359. *pcElementsFetched = 0;
  360. // Loop over all templates until we fill the ppCodeContext array or we've exhausted the collection
  361. // (when m_pEnumCodeContexts is NULL that means we are done)
  362. //
  363. while (cElements > 0 && m_pEnumCodeContexts)
  364. {
  365. // Fetch as many contexts as we can from the current iterator
  366. unsigned long cElementsFetched;
  367. HRESULT hrEnum = m_pEnumCodeContexts->Next(cElements, ppCodeContexts, &cElementsFetched);
  368. if (FAILED(hrEnum))
  369. return hrEnum;
  370. // If iterator did not fill entire array, advance to next one
  371. if (cElementsFetched < cElements)
  372. {
  373. // Advance - first release the current iterator
  374. m_pEnumCodeContexts->Release();
  375. m_pEnumCodeContexts = GetEnumerator(&m_iTemplate);
  376. }
  377. *pcElementsFetched += cElementsFetched;
  378. ppCodeContexts += cElementsFetched;
  379. cElements -= cElementsFetched;
  380. }
  381. // initialize the remaining structures
  382. while (cElements-- > 0)
  383. *ppCodeContexts++ = NULL;
  384. return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
  385. }
  386. /* ============================================================================
  387. CIncFileEnumCodeContexts::Skip
  388. Skip items (standard method)
  389. To rehash standard OLE semantics:
  390. We skip over the next "cElements" from the collection.
  391. Returns S_FALSE if less than "cElements" were skipped, S_OK
  392. otherwise.
  393. */
  394. HRESULT CIncFileEnumCodeContexts::Skip(unsigned long cElements)
  395. {
  396. /* Loop through the collection until either we reach the end or
  397. * cElements becomes zero. Since the iteration logic is
  398. * so complex, we do not repeat it here.
  399. */
  400. HRESULT hrElementFetched = S_OK;
  401. while (cElements > 0 && hrElementFetched == S_OK)
  402. {
  403. IDebugCodeContext *pCodeContext;
  404. hrElementFetched = Next(1, &pCodeContext, NULL);
  405. pCodeContext->Release();
  406. --cElements;
  407. }
  408. return (cElements == 0)? S_OK : S_FALSE;
  409. }
  410. /* ============================================================================
  411. CIncFileEnumCodeContexts::Reset
  412. Reset the iterator (standard method)
  413. */
  414. HRESULT CIncFileEnumCodeContexts::Reset()
  415. {
  416. m_iTemplate = 0;
  417. m_pEnumCodeContexts = GetEnumerator(&m_iTemplate);
  418. return S_OK;
  419. }
  420. /*
  421. *
  422. * C I n c F i l e D o c u m e n t C o n t e x t
  423. *
  424. */
  425. /* ============================================================================
  426. CIncFileDocumentContext::CIncFileDocumentContext
  427. Constructor
  428. */
  429. CIncFileDocumentContext::CIncFileDocumentContext
  430. (
  431. CIncFile *pIncFile,
  432. ULONG cchSourceOffset,
  433. ULONG cchText
  434. )
  435. {
  436. Assert (pIncFile != NULL);
  437. m_pIncFile = pIncFile;
  438. m_cchSourceOffset = cchSourceOffset;
  439. m_cchText = cchText;
  440. m_cRefs = 1;
  441. m_pIncFile->AddRef();
  442. }
  443. /* ============================================================================
  444. CIncFileDocumentContext::~CIncFileDocumentContext
  445. Destructor
  446. */
  447. CIncFileDocumentContext::~CIncFileDocumentContext
  448. (
  449. )
  450. {
  451. m_pIncFile->Release();
  452. }
  453. /* ============================================================================
  454. CIncFileDocumentContext::QueryInterface
  455. NOTE: QueryInterface here is also used by CIncFile to determine if an
  456. arbitrary document context is ours.
  457. */
  458. HRESULT CIncFileDocumentContext::QueryInterface
  459. (
  460. const GUID & guid,
  461. void ** ppvObj
  462. )
  463. {
  464. if (guid == IID_IUnknown ||
  465. guid == IID_IDebugDocumentContext ||
  466. guid == IID_IDenaliIncFileDocumentContext)
  467. {
  468. *ppvObj = this;
  469. AddRef();
  470. return S_OK;
  471. }
  472. else
  473. {
  474. *ppvObj = NULL;
  475. return E_NOINTERFACE;
  476. }
  477. }
  478. /* ============================================================================
  479. CIncFileDocumentContext::AddRef
  480. CIncFileDocumentContext::Release
  481. NOTE: Don't know if these need to be protected with Interlocked(In|De)crement.
  482. */
  483. ULONG CIncFileDocumentContext::AddRef()
  484. {
  485. InterlockedIncrement(&m_cRefs);
  486. return m_cRefs;
  487. }
  488. ULONG CIncFileDocumentContext::Release()
  489. {
  490. if (InterlockedDecrement(&m_cRefs) == 0)
  491. {
  492. delete this;
  493. return 0;
  494. }
  495. return m_cRefs;
  496. }
  497. /* ============================================================================
  498. CIncFileDocumentContext::GetDocument
  499. Return the document.
  500. */
  501. HRESULT CIncFileDocumentContext::GetDocument
  502. (
  503. /* [out] */ IDebugDocument **ppDebugDocument
  504. )
  505. {
  506. #ifndef PERF_DISABLE
  507. g_PerfData.Incr_DEBUGDOCREQ();
  508. #endif
  509. return m_pIncFile->QueryInterface(IID_IDebugDocument, reinterpret_cast<void **>(ppDebugDocument));
  510. }
  511. /* ============================================================================
  512. CIncFileDocumentContext::EnumCodeContexts
  513. Convert document offset to script offset and enumerate code contexts
  514. */
  515. HRESULT CIncFileDocumentContext::EnumCodeContexts
  516. (
  517. /* [out] */ IEnumDebugCodeContexts **ppEnumerator
  518. )
  519. {
  520. if ((*ppEnumerator = new CIncFileEnumCodeContexts(this)) == NULL)
  521. return E_OUTOFMEMORY;
  522. return S_OK;
  523. }