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.

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