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.

4396 lines
112 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Script Manager
  6. File: ScrptMgr.cpp
  7. Owner: AndrewS
  8. This file contains the implementation of the Scrip Manager,
  9. ie: siting an ActiveX Scripting engine (in our case VBScript) for Denali.
  10. ===================================================================*/
  11. #include "denpre.h"
  12. #pragma hdrstop
  13. #include "dbgcxt.h"
  14. #include "SMHash.h"
  15. #include "perfdata.h"
  16. #include "debugger.h"
  17. #include "wraptlib.h"
  18. // ATQ Scheduler
  19. #include "issched.hxx"
  20. #include "MemChk.h"
  21. CScriptManager g_ScriptManager;
  22. IWrapTypeLibs *g_pWrapTypelibs = NULL;
  23. #define RESPONSE_END_ERRORCODE ERROR_OPERATION_ABORTED
  24. HRESULT GetProgLangIdOfName(LPCSTR szProgLangName, PROGLANG_ID *pProgLangId);
  25. //*****************************************************************************
  26. // The following macros are used to catch exceptions thrown from the external
  27. // scripting engines.
  28. //
  29. // Use of TRY/CATCH blocks around calls to the script engine is controlled by
  30. // the DBG compile #define. If DBG is 1, then the TRY/CATCH blocks are NOT
  31. // used so that checked builds break into the debugger and we can examine why
  32. // the error occurred. If DBG is 0, then the TRY/CATCH blocks are used and
  33. // exceptions are captured and logged to the browser (if possible) and the NT
  34. // Event log.
  35. //
  36. // The TRYCATCH macros are:
  37. //
  38. // TRYCATCH(_s, _IFStr)
  39. // _s - statement to execute inside of TRY/CATCH block.
  40. // _IFStr - string containing the name of interface invoked
  41. // TRYCATCH_HR(_s, _hr, _IFStr)
  42. // _s - statement to execute inside of TRY/CATCH block.
  43. // _hr - HRESULT to store return from _s
  44. // _IFStr - string containing the name of interface invoked
  45. // TRYCATCH_NOHITOBJ(_s, _IFStr)
  46. // Same as TRYCATCH() except there is no Hitobj in the "this" object
  47. // TRYCATCH_HR_NOHITOBJ(_s, _hr, _IFStr)
  48. // Same as TRYCATCH_HR() except there is no Hitobj in the "this" object
  49. //
  50. // NOTES:
  51. // The macros also expect that there is a local variable defined in the function
  52. // the macros is used of type char * named _pFuncName.
  53. //
  54. // A minimal test capability is included to allow for random errors to be throw.
  55. // The test code is compiled in based on the TEST_TRYCATCH #define.
  56. //
  57. //*****************************************************************************
  58. //*****************************************************************************
  59. // TEST_TRYCATCH definitions
  60. //*****************************************************************************
  61. #define TEST_TRYCATCH 0
  62. #if TEST_TRYCATCH
  63. #define THROW_INTERVAL 57
  64. int g_TryCatchCount = 0;
  65. #define TEST_THROW_ERROR g_TryCatchCount++; if ((g_TryCatchCount % THROW_INTERVAL) == 0) {THROW(0x80070000+g_TryCatchCount);}
  66. #else
  67. #define TEST_THROW_ERROR
  68. #endif
  69. //*****************************************************************************
  70. // The following is the heart of the TRYCATCH macros. The definitions here are
  71. // based on the definition of DBG. Again, note that when DBG is off that the
  72. // TRYCATCH defines are removed.
  73. //*****************************************************************************
  74. #if DBG == 0
  75. #define START_TRYCATCH do { TRY
  76. #define END_TRYCATCH(_hr, _hitobj, _IFStr) \
  77. CATCH(nException) \
  78. HandleErrorMissingFilename(IDE_SCRIPT_ENGINE_GPF, _hitobj,TRUE,nException,_IFStr,_pFuncName); \
  79. _hr = nException; \
  80. END_TRY } while(0)
  81. #else
  82. #define START_TRYCATCH do {
  83. #define END_TRYCATCH(_hr, _hitobj, _IFStr) } while (0)
  84. #endif
  85. //*****************************************************************************
  86. // Definition of TRYCATCH_INT which is used by all of the TRYCATCH macros
  87. // described above.
  88. //*****************************************************************************
  89. #define TRYCATCH_INT(_s, _hr, _hitobj, _IFStr) \
  90. START_TRYCATCH \
  91. TEST_THROW_ERROR \
  92. _hr = _s; \
  93. END_TRYCATCH(_hr, _hitobj, _IFStr)
  94. //*****************************************************************************
  95. // Here are the actual definitions of the TRYCATCH macros described above.
  96. //*****************************************************************************
  97. #define TRYCATCH(_s, _IFStr) \
  98. do { \
  99. HRESULT _tempHR; \
  100. TRYCATCH_INT(_s, _tempHR, m_pHitObj, _IFStr); \
  101. } while (0)
  102. #define TRYCATCH_HR(_s, _hr, _IFStr) TRYCATCH_INT(_s, _hr, m_pHitObj, _IFStr)
  103. #define TRYCATCH_NOHITOBJ(_s, _IFStr) \
  104. do { \
  105. HRESULT _tempHR; \
  106. TRYCATCH_INT(_s, _tempHR, NULL, _IFStr); \
  107. } while (0)
  108. #define TRYCATCH_HR_NOHITOBJ(_s, _hr, _IFStr) TRYCATCH_INT(_s, _hr, NULL, _IFStr)
  109. /*===================================================================
  110. CActiveScriptEngine::CActiveScriptEngine
  111. Constructor for CActiveScriptEngine object
  112. Returns:
  113. Nothing
  114. Side effects:
  115. None.
  116. ===================================================================*/
  117. CActiveScriptEngine::CActiveScriptEngine()
  118. : m_cRef(1), m_fInited(FALSE), m_fZombie(FALSE), m_fScriptLoaded(FALSE),
  119. m_fObjectsLoaded(FALSE), m_fTemplateNameAllocated(FALSE),
  120. m_pAS(NULL), m_pASP(NULL), m_pDisp(NULL), m_pHIUpdate(NULL), m_lcid(LOCALE_SYSTEM_DEFAULT),
  121. m_pHitObj(NULL), m_szTemplateName(NULL), m_fScriptAborted(FALSE), m_fScriptTimedOut(FALSE),
  122. m_fScriptHadError(FALSE), m_fCorrupted(FALSE), m_fBeingDebugged(FALSE), m_pTemplate(NULL),
  123. m_dwInstanceID(0xBADF00D), m_dwSourceContext(0xBADF00D)
  124. {
  125. }
  126. /*===================================================================
  127. CActiveScriptEngine::~CActiveScriptEngine
  128. Destructor for CActiveScriptEngine object
  129. Returns:
  130. Nothing
  131. Side effects:
  132. None.
  133. ===================================================================*/
  134. CActiveScriptEngine::~CActiveScriptEngine()
  135. {
  136. if (m_fTemplateNameAllocated)
  137. delete[] m_szTemplateName;
  138. if (m_pTemplate)
  139. m_pTemplate->Release();
  140. }
  141. /*===================================================================
  142. CActiveScriptEngine::FinalRelease
  143. Call this when we are done with the object - Like release but
  144. it removes all of the interfaces we got, so that the ref.
  145. count can vanish when last external user is done with the engine
  146. Returns:
  147. Nothing
  148. Side effects:
  149. None.
  150. ===================================================================*/
  151. ULONG CActiveScriptEngine::FinalRelease()
  152. {
  153. static const char *_pFuncName = "CActiveScriptEngine::FinalRelease()";
  154. if (m_pDisp)
  155. {
  156. TRYCATCH(m_pDisp->Release(),"IScriptDispatch::Release()");
  157. m_pDisp = NULL;
  158. }
  159. if (m_pASP)
  160. {
  161. TRYCATCH(m_pASP->Release(),"IActiveScriptParse::Release()");
  162. m_pASP = NULL;
  163. }
  164. if (m_pHIUpdate)
  165. {
  166. TRYCATCH(m_pHIUpdate->Release(),"IHostInfoUpdate::Release()");
  167. m_pHIUpdate = NULL;
  168. }
  169. if (m_pAS)
  170. {
  171. HRESULT hr;
  172. // First "close" the engine
  173. TRYCATCH_HR(m_pAS->Close(), hr, "IActiveScript::Close()");
  174. Assert(SUCCEEDED(hr));
  175. // Then we can release it
  176. TRYCATCH(m_pAS->Release(), "IActiveScript::Release()");
  177. m_pAS = NULL;
  178. }
  179. ULONG cRefs = Release();
  180. Assert (cRefs == 0);
  181. return cRefs;
  182. }
  183. /*===================================================================
  184. CActiveScriptEngine::Init
  185. Init the script site object. This must only be called once.
  186. Returns:
  187. HRESULT. S_OK on success.
  188. Side effects:
  189. None.
  190. ===================================================================*/
  191. HRESULT CActiveScriptEngine::Init
  192. (
  193. PROGLANG_ID proglang_id,
  194. LPCTSTR szTemplateName,
  195. LCID lcid,
  196. CHitObj *pHitObj,
  197. CTemplate *pTemplate,
  198. DWORD dwSourceContext
  199. )
  200. {
  201. static const char *_pFuncName = "CActiveScriptEngine::Init()";
  202. HRESULT hr;
  203. UINT cTrys = 0;
  204. if (m_fInited)
  205. {
  206. Assert(FALSE);
  207. return(ERROR_ALREADY_INITIALIZED);
  208. }
  209. // Note: need to init these first, because we will need them if AS calls back into us during init.
  210. m_lcid = lcid;
  211. m_proglang_id = proglang_id;
  212. m_pHitObj = pHitObj;
  213. m_dwSourceContext = dwSourceContext;
  214. m_dwInstanceID = pHitObj->DWInstanceID();
  215. m_pTemplate = pTemplate;
  216. m_pTemplate->AddRef();
  217. lRetry:
  218. // Create an instance of the script engine for the given language
  219. hr = CoCreateInstance(proglang_id, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void**)&m_pAS);
  220. if (FAILED(hr))
  221. {
  222. /*
  223. * If some control (or other component) does a CoUninitialize on our thread, we will
  224. * never be able to create another object. In this case, we will get back CO_E_NOTINITIALIZED.
  225. * Try (once) to re-initialize and then create the object
  226. */
  227. if (hr == CO_E_NOTINITIALIZED && cTrys++ == 0)
  228. {
  229. MSG_Error(IDS_COUNINITIALIZE);
  230. hr = CoInitialize(NULL);
  231. if (SUCCEEDED(hr))
  232. goto lRetry;
  233. }
  234. goto LFail;
  235. }
  236. // Remember template name
  237. hr = StoreTemplateName(szTemplateName);
  238. if (FAILED(hr))
  239. goto LFail;
  240. // Tell ActiveScripting that this is our script site
  241. TRYCATCH_HR(m_pAS->SetScriptSite((IActiveScriptSite *)this), hr, "IActiveScript::SetScriptSite()");
  242. if (FAILED(hr))
  243. {
  244. goto LFail;
  245. }
  246. // Tell ActiveScripting which exceptions we want caught
  247. IActiveScriptProperty *pScriptProperty;
  248. TRYCATCH_HR(m_pAS->QueryInterface(IID_IActiveScriptProperty, reinterpret_cast<void **>(&pScriptProperty)), hr, "IActiveScript::QueryInterface()");
  249. if (SUCCEEDED(hr))
  250. {
  251. static const int rgnExceptionsToCatch[] =
  252. {
  253. STATUS_GUARD_PAGE_VIOLATION ,
  254. STATUS_DATATYPE_MISALIGNMENT ,
  255. STATUS_ACCESS_VIOLATION ,
  256. STATUS_INVALID_HANDLE ,
  257. STATUS_NO_MEMORY ,
  258. STATUS_ILLEGAL_INSTRUCTION ,
  259. STATUS_INVALID_DISPOSITION , // what's this? Do we need to catch it?
  260. STATUS_ARRAY_BOUNDS_EXCEEDED ,
  261. STATUS_FLOAT_DENORMAL_OPERAND ,
  262. STATUS_FLOAT_DIVIDE_BY_ZERO ,
  263. STATUS_FLOAT_INVALID_OPERATION ,
  264. STATUS_FLOAT_OVERFLOW ,
  265. STATUS_FLOAT_STACK_CHECK ,
  266. STATUS_INTEGER_DIVIDE_BY_ZERO ,
  267. STATUS_INTEGER_OVERFLOW ,
  268. STATUS_PRIVILEGED_INSTRUCTION ,
  269. STATUS_STACK_OVERFLOW
  270. };
  271. VARIANT varBoolTrue;
  272. VARIANT varExceptionType;
  273. V_VT(&varExceptionType) = VT_I4;
  274. V_VT(&varBoolTrue) = VT_BOOL;
  275. V_BOOL(&varBoolTrue) = -1;
  276. for (int i = 0; i < (sizeof rgnExceptionsToCatch) / sizeof(int); ++i)
  277. {
  278. V_I4(&varExceptionType) = rgnExceptionsToCatch[i];
  279. TRYCATCH(pScriptProperty->SetProperty(SCRIPTPROP_CATCHEXCEPTION, &varExceptionType, &varBoolTrue), "IActiveScriptProperty::SetProperty");
  280. }
  281. pScriptProperty->Release();
  282. }
  283. // Get ActiveScriptParse interface
  284. hr = GetASP();
  285. if (FAILED(hr))
  286. goto LFail;
  287. // Tell the script parser to init itself
  288. TRYCATCH_HR(m_pASP->InitNew(), hr, "IActiveScriptParse::InitNew()");
  289. if (FAILED(hr))
  290. goto LFail;
  291. // Get IDisp interface
  292. hr = GetIDisp();
  293. if (FAILED(hr))
  294. goto LFail;
  295. // Get IHostInfoUpdate interface
  296. hr = GetIHostInfoUpdate();
  297. if (FAILED(hr))
  298. goto LFail;
  299. m_fInited = TRUE;
  300. LFail:
  301. if (FAILED(hr))
  302. {
  303. if (m_pAS)
  304. {
  305. TRYCATCH(m_pAS->Release(),"IActiveScript::Release()");
  306. m_pAS = NULL;
  307. }
  308. if (m_pASP)
  309. {
  310. TRYCATCH(m_pASP->Release(),"IActiveScriptParse::Release()");
  311. m_pASP = NULL;
  312. }
  313. if (m_pDisp)
  314. {
  315. TRYCATCH(m_pDisp->Release(),"IScriptDispatch::Release()");
  316. m_pDisp = NULL;
  317. }
  318. if (m_pTemplate)
  319. {
  320. m_pTemplate->Release();
  321. m_pTemplate = NULL;
  322. }
  323. if (m_pHIUpdate)
  324. {
  325. TRYCATCH(m_pHIUpdate->Release(),"IHostInfoUpdate::Release()");
  326. m_pHIUpdate = NULL;
  327. }
  328. }
  329. return(hr);
  330. }
  331. /*===================================================================
  332. CActiveScriptEngine::StoreTemplateName
  333. Stores template name inside CActiveScriptEngine. Allocates
  334. buffer or uses internal one if the name fits.
  335. Returns:
  336. HRESULT. S_OK on success.
  337. Side effects:
  338. Might allocate memory for long template names
  339. ===================================================================*/
  340. HRESULT CActiveScriptEngine::StoreTemplateName
  341. (
  342. LPCTSTR szTemplateName
  343. )
  344. {
  345. DWORD cch = _tcslen(szTemplateName);
  346. if (((cch+1)*sizeof(TCHAR)) <= sizeof(m_szTemplateNameBuf))
  347. {
  348. m_szTemplateName = m_szTemplateNameBuf;
  349. m_fTemplateNameAllocated = FALSE;
  350. }
  351. else
  352. {
  353. m_szTemplateName = new TCHAR[cch+1];
  354. if (!m_szTemplateName)
  355. return E_OUTOFMEMORY;
  356. m_fTemplateNameAllocated = TRUE;
  357. }
  358. _tcscpy(m_szTemplateName, szTemplateName);
  359. return S_OK;
  360. }
  361. /*===================================================================
  362. CActiveScriptEngine::GetASP
  363. Get an ActiveScriptParser interface from ActiveScripting
  364. Returns:
  365. HRESULT. S_OK on success.
  366. Side effects:
  367. Fills in member variables
  368. ===================================================================*/
  369. HRESULT CActiveScriptEngine::GetASP
  370. (
  371. )
  372. {
  373. static const char *_pFuncName = "CActiveScriptEngine::GetASP()";
  374. HRESULT hr;
  375. Assert(m_pASP == NULL);
  376. m_pASP = NULL;
  377. // Get OLE Scripting parser interface, if any
  378. TRYCATCH_HR(m_pAS->QueryInterface(IID_IActiveScriptParse, (void **)&m_pASP), hr, "IActiveScript::QueryInterface()");
  379. if (m_pASP == NULL && SUCCEEDED(hr))
  380. hr = E_FAIL;
  381. if (FAILED(hr))
  382. {
  383. goto LFail;
  384. }
  385. LFail:
  386. if (FAILED(hr))
  387. {
  388. if (m_pASP)
  389. {
  390. TRYCATCH(m_pASP->Release(),"IActiveScriptParse::Release()");
  391. m_pASP = NULL;
  392. }
  393. }
  394. return(hr);
  395. }
  396. /*===================================================================
  397. CActiveScriptEngine::GetIDisp
  398. Get an IDispatch interface from ActiveScripting
  399. Returns:
  400. HRESULT. S_OK on success.
  401. Side effects:
  402. Fills in member variables
  403. ===================================================================*/
  404. HRESULT CActiveScriptEngine::GetIDisp
  405. (
  406. )
  407. {
  408. static const char *_pFuncName = "CActiveScriptEngine::GetIDisp()";
  409. HRESULT hr;
  410. Assert(m_pDisp == NULL);
  411. m_pDisp = NULL;
  412. // Get an IDispatch interface to be able to call functions in the script
  413. TRYCATCH_HR(m_pAS->GetScriptDispatch(NULL, &m_pDisp),hr,"IActiveScript::GetScriptDispatch()");
  414. if (m_pDisp == NULL && SUCCEEDED(hr))
  415. hr = E_FAIL;
  416. if (FAILED(hr))
  417. {
  418. goto LFail;
  419. }
  420. LFail:
  421. if (FAILED(hr))
  422. {
  423. if (m_pDisp)
  424. {
  425. TRYCATCH(m_pDisp->Release(),"IScriptDispatch::Release()");
  426. m_pDisp = NULL;
  427. }
  428. }
  429. return(hr);
  430. }
  431. /*===================================================================
  432. CActiveScriptEngine::GetIHostInfoUpdate
  433. Get an IHostInfoUpdate interface from ActiveScripting.
  434. This interface is used to advise the scripting engine that
  435. we have new information about the host (change in LCID for example)
  436. If we can't find the interface, we exit succesfully anyway.
  437. Returns:
  438. HRESULT. S_OK on success.
  439. Side effects:
  440. Fills in member variables
  441. ===================================================================*/
  442. HRESULT CActiveScriptEngine::GetIHostInfoUpdate
  443. (
  444. )
  445. {
  446. static const char *_pFuncName = "CActiveScriptEngine::GetIHostInfoUpdate()";
  447. HRESULT hr = S_OK;
  448. Assert(m_pHIUpdate == NULL);
  449. m_pHIUpdate = NULL;
  450. // Get an IHostInfoUpdate interface to be able to call functions in the script
  451. TRYCATCH_HR(m_pAS->QueryInterface(IID_IHostInfoUpdate, (void **) &m_pHIUpdate),
  452. hr,
  453. "IActiveScript::QueryInterface()");
  454. Assert(SUCCEEDED(hr) || hr == E_NOINTERFACE);
  455. return(S_OK);
  456. }
  457. /*===================================================================
  458. CActiveScriptEngine::ResetToUninitialized
  459. When we want to reuse and engine, we reset it to an uninited state
  460. before putting it on the FSQ
  461. Returns:
  462. HRESULT. S_OK on success.
  463. Side effects:
  464. None.
  465. ===================================================================*/
  466. HRESULT CActiveScriptEngine::ResetToUninitialized()
  467. {
  468. static const char *_pFuncName = "CActiveScriptEngine::ResetToUninitialized()";
  469. HRESULT hr = S_OK;
  470. // Reset our flags
  471. m_fScriptAborted = FALSE;
  472. m_fScriptTimedOut = FALSE;
  473. m_fScriptHadError = FALSE;
  474. m_fBeingDebugged = FALSE;
  475. // Release interfaces, they will need to be re-gotten when
  476. // the engine is reused
  477. if (m_pASP) {
  478. TRYCATCH(m_pASP->Release(),"IActiveScriptParse::Release()");
  479. m_pASP = NULL;
  480. }
  481. if (m_pDisp) {
  482. TRYCATCH(m_pDisp->Release(),"IScriptDispatch::Release()");
  483. m_pDisp = NULL;
  484. }
  485. if(m_pHIUpdate) {
  486. TRYCATCH(m_pHIUpdate->Release(),"IHostInfoUpdate::Release()");
  487. m_pHIUpdate = NULL;
  488. }
  489. // Hitobj will no longer be valid
  490. m_pHitObj = NULL;
  491. // Set the script state to Uninited
  492. if (m_pAS) {
  493. TRYCATCH_HR(ResetScript(), hr, "IActiveScript::SetScriptState()");
  494. }
  495. return(hr);
  496. }
  497. /*===================================================================
  498. CActiveScriptEngine::ReuseEngine
  499. Reusing an engine from the FSQ. Reset stuff
  500. Returns:
  501. HRESULT. S_OK on success.
  502. Side effects:
  503. Sets member variables.
  504. ===================================================================*/
  505. HRESULT CActiveScriptEngine::ReuseEngine
  506. (
  507. CHitObj *pHitObj,
  508. CTemplate *pTemplate,
  509. DWORD dwSourceContext,
  510. DWORD dwInstanceID
  511. )
  512. {
  513. static const char *_pFuncName = "CActiveScriptEngine::ReuseEngine()";
  514. HRESULT hr = S_OK;
  515. /* NOTE: we must reset the hitobj & other members BEFORE calling
  516. * any Active Scripting methods (esp. SetScriptSite) This is
  517. * because SetScriptSite queries us for the debug application, which
  518. * relies on the hitobj being set.
  519. */
  520. // reset the hitobj
  521. m_pHitObj = pHitObj;
  522. // Reset the debug document
  523. if (pTemplate)
  524. {
  525. if (m_pTemplate)
  526. m_pTemplate->Release();
  527. m_dwSourceContext = dwSourceContext;
  528. m_dwInstanceID = dwInstanceID;
  529. m_pTemplate = pTemplate;
  530. m_pTemplate->AddRef();
  531. }
  532. // If the engine is in the UNITIALIZED state ONLY then tell ActiveScripting
  533. // that this is our script site. (Scripts in the debug cache are already initialized)
  534. SCRIPTSTATE nScriptState;
  535. TRYCATCH_HR(m_pAS->GetScriptState(&nScriptState), hr, "IActiveScript::GetScriptState()");
  536. if (FAILED(hr))
  537. goto LFail;
  538. if (nScriptState == SCRIPTSTATE_UNINITIALIZED)
  539. {
  540. TRYCATCH_HR(m_pAS->SetScriptSite(static_cast<IActiveScriptSite *>(this)),hr, "IActiveScript::SetScriptState()");
  541. if (FAILED(hr))
  542. goto LFail;
  543. }
  544. // Get ActiveScriptParse interface
  545. hr = GetASP();
  546. if (FAILED(hr))
  547. goto LFail;
  548. // Get IDisp interface
  549. hr = GetIDisp();
  550. if (FAILED(hr))
  551. goto LFail;
  552. // Get IHostInfoUpdate interface
  553. hr = GetIHostInfoUpdate();
  554. if (FAILED(hr))
  555. goto LFail;
  556. AssertValid();
  557. LFail:
  558. return(hr);
  559. }
  560. /*===================================================================
  561. CActiveScriptEngine::MakeClone
  562. We are cloning a running script engine. Fill this new ActiveScriptEngine
  563. with the cloned ActiveScript.
  564. Returns:
  565. HRESULT. S_OK on success.
  566. Side effects:
  567. None.
  568. ===================================================================*/
  569. HRESULT CActiveScriptEngine::MakeClone
  570. (
  571. PROGLANG_ID proglang_id,
  572. LPCTSTR szTemplateName,
  573. LCID lcid,
  574. CHitObj *pHitObj,
  575. CTemplate *pTemplate,
  576. DWORD dwSourceContext,
  577. DWORD dwInstanceID,
  578. IActiveScript *pAS // The cloned script engine
  579. )
  580. {
  581. static const char *_pFuncName = "CActiveScriptEngine::MakeClone()";
  582. HRESULT hr;
  583. if (m_fInited)
  584. {
  585. Assert(FALSE);
  586. return(ERROR_ALREADY_INITIALIZED);
  587. }
  588. // Note: need to init these first, because we will need them if AS calls back into us during init.
  589. m_lcid = lcid;
  590. m_proglang_id = proglang_id;
  591. m_pHitObj = pHitObj;
  592. m_pAS = pAS;
  593. StoreTemplateName(szTemplateName);
  594. if (m_pTemplate)
  595. m_pTemplate->Release();
  596. m_dwSourceContext = dwSourceContext;
  597. m_dwInstanceID = dwInstanceID;
  598. m_pTemplate = pTemplate;
  599. m_pTemplate->AddRef();
  600. // We are not yet inited fully but SetScriptSite may call back into us so we must flag inited now.
  601. m_fInited = TRUE;
  602. // Tell ActiveScripting that this is our script site
  603. TRYCATCH_HR(m_pAS->SetScriptSite((IActiveScriptSite *)this), hr, "IActiveScript::SetScriptSite()");
  604. if (FAILED(hr))
  605. {
  606. goto LFail;
  607. }
  608. // Get ActiveScriptParse interface
  609. hr = GetASP();
  610. if (FAILED(hr))
  611. goto LFail;
  612. // Get IDisp interface
  613. hr = GetIDisp();
  614. if (FAILED(hr))
  615. goto LFail;
  616. // Get IHostInfoUpdate interface
  617. hr = GetIHostInfoUpdate();
  618. if (FAILED(hr))
  619. goto LFail;
  620. // Because we are a clone of an already loaded engine, we have script and objects loaded.
  621. m_fScriptLoaded = TRUE;
  622. m_fObjectsLoaded = TRUE;
  623. // We should be valid now.
  624. AssertValid();
  625. LFail:
  626. if (FAILED(hr))
  627. {
  628. m_fInited = FALSE;
  629. if (m_pAS)
  630. {
  631. // dont release the passed in script engine on failure
  632. m_pAS = NULL;
  633. }
  634. if (m_pASP)
  635. {
  636. TRYCATCH(m_pASP->Release(),"IActiveScriptParse::Release()");
  637. m_pASP = NULL;
  638. }
  639. if (m_pDisp)
  640. {
  641. TRYCATCH(m_pDisp->Release(),"IScriptDispatch::Release()");
  642. m_pDisp = NULL;
  643. }
  644. if (m_pTemplate)
  645. {
  646. m_pTemplate->Release();
  647. m_pTemplate = NULL;
  648. }
  649. if (m_pHIUpdate)
  650. {
  651. TRYCATCH(m_pHIUpdate->Release(),"IHostInfoUpdate::Release()");
  652. m_pHIUpdate = NULL;
  653. }
  654. }
  655. return(hr);
  656. }
  657. /*===================================================================
  658. CActiveScriptEngine::InterruptScript
  659. Stop the script from running
  660. Returns:
  661. HRESULT. S_OK on success.
  662. Side effects:
  663. Stops the script from running
  664. ===================================================================*/
  665. HRESULT CActiveScriptEngine::InterruptScript
  666. (
  667. BOOL fAbnormal // = TRUE
  668. )
  669. {
  670. static const char *_pFuncName = "CActiveScriptEngine::InterruptScript()";
  671. HRESULT hr;
  672. EXCEPINFO excepinfo;
  673. AssertValid();
  674. // Fill in the excepinfo. This will be passed to OnScriptError
  675. memset(&excepinfo, 0x0, sizeof(EXCEPINFO));
  676. if (fAbnormal)
  677. {
  678. m_fScriptTimedOut = TRUE;
  679. excepinfo.wCode = ERROR_SERVICE_REQUEST_TIMEOUT;
  680. m_pHitObj->SetRequestTimedout();
  681. }
  682. else
  683. {
  684. m_fScriptAborted = TRUE;
  685. excepinfo.wCode = RESPONSE_END_ERRORCODE; // Error code to ourselves - means Response.End was invoked
  686. }
  687. TRYCATCH_HR(m_pAS->InterruptScriptThread(SCRIPTTHREADID_BASE, // The thread in which the engine was instantiated
  688. &excepinfo,
  689. 0),
  690. hr,
  691. "IActiveScript::InterruptScriptThread()");
  692. return(hr);
  693. }
  694. /*===================================================================
  695. CActiveScriptEngine::UpdateLocaleInfo
  696. Advise the script engine that we want to update the lcid or
  697. code page
  698. Returns:
  699. HRESULT. S_OK on success.
  700. ===================================================================*/
  701. HRESULT CActiveScriptEngine::UpdateLocaleInfo
  702. (
  703. hostinfo hiNew
  704. )
  705. {
  706. static const char *_pFuncName = "CActiveScriptEngine::UpdateLocaleInfo()";
  707. HRESULT hr = S_OK;
  708. // If no IUpdateHost ineterface is available
  709. // just skip the call to UpdateInfo;
  710. if (m_pHIUpdate)
  711. TRYCATCH_HR(m_pHIUpdate->UpdateInfo(hiNew), hr, "IHostInfoUpdate::UpdateInfo()");
  712. return hr;
  713. }
  714. #ifdef DBG
  715. /*===================================================================
  716. CActiveScriptEngine::AssertValid
  717. Test to make sure that the CActiveScriptEngine object is currently correctly formed
  718. and assert if it is not.
  719. Returns:
  720. Side effects:
  721. None.
  722. ===================================================================*/
  723. VOID CActiveScriptEngine::AssertValid() const
  724. {
  725. Assert(m_fInited);
  726. Assert(m_pAS != NULL);
  727. Assert(m_pTemplate != NULL);
  728. }
  729. #endif // DBG
  730. /*
  731. *
  732. *
  733. *
  734. * I U n k n o w n M e t h o d s
  735. *
  736. *
  737. *
  738. *
  739. */
  740. /*===================================================================
  741. CActiveScriptEngine::QueryInterface
  742. CActiveScriptEngine::AddRef
  743. CActiveScriptEngine::Release
  744. IUnknown members for CActiveScriptEngine object.
  745. ===================================================================*/
  746. STDMETHODIMP CActiveScriptEngine::QueryInterface
  747. (
  748. REFIID riid,
  749. PVOID *ppvObj
  750. )
  751. {
  752. if (ppvObj == NULL)
  753. {
  754. Assert(FALSE);
  755. return E_POINTER;
  756. }
  757. *ppvObj = NULL;
  758. if (IsEqualIID(riid, IID_IUnknown))
  759. {
  760. // this IS NOT derived directly from IUnknown
  761. // typecast this to something that IS
  762. *ppvObj = static_cast<IActiveScriptSite *>(this);
  763. }
  764. else if (IsEqualIID(riid, IID_IActiveScriptSite))
  765. {
  766. *ppvObj = static_cast<IActiveScriptSite *>(this);
  767. }
  768. else if (IsEqualIID(riid, IID_IActiveScriptSiteDebug))
  769. {
  770. *ppvObj = static_cast<IActiveScriptSiteDebug *>(this);
  771. }
  772. else if (IsEqualIID(riid, IID_IHostInfoProvider))
  773. {
  774. *ppvObj = static_cast<IHostInfoProvider *>(this);
  775. }
  776. if (*ppvObj != NULL)
  777. {
  778. AddRef();
  779. return(S_OK);
  780. }
  781. return(E_NOINTERFACE);
  782. }
  783. STDMETHODIMP_(ULONG) CActiveScriptEngine::AddRef()
  784. {
  785. ++m_cRef;
  786. return(m_cRef);
  787. }
  788. STDMETHODIMP_(ULONG) CActiveScriptEngine::Release()
  789. {
  790. if (--m_cRef)
  791. return(m_cRef);
  792. delete this;
  793. return(0);
  794. }
  795. /*
  796. *
  797. *
  798. *
  799. * I A c t i v e S c r i p t S i t e M e t h o d s
  800. *
  801. *
  802. *
  803. *
  804. */
  805. /*===================================================================
  806. CActiveScriptEngine::GetLCID
  807. Provide the local id for the script to the script engine.
  808. Returns:
  809. HRESULT. Always returns S_OK.
  810. Side effects:
  811. None.
  812. ===================================================================*/
  813. STDMETHODIMP CActiveScriptEngine::GetLCID
  814. (
  815. LCID *plcid
  816. )
  817. {
  818. // It is OK to call this before we are fully inited.
  819. //AssertValid();
  820. *plcid = ((CActiveScriptEngine *)this)->m_lcid;
  821. return(S_OK);
  822. }
  823. /*===================================================================
  824. CActiveScriptEngine::GetItemInfo
  825. Provide requested info for a named item to the script engine. May be
  826. asked for IUnknown, ITypeInfo or both.
  827. Returns:
  828. HRESULT. S_OK on success.
  829. Side effects:
  830. None.
  831. ===================================================================*/
  832. STDMETHODIMP CActiveScriptEngine::GetItemInfo
  833. (
  834. LPCOLESTR pcszName,
  835. DWORD dwReturnMask,IUnknown **ppiunkItem,
  836. ITypeInfo **ppti
  837. )
  838. {
  839. HRESULT hr;
  840. AssertValid();
  841. // Assume none
  842. if (ppti)
  843. *ppti = NULL;
  844. if (ppiunkItem)
  845. *ppiunkItem = NULL;
  846. CHitObj *pHitObj = m_pHitObj;
  847. if (pHitObj == NULL)
  848. {
  849. // could happen when debugging and re-initializing
  850. // the scripting engine when storing it in the template
  851. // in this case GetItemInfo() is called for TYPELIB stuff
  852. ViperGetHitObjFromContext(&pHitObj);
  853. if (pHitObj == NULL)
  854. return TYPE_E_ELEMENTNOTFOUND;
  855. }
  856. // Calculate name length once
  857. DWORD cbName = CbWStr((LPWSTR)pcszName);
  858. // Special case for intrinsics
  859. IUnknown *punkIntrinsic = NULL;
  860. hr = pHitObj->GetIntrinsic((LPWSTR)pcszName, cbName, &punkIntrinsic);
  861. if (hr == S_OK)
  862. {
  863. if (dwReturnMask & SCRIPTINFO_IUNKNOWN)
  864. {
  865. Assert(ppiunkItem);
  866. Assert(punkIntrinsic);
  867. punkIntrinsic->AddRef();
  868. *ppiunkItem = punkIntrinsic;
  869. }
  870. return S_OK;
  871. }
  872. else if (hr == S_FALSE)
  873. {
  874. // Missing intrinsic case
  875. return TYPE_E_ELEMENTNOTFOUND;
  876. }
  877. // It's not an intrinsic -- try component collection
  878. CComponentObject *pObj = NULL;
  879. hr = pHitObj->GetComponent(csUnknown, (LPWSTR)pcszName, cbName, &pObj);
  880. if (hr == S_OK) // object found
  881. {
  882. if (dwReturnMask & SCRIPTINFO_IUNKNOWN)
  883. {
  884. Assert(ppiunkItem != NULL);
  885. hr = pObj->GetAddRefdIUnknown(ppiunkItem);
  886. }
  887. if (SUCCEEDED(hr))
  888. return S_OK;
  889. }
  890. // Could'n find -- output an error
  891. HandleItemNotFound(pcszName);
  892. return hr;
  893. }
  894. /*===================================================================
  895. CActiveScriptEngine::HandleItemNotFound
  896. Error handling due to item not found in GetItemInfo().
  897. Parameters:
  898. pcszName name of the item not found
  899. Returns:
  900. ===================================================================*/
  901. void CActiveScriptEngine::HandleItemNotFound
  902. (
  903. LPCOLESTR pcszName
  904. )
  905. {
  906. HRESULT hr = TYPE_E_ELEMENTNOTFOUND;
  907. CHAR *szErrT = NULL;
  908. CHAR szEngineT[255];
  909. CHAR szErr[255];
  910. TCHAR *szFileNameT = NULL;
  911. CHAR *szFileName = NULL;
  912. CHAR *szLineNum = NULL;
  913. CHAR *szEngine = NULL;
  914. CHAR *szErrCode = NULL;
  915. CHAR *szLongDes = NULL;
  916. ULONG ulLineError = 0;
  917. DWORD dwMask = 0x3;
  918. BOOLB fGuessedLine = FALSE;
  919. UINT ErrId = IDE_OOM;
  920. CWCharToMBCS convName;
  921. m_pTemplate->GetScriptSourceInfo(m_dwSourceContext, ulLineError, &szFileNameT, NULL, &ulLineError, NULL, &fGuessedLine);
  922. //Make a copy for error handling
  923. #if UNICODE
  924. szFileName = StringDupUTF8(szFileNameT);
  925. #else
  926. szFileName = StringDupA(szFileNameT);
  927. #endif
  928. if (!szFileName)
  929. {
  930. hr = E_OUTOFMEMORY;
  931. goto lCleanUp;
  932. }
  933. //get line num
  934. if (ulLineError)
  935. {
  936. szLineNum = (CHAR *)malloc(sizeof(CHAR)*10);
  937. if (szLineNum)
  938. _ltoa(ulLineError, szLineNum, 10);
  939. else
  940. {
  941. hr = E_OUTOFMEMORY;
  942. goto lCleanUp;
  943. }
  944. }
  945. //get engine
  946. CchLoadStringOfId(IDS_ENGINE, szEngineT, 255);
  947. szEngine = StringDupA(szEngineT);
  948. if (!szEngine)
  949. {
  950. hr = E_OUTOFMEMORY;
  951. goto lCleanUp;
  952. }
  953. //get informative string
  954. if (FAILED(hr = convName.Init((LPWSTR)pcszName))) {
  955. goto lCleanUp;
  956. }
  957. // Error string is: "Failed to create object 'objname'. Error code (code)."
  958. ErrId = IDE_SCRIPT_CANT_LOAD_OBJ;
  959. LoadErrResString(ErrId, &dwMask, NULL, NULL, szErr);
  960. if (szErr)
  961. {
  962. INT cch = strlen(szErr);
  963. szErrT = (CHAR *)malloc((CHAR)(cch + strlen(convName.GetString()) + 1));
  964. if (!szErrT)
  965. {
  966. hr = E_OUTOFMEMORY;
  967. goto lCleanUp;
  968. }
  969. sprintf(szErrT, szErr, convName.GetString());
  970. szErrCode = SzScodeToErrorCode(hr);
  971. }
  972. lCleanUp:
  973. //szErrT is the long description
  974. HandleError(ErrId, szFileName, szLineNum, szEngine, szErrCode, szErrT, NULL, m_pHitObj);
  975. }
  976. /*===================================================================
  977. CActiveScriptEngine::GetDocVersionString
  978. Return a string uniquely identifying the current document version
  979. from Denali's point of view.
  980. I dont think we need this. It is mostly interesting if
  981. the scripting engine is persisting scripts so that it can decide
  982. if a script needs a recompile. Since the scripting engine is
  983. not persisting anything for us, we dont need to do anything here.
  984. Returns:
  985. HRESULT. Always returns E_NOTIMPL.
  986. Side effects:
  987. None.
  988. ===================================================================*/
  989. STDMETHODIMP CActiveScriptEngine::GetDocVersionString
  990. (
  991. BSTR *pbstrVersion
  992. )
  993. {
  994. return(E_NOTIMPL);
  995. }
  996. /*===================================================================
  997. CActiveScriptEngine::RequestItems
  998. If this is called, it means that the Script engine wants us to call
  999. IActiveScript::AddNameItem() for each named item associated with the
  1000. script.
  1001. Returns:
  1002. HRESULT. Always returns S_OK.
  1003. Side effects:
  1004. None.
  1005. ===================================================================*/
  1006. STDMETHODIMP CActiveScriptEngine::RequestItems
  1007. (
  1008. BOOL fPersistNames // = TRUE
  1009. )
  1010. {
  1011. static const char *_pFuncName = "CActiveScriptEngine::RequestItems()";
  1012. HRESULT hr = S_OK;
  1013. AssertValid();
  1014. Assert (m_pHitObj != NULL);
  1015. DWORD grf = SCRIPTITEM_ISVISIBLE;
  1016. if (fPersistNames)
  1017. grf |= SCRIPTITEM_ISPERSISTENT;
  1018. /*
  1019. * Intrinsics
  1020. */
  1021. START_TRYCATCH
  1022. if (m_pHitObj->FIsBrowserRequest())
  1023. {
  1024. hr = m_pAS->AddNamedItem(WSZ_OBJ_RESPONSE, grf);
  1025. Assert(SUCCEEDED(hr));
  1026. hr = m_pAS->AddNamedItem(WSZ_OBJ_REQUEST, grf);
  1027. Assert(SUCCEEDED(hr));
  1028. }
  1029. hr = m_pAS->AddNamedItem(WSZ_OBJ_SERVER, grf);
  1030. Assert(SUCCEEDED(hr));
  1031. if (m_pHitObj->FHasSession())
  1032. {
  1033. hr = m_pAS->AddNamedItem(WSZ_OBJ_SESSION, grf);
  1034. Assert(SUCCEEDED(hr));
  1035. }
  1036. hr = m_pAS->AddNamedItem(WSZ_OBJ_APPLICATION, grf);
  1037. Assert(SUCCEEDED(hr));
  1038. hr = m_pAS->AddNamedItem(WSZ_OBJ_OBJECTCONTEXT, grf);
  1039. Assert(SUCCEEDED(hr));
  1040. /*
  1041. * Components from different collections
  1042. */
  1043. CComponentIterator CompIter(m_pHitObj);
  1044. LPWSTR strObjName;
  1045. while (strObjName = CompIter.WStrNextComponentName())
  1046. {
  1047. hr = m_pAS->AddNamedItem(strObjName, grf);
  1048. if (FAILED(hr))
  1049. break;
  1050. }
  1051. Assert(SUCCEEDED(hr));
  1052. /*
  1053. * Type library wrappers. (Has to be last in order to be called
  1054. * only when everything else fails.
  1055. */
  1056. // Special flag value for typelib wrappers
  1057. grf |= SCRIPTITEM_GLOBALMEMBERS;
  1058. if (m_pHitObj->PTypeLibWrapper())
  1059. {
  1060. hr = m_pAS->AddNamedItem(WSZ_OBJ_ASPPAGETLB, grf);
  1061. Assert(SUCCEEDED(hr));
  1062. }
  1063. // GLOBAL.ASA typelib wrapper is added always
  1064. // because each page does not pick up changes to
  1065. // GLOBAL.ASA and there's no way to figure out
  1066. // when TYPELIBs get added to GLOBAL.ASA
  1067. hr = m_pAS->AddNamedItem(WSZ_OBJ_ASPGLOBALTLB, grf);
  1068. Assert(SUCCEEDED(hr));
  1069. END_TRYCATCH(hr, m_pHitObj, "IActiveScript::AddNamedItem");
  1070. // We are required to return OK
  1071. return(S_OK);
  1072. }
  1073. /*===================================================================
  1074. CActiveScriptEngine::RequestTypeLibs
  1075. If this is called, it means that the Script engine wants us to call
  1076. IActiveScript::AddTypeLib() for each typelib associated with the
  1077. script. It is unclear to me that this will ever be called in our case.
  1078. Returns:
  1079. HRESULT. Always returns S_OK.
  1080. Side effects:
  1081. None.
  1082. ===================================================================*/
  1083. STDMETHODIMP CActiveScriptEngine::RequestTypeLibs()
  1084. {
  1085. AssertValid();
  1086. // We have no typelibs for the namespace
  1087. return(S_OK);
  1088. }
  1089. /*===================================================================
  1090. CActiveScriptEngine::OnEnterScript
  1091. Host callback to indicate that the script has started executing
  1092. Returns:
  1093. HRESULT. Always returns S_OK.
  1094. Side effects:
  1095. None.
  1096. ===================================================================*/
  1097. STDMETHODIMP CActiveScriptEngine::OnEnterScript()
  1098. {
  1099. return(S_OK);
  1100. }
  1101. /*===================================================================
  1102. CActiveScriptEngine::OnLeaveScript
  1103. Host callback to indicate that the script has stopped executing
  1104. Returns:
  1105. HRESULT. Always returns S_OK.
  1106. Side effects:
  1107. None.
  1108. ===================================================================*/
  1109. STDMETHODIMP CActiveScriptEngine::OnLeaveScript()
  1110. {
  1111. return(S_OK);
  1112. }
  1113. /*===================================================================
  1114. CActiveScriptEngine::GetHostInfo
  1115. Host callback to for furnishing LCID and code page info
  1116. Returns:
  1117. HRESULT. Always returns S_OK.
  1118. Side effects:
  1119. None.
  1120. ===================================================================*/
  1121. STDMETHODIMP CActiveScriptEngine::GetHostInfo(hostinfo hostinfoRequest, void **ppvInfo)
  1122. {
  1123. Assert(hostinfoRequest == hostinfoLocale || hostinfoRequest == hostinfoCodePage);
  1124. HRESULT hr = S_OK;
  1125. if (hostinfoRequest == hostinfoLocale)
  1126. {
  1127. // Allocate an LCID and set it to the current
  1128. // value for the HitObj
  1129. *ppvInfo = CoTaskMemAlloc(sizeof(UINT));
  1130. if (!*ppvInfo)
  1131. hr = E_OUTOFMEMORY;
  1132. else
  1133. (*(UINT *)*ppvInfo) = m_pHitObj->GetLCID();
  1134. }
  1135. else if (hostinfoRequest == hostinfoCodePage)
  1136. {
  1137. // Allocate an code page and set it to the current
  1138. // value for the HitObj
  1139. *ppvInfo = CoTaskMemAlloc(sizeof(UINT));
  1140. if (!*ppvInfo)
  1141. hr = E_OUTOFMEMORY;
  1142. else
  1143. (*(UINT *)*ppvInfo) = m_pHitObj->GetCodePage();
  1144. }
  1145. else
  1146. hr = E_FAIL;
  1147. return(hr);
  1148. }
  1149. /*===================================================================
  1150. CActiveScriptEngine::OnScriptTerminate
  1151. Host callback to indicate that the script has completed.
  1152. Returns:
  1153. HRESULT. Always returns S_OK.
  1154. Side effects:
  1155. None.
  1156. ===================================================================*/
  1157. STDMETHODIMP CActiveScriptEngine::OnScriptTerminate
  1158. (
  1159. const VARIANT *pvarResult,
  1160. const EXCEPINFO *pexcepinfo
  1161. )
  1162. {
  1163. return(S_OK);
  1164. }
  1165. /*===================================================================
  1166. CActiveScriptEngine::OnStateChange
  1167. Host callback to indicate that the script has changed state (e.g. from
  1168. Uninitialized to Loaded.)
  1169. Returns:
  1170. HRESULT. Always returns S_OK.
  1171. Side effects:
  1172. None.
  1173. ===================================================================*/
  1174. STDMETHODIMP CActiveScriptEngine::OnStateChange
  1175. (
  1176. SCRIPTSTATE ssScriptState
  1177. )
  1178. {
  1179. return(S_OK);
  1180. }
  1181. /*===================================================================
  1182. CActiveScriptEngine::OnScriptError
  1183. Host callback to indicate that an error has occured in the script.
  1184. We should handle the error. We will return E_FAIL to indicate that we
  1185. want the script to terminate.
  1186. Returns:
  1187. HRESULT. E_FAIL -- Terminate executing the script.
  1188. Side effects:
  1189. None.
  1190. ===================================================================*/
  1191. STDMETHODIMP CActiveScriptEngine::OnScriptError
  1192. (
  1193. IActiveScriptError __RPC_FAR *pscripterror
  1194. )
  1195. {
  1196. Assert(pscripterror);
  1197. AssertValid();
  1198. // Bug 153: If we terminate the script due to Response.End, dont show an error
  1199. // NOTE: ActiveXScripting was failing to pass us our excepinfo. Use member flags
  1200. // ALSO: ActiveXScripting has fixed the problem of failing to pass us our excepinfo, but the
  1201. // way we are doing this with flags works just fine.
  1202. if (m_fScriptAborted)
  1203. {
  1204. goto LRet;
  1205. }
  1206. if (m_fScriptTimedOut)
  1207. {
  1208. //Load Default Engine from resource
  1209. char szEngine[128];
  1210. DWORD cch;
  1211. cch = CchLoadStringOfId(IDS_ENGINE, szEngine, 128);
  1212. szEngine[cch] = '\0';
  1213. CHAR *szFileName;
  1214. #if UNICODE
  1215. szFileName = StringDupUTF8(m_pHitObj->PSzCurrTemplateVirtPath());
  1216. #else
  1217. szFileName = StringDupA(m_pHitObj->PSzCurrTemplateVirtPath());
  1218. #endif
  1219. HandleError(IDE_SCRIPT_TIMEOUT,
  1220. szFileName,
  1221. NULL,
  1222. StringDupA(szEngine),
  1223. NULL,
  1224. NULL,
  1225. NULL,
  1226. m_pHitObj,
  1227. NULL);
  1228. if(m_pHitObj)
  1229. {
  1230. m_pHitObj->SetExecStatus(eExecTimedOut);
  1231. }
  1232. goto LRet;
  1233. }
  1234. // OnScriptErrorDebug calls OnScriptError. use this test to be sure we don't log error
  1235. // twice if we are called twice. (won't happen with present debugging implementation,
  1236. // but externals may change.)
  1237. if (m_fScriptHadError)
  1238. {
  1239. goto LRet;
  1240. }
  1241. m_fScriptHadError = TRUE; // Note that the script had an error so we can abort transactions (if any)
  1242. if (pscripterror)
  1243. {
  1244. // If there was an error in the script, first see if we should pop up the debugger
  1245. // (ONLY bring up Script Debugger; VID will do the right thing on its own)
  1246. //
  1247. // NEW CHANGE: always bring error description to browser, since VID does not
  1248. // give sufficient description.
  1249. //
  1250. // With the current TRY_CATCH blocks in place..we should never hit this assert.
  1251. Assert (m_pHitObj);
  1252. if (FCaesars() && m_pHitObj && m_pHitObj->PAppln()->FDebuggable())
  1253. DebugError(pscripterror, m_pTemplate, m_dwSourceContext, g_pDebugApp);
  1254. HandleError(pscripterror, m_pTemplate, m_dwSourceContext, NULL, m_pHitObj);
  1255. }
  1256. LRet:
  1257. // Bug 99718 return S_OK to tell the script engine that we handled the error ok.
  1258. // Returning E_FAIL would not stop the scripting engine, this was a doc error.
  1259. return(S_OK);
  1260. }
  1261. /*
  1262. *
  1263. *
  1264. *
  1265. * I A c t i v e S c r i p t S i t e D e b u g M e t h o d s
  1266. *
  1267. *
  1268. *
  1269. *
  1270. */
  1271. /*===================================================================
  1272. CActiveScriptEngine::OnScriptErrorDebug
  1273. Callback for debugger to query host on what to do on exception.
  1274. NOTE: Theoretically, we would set *pfCallOnScriptErrorWhenContinuing
  1275. to TRUE and not call OnScriptError, and set *pfEnterDebugger
  1276. to TRUE or FALSE based on whether debugging is enabled and
  1277. whether user wants to debug.
  1278. However, in practice, *pfCallOnScriptErrorWhenContinuing is
  1279. not honored (OnScriptError is NOT called in any case), and
  1280. the VID team wants us to pretend like we don't implement
  1281. this interface. However, we always need our "OnScriptError"
  1282. code to execute, so we call our OnScriptError function
  1283. explicitly, then fail
  1284. Returns:
  1285. HRESULT. always returns E_NOTIMPL
  1286. Side effects:
  1287. calls OnScriptError
  1288. ===================================================================*/
  1289. STDMETHODIMP CActiveScriptEngine::OnScriptErrorDebug
  1290. (
  1291. IActiveScriptErrorDebug *pscripterror,
  1292. BOOL *pfEnterDebugger,
  1293. BOOL *pfCallOnScriptErrorWhenContinuing
  1294. )
  1295. {
  1296. OnScriptError(pscripterror);
  1297. return E_NOTIMPL;
  1298. }
  1299. /*===================================================================
  1300. CActiveScriptEngine::GetDocumentContextFromPosition
  1301. Create a document context (file + offset + length) from an offset in the
  1302. script.
  1303. Returns:
  1304. HRESULT. S_OK on success.
  1305. ===================================================================*/
  1306. HRESULT CActiveScriptEngine::GetDocumentContextFromPosition
  1307. (
  1308. /* [in] */ DWORD_PTR dwSourceContext,
  1309. /* [in] */ ULONG cchTargetOffset,
  1310. /* [in] */ ULONG cchText,
  1311. /* [out] */ IDebugDocumentContext **ppDocumentContext)
  1312. {
  1313. static const char *_pFuncName = "CActiveScriptEngine::GetDocumentContextFromPosition()";
  1314. TCHAR *szSourceFile;
  1315. ULONG cchSourceOffset;
  1316. ULONG cchSourceText;
  1317. IActiveScriptDebug *pASD;
  1318. // Convert offset in script engine to source location, and get debugging interfaces
  1319. m_pTemplate->GetSourceOffset(m_dwSourceContext, cchTargetOffset, &szSourceFile, &cchSourceOffset, &cchSourceText);
  1320. HRESULT hr;
  1321. TRYCATCH_HR(m_pAS->QueryInterface(IID_IActiveScriptDebug, reinterpret_cast<void **>(&pASD)),
  1322. hr,
  1323. "IActiveScript::QueryInterface()");
  1324. if (FAILED(hr))
  1325. return(E_FAIL);
  1326. // If this is in the main file, create a document context based on the CTemplate compiled source
  1327. if (_tcscmp(szSourceFile, m_pTemplate->GetSourceFileName()) == 0)
  1328. {
  1329. if (
  1330. (*ppDocumentContext = new CTemplateDocumentContext(m_pTemplate, cchSourceOffset, cchSourceText, pASD, m_dwSourceContext, cchTargetOffset))
  1331. == NULL
  1332. )
  1333. {
  1334. pASD->Release();
  1335. return E_OUTOFMEMORY;
  1336. }
  1337. }
  1338. // source refers to an include file, so create a documet context based on cached CIncFile dependency graph
  1339. else
  1340. {
  1341. CIncFile *pIncFile;
  1342. if (FAILED(g_IncFileMap.GetIncFile(szSourceFile, &pIncFile)))
  1343. return E_FAIL;
  1344. if (
  1345. (*ppDocumentContext = new CIncFileDocumentContext(pIncFile, cchSourceOffset, cchSourceText))
  1346. == NULL
  1347. )
  1348. {
  1349. TRYCATCH(pASD->Release(),"IActiveScriptDebug::Release()");
  1350. pIncFile->Release();
  1351. return E_OUTOFMEMORY;
  1352. }
  1353. pIncFile->Release();
  1354. }
  1355. TRYCATCH(pASD->Release(),"IActiveScriptDebug::Release()");
  1356. m_fBeingDebugged = TRUE;
  1357. return S_OK;
  1358. }
  1359. /*===================================================================
  1360. CActiveScriptEngine::GetApplication
  1361. Return a pointer to the application that the script resides in.
  1362. Returns:
  1363. HRESULT. Always succeeds.
  1364. ===================================================================*/
  1365. HRESULT CActiveScriptEngine::GetApplication
  1366. (
  1367. /* [out] */ IDebugApplication **ppDebugApp
  1368. )
  1369. {
  1370. Assert (m_pTemplate != NULL);
  1371. if (m_pTemplate->FDebuggable())
  1372. {
  1373. Assert (g_pDebugApp);
  1374. *ppDebugApp = g_pDebugApp;
  1375. (*ppDebugApp)->AddRef();
  1376. return S_OK;
  1377. }
  1378. else
  1379. {
  1380. *ppDebugApp = NULL;
  1381. return E_FAIL;
  1382. }
  1383. }
  1384. /*===================================================================
  1385. CActiveScriptEngine::GetRootApplicationNode
  1386. Return a pointer to the top level node (for browsing)
  1387. Returns:
  1388. HRESULT. Always succeeds.
  1389. ===================================================================*/
  1390. HRESULT CActiveScriptEngine::GetRootApplicationNode
  1391. (
  1392. /* [out] */ IDebugApplicationNode **ppRootNode
  1393. )
  1394. {
  1395. Assert (m_pTemplate != NULL);
  1396. if (m_pTemplate->FDebuggable())
  1397. {
  1398. Assert (g_pDebugAppRoot);
  1399. *ppRootNode = g_pDebugAppRoot;
  1400. (*ppRootNode)->AddRef();
  1401. return S_OK;
  1402. }
  1403. else
  1404. {
  1405. *ppRootNode = NULL;
  1406. return E_FAIL;
  1407. }
  1408. }
  1409. /*
  1410. *
  1411. *
  1412. *
  1413. * C S c r i p t E n g i n e M e t h o d s
  1414. *
  1415. *
  1416. *
  1417. *
  1418. */
  1419. /*===================================================================
  1420. CActiveScriptEngine::AddScriptlet
  1421. Add a piece of code to the script engine.
  1422. Returns:
  1423. HRESULT. S_OK on success.
  1424. Side effects:
  1425. Adds script code to the engine. Potentially allocates memory.
  1426. ===================================================================*/
  1427. HRESULT CActiveScriptEngine::AddScriptlet
  1428. (
  1429. LPCOLESTR wstrScript // scriptlet text
  1430. )
  1431. {
  1432. static const char *_pFuncName = "CActiveScriptEngine::AddScriptlet()";
  1433. HRESULT hr;
  1434. EXCEPINFO excepinfo;
  1435. AssertValid();
  1436. // Tell ActiveScripting to add the script to the engine
  1437. TRYCATCH_HR(m_pASP->ParseScriptText(
  1438. wstrScript, // the scriptlet text
  1439. NULL, // pstrItemName
  1440. NULL, // punkContext
  1441. //L"</SCRIPT>", // End Delimiter -- Engine will never see this, but does tell it to strip comments.
  1442. L"STRIP EMBEDDED HTML COMMENTS", // Tells the ScriptEngine to strip comments INPLACE
  1443. m_dwSourceContext, // dwSourceContextCookie
  1444. 1, // ulStartingLineNumber
  1445. SCRIPTTEXT_ISPERSISTENT | SCRIPTTEXT_HOSTMANAGESSOURCE,
  1446. NULL, // pvarResult
  1447. &excepinfo), // exception info filled in on error
  1448. hr,
  1449. "IActiveScriptParse::ParseScriptText()");
  1450. if (SUCCEEDED(hr))
  1451. m_fScriptLoaded = TRUE;
  1452. return(hr);
  1453. }
  1454. /*===================================================================
  1455. CActiveScriptEngine::AddObjects
  1456. Add named objects to the script name space
  1457. Returns:
  1458. HRESULT. Always returns S_OK.
  1459. Side effects:
  1460. None.
  1461. ===================================================================*/
  1462. HRESULT CActiveScriptEngine::AddObjects
  1463. (
  1464. BOOL fPersistNames // = TRUE
  1465. )
  1466. {
  1467. HRESULT hr = S_OK;
  1468. AssertValid();
  1469. // There must be a hit object set
  1470. Assert(m_pHitObj != NULL);
  1471. // Leverage RequestItems to give AS all the names
  1472. hr = RequestItems(fPersistNames);
  1473. if (SUCCEEDED(hr))
  1474. m_fObjectsLoaded = TRUE;
  1475. return(hr);
  1476. }
  1477. /*===================================================================
  1478. CActiveScriptEngine::AddAdditionalObject
  1479. Add additional named objects to the script name space beyond the
  1480. names already added with AddObject. Note: the caller MUST have
  1481. added then names to the HitObj before making this call
  1482. Returns:
  1483. HRESULT. S_OK on success
  1484. Side effects:
  1485. None.
  1486. ===================================================================*/
  1487. HRESULT CActiveScriptEngine::AddAdditionalObject
  1488. (
  1489. LPWSTR strObjName,
  1490. BOOL fPersistNames // = TRUE
  1491. )
  1492. {
  1493. static const char *_pFuncName = "CActiveScriptEngine::AddAdditionalObject()";
  1494. HRESULT hr = S_OK;
  1495. DWORD grf;
  1496. AssertValid();
  1497. // There must be a hit object set
  1498. Assert(m_pHitObj != NULL);
  1499. // CONSIDER: It would be nice in debug code to walk the hitobj objlist and make sure
  1500. // that the given name is in there
  1501. /*
  1502. * Give AS the names
  1503. */
  1504. grf = SCRIPTITEM_ISVISIBLE;
  1505. if (fPersistNames)
  1506. grf |= SCRIPTITEM_ISPERSISTENT;
  1507. TRYCATCH_HR(m_pAS->AddNamedItem(strObjName, grf), hr, "IActiveScript::AddNamedItem()");
  1508. Assert(SUCCEEDED(hr)); // Should never fail!
  1509. return(hr);
  1510. }
  1511. /*===================================================================
  1512. CActiveScriptEngine::AddScriptingNamespace
  1513. Add the given scripting namespace object to the engine.
  1514. Note that it is added as GLOBALMEMBERS, and Not as ISPERSISTENT
  1515. Returns:
  1516. HRESULT. S_OK on success
  1517. Side effects:
  1518. None.
  1519. ===================================================================*/
  1520. HRESULT CActiveScriptEngine::AddScriptingNamespace
  1521. (
  1522. )
  1523. {
  1524. static const char *_pFuncName = "CActiveScriptEngine::AddScriptingNamespace()";
  1525. HRESULT hr = S_OK;
  1526. AssertValid();
  1527. Assert(m_pHitObj != NULL);
  1528. /*
  1529. * Give AXS the name and mark it GLOBALMEMBERS so all members are top level names
  1530. * in the namespace
  1531. */
  1532. TRYCATCH_HR(m_pAS->AddNamedItem(WSZ_OBJ_SCRIPTINGNAMESPACE, SCRIPTITEM_ISVISIBLE | SCRIPTITEM_GLOBALMEMBERS),
  1533. hr,
  1534. "IActiveScript::AddNamedItem()");
  1535. Assert(SUCCEEDED(hr)); // Should never fail!
  1536. return(hr);
  1537. }
  1538. /*===================================================================
  1539. CActiveScriptEngine::CheckEntryPoint
  1540. Determines if the specific named entry point exists in the given script.
  1541. Returns:
  1542. S_OK if found
  1543. DISP_E_UNKNOWNNAME if not found
  1544. Other OLE errors may be returned
  1545. Side effects:
  1546. None
  1547. ===================================================================*/
  1548. HRESULT CActiveScriptEngine::CheckEntryPoint
  1549. (
  1550. LPCOLESTR strEntryPoint // The name of the sub/fn to look for
  1551. )
  1552. {
  1553. static const char *_pFuncName = "CActiveScriptEngine::CheckEntryPoint()";
  1554. HRESULT hr;
  1555. DISPID dispid;
  1556. AssertValid();
  1557. if (strEntryPoint == NULL)
  1558. {
  1559. Assert(FALSE);
  1560. hr = DISP_E_UNKNOWNNAME;
  1561. }
  1562. else
  1563. {
  1564. // Get the DISPID of the method to call
  1565. TRYCATCH_HR(m_pDisp->GetIDsOfNames(IID_NULL, // REFIID - Reserved, must be NULL
  1566. (LPOLESTR *)&strEntryPoint, // Array of names to look up
  1567. 1, // Number of names in array
  1568. m_lcid, // Locale id
  1569. &dispid), // returned dispid
  1570. hr,
  1571. "IScriptDispatch::GetIDsOfNames()");
  1572. // Only error we expect is DISP_E_UNKNOWNNAME (or DISP_E_MEMBERNOTFOUND)
  1573. Assert(hr == S_OK || hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND);
  1574. }
  1575. return(hr);
  1576. }
  1577. /*===================================================================
  1578. CActiveScriptEngine::Call
  1579. Runs the specified function.
  1580. If a specific named entry point is provided (e.g. Session_OnStart)
  1581. then we will call that by name. Otherwise (e.g. a "main" script),
  1582. pass NULL for the name and we will run just the mainline code.
  1583. Calls TryCall (optionally from under TRY CATCH) to do the job
  1584. Returns:
  1585. HRESULT. S_OK on success.
  1586. Side effects:
  1587. May have various side effects depending on the script run
  1588. ===================================================================*/
  1589. HRESULT CActiveScriptEngine::Call
  1590. (
  1591. LPCOLESTR strEntryPoint // The name of the sub/fn to call (may be NULL for "main")
  1592. )
  1593. {
  1594. HRESULT hr;
  1595. AssertValid();
  1596. if (Glob(fExceptionCatchEnable)) {
  1597. // Catch any GPFs in VBS, OleAut, or external components
  1598. TRY
  1599. hr = TryCall(strEntryPoint);
  1600. CATCH(nExcept)
  1601. /*
  1602. * Catching a GPF or stack overflow
  1603. * Report it to the user, Assert (if debug), and exit with E_UNEXPECTED.
  1604. */
  1605. if (STATUS_STACK_OVERFLOW == nExcept) {
  1606. HandleErrorMissingFilename(IDE_STACK_OVERFLOW, m_pHitObj);
  1607. #if UNICODE
  1608. DBGPRINTF((DBG_CONTEXT, "Invoking the script '%S' overflowed the stack", m_szTemplateName));
  1609. #else
  1610. DBGPRINTF((DBG_CONTEXT, "Invoking the script '%s' overflowed the stack", m_szTemplateName));
  1611. #endif
  1612. }
  1613. else {
  1614. HandleErrorMissingFilename(IDE_SCRIPT_GPF, m_pHitObj, TRUE, nExcept);
  1615. #if UNICODE
  1616. DBGPRINTF((DBG_CONTEXT, "Invoking the script '%S' threw an exception (%x).", m_szTemplateName, nExcept));
  1617. #else
  1618. DBGPRINTF((DBG_CONTEXT, "Invoking the script '%s' threw an exception (%x).", m_szTemplateName, nExcept));
  1619. #endif
  1620. }
  1621. // Dont reuse the engine
  1622. m_fCorrupted = TRUE;
  1623. hr = E_UNEXPECTED;
  1624. END_TRY
  1625. }
  1626. else {
  1627. // Don't catch exceptions
  1628. hr = TryCall(strEntryPoint);
  1629. }
  1630. return(hr);
  1631. }
  1632. /*===================================================================
  1633. CActiveScriptEngine::TryCall
  1634. Runs the specified function.
  1635. If a specific named entry point is provided (e.g. Session_OnStart)
  1636. then we will call that by name. Otherwise (e.g. a "main" script),
  1637. pass NULL for the name and we will run just the mainline code.
  1638. Called from Call (optionally from under TRY CATCH)
  1639. Returns:
  1640. HRESULT. S_OK on success.
  1641. Side effects:
  1642. May have various side effects depending on the script run
  1643. ===================================================================*/
  1644. HRESULT CActiveScriptEngine::TryCall
  1645. (
  1646. LPCOLESTR strEntryPoint // The name of the sub/fn to call (may be NULL for "main")
  1647. )
  1648. {
  1649. HRESULT hr;
  1650. DISPID dispid;
  1651. DISPPARAMS dispparams;
  1652. UINT nArgErr;
  1653. /*
  1654. * Before calling any code we will transition the script to "STARTED" state.
  1655. * This is part of the ActiveXScripting Reset work.
  1656. */
  1657. hr = m_pAS->SetScriptState(SCRIPTSTATE_STARTED);
  1658. if (FAILED(hr))
  1659. {
  1660. Assert(FALSE);
  1661. goto LRet;
  1662. }
  1663. if (strEntryPoint != NULL)
  1664. {
  1665. // Get the DISPID of the method to call
  1666. hr = m_pDisp->GetIDsOfNames(IID_NULL, // REFIID - Reserved, must be NULL
  1667. (LPOLESTR *)&strEntryPoint, // Array of names to look up
  1668. 1, // Number of names in array
  1669. m_lcid, // Locale id
  1670. &dispid); // returned dispid
  1671. if (FAILED(hr))
  1672. {
  1673. // Only error we expect is DISP_E_UNKNOWNNAME (or DISP_E_MEMBERNOTFOUND)
  1674. Assert(hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND);
  1675. goto LRet;
  1676. }
  1677. // There are no arguments
  1678. memset(&dispparams, 0, sizeof(dispparams));
  1679. // Invoke it
  1680. hr = m_pDisp->Invoke(dispid, // dispid to invoke
  1681. IID_NULL, // REFIID - Reserved, must be NULL
  1682. m_lcid, // Locale id
  1683. DISPATCH_METHOD, // Calling a method, not a property get/put
  1684. &dispparams, // pass arguments
  1685. NULL, // return value
  1686. NULL, // We aren't interested in the exception info
  1687. &nArgErr); // if there is a Type Mismatch, which argument was the problem
  1688. }
  1689. LRet:
  1690. return(hr);
  1691. }
  1692. /*
  1693. *
  1694. *
  1695. *
  1696. * C S c r i p t M a n a g e r
  1697. *
  1698. *
  1699. *
  1700. *
  1701. */
  1702. /*===================================================================
  1703. CScriptManager::CScriptManager
  1704. Constructor for CScriptManager object
  1705. Returns:
  1706. Nothing
  1707. Side effects:
  1708. None.
  1709. ===================================================================*/
  1710. CScriptManager::CScriptManager()
  1711. : m_fInited(FALSE), m_idScriptKiller(0)
  1712. {
  1713. }
  1714. /*===================================================================
  1715. CScriptManager::~CScriptManager
  1716. Destructor for CScriptManager object
  1717. Returns:
  1718. Nothing
  1719. Side effects:
  1720. None.
  1721. ===================================================================*/
  1722. CScriptManager::~CScriptManager()
  1723. {
  1724. }
  1725. /*===================================================================
  1726. CScriptManager::Init
  1727. Init the script manager. This must only be called once.
  1728. Returns:
  1729. HRESULT. S_OK on success.
  1730. Side effects:
  1731. None.
  1732. ===================================================================*/
  1733. HRESULT CScriptManager::Init
  1734. (
  1735. )
  1736. {
  1737. static const char *_pFuncName = "CScriptManager::Init()";
  1738. HRESULT hr;
  1739. BOOL fPLLInited = FALSE;
  1740. BOOL fcsPLLInited = FALSE;
  1741. BOOL fFSQInited = FALSE;
  1742. BOOL fcsFSQInited = FALSE;
  1743. BOOL fRSLInited = FALSE;
  1744. BOOL fcsRSLInited = FALSE;
  1745. DWORD cBuckets;
  1746. DWORD rgPrime[] = { 3, 11, 23, 57, 89 };
  1747. WORD iP;
  1748. IActiveScript *pAST = NULL;
  1749. static const GUID uid_VBScript = { 0xB54F3741, 0x5B07, 0x11cf, { 0xA4, 0xB0, 0x00, 0xAA, 0x00, 0x4A, 0x55, 0xE8}};
  1750. // Illegal to re-init
  1751. if (m_fInited)
  1752. {
  1753. Assert(FALSE);
  1754. return(ERROR_ALREADY_INITIALIZED);
  1755. }
  1756. // Create the critical sections for serializing access to lists
  1757. ErrInitCriticalSection(&m_cSPLL, hr);
  1758. if (FAILED(hr))
  1759. goto LError;
  1760. fcsPLLInited = TRUE;
  1761. ErrInitCriticalSection(&m_csFSQ, hr);
  1762. if (FAILED(hr))
  1763. goto LError;
  1764. fcsFSQInited = TRUE;
  1765. ErrInitCriticalSection(&m_csRSL, hr);
  1766. if (FAILED(hr))
  1767. goto LError;
  1768. fcsRSLInited = TRUE;
  1769. // List of programming language clsid's
  1770. hr = m_hTPLL.Init();
  1771. if (FAILED(hr))
  1772. goto LError;
  1773. fPLLInited = TRUE;
  1774. // Free Script Queue
  1775. // Init it with a prime # of buckets in relation to script engine cache max
  1776. cBuckets = (Glob(dwScriptEngineCacheMax) / 2) + 1;
  1777. for (iP = (sizeof(rgPrime) / sizeof(DWORD)) - 1; iP > 0; iP--)
  1778. if (rgPrime[iP] < cBuckets)
  1779. {
  1780. cBuckets = rgPrime[iP];
  1781. break;
  1782. }
  1783. if (cBuckets < rgPrime[1])
  1784. cBuckets = rgPrime[0];
  1785. hr = m_htFSQ.Init(cBuckets);
  1786. if (FAILED(hr))
  1787. goto LError;
  1788. fFSQInited = TRUE;
  1789. // Running Script List
  1790. // Init it with a prime # of buckets in relation to max # of threads
  1791. cBuckets = Glob(dwThreadMax) / 2;
  1792. for (iP = (sizeof(rgPrime) / sizeof(DWORD)) - 1; iP > 0; iP--)
  1793. if (rgPrime[iP] < cBuckets)
  1794. {
  1795. cBuckets = rgPrime[iP];
  1796. break;
  1797. }
  1798. if (cBuckets < rgPrime[1])
  1799. cBuckets = rgPrime[0];
  1800. hr = m_htRSL.Init(cBuckets);
  1801. if (FAILED(hr))
  1802. goto LError;
  1803. fRSLInited = TRUE;
  1804. // Schedule script killer
  1805. m_msecScriptKillerTimeout = Glob(dwScriptTimeout) * 500;
  1806. m_idScriptKiller = ScheduleWorkItem
  1807. (
  1808. CScriptManager::ScriptKillerSchedulerCallback, // callback
  1809. this, // context
  1810. m_msecScriptKillerTimeout, // timeout
  1811. TRUE // periodic
  1812. );
  1813. if (!m_idScriptKiller)
  1814. {
  1815. hr = E_FAIL;
  1816. goto LError;
  1817. }
  1818. // TypeLib support: Create a scripting engine and QI it for the TypeLib wrapper support
  1819. hr = CoCreateInstance(uid_VBScript, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void**)&pAST);
  1820. if (FAILED(hr))
  1821. goto LError;
  1822. TRYCATCH_HR_NOHITOBJ(pAST->QueryInterface(IID_IWrapTypeLibs, (VOID **)&g_pWrapTypelibs),
  1823. hr,
  1824. "IActiveScript::QueryInterface()");
  1825. TRYCATCH_NOHITOBJ(pAST->Release(),"IActiveScript::Release()"); // No longer need the pointer to the engine
  1826. if (FAILED(hr))
  1827. goto LError;
  1828. // All OK. We are inited.
  1829. m_fInited = TRUE;
  1830. goto LExit;
  1831. LError:
  1832. if (m_idScriptKiller)
  1833. RemoveWorkItem(m_idScriptKiller);
  1834. if (fcsPLLInited)
  1835. DeleteCriticalSection(&m_cSPLL);
  1836. if (fcsFSQInited)
  1837. DeleteCriticalSection(&m_csFSQ);
  1838. if (fcsRSLInited)
  1839. DeleteCriticalSection(&m_csRSL);
  1840. if (fPLLInited)
  1841. m_hTPLL.UnInit();
  1842. if (fFSQInited)
  1843. m_htFSQ.UnInit();
  1844. if (fRSLInited)
  1845. m_htRSL.UnInit();
  1846. if (pAST)
  1847. TRYCATCH_NOHITOBJ(pAST->Release(),"IActiveScript::Release()");
  1848. if (g_pWrapTypelibs)
  1849. {
  1850. TRYCATCH_NOHITOBJ(g_pWrapTypelibs->Release(),"IWrapTypeLibs::Release()");
  1851. g_pWrapTypelibs = NULL;
  1852. }
  1853. LExit:
  1854. return(hr);
  1855. }
  1856. /*===================================================================
  1857. CScriptManager::UnInit
  1858. UnInit the script manager. This must only be called once.
  1859. Returns:
  1860. HRESULT. S_OK on success.
  1861. Side effects:
  1862. None.
  1863. ===================================================================*/
  1864. HRESULT CScriptManager::UnInit
  1865. (
  1866. )
  1867. {
  1868. static const char *_pFuncName = "CScriptManager::UnInit()";
  1869. HRESULT hr = S_OK, hrT;
  1870. if (m_fInited)
  1871. {
  1872. // Un-schedule script killer
  1873. if (m_idScriptKiller)
  1874. {
  1875. RemoveWorkItem(m_idScriptKiller);
  1876. m_idScriptKiller = 0;
  1877. }
  1878. // Uninit each of the lists. Attempt to uninit them all, even if we get an error.
  1879. // Dont lose any errors along the way.
  1880. hr = UnInitASEElems();
  1881. hrT = UnInitPLL();
  1882. if (SUCCEEDED(hr))
  1883. hr = hrT;
  1884. hrT = m_hTPLL.UnInit();
  1885. if (SUCCEEDED(hr))
  1886. hr = hrT;
  1887. hrT = m_htFSQ.UnInit();
  1888. if (SUCCEEDED(hr))
  1889. hr = hrT;
  1890. hrT = m_htRSL.UnInit();
  1891. if (SUCCEEDED(hr))
  1892. hr = hrT;
  1893. if (g_pWrapTypelibs)
  1894. {
  1895. TRYCATCH_NOHITOBJ(g_pWrapTypelibs->Release(),"IWrapTypeLibs::Release()");
  1896. g_pWrapTypelibs = NULL;
  1897. }
  1898. // Free the critical sections (bug 1140: do this after freeing everything else)
  1899. DeleteCriticalSection(&m_cSPLL);
  1900. DeleteCriticalSection(&m_csFSQ);
  1901. DeleteCriticalSection(&m_csRSL);
  1902. m_fInited = FALSE;
  1903. }
  1904. return(hr);
  1905. }
  1906. /*===================================================================
  1907. CScriptManager::AdjustScriptKillerTimeout
  1908. Adjust (shorten) script killer timeout when needed.
  1909. The caller should take care of the critical sectioning.
  1910. Parameters:
  1911. msecNewTimeout new suggested timeout value (in ms)
  1912. Returns:
  1913. HRESULT. S_OK on success.
  1914. ===================================================================*/
  1915. HRESULT CScriptManager::AdjustScriptKillerTimeout
  1916. (
  1917. DWORD msecNewTimeout
  1918. )
  1919. {
  1920. const DWORD MSEC_MIN_SCRIPT_TIMEOUT = 5000; // 5 seconds
  1921. if (!m_idScriptKiller)
  1922. return E_FAIL; // no script killer scheduled
  1923. // don't set to < minimum
  1924. if (msecNewTimeout < MSEC_MIN_SCRIPT_TIMEOUT)
  1925. msecNewTimeout = MSEC_MIN_SCRIPT_TIMEOUT;
  1926. if (m_msecScriptKillerTimeout <= msecNewTimeout)
  1927. return S_OK; // the timeout already short enough
  1928. if (ScheduleAdjustTime(
  1929. m_idScriptKiller,
  1930. msecNewTimeout) == S_OK)
  1931. {
  1932. m_msecScriptKillerTimeout = msecNewTimeout;
  1933. return S_OK;
  1934. }
  1935. else
  1936. {
  1937. return E_FAIL;
  1938. }
  1939. }
  1940. /*===================================================================
  1941. CScriptManager::GetEngine
  1942. Return an engine to the caller. Ideally, we will find an engine
  1943. that already has the given script in it in our Free Script Queue
  1944. and will just hand it out. If there isnt one, then we will look
  1945. in the Running Script List and attempt to clone a running script.
  1946. Failing that, we will create a new script
  1947. engine. We return an ENGINESTATE state indicating if the engine
  1948. is filled with script or not.
  1949. Returns:
  1950. HRESULT. S_OK on success.
  1951. Side effects:
  1952. Potentially allocates memory.
  1953. ===================================================================*/
  1954. HRESULT CScriptManager::GetEngine
  1955. (
  1956. LCID lcid, // The system language to use
  1957. PROGLANG_ID& progLangId, // prog lang id of the script
  1958. LPCTSTR szTemplateName, // Template we want an engine for
  1959. CHitObj *pHitObj, // Hit obj to use in this engine
  1960. CScriptEngine **ppSE, // Returned script engine
  1961. ENGINESTATE *pdwState, // Current state of the engine
  1962. CTemplate *pTemplate, // template which engine is based from
  1963. DWORD dwSourceContext // source context cookie (engine ID)
  1964. )
  1965. {
  1966. HRESULT hr = S_OK;
  1967. CActiveScriptEngine *pASE = NULL;
  1968. CASEElem *pASEElem = NULL;
  1969. DWORD dwInstanceID = pHitObj->DWInstanceID();
  1970. AssertValid();
  1971. /* NOTE progLangId must be valid because CTemplate::Compile()
  1972. fails way upstream of this point if it cannot generate a valid progLangId.
  1973. Unfortunately there is no easy way to assert progLangId is valid ...
  1974. */
  1975. /*
  1976. * First try to find the engine in the FSQ
  1977. *
  1978. * Note: We are going to enter our CS now, and keep it until we have
  1979. * secured the engine for ourselves. Otherwise, it might be possible
  1980. * for us to get an engine, and then have another thread get the
  1981. * same engine before we manage to get it off of the FSQ.
  1982. * This makes the code a little hard to read, but is nessecary.
  1983. */
  1984. EnterCriticalSection(&m_csFSQ);
  1985. #ifndef PERF_DISABLE
  1986. g_PerfData.Incr_ENGINECACHETRYS();
  1987. #endif
  1988. #ifndef REUSE_ENGINE
  1989. // This will only find fully loaded engines
  1990. hr = FindEngineInList(szTemplateName, progLangId, dwInstanceID, /*fFSQ*/TRUE, &pASEElem);
  1991. #endif
  1992. if (FAILED(hr))
  1993. {
  1994. LeaveCriticalSection(&m_csFSQ);
  1995. goto LFail;
  1996. }
  1997. if (pASEElem == NULL || pASEElem->PASE() == NULL)
  1998. {
  1999. LeaveCriticalSection(&m_csFSQ);
  2000. }
  2001. else
  2002. {
  2003. // We got an engine we want to use, remove it from FSQ
  2004. (VOID)m_htFSQ.RemoveElem(pASEElem);
  2005. #ifndef PERF_DISABLE
  2006. g_PerfData.Decr_SCRIPTFREEENG();
  2007. #endif
  2008. LeaveCriticalSection(&m_csFSQ);
  2009. pASE = pASEElem->PASE();
  2010. Assert(!pASE->FIsZombie());
  2011. Assert(pASE->FFullyLoaded());
  2012. hr = pASE->ReuseEngine(pHitObj, pTemplate, dwSourceContext, dwInstanceID);
  2013. if (FAILED(hr))
  2014. goto LFail;
  2015. // Got an engine for sure...so just incr the cache hit count
  2016. #ifndef PERF_DISABLE
  2017. g_PerfData.Incr_ENGINECACHEHITS();
  2018. #endif
  2019. }
  2020. /*
  2021. * If not found, try to find the engine in the RSL and clone it
  2022. */
  2023. if (pASE == NULL)
  2024. {
  2025. CASEElem *pASEElemRunning = NULL;
  2026. CActiveScriptEngine *pASERunning = NULL;
  2027. // If we do find an engine to clone, dont let anyone at it until we've cloned it
  2028. EnterCriticalSection(&m_csRSL);
  2029. #ifndef CLONE
  2030. hr = FindEngineInList(szTemplateName, progLangId, dwInstanceID, /*fFSQ*/FALSE, &pASEElemRunning);
  2031. #else // CLONE
  2032. // Clone turned off - pretend one wasnt found
  2033. pASEElemRunning = NULL;
  2034. #endif
  2035. /*
  2036. * If we didnt find an element, or it was null, or (bug 1225) it was corrupted
  2037. * by a GPF running a script, or it was a zombie, then leave the CS and continue.
  2038. */
  2039. if (FAILED(hr) || pASEElemRunning == NULL || pASEElemRunning->PASE() == NULL ||
  2040. pASEElemRunning->PASE()->FIsCorrupted() || pASEElemRunning->PASE()->FIsZombie())
  2041. {
  2042. LeaveCriticalSection(&m_csRSL);
  2043. if (FAILED(hr))
  2044. goto LFail;
  2045. }
  2046. else
  2047. {
  2048. pASERunning = pASEElemRunning->PASE();
  2049. Assert(pASERunning != NULL);
  2050. }
  2051. if (pASERunning != NULL)
  2052. {
  2053. IActiveScript *pAS, *pASClone;
  2054. Assert(!pASERunning->FIsZombie());
  2055. Assert(pASERunning->FFullyLoaded());
  2056. // Found a running engine, clone it
  2057. pAS = pASERunning->GetActiveScript();
  2058. Assert(pAS != NULL);
  2059. hr = pAS->Clone(&pASClone);
  2060. // We've cloned the engine, we can let go of the CS
  2061. LeaveCriticalSection(&m_csRSL);
  2062. // Scripting engines are not required to implement clone. If we get an error,
  2063. // just continue on and create a new engine
  2064. if (FAILED(hr))
  2065. {
  2066. Assert(hr == E_NOTIMPL); // I only expect E_NOTIMPL
  2067. Assert(pASE == NULL); // the ASE should not be filled in
  2068. pASE = NULL;
  2069. hr = S_OK;
  2070. }
  2071. else
  2072. {
  2073. // Got back a cloned IActiveScript. Create a new ASE and fill it in
  2074. pASE = new CActiveScriptEngine;
  2075. if (!pASE)
  2076. {
  2077. hr = E_OUTOFMEMORY;
  2078. pASClone->Release();
  2079. goto LFail;
  2080. }
  2081. hr = pASE->MakeClone(progLangId, szTemplateName, lcid, pHitObj, pTemplate, dwSourceContext, dwInstanceID, pASClone);
  2082. if (FAILED(hr))
  2083. {
  2084. // if we failed, we must release the clone AS
  2085. pASClone->Release();
  2086. goto LFail;
  2087. }
  2088. }
  2089. }
  2090. }
  2091. /*
  2092. * Have an engine that we can reuse
  2093. */
  2094. if (pASE != NULL)
  2095. {
  2096. // Reusing an engine. Let the caller know that it is already initialized
  2097. *pdwState = SCRIPTSTATE_INITIALIZED;
  2098. goto LHaveEngine;
  2099. }
  2100. /*
  2101. * No suitable engine to reuse. Return a new one
  2102. */
  2103. pASE = new CActiveScriptEngine;
  2104. if (!pASE)
  2105. {
  2106. hr = E_OUTOFMEMORY;
  2107. goto LFail;
  2108. }
  2109. hr = pASE->Init(progLangId, szTemplateName, lcid, pHitObj, pTemplate, dwSourceContext);
  2110. if (FAILED(hr))
  2111. goto LFail;
  2112. // This is a new engine, let the caller know it is uninitialized
  2113. *pdwState = SCRIPTSTATE_UNINITIALIZED;
  2114. LHaveEngine:
  2115. // Return the engine as a CScriptEngine -- the caller only needs those interfaces
  2116. pASE->AssertValid(); // The engine we're about to give back should be valid
  2117. *ppSE = (CScriptEngine *)pASE;
  2118. // Put the engine on the Running Scrips List
  2119. // If we got this engine from the FSQ, reuse that elem.
  2120. if (pASEElem == NULL)
  2121. {
  2122. pASEElem = new CASEElem;
  2123. if (!pASEElem)
  2124. {
  2125. hr = E_OUTOFMEMORY;
  2126. goto LFail;
  2127. }
  2128. hr = pASEElem->Init(pASE);
  2129. if (FAILED(hr))
  2130. {
  2131. Assert(FALSE); // Shouldnt fail
  2132. delete pASEElem;
  2133. goto LFail;
  2134. }
  2135. }
  2136. /*
  2137. * Above, we may have gotten an engine from the FSQ or cloned on from the RSL or
  2138. * created a new one. And, we are about to put that engine on the RSL. However,
  2139. * it is possible that the template in question was flushed due to a change notification
  2140. * while this was going on. Regardless of how we got the engine, there is the possibility
  2141. * that the template was flushed while we were holding onto an engine which was not on
  2142. * any list (the FSQ or RSL), and so we have an engine which should be flushed but isnt.
  2143. * We can detect this by seeing if the template is marked as being a Zombie. If it is
  2144. * we must mark this engine as being a zombie too, so it wont be returned to the FSQ when
  2145. * it is done running. Note that once we add this engine to the RSL we are "safe", because
  2146. * any flushes after that point would correctly zombify the engine.
  2147. */
  2148. EnterCriticalSection(&m_csRSL);
  2149. if (pTemplate->FIsZombie())
  2150. {
  2151. // The template asking for this engine is obsolete. Make sure that no
  2152. // one else will use this engine by marking it zombie
  2153. DBGPRINTF((DBG_CONTEXT, "[CScriptManager] Zombie template found.\n"));
  2154. (*ppSE)->Zombify();
  2155. }
  2156. (VOID)m_htRSL.AddElem(pASEElem);
  2157. LeaveCriticalSection(&m_csRSL);
  2158. // Set the time that the engine was handed out so we will know when to kill it
  2159. pASE->SetTimeStarted(time(NULL));
  2160. LFail:
  2161. Assert(SUCCEEDED(hr) || hr == TYPE_E_ELEMENTNOTFOUND);
  2162. return(hr);
  2163. }
  2164. /*===================================================================
  2165. CScriptManager::ReturnEngineToCache
  2166. Caller is done with the engine. Return it to the cache.
  2167. Returns:
  2168. HRESULT. S_OK on success.
  2169. Side effects:
  2170. Potentially allocates memory.
  2171. ===================================================================*/
  2172. HRESULT CScriptManager::ReturnEngineToCache
  2173. (
  2174. CScriptEngine **ppSE,
  2175. CAppln *pAppln
  2176. )
  2177. {
  2178. HRESULT hr = S_OK;
  2179. CASEElem *pASEElem;
  2180. CActiveScriptEngine *pASE;
  2181. Assert(ppSE != NULL);
  2182. Assert(*ppSE != NULL);
  2183. pASE = static_cast<CActiveScriptEngine *>(*ppSE);
  2184. // Remove the engine from the Running Script List
  2185. EnterCriticalSection( &m_csRSL );
  2186. hr = FindASEElemInList(static_cast<CActiveScriptEngine *>(*ppSE), /*fFSQ*/FALSE, &pASEElem);
  2187. if (FAILED(hr)) {
  2188. LeaveCriticalSection( &m_csRSL );
  2189. goto LExit;
  2190. }
  2191. // Note: Sometimes a script will not be in the RSL! This occurs when
  2192. // we are reusing a script that is stored in the CTemplate object.
  2193. // (When the script is reloaded, it is retrieved directly from the
  2194. // template, bypassing our code which places engines on the RSL)
  2195. //
  2196. if (pASEElem != NULL)
  2197. m_htRSL.RemoveElem(pASEElem);
  2198. LeaveCriticalSection( &m_csRSL );
  2199. /*
  2200. * If the engine was zombified while it was running, deallocate it.
  2201. * Or, if there was a GPF while then engine was running, then it might
  2202. * be in a corrupted state (bug 1225). Also remove it in that case.
  2203. */
  2204. pASE = static_cast<CActiveScriptEngine *>(*ppSE);
  2205. if (pASE->FIsZombie() || pASE->FIsCorrupted()) {
  2206. delete pASEElem;
  2207. pASE->FinalRelease();
  2208. goto LExit;
  2209. }
  2210. HRESULT hrT;
  2211. /*
  2212. * We want to reuse this engine. Try to return it to the "Uninitialized"
  2213. * state. Some engine languages arent able to do this. If it fails, deallocate
  2214. * the engine; it cant be reused.
  2215. */
  2216. hrT = pASE->ResetToUninitialized();
  2217. if (FAILED(hrT)) {
  2218. // Engine doesnt support this, sigh. Deallocate and continue.
  2219. delete pASEElem;
  2220. pASE->FinalRelease();
  2221. goto LExit;
  2222. }
  2223. // Get the pTemplate for this engine
  2224. CTemplate *pTemplate;
  2225. DWORD dwEngine;
  2226. pASE->GetDebugDocument(&pTemplate, &dwEngine);
  2227. // CONSIDER: Better strategy for keeping live scripts?
  2228. // Only remember good (no compiler errors) scripts in the template
  2229. if (pAppln->FDebuggable() && pASE->FFullyLoaded() && pTemplate && !pTemplate->FDontAttach()) {
  2230. // Template is marked as incomplete (invalid) when change notification occurs
  2231. // and template is flushed from cache. In this case, don't cache in CTemplate
  2232. // object!
  2233. if (pTemplate->FIsValid())
  2234. pTemplate->AddScript(dwEngine, pASE);
  2235. // NOTE: Always release the scripting engine. Exec code is structured so that it
  2236. // consumes a reference (either through GetEngine() or CTemplate::GetActiveScript())
  2237. // and assumes that ReturnToCache will release its reference.
  2238. // CONSIDER: Bad design. Caller should do the release
  2239. delete pASEElem;
  2240. pASE->Release();
  2241. }
  2242. else {
  2243. // reuse engines, not debugging
  2244. /*
  2245. * We removed the engine from the RSL, put it onto the FSQ for potential reuse.
  2246. *
  2247. * In certain multi-threaded change-notify situations it is possible
  2248. * that the template was flushed (zombied) while we were in the middle
  2249. * of returning this engine to the cache. That is to say, between the time
  2250. * that we took the engine off the RSL and when we are going to put it on the FSQ
  2251. * it might have been flushed. In that case, this engine should
  2252. * not go into the FSQ, but should be deleted instead. Check for that case.
  2253. * Do that inside the FSQ CS so that we are safe from the template getting zombied
  2254. * after we do the test but before the engine goes into the FSQ. Also, do not
  2255. * put template on FSQ during shut down phase, since FSQ may go away soon, and
  2256. * the final destination of the engine is FinalRelease() anyway.
  2257. */
  2258. EnterCriticalSection(&m_csFSQ);
  2259. if (!pTemplate->FIsZombie() && !IsShutDownInProgress()) {
  2260. AddToFSQ(pASEElem);
  2261. }
  2262. else {
  2263. delete pASEElem;
  2264. pASE->FinalRelease();
  2265. }
  2266. LeaveCriticalSection(&m_csFSQ);
  2267. }
  2268. LExit:
  2269. return(hr);
  2270. }
  2271. /*===================================================================
  2272. CScriptManager::FlushCache
  2273. A script has been edited; cached versions must be discarded
  2274. Returns:
  2275. HRESULT. S_OK on success.
  2276. Side effects:
  2277. Potentially allocates memory.
  2278. ===================================================================*/
  2279. HRESULT CScriptManager::FlushCache
  2280. (
  2281. LPCTSTR szTemplateName
  2282. )
  2283. {
  2284. HRESULT hr = S_OK;
  2285. CASEElem *pASEElem;
  2286. CASEElem *pASEElemNext = NULL;
  2287. CActiveScriptEngine *pASE;
  2288. // There exists a condition during shutdown where the script
  2289. // manager could be uninited and still have calls made on it.
  2290. // This occurs when there are flush threads outstanding for
  2291. // the template cache during shutdown. Since the script manager
  2292. // is uninited before the template manager, where a check is made
  2293. // for active flush threads, the script manager indeed could be
  2294. // called after it is uninited.
  2295. if (m_fInited == FALSE)
  2296. return S_OK;
  2297. EnterCriticalSection(&m_csRSL);
  2298. EnterCriticalSection(&m_csFSQ);
  2299. // First Zombify engines on the RSL of the given name.
  2300. // Note: must explicitly loop through all elements, since the hash table implementation
  2301. // doesnt support FindNext to find subsequent elements of the same name. Repeated
  2302. // calls to find returns the same element over and over
  2303. // CONSIDER: I have written a custom FindElem. Consider using it.
  2304. pASEElem = (CASEElem *)m_htRSL.Head();
  2305. while (pASEElem != NULL)
  2306. {
  2307. pASEElemNext = (CASEElem *)pASEElem->m_pNext;
  2308. pASE = pASEElem->PASE();
  2309. if (_tcsicmp(pASE->SzTemplateName(), szTemplateName) == 0)
  2310. {
  2311. pASE->Zombify();
  2312. #ifndef PERF_DISABLE
  2313. g_PerfData.Incr_ENGINEFLUSHES();
  2314. #endif
  2315. }
  2316. pASEElem = pASEElemNext;
  2317. }
  2318. // Now throw out engines on the FSQ of the given name
  2319. // Delete any item with the given name (may be several)
  2320. pASEElem = (CASEElem *)m_htFSQ.Head();
  2321. while (pASEElem != NULL)
  2322. {
  2323. pASEElemNext = (CASEElem *)pASEElem->m_pNext;
  2324. pASE = pASEElem->PASE();
  2325. if (_tcsicmp(pASE->SzTemplateName(), szTemplateName) == 0)
  2326. {
  2327. (VOID)m_htFSQ.RemoveElem(pASEElem);
  2328. #ifndef PERF_DISABLE
  2329. g_PerfData.Decr_SCRIPTFREEENG();
  2330. g_PerfData.Incr_ENGINEFLUSHES();
  2331. #endif
  2332. pASE->FinalRelease();
  2333. delete pASEElem;
  2334. }
  2335. pASEElem = pASEElemNext;
  2336. }
  2337. LeaveCriticalSection(&m_csFSQ);
  2338. LeaveCriticalSection(&m_csRSL);
  2339. return(hr);
  2340. }
  2341. /*===================================================================
  2342. CScriptManager::FlushAll
  2343. global.asa changed, everything must go
  2344. Returns:
  2345. HRESULT. S_OK on success.
  2346. Side effects:
  2347. Potentially allocates memory.
  2348. ===================================================================*/
  2349. HRESULT CScriptManager::FlushAll
  2350. (
  2351. )
  2352. {
  2353. HRESULT hr = S_OK;
  2354. CASEElem *pASEElem;
  2355. CASEElem *pASEElemNext = NULL;
  2356. CActiveScriptEngine *pASE;
  2357. AssertValid();
  2358. EnterCriticalSection(&m_csRSL);
  2359. EnterCriticalSection(&m_csFSQ);
  2360. // First Zombify all engines on the RSL
  2361. // Note: must explicitly loop through all elements, since the hash table implementation
  2362. // doesnt support FindNext to find subsequent elements of the same name. Repeated
  2363. // calls to find returns the same element over and over
  2364. // CONSIDER: I have written a custom FindElem. Consider using it.
  2365. pASEElem = (CASEElem *)m_htRSL.Head();
  2366. while (pASEElem != NULL)
  2367. {
  2368. pASEElemNext = (CASEElem *)pASEElem->m_pNext;
  2369. pASEElem->PASE()->Zombify();
  2370. #ifndef PERF_DISABLE
  2371. g_PerfData.Incr_ENGINEFLUSHES();
  2372. #endif
  2373. pASEElem = pASEElemNext;
  2374. }
  2375. // Now throw out engines on the FSQ
  2376. pASEElem = (CASEElem *)m_htFSQ.Head();
  2377. while (pASEElem != NULL)
  2378. {
  2379. pASEElemNext = (CASEElem *)pASEElem->m_pNext;
  2380. (VOID)m_htFSQ.RemoveElem(pASEElem);
  2381. pASEElem->PASE()->FinalRelease();
  2382. delete pASEElem;
  2383. #ifndef PERF_DISABLE
  2384. g_PerfData.Incr_ENGINEFLUSHES();
  2385. g_PerfData.Decr_SCRIPTFREEENG();
  2386. #endif
  2387. pASEElem = pASEElemNext;
  2388. }
  2389. LeaveCriticalSection(&m_csFSQ);
  2390. LeaveCriticalSection(&m_csRSL);
  2391. return(hr);
  2392. }
  2393. /*===================================================================
  2394. CScriptManager::GetDebugScript
  2395. Try to find an engine via template pointer, and query for IActiveScriptDebug,
  2396. in the RSL.
  2397. Returns:
  2398. An AddRef'ed copy of the script engine if found, or NULL if not.
  2399. ===================================================================*/
  2400. IActiveScriptDebug *
  2401. CScriptManager::GetDebugScript
  2402. (
  2403. CTemplate *pTemplate,
  2404. DWORD dwSourceContext
  2405. )
  2406. {
  2407. EnterCriticalSection(&m_csRSL);
  2408. CASEElem *pASEElem = static_cast<CASEElem *>(m_htRSL.Head());
  2409. while (pASEElem != NULL)
  2410. {
  2411. CTemplate *pScriptTemplate = NULL;
  2412. DWORD dwScriptSourceContext = -1;
  2413. CActiveScriptEngine *pASE = pASEElem->PASE();
  2414. pASE->GetDebugDocument(&pScriptTemplate, &dwScriptSourceContext);
  2415. if (pTemplate == pScriptTemplate && dwSourceContext == dwScriptSourceContext)
  2416. {
  2417. IActiveScript *pActiveScript = pASE->GetActiveScript();
  2418. void *pDebugScript;
  2419. if (SUCCEEDED(pActiveScript->QueryInterface(IID_IActiveScriptDebug, &pDebugScript)))
  2420. {
  2421. pASE->IsBeingDebugged();
  2422. LeaveCriticalSection(&m_csRSL);
  2423. return reinterpret_cast<IActiveScriptDebug *>(pDebugScript);
  2424. }
  2425. else
  2426. {
  2427. LeaveCriticalSection(&m_csRSL);
  2428. return NULL;
  2429. }
  2430. }
  2431. pASEElem = static_cast<CASEElem *>(pASEElem->m_pNext);
  2432. }
  2433. LeaveCriticalSection(&m_csRSL);
  2434. return NULL;
  2435. }
  2436. /*===================================================================
  2437. CScriptManager::FindEngineInList
  2438. Try to find an engine of the given name in the given list (either
  2439. the FSQ or the RSL.)
  2440. Returns:
  2441. HRESULT. S_OK on success.
  2442. ppASEElem contains found engine
  2443. ===================================================================*/
  2444. HRESULT CScriptManager::FindEngineInList
  2445. (
  2446. LPCTSTR szTemplateName, // Template we want an engine for
  2447. PROGLANG_ID progLangId, // what language do we want this engine for
  2448. DWORD dwInstanceID, // which server instance
  2449. BOOL fFSQ, // TRUE -> look in FSQ, FALSE -> look in RSQ
  2450. CASEElem **ppASEElem
  2451. )
  2452. {
  2453. HRESULT hr = S_OK;
  2454. DWORD cb;
  2455. AssertValid();
  2456. Assert(ppASEElem != NULL);
  2457. *ppASEElem = NULL;
  2458. // Key is name
  2459. cb = _tcslen(szTemplateName)*sizeof(TCHAR);
  2460. if (fFSQ)
  2461. {
  2462. EnterCriticalSection(&m_csFSQ);
  2463. *ppASEElem = static_cast<CASEElem *>(m_htFSQ.FindElem((VOID *)szTemplateName, cb,
  2464. progLangId, dwInstanceID, /*fCheckLoaded*/TRUE));
  2465. LeaveCriticalSection(&m_csFSQ);
  2466. }
  2467. else
  2468. {
  2469. EnterCriticalSection(&m_csRSL);
  2470. *ppASEElem = static_cast<CASEElem *>(m_htRSL.FindElem((VOID *)szTemplateName, cb,
  2471. progLangId, dwInstanceID, /*fCheckLoaded*/TRUE));
  2472. LeaveCriticalSection(&m_csRSL);
  2473. }
  2474. return(hr);
  2475. }
  2476. /*===================================================================
  2477. CScriptManager::FindASEElemInList
  2478. Given an ASE, find its corresponding ASEElem in the hash table. Note
  2479. that this is relatively slow because it is doing a linked list traversal
  2480. not a hash table lookup.
  2481. CONSIDER: create second hash table to do this quickly.
  2482. Returns:
  2483. HRESULT. S_OK on success.
  2484. ppASEElem contains found engine
  2485. ===================================================================*/
  2486. HRESULT CScriptManager::FindASEElemInList
  2487. (
  2488. CActiveScriptEngine *pASE,
  2489. BOOL fFSQ, // TRUE -> look in FSQ, FALSE -> look in RSQ
  2490. CASEElem **ppASEElem
  2491. )
  2492. {
  2493. HRESULT hr = S_OK;
  2494. CASEElem *pASEElem;
  2495. AssertValid();
  2496. Assert(pASE != NULL);
  2497. Assert(ppASEElem != NULL);
  2498. *ppASEElem = NULL;
  2499. if (fFSQ)
  2500. {
  2501. EnterCriticalSection(&m_csFSQ);
  2502. pASEElem = static_cast<CASEElem *>(m_htFSQ.Head());
  2503. }
  2504. else
  2505. {
  2506. EnterCriticalSection(&m_csRSL);
  2507. pASEElem = static_cast<CASEElem *>(m_htRSL.Head());
  2508. }
  2509. while (pASEElem != NULL)
  2510. {
  2511. if (pASE == pASEElem->PASE())
  2512. break;
  2513. pASEElem = static_cast<CASEElem *>(pASEElem->m_pNext);
  2514. }
  2515. if (fFSQ)
  2516. LeaveCriticalSection(&m_csFSQ);
  2517. else
  2518. LeaveCriticalSection(&m_csRSL);
  2519. *ppASEElem = pASEElem;
  2520. return(hr);
  2521. }
  2522. /*===================================================================
  2523. CScriptManager::KillOldEngines
  2524. Loops through all running engines and kills any engines which are "old"
  2525. (presumably they are stuck in an infinite loop in VBS.)
  2526. Returns:
  2527. HRESULT. S_OK on success.
  2528. Side effects:
  2529. Potentially kills off engines
  2530. ===================================================================*/
  2531. HRESULT CScriptManager::KillOldEngines
  2532. (
  2533. BOOLB fKillNow // Kill all engines now if TRUE
  2534. )
  2535. {
  2536. HRESULT hr = S_OK;
  2537. CASEElem *pASEElem, *pASEElemNext;
  2538. time_t timeNow;
  2539. time_t timeRunning;
  2540. CActiveScriptEngine *pASE;
  2541. AssertValid();
  2542. timeNow = time(NULL);
  2543. EnterCriticalSection(&m_csRSL);
  2544. pASEElemNext = static_cast<CASEElem *>(m_htRSL.Head());
  2545. /*
  2546. * Loop through each element. Turn it into an ASE.
  2547. * If it is older than cSeconds, then kill it.
  2548. */
  2549. while (pASEElemNext)
  2550. {
  2551. pASEElem = pASEElemNext;
  2552. pASEElemNext = static_cast<CASEElem *>(pASEElemNext->m_pNext);
  2553. pASE = pASEElem->PASE();
  2554. timeRunning = timeNow - pASE->TimeStarted();
  2555. if (TRUE == fKillNow || timeRunning >= pASE->GetTimeout())
  2556. {
  2557. // Too old. Kill it.
  2558. pASE->InterruptScript();
  2559. }
  2560. }
  2561. LeaveCriticalSection(&m_csRSL);
  2562. return(hr);
  2563. }
  2564. /*===================================================================
  2565. CScriptManager::EmptyRunningScriptList
  2566. When we are going to shut down, the RSL must be empty. This routine
  2567. kills off all running engines, then waits up to 5 minutes
  2568. for the engines to leave the RSL. Added for Bug 1140
  2569. Returns:
  2570. HRESULT. S_OK on success.
  2571. Side effects:
  2572. Potentially kills off engines
  2573. ===================================================================*/
  2574. HRESULT CScriptManager::EmptyRunningScriptList
  2575. (
  2576. )
  2577. {
  2578. HRESULT hr;
  2579. UINT cTrys;
  2580. hr = KillOldEngines(TRUE);
  2581. Assert(SUCCEEDED(hr));
  2582. for (cTrys = 0; cTrys < 300; cTrys++)
  2583. {
  2584. if (static_cast<CASEElem *>(m_htRSL.Head()) == NULL)
  2585. break;
  2586. Sleep(1000); // sleep 1 seconds
  2587. }
  2588. return(S_OK);
  2589. }
  2590. /*===================================================================
  2591. CScriptManager::UnInitASEElems
  2592. Free engines in FSQ and RSL
  2593. Returns:
  2594. HRESULT. S_OK on success.
  2595. Side effects:
  2596. Frees memory
  2597. ===================================================================*/
  2598. HRESULT CScriptManager::UnInitASEElems()
  2599. {
  2600. CASEElem *pASEElem = NULL;
  2601. CASEElem *pASEElemNext = NULL;
  2602. // First the FSQ
  2603. EnterCriticalSection(&m_csFSQ);
  2604. pASEElem = static_cast<CASEElem *>(m_htFSQ.Head());
  2605. while (pASEElem != NULL)
  2606. {
  2607. pASEElemNext = static_cast<CASEElem *>(pASEElem->m_pNext);
  2608. pASEElem->PASE()->FinalRelease();
  2609. delete pASEElem;
  2610. pASEElem = pASEElemNext;
  2611. }
  2612. LeaveCriticalSection(&m_csFSQ);
  2613. /*
  2614. * Next the RSL (note: this really should be empty)
  2615. *
  2616. * Bug 1140: This is very dangerous, but we have no choice left at this point
  2617. */
  2618. EnterCriticalSection(&m_csRSL);
  2619. pASEElem = static_cast<CASEElem *>(m_htRSL.Head());
  2620. while (pASEElem != NULL)
  2621. {
  2622. pASEElemNext = static_cast<CASEElem *>(pASEElem->m_pNext);
  2623. pASEElem->PASE()->FinalRelease();
  2624. delete pASEElem;
  2625. pASEElem = pASEElemNext;
  2626. }
  2627. LeaveCriticalSection(&m_csRSL);
  2628. return(S_OK);
  2629. }
  2630. /*===================================================================
  2631. CScriptManager::AddToFSQ
  2632. Add the given ASEElem to the FSQ and to the front of the LRU list
  2633. Returns:
  2634. HRESULT. S_OK on success.
  2635. Side effects:
  2636. None.
  2637. ===================================================================*/
  2638. HRESULT CScriptManager::AddToFSQ
  2639. (
  2640. CASEElem *pASEElem
  2641. )
  2642. {
  2643. HRESULT hr = S_OK;
  2644. Assert(pASEElem != NULL);
  2645. // If CacheMax is 0, this is a NoOp
  2646. if (Glob(dwScriptEngineCacheMax) <= 0)
  2647. {
  2648. // delete the passed in ASEElem because it wont be saved
  2649. pASEElem->PASE()->FinalRelease();
  2650. delete pASEElem;
  2651. return(S_OK);
  2652. }
  2653. EnterCriticalSection(&m_csFSQ);
  2654. // Add the element to the FSQ
  2655. (VOID)m_htFSQ.AddElem(pASEElem);
  2656. #ifndef PERF_DISABLE
  2657. g_PerfData.Incr_SCRIPTFREEENG();
  2658. #endif
  2659. // Check the FSQ LRU too see if it is too long
  2660. CheckFSQLRU();
  2661. LeaveCriticalSection(&m_csFSQ);
  2662. return(hr);
  2663. }
  2664. /*===================================================================
  2665. CScriptManager::CheckFSQLRU
  2666. Check to see if the FSQ is too long, and if so throw out the LRU engine
  2667. WARNING: Caller must enter FSQ critical section before calling
  2668. Returns:
  2669. HRESULT. S_OK on success.
  2670. Side effects:
  2671. None.
  2672. ===================================================================*/
  2673. HRESULT CScriptManager::CheckFSQLRU()
  2674. {
  2675. HRESULT hr = S_OK;
  2676. CASEElem *pASEElemOld;
  2677. CActiveScriptEngine *pASE;
  2678. // If the list isnt too long, noop
  2679. if (m_htFSQ.Count() <= Glob(dwScriptEngineCacheMax) || Glob(dwScriptEngineCacheMax) == 0xFFFFFFFF)
  2680. return(S_OK);
  2681. // FSQLRU list is too long, remove oldest
  2682. Assert (! m_htFSQ.FLruElemIsEmpty( m_htFSQ.End() ));
  2683. pASEElemOld = static_cast<CASEElem *>(m_htFSQ.RemoveElem(m_htFSQ.End()));
  2684. Assert(pASEElemOld != NULL);
  2685. pASE = pASEElemOld->PASE();
  2686. #ifndef PERF_DISABLE
  2687. g_PerfData.Decr_SCRIPTFREEENG();
  2688. #endif
  2689. // Delete the engine
  2690. delete pASEElemOld;
  2691. pASE->FinalRelease();
  2692. return(hr);
  2693. }
  2694. /*===================================================================
  2695. CScriptManager::UnInitPLL
  2696. Free the names of the script engines
  2697. Returns:
  2698. HRESULT. S_OK on success.
  2699. Side effects:
  2700. Frees memory
  2701. ===================================================================*/
  2702. HRESULT CScriptManager::UnInitPLL()
  2703. {
  2704. CPLLElem *pPLLElem = NULL;
  2705. CPLLElem *pPLLElemNext = NULL;
  2706. pPLLElem = (CPLLElem *)m_hTPLL.Head();
  2707. while (pPLLElem != NULL)
  2708. {
  2709. pPLLElemNext = (CPLLElem *)pPLLElem->m_pNext;
  2710. if (pPLLElem->m_pKey != NULL)
  2711. free((CHAR *)(pPLLElem->m_pKey));
  2712. pPLLElem->m_pKey = NULL;
  2713. delete pPLLElem;
  2714. pPLLElem = pPLLElemNext;
  2715. }
  2716. return(S_OK);
  2717. }
  2718. /*===================================================================
  2719. CScriptManager::ProgLangIdOfLangName
  2720. Given a programming language name, get the CLSID of the ActiveX Scripting
  2721. Engine which runs that language.
  2722. WARNING: Needs to look in the registry for this info. Maybe slow
  2723. Returns:
  2724. HRESULT. S_OK on success.
  2725. Side effects:
  2726. None.
  2727. ===================================================================*/
  2728. HRESULT CScriptManager::ProgLangIdOfLangName
  2729. (
  2730. LPCSTR szProgLang, // The programming lang of the script
  2731. PROGLANG_ID *pProgLangId // The programming language id
  2732. )
  2733. {
  2734. HRESULT hr = S_OK;
  2735. CPLLElem *pPLLElem;
  2736. AssertValid();
  2737. EnterCriticalSection(&m_cSPLL);
  2738. pPLLElem = (CPLLElem *) m_hTPLL.FindElem((VOID *)szProgLang, strlen(szProgLang));
  2739. if (pPLLElem != NULL)
  2740. {
  2741. *pProgLangId = pPLLElem->ProgLangId();
  2742. }
  2743. else
  2744. {
  2745. // Not already in list, look in registry
  2746. hr = GetProgLangIdOfName(szProgLang, pProgLangId);
  2747. if (FAILED(hr))
  2748. {
  2749. hr = TYPE_E_ELEMENTNOTFOUND;
  2750. goto LExit;
  2751. }
  2752. // Add it to the list so we dont have to re-look it up
  2753. hr = AddProgLangToPLL((CHAR *)szProgLang, *pProgLangId);
  2754. if (FAILED(hr))
  2755. goto LExit;
  2756. }
  2757. LExit:
  2758. LeaveCriticalSection(&m_cSPLL);
  2759. return(hr);
  2760. }
  2761. /*===================================================================
  2762. CScriptManager::AddProgLangToPLL
  2763. Keep list of programming language CLSIDs so we dont have to look
  2764. them up every time. Add the given programming language name/id pair
  2765. to the Programming Language List.
  2766. Returns:
  2767. HRESULT. S_OK on success.
  2768. Side effects:
  2769. None.
  2770. ===================================================================*/
  2771. HRESULT CScriptManager::AddProgLangToPLL
  2772. (
  2773. CHAR *szProgLangName,
  2774. PROGLANG_ID progLangId
  2775. )
  2776. {
  2777. HRESULT hr;
  2778. CPLLElem *pPLLElem = NULL;
  2779. // Put the language clsid on the Programming Language List
  2780. pPLLElem = new CPLLElem;
  2781. if (!pPLLElem)
  2782. {
  2783. hr = E_OUTOFMEMORY;
  2784. goto LFail;
  2785. }
  2786. hr = pPLLElem->Init(szProgLangName, progLangId);
  2787. if (FAILED(hr))
  2788. {
  2789. Assert(FALSE); // Shouldnt fail
  2790. goto LFail;
  2791. }
  2792. EnterCriticalSection(&m_cSPLL);
  2793. (VOID)m_hTPLL.AddElem(pPLLElem);
  2794. LeaveCriticalSection(&m_cSPLL);
  2795. LFail:
  2796. return(hr);
  2797. }
  2798. /*===================================================================
  2799. CScriptManager::ScriptKillerSchedulerCallback
  2800. Static method implements ATQ scheduler callback functions.
  2801. Replaces script killer thread
  2802. Parameters:
  2803. void *pv context pointer (points to script mgr)
  2804. Returns:
  2805. Side effects:
  2806. None.
  2807. ===================================================================*/
  2808. void WINAPI CScriptManager::ScriptKillerSchedulerCallback
  2809. (
  2810. void *pv
  2811. )
  2812. {
  2813. if (IsShutDownInProgress())
  2814. return;
  2815. Assert(pv);
  2816. CScriptManager *pScriptMgr = reinterpret_cast<CScriptManager *>(pv);
  2817. if (pScriptMgr->m_fInited)
  2818. {
  2819. pScriptMgr->KillOldEngines();
  2820. }
  2821. }
  2822. #ifdef DBG
  2823. /*===================================================================
  2824. CScriptManager::AssertValid
  2825. Test to make sure that the CScriptManager object is currently correctly formed
  2826. and assert if it is not.
  2827. Returns:
  2828. Side effects:
  2829. None.
  2830. ===================================================================*/
  2831. VOID CScriptManager::AssertValid() const
  2832. {
  2833. Assert(m_fInited);
  2834. }
  2835. #endif // DBG
  2836. /*
  2837. *
  2838. *
  2839. *
  2840. * C A S E E l e m
  2841. *
  2842. * Active Script Engine Elements
  2843. *
  2844. *
  2845. *
  2846. */
  2847. /*===================================================================
  2848. CASEElem::~CASEElem
  2849. Destructor for CASEElem object.
  2850. Returns:
  2851. Nothing
  2852. Side effects:
  2853. None
  2854. ===================================================================*/
  2855. CASEElem::~CASEElem()
  2856. {
  2857. }
  2858. /*===================================================================
  2859. CASEElem::Init
  2860. Init the Active Script Engine Elem. This must only be called once.
  2861. Returns:
  2862. HRESULT. S_OK on success.
  2863. Side effects:
  2864. None.
  2865. ===================================================================*/
  2866. HRESULT CASEElem::Init
  2867. (
  2868. CActiveScriptEngine *pASE
  2869. )
  2870. {
  2871. HRESULT hr = S_OK;
  2872. TCHAR *szT = pASE->SzTemplateName();
  2873. if (szT == NULL)
  2874. {
  2875. Assert(FALSE);
  2876. return(E_FAIL);
  2877. }
  2878. // Key is name
  2879. hr = CLinkElem::Init((LPVOID) szT, _tcslen(szT)*sizeof(TCHAR));
  2880. if (FAILED(hr))
  2881. {
  2882. Assert(FALSE); // Shouldnt fail
  2883. return(hr);
  2884. }
  2885. m_pASE = pASE;
  2886. return(hr);
  2887. }
  2888. /*
  2889. *
  2890. *
  2891. *
  2892. * C P L L E l e m
  2893. *
  2894. * Programming Language List Element
  2895. *
  2896. *
  2897. *
  2898. *
  2899. */
  2900. /*===================================================================
  2901. CPLLElem::~CPLLElem
  2902. Destructor for CPLLElem object.
  2903. Returns:
  2904. Nothing
  2905. Side effects:
  2906. Deallocates memory
  2907. ===================================================================*/
  2908. CPLLElem::~CPLLElem()
  2909. {
  2910. CHAR *szT;
  2911. // Free the memory allocated for the key string
  2912. szT = (CHAR *)m_pKey;
  2913. if (szT != NULL)
  2914. free(szT);
  2915. m_pKey = NULL;
  2916. }
  2917. /*===================================================================
  2918. CPLLElem::Init
  2919. Init the Prog Lang Elem. This must only be called once.
  2920. Returns:
  2921. HRESULT. S_OK on success.
  2922. Side effects:
  2923. Allocates memory
  2924. ===================================================================*/
  2925. HRESULT CPLLElem::Init
  2926. (
  2927. CHAR *szProgLangName,
  2928. PROGLANG_ID progLangId
  2929. )
  2930. {
  2931. HRESULT hr = S_OK;
  2932. CHAR *szT;
  2933. UINT cch;
  2934. if (szProgLangName == NULL)
  2935. {
  2936. Assert(FALSE);
  2937. return(E_FAIL);
  2938. }
  2939. cch = strlen(szProgLangName);
  2940. szT = (CHAR *)malloc(cch+1);
  2941. if (!szT)
  2942. {
  2943. return(E_OUTOFMEMORY);
  2944. }
  2945. strcpy(szT, szProgLangName);
  2946. hr = CLinkElem::Init((LPVOID) szT, cch);
  2947. if (FAILED(hr))
  2948. {
  2949. Assert(FALSE); // Shouldnt fail
  2950. free(szT);
  2951. return(hr);
  2952. }
  2953. m_ProgLangId = progLangId;
  2954. return(hr);
  2955. }
  2956. /*===================================================================
  2957. GetProgLangIdOfName
  2958. Given the name of a programming language, get its programming
  2959. language Id from the registry.
  2960. Returns:
  2961. HRESULT. S_OK on success.
  2962. Side effects:
  2963. None.
  2964. ===================================================================*/
  2965. HRESULT GetProgLangIdOfName
  2966. (
  2967. LPCSTR szProgLangName,
  2968. PROGLANG_ID *pProgLangId
  2969. )
  2970. {
  2971. HRESULT hr = S_OK;
  2972. LONG lT;
  2973. HKEY hkeyRoot, hkeyCLSID;
  2974. DWORD dwType;
  2975. CLSID clsid;
  2976. CHAR szClsid[40];
  2977. DWORD cbData;
  2978. LPOLESTR strClsid;
  2979. CMBCSToWChar convStr;
  2980. // The programming language id is really the CLSID of the scripting engine
  2981. // It is in the registry under HKEY_CLASSES_ROOT. Under the script name,
  2982. // there is a key for "CLSID". The CLSID is a value under the
  2983. // engine name. E.g. \HKEY_CLASSES_ROOT\VBScript\CLSID
  2984. lT = RegOpenKeyExA(HKEY_CLASSES_ROOT, szProgLangName, 0,
  2985. KEY_READ, &hkeyRoot);
  2986. if (lT != ERROR_SUCCESS)
  2987. return(HRESULT_FROM_WIN32(lT));
  2988. lT = RegOpenKeyExA(hkeyRoot, "CLSID", 0,
  2989. KEY_READ, &hkeyCLSID);
  2990. RegCloseKey(hkeyRoot);
  2991. if (lT != ERROR_SUCCESS)
  2992. return(HRESULT_FROM_WIN32(lT));
  2993. cbData = sizeof(szClsid);
  2994. lT = RegQueryValueExA(hkeyCLSID, NULL, 0, &dwType, (BYTE *)szClsid, &cbData);
  2995. if (lT != ERROR_SUCCESS)
  2996. {
  2997. hr = HRESULT_FROM_WIN32(lT);
  2998. goto lExit;
  2999. }
  3000. Assert(cbData <= sizeof(szClsid));
  3001. // What we got back was the GUID as a string (e.g. {089999-444....}). Convert to a CLSID
  3002. convStr.Init(szClsid);
  3003. strClsid = convStr.GetString();
  3004. hr = CLSIDFromString(strClsid, &clsid);
  3005. *pProgLangId = clsid;
  3006. lExit:
  3007. RegCloseKey(hkeyCLSID);
  3008. return(hr);
  3009. }
  3010. /*
  3011. *
  3012. *
  3013. *
  3014. * C S c r i p t i n g N a m e s p a c e
  3015. *
  3016. * Scripting namespace object
  3017. *
  3018. *
  3019. *
  3020. */
  3021. /*===================================================================
  3022. CScriptingNamespace::CScriptingNamespace
  3023. Constructor for CScriptingNamespace object.
  3024. Returns:
  3025. Nothing
  3026. Side effects:
  3027. None
  3028. ===================================================================*/
  3029. CScriptingNamespace::CScriptingNamespace()
  3030. : m_fInited(FALSE), m_cRef(1), m_cEngDispMac(0)
  3031. {
  3032. }
  3033. /*===================================================================
  3034. CScriptingNamespace::~CScriptingNamespace
  3035. Destructor for CScriptingNamespace object.
  3036. Returns:
  3037. Nothing
  3038. Side effects:
  3039. Deallocates memory
  3040. ===================================================================*/
  3041. CScriptingNamespace::~CScriptingNamespace()
  3042. {
  3043. UnInit();
  3044. }
  3045. /*===================================================================
  3046. CScriptingNamespace::Init
  3047. Init the CScriptingNamespace object.
  3048. Returns:
  3049. S_OK on success
  3050. ===================================================================*/
  3051. HRESULT CScriptingNamespace::Init()
  3052. {
  3053. Assert(m_fInited == FALSE);
  3054. m_fInited = TRUE;
  3055. AssertValid();
  3056. return(S_OK);
  3057. }
  3058. /*===================================================================
  3059. CScriptingNamespace::UnInit
  3060. Free the script engine dispatch's
  3061. Returns:
  3062. HRESULT. S_OK on success.
  3063. Side effects:
  3064. Frees memory
  3065. ===================================================================*/
  3066. HRESULT CScriptingNamespace::UnInit()
  3067. {
  3068. static const char *_pFuncName = "CScriptingNamespace::UnInit()";
  3069. CEngineDispElem *pElem = NULL;
  3070. ENGDISPBUCKET *pBucket = NULL;
  3071. if (!m_fInited)
  3072. return(S_OK);
  3073. while (!m_listSE.FIsEmpty())
  3074. {
  3075. pElem = static_cast<CEngineDispElem *>(m_listSE.PNext());
  3076. TRYCATCH_NOHITOBJ(pElem->m_pDisp->Release(),"IScriptDispatch::Release()");
  3077. if (pElem->m_pDispEx) {
  3078. TRYCATCH_NOHITOBJ(pElem->m_pDispEx->Release(),"IScriptDispatchEx::Release()");
  3079. }
  3080. delete pElem;
  3081. }
  3082. while (!m_listEngDisp.FIsEmpty())
  3083. {
  3084. pBucket = static_cast<ENGDISPBUCKET *>(m_listEngDisp.PNext());
  3085. delete pBucket;
  3086. }
  3087. m_cEngDispMac = 0;
  3088. m_fInited = FALSE;
  3089. return(S_OK);
  3090. }
  3091. /*===================================================================
  3092. CScriptingNamespace::ReInit
  3093. Reinit the scripting namespace object
  3094. Returns:
  3095. HRESULT. S_OK on success.
  3096. Side effects:
  3097. Frees memory
  3098. ===================================================================*/
  3099. HRESULT CScriptingNamespace::ReInit()
  3100. {
  3101. HRESULT hr;
  3102. hr = UnInit();
  3103. if (SUCCEEDED(hr))
  3104. hr = Init();
  3105. return(hr);
  3106. }
  3107. /*===================================================================
  3108. CScriptingNamespace::AddEngineToNamespace
  3109. Add an engine to the list of engines
  3110. Returns:
  3111. S_OK on success
  3112. ===================================================================*/
  3113. HRESULT CScriptingNamespace::AddEngineToNamespace(CActiveScriptEngine *pASE)
  3114. {
  3115. static const char *_pFuncName = "CScriptingNamespace::AddEngineToNamespace()";
  3116. HRESULT hr;
  3117. IDispatch *pDisp = NULL;
  3118. CEngineDispElem *pElem;
  3119. AssertValid();
  3120. Assert(pASE != NULL);
  3121. pASE->AssertValid();
  3122. TRYCATCH_HR_NOHITOBJ(pASE->GetActiveScript()->GetScriptDispatch(NULL, &pDisp),
  3123. hr,
  3124. "IActiveScript::GetScriptDispatch()"); // FYI - does addref
  3125. if (FAILED(hr))
  3126. {
  3127. goto LFail;
  3128. }
  3129. else
  3130. if (pDisp == NULL)
  3131. {
  3132. hr = E_FAIL;
  3133. goto LFail;
  3134. }
  3135. // Add the engine to the engine hash table.
  3136. pElem = new CEngineDispElem;
  3137. if (pElem == NULL)
  3138. {
  3139. hr = E_OUTOFMEMORY;
  3140. goto LFail;
  3141. }
  3142. pElem->m_pDisp = pDisp;
  3143. pElem->m_pDispEx = NULL;
  3144. // QI for IDispatchEx if available
  3145. TRYCATCH_NOHITOBJ(pDisp->QueryInterface(IID_IDispatchEx, (void **)&pElem->m_pDispEx),"IScriptDispatch::QueryInterface()");
  3146. pElem->AppendTo(m_listSE);
  3147. return(S_OK);
  3148. LFail:
  3149. if (pDisp) {
  3150. TRYCATCH_NOHITOBJ(pDisp->Release(),"IScriptDispatch::Release()");
  3151. }
  3152. return(hr);
  3153. }
  3154. /*===================================================================
  3155. CScriptingNamespace::QueryInterface
  3156. CScriptingNamespace::AddRef
  3157. CScriptingNamespace::Release
  3158. IUnknown members for CScriptingNamespace object.
  3159. ===================================================================*/
  3160. STDMETHODIMP CScriptingNamespace::QueryInterface(REFIID iid, void **ppvObj)
  3161. {
  3162. AssertValid();
  3163. if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IDispatchEx)
  3164. {
  3165. *ppvObj = this;
  3166. AddRef();
  3167. return S_OK;
  3168. }
  3169. *ppvObj = NULL;
  3170. return E_NOINTERFACE;
  3171. }
  3172. STDMETHODIMP_(ULONG) CScriptingNamespace::AddRef(void)
  3173. {
  3174. AssertValid();
  3175. return ++m_cRef;
  3176. }
  3177. STDMETHODIMP_(ULONG) CScriptingNamespace::Release(void)
  3178. {
  3179. if (--m_cRef > 0)
  3180. return m_cRef;
  3181. delete this;
  3182. return 0;
  3183. }
  3184. /*===================================================================
  3185. CScriptingNamespace::GetTypeInfoCount
  3186. We have no typeinfo, so 0.
  3187. Parameters:
  3188. pcInfo UINT * to the location to receive
  3189. the count of interfaces.
  3190. Return Value:
  3191. HRESULT S_OK or a general error code.
  3192. ===================================================================*/
  3193. STDMETHODIMP CScriptingNamespace::GetTypeInfoCount(UINT *pcInfo)
  3194. {
  3195. AssertValid();
  3196. *pcInfo = 0;
  3197. return S_OK;
  3198. }
  3199. /*===================================================================
  3200. CScriptingNamespace::GetTypeInfo
  3201. We dont have a typeinfo
  3202. Parameters:
  3203. itInfo UINT reserved. Must be zero.
  3204. lcid LCID providing the locale for the type
  3205. information. If the object does not support
  3206. localization, this is ignored.
  3207. ppITypeInfo ITypeInfo ** in which to store the ITypeInfo
  3208. interface for the object.
  3209. Return Value:
  3210. HRESULT S_OK or a general error code.
  3211. ===================================================================*/
  3212. STDMETHODIMP CScriptingNamespace::GetTypeInfo
  3213. (
  3214. UINT itInfo,
  3215. LCID lcid,
  3216. ITypeInfo **ppITypeInfo
  3217. )
  3218. {
  3219. AssertValid();
  3220. *ppITypeInfo = NULL;
  3221. return(E_NOTIMPL);
  3222. }
  3223. /*===================================================================
  3224. CScriptingNamespace::GetIDsOfNames
  3225. Looks through all the engines we know about, calling GetIdsOfNames on
  3226. them till we find the requested name.
  3227. Parameters:
  3228. riid REFIID reserved. Must be IID_NULL.
  3229. rgszNames OLECHAR ** pointing to the array of names to be mapped.
  3230. cNames UINT number of names to be mapped.
  3231. lcid LCID of the locale.
  3232. rgDispID DISPID * caller allocated array containing IDs
  3233. corresponging to those names in rgszNames.
  3234. Return Value:
  3235. HRESULT S_OK or a general error code.
  3236. ===================================================================*/
  3237. STDMETHODIMP CScriptingNamespace::GetIDsOfNames
  3238. (
  3239. REFIID riid,
  3240. OLECHAR **rgszNames,
  3241. UINT cNames,
  3242. LCID lcid,
  3243. DISPID *rgDispID
  3244. )
  3245. {
  3246. static const char *_pFuncName = "CScriptingNamespace::GetIDsOfNames()";
  3247. HRESULT hr;
  3248. CEngineDispElem *pElem;
  3249. AssertValid();
  3250. if (IID_NULL != riid)
  3251. return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  3252. /*
  3253. * Loop through the engines we know about until we find the one that has the requested name
  3254. * (or hit the end of the list, in which case it is not found)
  3255. */
  3256. for (pElem = static_cast<CEngineDispElem *>(m_listSE.PNext());
  3257. pElem != &m_listSE;
  3258. pElem = static_cast<CEngineDispElem *>(pElem->PNext()))
  3259. {
  3260. Assert(pElem->m_pDisp != NULL);
  3261. TRYCATCH_HR_NOHITOBJ(pElem->m_pDisp->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispID),
  3262. hr,
  3263. "IScriptDispatch::GetIDsOfNames()");
  3264. if (SUCCEEDED(hr))
  3265. {
  3266. return CacheDispID(pElem, rgDispID[0], rgDispID);
  3267. }
  3268. }
  3269. return DISP_E_UNKNOWNNAME;
  3270. }
  3271. /*===================================================================
  3272. CScriptingNamespace::Invoke
  3273. Map the dispID to the correct engine, and pass the invoke on to that
  3274. engine.
  3275. Parameters:
  3276. dispID DISPID of the method or property of interest.
  3277. riid REFIID reserved, must be IID_NULL.
  3278. lcid LCID of the locale.
  3279. wFlags USHORT describing the context of the invocation.
  3280. pDispParams DISPPARAMS * to the array of arguments.
  3281. pVarResult VARIANT * in which to store the result. Is
  3282. NULL if the caller is not interested.
  3283. pExcepInfo EXCEPINFO * to exception information.
  3284. puArgErr UINT * in which to store the index of an
  3285. invalid parameter if DISP_E_TYPEMISMATCH
  3286. is returned.
  3287. Return Value:
  3288. HRESULT S_OK or a general error code.
  3289. ===================================================================*/
  3290. STDMETHODIMP CScriptingNamespace::Invoke
  3291. (
  3292. DISPID dispID,
  3293. REFIID riid,
  3294. LCID lcid,
  3295. unsigned short wFlags,
  3296. DISPPARAMS *pDispParams,
  3297. VARIANT *pVarResult,
  3298. EXCEPINFO *pExcepInfo,
  3299. UINT *puArgErr
  3300. )
  3301. {
  3302. static const char *_pFuncName = "CScriptingNamespace::Invoke()";
  3303. HRESULT hr;
  3304. ENGDISP *pEngDisp;
  3305. AssertValid();
  3306. // riid is supposed to be IID_NULL always
  3307. if (IID_NULL != riid)
  3308. return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  3309. // navigate to the correct ENGDISP structure
  3310. hr = FetchDispID(dispID, &pEngDisp);
  3311. if (FAILED(hr))
  3312. return hr;
  3313. Assert(pEngDisp->pDisp != NULL);
  3314. // invoke
  3315. TRYCATCH_HR_NOHITOBJ(pEngDisp->pDisp->Invoke
  3316. (
  3317. pEngDisp->dispid,
  3318. riid,
  3319. lcid,
  3320. wFlags,
  3321. pDispParams,
  3322. pVarResult,
  3323. pExcepInfo,
  3324. puArgErr
  3325. ),
  3326. hr,
  3327. "IScriptDispatch::Invoke()");
  3328. return hr;
  3329. }
  3330. /*===================================================================
  3331. CScriptingNamespace:: IDispatchEx implementation stubs
  3332. ===================================================================*/
  3333. STDMETHODIMP CScriptingNamespace::DeleteMemberByDispID(DISPID id)
  3334. {
  3335. return E_NOTIMPL;
  3336. }
  3337. STDMETHODIMP CScriptingNamespace::DeleteMemberByName(BSTR bstrName, DWORD grfdex)
  3338. {
  3339. return E_NOTIMPL;
  3340. }
  3341. STDMETHODIMP CScriptingNamespace::GetMemberName(DISPID id, BSTR *pbstrName)
  3342. {
  3343. return E_NOTIMPL;
  3344. }
  3345. STDMETHODIMP CScriptingNamespace::GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
  3346. {
  3347. return E_NOTIMPL;
  3348. }
  3349. STDMETHODIMP CScriptingNamespace::GetNameSpaceParent(IUnknown **ppunk)
  3350. {
  3351. return E_NOTIMPL;
  3352. }
  3353. STDMETHODIMP CScriptingNamespace::GetNextDispID(DWORD grfdex, DISPID id, DISPID *pid)
  3354. {
  3355. return E_NOTIMPL;
  3356. }
  3357. /*===================================================================
  3358. CScriptingNamespace::GetDispID
  3359. IDispatchEx replacement for GetIDsOfNames
  3360. ===================================================================*/
  3361. STDMETHODIMP CScriptingNamespace::GetDispID
  3362. (
  3363. BSTR bstrName,
  3364. DWORD grfdex,
  3365. DISPID *pid
  3366. )
  3367. {
  3368. static const char *_pFuncName = "CScriptingNamespace::GetDispID()";
  3369. HRESULT hr;
  3370. CEngineDispElem *pElem = NULL;
  3371. grfdex &= ~fdexNameEnsure; // engines shouldn't create new names
  3372. // Try IDispatchEx for all engines that have it
  3373. for (pElem = static_cast<CEngineDispElem *>(m_listSE.PNext());
  3374. pElem != &m_listSE;
  3375. pElem = static_cast<CEngineDispElem *>(pElem->PNext()))
  3376. {
  3377. if (pElem->m_pDispEx != NULL)
  3378. {
  3379. TRYCATCH_HR_NOHITOBJ(pElem->m_pDispEx->GetDispID(bstrName, grfdex, pid),
  3380. hr,
  3381. "IScriptDispatchEx::GetDispID()");
  3382. if (SUCCEEDED(hr))
  3383. {
  3384. return CacheDispID(pElem, *pid, pid);
  3385. }
  3386. }
  3387. }
  3388. // Try IDispatch for engines that don't have IDispatchEx
  3389. for (pElem = static_cast<CEngineDispElem *>(m_listSE.PNext());
  3390. pElem != &m_listSE;
  3391. pElem = static_cast<CEngineDispElem *>(pElem->PNext()))
  3392. {
  3393. if (pElem->m_pDispEx == NULL)
  3394. {
  3395. Assert(pElem->m_pDisp != NULL);
  3396. TRYCATCH_HR_NOHITOBJ(pElem->m_pDisp->GetIDsOfNames
  3397. (
  3398. IID_NULL,
  3399. &bstrName,
  3400. 1,
  3401. LOCALE_SYSTEM_DEFAULT,
  3402. pid
  3403. ),
  3404. hr,
  3405. "IScriptDispatch::GetIDsOfNames()");
  3406. if (SUCCEEDED(hr))
  3407. {
  3408. return CacheDispID(pElem, *pid, pid);
  3409. }
  3410. }
  3411. }
  3412. return DISP_E_UNKNOWNNAME;
  3413. }
  3414. /*===================================================================
  3415. CScriptingNamespace::Invoke
  3416. IDispatchEx replacement for Invoke
  3417. ===================================================================*/
  3418. STDMETHODIMP CScriptingNamespace::InvokeEx
  3419. (
  3420. DISPID id,
  3421. LCID lcid,
  3422. WORD wFlags,
  3423. DISPPARAMS *pdp,
  3424. VARIANT *pVarRes,
  3425. EXCEPINFO *pei,
  3426. IServiceProvider *pspCaller
  3427. )
  3428. {
  3429. static const char *_pFuncName = "CScriptingNamespace::InvokeEx()";
  3430. HRESULT hr;
  3431. ENGDISP *pEngDisp;
  3432. // navigate to the correct ENGDISP structure
  3433. hr = FetchDispID(id, &pEngDisp);
  3434. if (FAILED(hr))
  3435. return hr;
  3436. if (pEngDisp->pDispEx != NULL)
  3437. {
  3438. // InvokeEx if the engine supports IDispatchEx
  3439. TRYCATCH_HR_NOHITOBJ(pEngDisp->pDispEx->InvokeEx
  3440. (
  3441. pEngDisp->dispid,
  3442. lcid,
  3443. wFlags,
  3444. pdp,
  3445. pVarRes,
  3446. pei,
  3447. pspCaller
  3448. ),
  3449. hr,
  3450. "IScriptDispatchEx::InvokeEx()");
  3451. }
  3452. else
  3453. {
  3454. // use IDispatch::Invoke if the engine doesn't support IDispatchEx
  3455. Assert(pEngDisp->pDisp != NULL);
  3456. UINT uArgErr;
  3457. TRYCATCH_HR_NOHITOBJ(pEngDisp->pDisp->Invoke
  3458. (
  3459. pEngDisp->dispid,
  3460. IID_NULL,
  3461. lcid,
  3462. wFlags,
  3463. pdp,
  3464. pVarRes,
  3465. pei,
  3466. &uArgErr
  3467. ),
  3468. hr,
  3469. "IScriptDispatch::Invoke()");
  3470. }
  3471. return hr;
  3472. }
  3473. /*===================================================================
  3474. CScriptingNamespace::CacheDispID
  3475. Adds new DISPID to the list
  3476. Parameters
  3477. pEngine -- engine for which disp id found
  3478. dispidEngine -- found dispid
  3479. pdispidCached -- [out] cached dispid (for ScriptingNamespace)
  3480. Returns
  3481. HRESULT
  3482. ===================================================================*/
  3483. HRESULT CScriptingNamespace::CacheDispID
  3484. (
  3485. CEngineDispElem *pEngine,
  3486. DISPID dispidEngine,
  3487. DISPID *pdispidCached
  3488. )
  3489. {
  3490. ENGDISPBUCKET *pEngDispBucket;
  3491. // See if we need to add another bucket
  3492. if ((m_cEngDispMac % ENGDISPMAX) == 0)
  3493. {
  3494. pEngDispBucket = new ENGDISPBUCKET;
  3495. if (pEngDispBucket == NULL)
  3496. return E_OUTOFMEMORY;
  3497. pEngDispBucket->AppendTo(m_listEngDisp);
  3498. }
  3499. // Navigate to the correct bucket
  3500. unsigned iEngDisp = m_cEngDispMac;
  3501. pEngDispBucket = static_cast<ENGDISPBUCKET *>(m_listEngDisp.PNext());
  3502. while (iEngDisp > ENGDISPMAX)
  3503. {
  3504. iEngDisp -= ENGDISPMAX;
  3505. pEngDispBucket = static_cast<ENGDISPBUCKET *>(pEngDispBucket->PNext());
  3506. }
  3507. pEngDispBucket->rgEngDisp[iEngDisp].dispid = dispidEngine;
  3508. pEngDispBucket->rgEngDisp[iEngDisp].pDisp = pEngine->m_pDisp;
  3509. pEngDispBucket->rgEngDisp[iEngDisp].pDispEx = pEngine->m_pDispEx;
  3510. // Return index as the dispid
  3511. *pdispidCached = (DISPID)m_cEngDispMac;
  3512. m_cEngDispMac++;
  3513. return S_OK;
  3514. }
  3515. /*===================================================================
  3516. CScriptingNamespace::FetchDispID
  3517. Find ENGDISP by DISPID
  3518. Parameters
  3519. dispid - in
  3520. ppEngDisp - out
  3521. Returns
  3522. HRESULT
  3523. ===================================================================*/
  3524. HRESULT CScriptingNamespace::FetchDispID
  3525. (
  3526. DISPID dispid,
  3527. ENGDISP **ppEngDisp
  3528. )
  3529. {
  3530. if (dispid >= (DISPID)m_cEngDispMac)
  3531. return E_FAIL;
  3532. unsigned iEngDisp = dispid;
  3533. ENGDISPBUCKET *pEngDispBucket = static_cast<ENGDISPBUCKET *>(m_listEngDisp.PNext());
  3534. while (iEngDisp > ENGDISPMAX)
  3535. {
  3536. iEngDisp -= ENGDISPMAX;
  3537. pEngDispBucket = static_cast<ENGDISPBUCKET *>(pEngDispBucket->PNext());
  3538. }
  3539. *ppEngDisp = &pEngDispBucket->rgEngDisp[iEngDisp];
  3540. return S_OK;
  3541. }
  3542. #ifdef DBG
  3543. /*===================================================================
  3544. CScriptingNamespace::AssertValid
  3545. Test to make sure that the CScriptingNamespace object is currently correctly formed
  3546. and assert if it is not.
  3547. Returns:
  3548. Side effects:
  3549. None.
  3550. ===================================================================*/
  3551. VOID CScriptingNamespace::AssertValid() const
  3552. {
  3553. Assert(m_fInited);
  3554. Assert(m_cRef > 0);
  3555. }
  3556. #endif // DBG
  3557. /*
  3558. *
  3559. *
  3560. * U t i l i t i e s
  3561. *
  3562. * General utility functions
  3563. *
  3564. */
  3565. /*===================================================================
  3566. WrapTypeLibs
  3567. Utility routine to take an array of Typelibs, and return an IDispatch
  3568. implementation that wraps the array of typelibs.
  3569. Parameters:
  3570. ITypeLib **prgpTypeLib - pointer to an array of typelibs
  3571. UINT cTypeLibs - count of typelibs in array
  3572. IDispatch **ppDisp - returned IDispatch
  3573. Return Value:
  3574. HRESULT S_OK or a general error code.
  3575. ===================================================================*/
  3576. HRESULT WrapTypeLibs
  3577. (
  3578. ITypeLib **prgpTypeLib,
  3579. UINT cTypeLibs,
  3580. IDispatch **ppDisp
  3581. )
  3582. {
  3583. HRESULT hr;
  3584. Assert(g_pWrapTypelibs != NULL);
  3585. Assert(prgpTypeLib != NULL);
  3586. Assert(cTypeLibs > 0);
  3587. Assert(ppDisp != NULL);
  3588. hr = g_pWrapTypelibs->WrapTypeLib(prgpTypeLib, cTypeLibs, ppDisp);
  3589. return(hr);
  3590. }