Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1461 lines
44 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Executor
  6. Owner: DGottner
  7. File: executor.cpp
  8. This file contains the executor, whose job is to co-ordinate the
  9. execution of Denali scripts.
  10. ===================================================================*/
  11. #include "denpre.h"
  12. #pragma hdrstop
  13. #include "exec.h"
  14. #include "response.h"
  15. #include "request.h"
  16. #include "perfdata.h"
  17. #include "memchk.h"
  18. // Local declarations
  19. HRESULT ExecuteGlobal(CHitObj *pHitObj,
  20. const CIntrinsicObjects &intrinsics,
  21. ActiveEngineInfo *pEngineInfo);
  22. HRESULT ExecuteRequest(CTemplate *pTemplate, CHitObj *pHitObj,
  23. const CIntrinsicObjects &intrinsics,
  24. ActiveEngineInfo *pEngineInfo);
  25. HRESULT ReInitIntrinsics(CHitObj *pHitObj, const CIntrinsicObjects &intrinsics,
  26. ActiveEngineInfo *pEngineInfo, BOOL fPostGlobal);
  27. HRESULT AllocAndLoadEngines(CHitObj *pHitObj, CTemplate *pTemplate, ActiveEngineInfo *pEngineInfo,
  28. CScriptingNamespace *pScriptingNamespace, BOOL fGlobalAsa);
  29. VOID DeAllocAndFreeEngines(ActiveEngineInfo *pEngineInfo, CAppln *pAppln, IASPObjectContextCustom *);
  30. CScriptEngine *GetScriptEngine(int iScriptEngine, void *pvData);
  31. HRESULT CallScriptFunctionOfEngine(ActiveEngineInfo &engineInfo, short iScriptBlock, wchar_t *strFunction,
  32. IASPObjectContextCustom *pTxnScriptContextCustom, BOOLB *pfAborted);
  33. HRESULT CallScriptFunction(ActiveEngineInfo &engineInfo, wchar_t *strFunction,
  34. IASPObjectContextCustom *pTxnScriptContextCustom, BOOLB *pfAborted);
  35. HRESULT TestScriptFunction(ActiveEngineInfo &engineInfo, wchar_t *strFunction);
  36. /*===================================================================
  37. Execute
  38. Execute a request:
  39. First determine if Global needs to be called
  40. then invoke actual requested template
  41. Parameters:
  42. pTemplate - pointer to loaded template (could be NULL)
  43. pHitObj - pointer to the hit object
  44. intrinsics - pointers to the intrinsic IUnknown pointers.
  45. fChild - flag: TRUE when child request (Server.Execute())
  46. Returns:
  47. S_OK on success
  48. ===================================================================*/
  49. HRESULT Execute
  50. (
  51. CTemplate *pTemplate,
  52. CHitObj *pHitObj,
  53. const CIntrinsicObjects &intrinsics,
  54. BOOL fChild
  55. )
  56. {
  57. HRESULT hr = S_OK;
  58. ActiveEngineInfo engineInfo;
  59. BOOL fRanGlobal = FALSE;
  60. // The hit obj must be valid
  61. Assert(pHitObj != NULL);
  62. pHitObj->AssertValid();
  63. // Check for valid Session codepage. We do it here, rather than in CSession::Init in
  64. // order to avoid generic "New Session Failed" message.
  65. if (pHitObj->GetCodePage() != CP_ACP && !IsValidCodePage(pHitObj->GetCodePage()))
  66. {
  67. HandleErrorMissingFilename(IDE_BAD_CODEPAGE_IN_MB, pHitObj);
  68. return E_FAIL;
  69. }
  70. // Give the engine list to the hitobject
  71. pHitObj->SetActiveEngineInfo(&engineInfo);
  72. /*
  73. * If there is a Global.ASA, call it
  74. */
  75. if (pHitObj->GlobalAspPath() && !fChild)
  76. {
  77. // Clear out the engine info
  78. engineInfo.cEngines = 0;
  79. engineInfo.cActiveEngines = 0;
  80. engineInfo.rgActiveEngines = NULL;
  81. // Init the intrinsics
  82. hr = ReInitIntrinsics(pHitObj, intrinsics, &engineInfo, /* fPostGlobal*/ FALSE);
  83. if (FAILED(hr))
  84. return(hr);
  85. hr = ExecuteGlobal(pHitObj, intrinsics, &engineInfo);
  86. if (intrinsics.PResponse() && intrinsics.PResponse()->FResponseAborted())
  87. {
  88. hr = S_OK;
  89. goto LExit;
  90. }
  91. if (E_SOURCE_FILE_IS_EMPTY == hr)
  92. // bug 977: silently ignore empty global.asa file
  93. hr = S_OK;
  94. else if (FAILED(hr))
  95. {
  96. // Bug 481: If global.asa fails due to Response.End (or Response.Redirect),
  97. // then halt execution of the calling script. If the
  98. // script fails due to Response.End, then return OK status
  99. //
  100. if (hr == DISP_E_EXCEPTION)
  101. hr = S_OK;
  102. // In any case, blow out of here
  103. goto LExit;
  104. }
  105. // Running Global.asa added the scripting namespace to the hitobj. This will cause us problems
  106. // later, remove it.
  107. pHitObj->RemoveScriptingNamespace();
  108. fRanGlobal = TRUE;
  109. }
  110. /*
  111. * If this is not a browser request, then we are done
  112. * For non-browser requests, we do want to run Global.asa (if any), but there is no real template to run.
  113. */
  114. if (!pHitObj->FIsBrowserRequest())
  115. {
  116. hr = S_OK;
  117. goto LExit;
  118. }
  119. // Clear out (or re-clear out) the engine info
  120. engineInfo.cEngines = 0;
  121. engineInfo.cActiveEngines = 0;
  122. engineInfo.rgActiveEngines = NULL;
  123. // Init or Re-Init the intrinsics
  124. ReInitIntrinsics(pHitObj, intrinsics, &engineInfo, fRanGlobal || fChild);
  125. if (!fChild)
  126. {
  127. // For non-child requests hand new Template to Response object
  128. // (for child requests already done)
  129. intrinsics.PResponse()->ReInitTemplate(pTemplate, pHitObj->PSzNewSessionCookie());
  130. }
  131. else
  132. {
  133. // For child requests hand new engine info to the response object
  134. intrinsics.PResponse()->SwapScriptEngineInfo(&engineInfo);
  135. }
  136. // Run the main template
  137. if (pTemplate->FScriptless() && !pHitObj->PAppln()->FDebuggable())
  138. {
  139. // special case scriptless pages
  140. hr = intrinsics.PResponse()->WriteBlock(0);
  141. }
  142. else
  143. {
  144. hr = ExecuteRequest(pTemplate, pHitObj, intrinsics, &engineInfo);
  145. }
  146. LExit:
  147. intrinsics.PResponse()->SwapScriptEngineInfo(NULL);
  148. pHitObj->SetActiveEngineInfo(NULL);
  149. return hr;
  150. }
  151. /*===================================================================
  152. ExecRequest
  153. Execute a request for an actual template (not Global.asa)
  154. execute a request by
  155. - getting the script name
  156. - loading the script into memory
  157. - interpreting the opcodes
  158. Parameters:
  159. pTemplate - pointer to loaded template
  160. pHitObj - pointer to the hit object
  161. intrinsics - pointers to the intrinsic IUnknown pointers.
  162. pEngineInfo - pointers to engine info
  163. Returns:
  164. S_OK on success
  165. ===================================================================*/
  166. HRESULT ExecuteRequest
  167. (
  168. CTemplate *pTemplate,
  169. CHitObj *pHitObj,
  170. const CIntrinsicObjects &intrinsics,
  171. ActiveEngineInfo *pEngineInfo
  172. )
  173. {
  174. HRESULT hr = S_OK;
  175. IASPObjectContextCustom *pTxnScriptContextCustom = NULL;
  176. IASPObjectContext *pTxnScriptContext = NULL;
  177. BOOLB fAborted = FALSE;
  178. BOOLB fDebuggerNotifiedOnStart = FALSE;
  179. #ifndef PERF_DISABLE
  180. BOOLB fPerfTransPending = FALSE;
  181. #endif
  182. // The template must be valid
  183. Assert(pTemplate);
  184. // The hit obj must be valid
  185. Assert(pHitObj != NULL);
  186. pHitObj->AssertValid();
  187. // This function should never be called on a non-browser request
  188. Assert(pHitObj->FIsBrowserRequest());
  189. // Remember template's type library wrapper with the HitObj
  190. if (pTemplate->PTypeLibWrapper())
  191. pHitObj->SetTypeLibWrapper(pTemplate->PTypeLibWrapper());
  192. /*
  193. * Bug 86404: If this script is transacted, then create a new "real" ASP ObjectContext object
  194. * and add it to the objects list. If the page is not transacted, then
  195. * CHitObj::UseObjectContext will use pre-instantiated "zombie" ObjectContext object.
  196. */
  197. if (pTemplate->FTransacted())
  198. {
  199. IObjectContext *pContext;
  200. if (FAILED(hr = GetObjectContext(&pContext)))
  201. goto LExit;
  202. /*
  203. * Incredibly obscure bug in OLE32. If OLE needs to spin up an MTA thread in order to
  204. * create the class factory for the ASPObjectContext object, then the thread needs to be
  205. * created by the unimpersonated user.
  206. * NOTE: This can be removed after the new OLE32 ships in NT4 SP4
  207. */
  208. RevertToSelf();
  209. hr = pContext->CreateInstance
  210. (
  211. CLSIDObjectContextFromTransType(pTemplate->GetTransType()),
  212. IID_IASPObjectContextCustom,
  213. reinterpret_cast<void **>(&pTxnScriptContextCustom)
  214. );
  215. // Restore Impersonation
  216. HANDLE hThread = GetCurrentThread();
  217. SetThreadToken(&hThread, pHitObj->HImpersonate());
  218. pContext->Release();
  219. if (FAILED(hr))
  220. goto LExit;
  221. hr = pTxnScriptContextCustom->QueryInterface(IID_IASPObjectContext,
  222. reinterpret_cast<void **>(&pTxnScriptContext));
  223. if (FAILED(hr))
  224. goto LExit;
  225. pHitObj->AddObjectContext(pTxnScriptContext);
  226. pTxnScriptContext->Release();
  227. #ifndef PERF_DISABLE
  228. g_PerfData.Incr_TRANSTOTAL();
  229. g_PerfData.Incr_TRANSPENDING();
  230. fPerfTransPending = TRUE;
  231. #endif
  232. }
  233. // load script engines
  234. hr = AllocAndLoadEngines(pHitObj, pTemplate, pEngineInfo, intrinsics.PScriptingNamespace(), /* fGlobalAsa */FALSE);
  235. if (FAILED(hr))
  236. {
  237. pHitObj->SetCompilationFailed();
  238. goto LExit;
  239. }
  240. // If debugging, notify debugger ONPAGESTART
  241. // BUG 138773: Notify debugger AFTER scripts load
  242. // (script must be in running state when AttachTo() is called because debugger may want a code context)
  243. //
  244. if (pHitObj->PAppln()->FDebuggable())
  245. {
  246. pTemplate->AttachTo(pHitObj->PAppln());
  247. if (SUCCEEDED(pTemplate->NotifyDebuggerOnPageEvent(TRUE)))
  248. fDebuggerNotifiedOnStart = TRUE;
  249. }
  250. // bug 1009: if no script engines, do not attempt to do anything
  251. if(0 == pTemplate->CountScriptEngines())
  252. goto LExit;
  253. // run the script by calling primary script engine's global code
  254. hr = CallScriptFunctionOfEngine(
  255. *pEngineInfo, // engine-info
  256. 0, // primary script engine
  257. NULL, // call the engine's global code
  258. pTxnScriptContextCustom,
  259. &fAborted
  260. );
  261. if (FAILED(hr) && hr != CONTEXT_E_ABORTED)
  262. {
  263. /*
  264. * The cryptically named CONTEXT_E_OLDREF error in this case means that
  265. * we are trying to run a transacted web page, but DTC isnt running.
  266. * CONTEXT_E_TMNOTAVAILABLE means the same thing. God knows why
  267. */
  268. if (hr == CONTEXT_E_OLDREF || hr == CONTEXT_E_TMNOTAVAILABLE)
  269. {
  270. HandleErrorMissingFilename(IDE_EXECUTOR_DTC_NOT_RUNNING, pHitObj);
  271. }
  272. // Regardless of the error, exit
  273. goto LExit;
  274. }
  275. /*
  276. * If this is a transacted web page, then run either the OnTransactionCommit
  277. * or OnTransactionAbort method in the script, if any.
  278. *
  279. * If the script writer did an explicit SetAbort, or a component run by the script
  280. * did a SetAbort, then we run OnTransactionAbort, otherwise run OnTransactionCommit
  281. */
  282. if (pTemplate->FTransacted())
  283. {
  284. #ifndef PERF_DISABLE
  285. g_PerfData.Incr_TRANSPERSEC();
  286. #endif
  287. if (hr == CONTEXT_E_ABORTED || fAborted)
  288. {
  289. // Reset the error... dont communicate this back to the caller as an actual error
  290. hr = S_OK;
  291. hr = CallScriptFunction(*pEngineInfo, L"OnTransactionAbort", NULL, &fAborted);
  292. #ifndef PERF_DISABLE
  293. g_PerfData.Incr_TRANSABORTED();
  294. #endif
  295. }
  296. else
  297. {
  298. hr = CallScriptFunction(*pEngineInfo, L"OnTransactionCommit", NULL, &fAborted);
  299. #ifndef PERF_DISABLE
  300. g_PerfData.Incr_TRANSCOMMIT();
  301. #endif
  302. }
  303. // Ignore UNKNOWNNAME -- this means the author didnt write the method, which is fine
  304. if (hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND)
  305. hr = S_OK;
  306. if (FAILED(hr))
  307. goto LExit;
  308. }
  309. LExit:
  310. #ifndef PERF_DISABLE
  311. if (fPerfTransPending)
  312. g_PerfData.Decr_TRANSPENDING();
  313. #endif
  314. // Uninit the scripting namespace
  315. (VOID)intrinsics.PScriptingNamespace()->UnInit();
  316. // Return the engine(s) to cache
  317. DeAllocAndFreeEngines(pEngineInfo, pHitObj->PAppln(), pTxnScriptContextCustom);
  318. // If debugging, notify debugger ONPAGEDONE
  319. if (fDebuggerNotifiedOnStart)
  320. {
  321. Assert(pHitObj->PAppln()->FDebuggable());
  322. pTemplate->NotifyDebuggerOnPageEvent(FALSE);
  323. }
  324. // Remove the ASP ObjectContext object from the namespace, and dealloc it if we allocated one
  325. pHitObj->RemoveObjectContext();
  326. if (pTxnScriptContextCustom)
  327. {
  328. pTxnScriptContextCustom->Release();
  329. }
  330. return hr;
  331. }
  332. /*===================================================================
  333. ExecuteGlobal
  334. UNDONE: handle script engine the same manner as mainline script engines
  335. with respect to debugging.
  336. Execute code in Global.ASA as part of application or session start or end.
  337. Parameters:
  338. pHitObj - pointer to the hit object
  339. intrinsics - pointers to the intrinsic IUnknown pointers.
  340. pEngineInfo - pointers to engine info
  341. pfDeleteSession - true if global.asa failed, and therefore the caller should
  342. Returns:
  343. S_OK on success
  344. ===================================================================*/
  345. HRESULT ExecuteGlobal
  346. (
  347. CHitObj *pHitObj,
  348. const CIntrinsicObjects &intrinsics,
  349. ActiveEngineInfo *pEngineInfo
  350. )
  351. {
  352. HRESULT hr = S_OK;
  353. CTemplate *pTemplate = NULL;
  354. IASPObjectContextCustom *pTxnScriptContextCustom = NULL;
  355. IASPObjectContext *pTxnScriptContext = NULL;
  356. WORD iEng;
  357. BOOLB fAborted = FALSE;
  358. BOOLB fDebuggerNotifiedOnStart = FALSE;
  359. BOOL fUnHideRequestAndResponse = FALSE;
  360. BOOL fOnStartAppln = FALSE;
  361. BOOL fOnEndAppln = FALSE;
  362. BOOL fOnEndSession = FALSE;
  363. BOOL fGlobalAsaInCache;
  364. BOOL fApplnStarted = FALSE;
  365. // The hit obj must be there, be valid, & have a global.asa name
  366. Assert(pHitObj != NULL);
  367. pHitObj->AssertValid();
  368. Assert(pHitObj->GlobalAspPath() != NULL && *(pHitObj->GlobalAspPath()) != '\0');
  369. // Other arg's must be right
  370. Assert(pEngineInfo != NULL);
  371. // Load the script - cache will AddRef
  372. // bug 1051: load template before possibly removing response object (in switch block, below),
  373. // so error reporting to browser will work
  374. hr = LoadTemplate(pHitObj->GlobalAspPath(), pHitObj, &pTemplate, intrinsics, /* fGlobalAsa */ TRUE, &fGlobalAsaInCache);
  375. if (FAILED(hr))
  376. goto LExit;
  377. Assert(pTemplate != NULL);
  378. // Remember GLOBAL.ASA's type library wrapper with the application
  379. // on the first request
  380. if (pHitObj->FStartApplication() && pTemplate->PTypeLibWrapper())
  381. {
  382. pHitObj->PAppln()->SetGlobTypeLibWrapper(pTemplate->PTypeLibWrapper());
  383. }
  384. /*
  385. * Bug 86404: If this script is transacted, then create a new "real" ASP ObjectContext object
  386. * and add it to the objects list. If the page is not transacted, then
  387. * CHitObj::UseObjectContext will use pre-instantiated "zombie" ObjectContext.
  388. */
  389. if (pTemplate->FTransacted())
  390. {
  391. IObjectContext *pContext;
  392. if (FAILED(hr = GetObjectContext(&pContext)))
  393. goto LExit;
  394. /*
  395. * Incredibly obscure bug in OLE32. If OLE needs to spin up an MTA thread in order to
  396. * create the class factory for the ASPObjectContext object, then the thread needs to be
  397. * created by the unimpersonated user.
  398. * NOTE: This can be removed after the new OLE32 ships in NT4 SP4
  399. */
  400. RevertToSelf();
  401. hr = pContext->CreateInstance
  402. (
  403. CLSIDObjectContextFromTransType(pTemplate->GetTransType()),
  404. IID_IASPObjectContextCustom,
  405. reinterpret_cast<void **>(&pTxnScriptContextCustom)
  406. );
  407. // Restore Impersonation
  408. HANDLE hThread = GetCurrentThread();
  409. SetThreadToken(&hThread, pHitObj->HImpersonate());
  410. pContext->Release();
  411. if (FAILED(hr))
  412. goto LExit;
  413. hr = pTxnScriptContextCustom->QueryInterface(IID_IASPObjectContext, reinterpret_cast<void **>(&pTxnScriptContext));
  414. if (FAILED(hr))
  415. goto LExit;
  416. // add to namespace
  417. pHitObj->AddObjectContext(pTxnScriptContext);
  418. pTxnScriptContext->Release();
  419. }
  420. Assert(pHitObj->FIsValidRequestType());
  421. // Figure out which events to trigger
  422. if (pHitObj->FIsBrowserRequest())
  423. {
  424. fOnStartAppln = pHitObj->FStartApplication();
  425. if (fOnStartAppln)
  426. {
  427. // Hide response and request intrinsics from namespace
  428. pHitObj->HideRequestAndResponseIntrinsics();
  429. // Flag that intrinsics need to be un-hidden back in.
  430. fUnHideRequestAndResponse = TRUE;
  431. }
  432. }
  433. else if (pHitObj->FIsSessionCleanupRequest())
  434. {
  435. fOnEndSession = TRUE;
  436. }
  437. else if (pHitObj->FIsApplnCleanupRequest())
  438. {
  439. fOnEndAppln = TRUE;
  440. }
  441. // If debugging, notify debugger ONPAGESTART
  442. if (pHitObj->PAppln()->FDebuggable())
  443. {
  444. if (SUCCEEDED(pTemplate->NotifyDebuggerOnPageEvent(TRUE)))
  445. fDebuggerNotifiedOnStart = TRUE;
  446. }
  447. hr = AllocAndLoadEngines(pHitObj, pTemplate, pEngineInfo, intrinsics.PScriptingNamespace(), /* fGlobalAsa */TRUE);
  448. if (FAILED(hr))
  449. goto LExit;
  450. // BUG 93991: Defer registration of new document with debugger until after script engines have
  451. // been loaded
  452. //
  453. if (!fGlobalAsaInCache && pHitObj->PAppln()->FDebuggable())
  454. pTemplate->AttachTo(pHitObj->PAppln());
  455. // bug 975: if no script engines, do not attempt to call event functions
  456. if(0 == pTemplate->CountScriptEngines())
  457. goto LExit;
  458. /*
  459. * Call event functions as required
  460. * bug 459: event functions may be in any script engine
  461. */
  462. // First run Application_OnStart
  463. if (fOnStartAppln)
  464. {
  465. pHitObj->SetEventState(eEventAppOnStart);
  466. hr = CallScriptFunction(*pEngineInfo, L"Application_OnStart", pTxnScriptContextCustom, &fAborted);
  467. if (SUCCEEDED(hr) || hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND ||
  468. intrinsics.PResponse()->FResponseAborted())
  469. {
  470. if (fUnHideRequestAndResponse)
  471. {
  472. pHitObj->UnHideRequestAndResponseIntrinsics();
  473. fUnHideRequestAndResponse = FALSE;
  474. }
  475. fApplnStarted = TRUE;
  476. hr = S_OK;
  477. }
  478. else
  479. {
  480. goto LExit;
  481. }
  482. }
  483. if (pHitObj->FStartSession())
  484. {
  485. // If application on start was run, add Response and Request names to script engines
  486. if (fOnStartAppln)
  487. {
  488. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  489. {
  490. if (FAILED(hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddAdditionalObject(WSZ_OBJ_RESPONSE, FALSE)))
  491. goto LExit;
  492. if (FAILED(hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddAdditionalObject(WSZ_OBJ_REQUEST, FALSE)))
  493. goto LExit;
  494. }
  495. }
  496. pHitObj->SetEventState(eEventSesOnStart);
  497. hr = CallScriptFunction(*pEngineInfo, L"Session_OnStart", pTxnScriptContextCustom, &fAborted);
  498. if (FAILED(hr) && hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND &&
  499. !intrinsics.PResponse()->FResponseAborted())
  500. {
  501. // Mark session as on-start-failed - to be deleted soon
  502. pHitObj->SessionOnStartFailed();
  503. }
  504. else
  505. {
  506. if (SUCCEEDED(hr))
  507. {
  508. // Mark as on-start-invoked -- need to wait for timeout
  509. pHitObj->SessionOnStartInvoked();
  510. }
  511. // Check if Session_OnEnd Present
  512. if (SUCCEEDED(TestScriptFunction(*pEngineInfo, L"Session_OnEnd")))
  513. {
  514. // Mark as on-end-present -- need to execute OnEnd later
  515. pHitObj->SessionOnEndPresent();
  516. }
  517. hr = S_OK;
  518. }
  519. goto LExit;
  520. }
  521. if (fOnEndSession)
  522. {
  523. pHitObj->SetEventState(eEventSesOnEnd);
  524. hr = CallScriptFunction(*pEngineInfo, L"Session_OnEnd", pTxnScriptContextCustom, &fAborted);
  525. // We are failing silently here, since there is no corrective action we could take
  526. }
  527. if (fOnEndAppln)
  528. {
  529. pHitObj->SetEventState(eEventAppOnEnd);
  530. hr = CallScriptFunction(*pEngineInfo, L"Application_OnEnd", pTxnScriptContextCustom, &fAborted);
  531. // We are failing silently here, since there is no corrective action we could take
  532. }
  533. LExit:
  534. if (fUnHideRequestAndResponse)
  535. {
  536. pHitObj->UnHideRequestAndResponseIntrinsics();
  537. }
  538. if (FAILED(hr) && (hr != E_SOURCE_FILE_IS_EMPTY) && pHitObj->FStartApplication() && !fApplnStarted)
  539. {
  540. pHitObj->ApplnOnStartFailed();
  541. }
  542. pHitObj->SetEventState(eEventNone);
  543. // Uninit the scripting namespace
  544. (VOID)intrinsics.PScriptingNamespace()->UnInit();
  545. // Release the template
  546. if (pTemplate)
  547. {
  548. // bug 975: if no script engines, do not do this
  549. if(pTemplate->CountScriptEngines() > 0)
  550. // Return the engine(s) to cache
  551. DeAllocAndFreeEngines(pEngineInfo, pHitObj->PAppln(), pTxnScriptContextCustom);
  552. // If debugging, notify debugger ONPAGEDONE
  553. if (fDebuggerNotifiedOnStart)
  554. {
  555. Assert(pHitObj->PAppln()->FDebuggable());
  556. pTemplate->NotifyDebuggerOnPageEvent(FALSE);
  557. }
  558. pTemplate->Release();
  559. }
  560. // Remove the ASP ObjectContext object from the namespace, and dealloc it if we allocated one
  561. pHitObj->RemoveObjectContext();
  562. if (pTxnScriptContextCustom)
  563. {
  564. pTxnScriptContextCustom->Release();
  565. }
  566. // It is OK if the event function was not found in global.asa
  567. if (hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND)
  568. {
  569. hr = S_OK;
  570. }
  571. return hr;
  572. }
  573. /*===================================================================
  574. CIntrinsicObjects::Prepare
  575. Prepare intrinsics for the request processing
  576. Parameters:
  577. pSession session holding the instrinsics (can be NULL)
  578. Returns:
  579. HRESULT
  580. ===================================================================*/
  581. HRESULT CIntrinsicObjects::Prepare
  582. (
  583. CSession *pSession
  584. )
  585. {
  586. HRESULT hr = S_OK;
  587. if (pSession)
  588. {
  589. // get request, response, server from session
  590. if (SUCCEEDED(hr))
  591. {
  592. m_pRequest = pSession->PRequest();
  593. if (m_pRequest)
  594. m_pRequest->AddRef();
  595. else
  596. hr = E_FAIL;
  597. }
  598. if (SUCCEEDED(hr))
  599. {
  600. m_pResponse = pSession->PResponse();
  601. if (m_pResponse)
  602. m_pResponse->AddRef();
  603. else
  604. hr = E_FAIL;
  605. }
  606. if (SUCCEEDED(hr))
  607. {
  608. m_pServer = pSession->PServer();
  609. if (m_pServer)
  610. m_pServer->AddRef();
  611. else
  612. hr = E_FAIL;
  613. }
  614. }
  615. else
  616. {
  617. // create new request, response, server
  618. if (SUCCEEDED(hr))
  619. {
  620. m_pRequest = new CRequest;
  621. if (!m_pRequest)
  622. hr = E_OUTOFMEMORY;
  623. }
  624. if (SUCCEEDED(hr))
  625. {
  626. m_pResponse = new CResponse;
  627. if (!m_pResponse)
  628. hr = E_OUTOFMEMORY;
  629. }
  630. if (SUCCEEDED(hr))
  631. {
  632. m_pServer = new CServer;
  633. if (!m_pServer)
  634. hr = E_OUTOFMEMORY;
  635. }
  636. }
  637. // init request, response, server
  638. if (SUCCEEDED(hr))
  639. {
  640. Assert(m_pRequest);
  641. hr = m_pRequest->Init();
  642. }
  643. if (SUCCEEDED(hr))
  644. {
  645. Assert(m_pResponse);
  646. hr = m_pResponse->Init();
  647. }
  648. if (SUCCEEDED(hr))
  649. {
  650. Assert(m_pServer);
  651. hr = m_pServer->Init();
  652. }
  653. // create the scripting namespace
  654. if (SUCCEEDED(hr))
  655. {
  656. m_pScriptingNamespace = new CScriptingNamespace;
  657. if (!m_pScriptingNamespace)
  658. hr = E_OUTOFMEMORY;
  659. }
  660. // cleanup on error
  661. if (FAILED(hr))
  662. Cleanup();
  663. m_fIsChild = FALSE;
  664. return hr;
  665. }
  666. /*===================================================================
  667. CIntrinsicObjects::PrepareChild
  668. Prepare intrinsics structure for a child request
  669. Parameters:
  670. pResponse parent intrinsic
  671. pRequest parent intrinsic
  672. pServer parent intrinsic
  673. Returns:
  674. HRESULT
  675. ===================================================================*/
  676. HRESULT CIntrinsicObjects::PrepareChild
  677. (
  678. CResponse *pResponse,
  679. CRequest *pRequest,
  680. CServer *pServer
  681. )
  682. {
  683. HRESULT hr = S_OK;
  684. if (!pResponse || !pRequest || !pServer)
  685. {
  686. hr = E_FAIL;
  687. }
  688. if (SUCCEEDED(hr))
  689. {
  690. m_pResponse = pResponse;
  691. m_pResponse->AddRef();
  692. m_pRequest = pRequest;
  693. m_pRequest->AddRef();
  694. m_pServer = pServer;
  695. m_pServer->AddRef();
  696. m_fIsChild = TRUE;
  697. }
  698. if (SUCCEEDED(hr))
  699. {
  700. m_pScriptingNamespace = new CScriptingNamespace;
  701. if (!m_pScriptingNamespace)
  702. hr = E_OUTOFMEMORY;
  703. }
  704. if (FAILED(hr))
  705. Cleanup();
  706. return hr;
  707. }
  708. /*===================================================================
  709. CIntrinsicObjects::Cleanup
  710. Cleanup the intrinsics after the request processing
  711. Parameters:
  712. Returns:
  713. S_OK
  714. ===================================================================*/
  715. HRESULT CIntrinsicObjects::Cleanup()
  716. {
  717. if (m_pRequest)
  718. {
  719. if (!m_fIsChild)
  720. m_pRequest->UnInit();
  721. m_pRequest->Release();
  722. m_pRequest = NULL;
  723. }
  724. if (m_pResponse)
  725. {
  726. if (!m_fIsChild)
  727. m_pResponse->UnInit();
  728. m_pResponse->Release();
  729. m_pResponse = NULL;
  730. }
  731. if (m_pServer)
  732. {
  733. if (!m_fIsChild)
  734. m_pServer->UnInit();
  735. m_pServer->Release();
  736. m_pServer = NULL;
  737. }
  738. if (m_pScriptingNamespace)
  739. {
  740. m_pScriptingNamespace->Release();
  741. m_pScriptingNamespace = NULL;
  742. }
  743. return S_OK;
  744. }
  745. /*===================================================================
  746. ReInitIntrinsics
  747. Call re-init on each of the intrinsics that require it
  748. to run a new page.
  749. Parameters:
  750. pHitObj - pointer to the hit object
  751. intrinsics - pointers to the intrinsic IUnknown pointers.
  752. pEngineInfo - some engine info
  753. fPostGlobal - Is this a reinit after running global.asa?
  754. Returns:
  755. S_OK on success
  756. ===================================================================*/
  757. HRESULT ReInitIntrinsics
  758. (
  759. CHitObj *pHitObj,
  760. const CIntrinsicObjects &intrinsics,
  761. ActiveEngineInfo *pEngineInfo,
  762. BOOL fPostGlobal
  763. )
  764. {
  765. HRESULT hr;
  766. Assert(pHitObj != NULL);
  767. pHitObj->AssertValid();
  768. Assert(pEngineInfo != NULL);
  769. // Hand the new CIsapiReqInfo to the Server object
  770. // Note on bug 682: We do always need to re-init CServer because it takes the phitobj
  771. if (FAILED(hr = intrinsics.PServer()->ReInit(pHitObj->PIReq(), pHitObj)))
  772. goto LExit;
  773. if (FAILED(hr = intrinsics.PScriptingNamespace()->Init()))
  774. goto LExit;
  775. /*
  776. * Bug 682 & 671 (better fix to 452 & 512)
  777. * Dont re-init the Request & response objects after running a Global.Asa
  778. * because, the running of global.asa may have set cookies into request (bug 671), that reinit
  779. * would wipe, and the global.asa may have output headers (or other stuff) which impacts the response
  780. * object (bug 512) that we dont want to reset.
  781. */
  782. if (!fPostGlobal)
  783. {
  784. if (FAILED(hr = intrinsics.PRequest()->ReInit(pHitObj->PIReq(), pHitObj)))
  785. goto LExit;
  786. if (FAILED(hr = intrinsics.PResponse()->ReInit(
  787. pHitObj->PIReq(),
  788. pHitObj->PSzNewSessionCookie(),
  789. intrinsics.PRequest(),
  790. GetScriptEngine,
  791. pEngineInfo,
  792. pHitObj
  793. )))
  794. goto LExit;
  795. }
  796. LExit:
  797. return(hr);
  798. }
  799. /*===================================================================
  800. LoadTemplate
  801. Load a template, cleanup and give appropriate errors on failure.
  802. Parameters:
  803. szFile - the file to load a template for
  804. pHitObj - pointer to the hit object
  805. ppTemplate - The returned loaded template
  806. fGlobalAsa - is this for Global.asa?
  807. Returns:
  808. S_OK on success
  809. ===================================================================*/
  810. HRESULT LoadTemplate
  811. (
  812. const TCHAR *szFile,
  813. CHitObj *pHitObj,
  814. CTemplate **ppTemplate,
  815. const CIntrinsicObjects &intrinsics,
  816. BOOL fGlobalAsa,
  817. BOOL *pfTemplateInCache)
  818. {
  819. HRESULT hr;
  820. Assert(pHitObj != NULL);
  821. pHitObj->AssertValid();
  822. Assert(ppTemplate != NULL);
  823. // Load the script - cache will AddRef
  824. if (FAILED(hr = g_TemplateCache.Load(
  825. fGlobalAsa,
  826. szFile,
  827. pHitObj->DWInstanceID(),
  828. pHitObj,
  829. ppTemplate,
  830. pfTemplateInCache)))
  831. {
  832. // CONSIDER moving this cleanup into Template.Load
  833. if (hr == E_COULDNT_OPEN_SOURCE_FILE || hr == E_SOURCE_FILE_IS_EMPTY)
  834. {
  835. // Load error string from string table
  836. // BUG 731: added if to retrieve the correct header
  837. WCHAR szwErr[128];
  838. if (hr == E_COULDNT_OPEN_SOURCE_FILE)
  839. {
  840. CwchLoadStringOfId(IDH_404_OBJECT_NOT_FOUND, szwErr, 128);
  841. intrinsics.PResponse()->put_Status( szwErr );
  842. HandleSysError(404, 0, IDE_404_OBJECT_NOT_FOUND, NULL, NULL, pHitObj);
  843. #ifndef PERF_DISABLE
  844. g_PerfData.Incr_REQNOTFOUND();
  845. #endif
  846. }
  847. // bug 977: silently ignore empty global.asa file
  848. else if ((E_SOURCE_FILE_IS_EMPTY == hr) && !fGlobalAsa)
  849. {
  850. CwchLoadStringOfId(IDH_204_NO_CONTENT, szwErr, 128);
  851. intrinsics.PResponse()->put_Status( szwErr );
  852. HandleSysError(204, 0, IDE_204_NO_CONTENT, NULL, NULL, pHitObj);
  853. }
  854. }
  855. // fix for bug 371
  856. if (*ppTemplate)
  857. {
  858. (*ppTemplate)->Release();
  859. *ppTemplate = NULL;
  860. }
  861. if (hr == E_OUTOFMEMORY)
  862. {
  863. DBGPRINTF((DBG_CONTEXT, "Loading template returned E_OUTOFMEMORY. Flushing template & Script Cache.\n"));
  864. g_TemplateCache.FlushAll();
  865. g_ScriptManager.FlushAll();
  866. }
  867. }
  868. return(hr);
  869. }
  870. /*===================================================================
  871. AllocAndLoadEngines
  872. Allocate and load all the engines we need
  873. Parameters:
  874. pHitObj - The hit object
  875. pTemplate - The template we're gonna run
  876. pEngineInfo - Engine info to fill in
  877. pScriptingNamespace - scripting namespace
  878. fGlobalAsa - Are we loading engines to run global.asa?
  879. Returns:
  880. S_OK on success
  881. ===================================================================*/
  882. HRESULT AllocAndLoadEngines
  883. (
  884. CHitObj *pHitObj,
  885. CTemplate *pTemplate,
  886. ActiveEngineInfo *pEngineInfo,
  887. CScriptingNamespace *pScriptingNamespace,
  888. BOOL fGlobalAsa
  889. )
  890. {
  891. HRESULT hr = S_OK;
  892. int iObj;
  893. WORD iEng;
  894. WORD iScriptBlock;
  895. WORD cEngines = pTemplate->CountScriptEngines();
  896. Assert(pHitObj != NULL);
  897. pHitObj->AssertValid();
  898. Assert(pTemplate != NULL);
  899. Assert(pEngineInfo != NULL);
  900. Assert(pScriptingNamespace != NULL);
  901. // Load objects from template into hit object
  902. for (iObj = pTemplate->Count(tcompObjectInfo) - 1; iObj >= 0; --iObj)
  903. {
  904. CHAR *szObjectName = NULL;
  905. CLSID clsid;
  906. CompScope scope;
  907. CompModel model;
  908. CMBCSToWChar convStr;
  909. // get object-info from template and add to hitobj's list of objects
  910. hr = pTemplate->GetObjectInfo(iObj, &szObjectName, &clsid, &scope, &model);
  911. if(FAILED(hr))
  912. goto LExit;
  913. hr = convStr.Init(szObjectName);
  914. if (FAILED(hr))
  915. goto LExit;
  916. // ignore error ?
  917. pHitObj->AddComponent(ctTagged, clsid, scope, model, convStr.GetString());
  918. }
  919. // bug 975: if no script engines, exit now
  920. if(cEngines == 0)
  921. goto LExit;
  922. // Allocate space for script engines
  923. //
  924. // NOTE: There is a timing problem here in that the response object needs to
  925. // be instantiated before we instantiate the script engines, but the
  926. // response object needs to be able to access the list of active script
  927. // engines, because it may need to halt execution. To accomplish this,
  928. // the response object is passed a pointer to the "EngineInfo" structure
  929. // as a pointer, and then we modify the contents of the pointer right under
  930. // its nose. We pass an accessor function via pointer so that response just
  931. // sees a void pointer.
  932. //
  933. if (cEngines == 1)
  934. {
  935. // don't do allocations in case of one engine
  936. pEngineInfo->rgActiveEngines = & (pEngineInfo->siOneActiveEngine);
  937. }
  938. else
  939. {
  940. pEngineInfo->rgActiveEngines = new ScriptingInfo[cEngines];
  941. if (pEngineInfo->rgActiveEngines == NULL)
  942. {
  943. hr = E_OUTOFMEMORY;
  944. goto LExit;
  945. }
  946. }
  947. pEngineInfo->cEngines = cEngines;
  948. pEngineInfo->cActiveEngines = 0; // number of SUCCESSFULLY instantiated engines
  949. // Load all of the script engines in advance.
  950. for (iScriptBlock = 0; iScriptBlock < cEngines; ++iScriptBlock)
  951. {
  952. LPCOLESTR wstrScript;
  953. SCRIPTSTATE nScriptState;
  954. ScriptingInfo *pScriptInfo = &pEngineInfo->rgActiveEngines[iScriptBlock];
  955. pTemplate->GetScriptBlock(
  956. iScriptBlock,
  957. &pScriptInfo->szScriptEngine,
  958. &pScriptInfo->pProgLangId,
  959. &wstrScript);
  960. // Populate information required for the line mapping callback.
  961. //
  962. pScriptInfo->LineMapInfo.iScriptBlock = iScriptBlock;
  963. pScriptInfo->LineMapInfo.pTemplate = pTemplate;
  964. // acquire a script engine by:
  965. //
  966. // getting an engine from the template object (if it has one)
  967. // else from the script manager.
  968. //
  969. // If we are in debug mode, the templates tend to be greedy and hold
  970. // onto script engines. (See notes in scrptmgr.h)
  971. //
  972. pScriptInfo->pScriptEngine = NULL;
  973. if (pHitObj->PAppln()->FDebuggable())
  974. {
  975. pScriptInfo->pScriptEngine = pTemplate->GetActiveScript(iScriptBlock);
  976. if (pScriptInfo->pScriptEngine)
  977. {
  978. // If we got one, we don't need to re-init the engine
  979. nScriptState = SCRIPTSTATE_INITIALIZED;
  980. hr = static_cast<CActiveScriptEngine *>(pScriptInfo->pScriptEngine)->ReuseEngine(pHitObj, NULL, iScriptBlock, pHitObj->DWInstanceID());
  981. }
  982. }
  983. if (pScriptInfo->pScriptEngine == NULL)
  984. {
  985. hr = g_ScriptManager.GetEngine(LOCALE_SYSTEM_DEFAULT,
  986. *(pScriptInfo->pProgLangId),
  987. pTemplate->GetSourceFileName(),
  988. pHitObj,
  989. &pScriptInfo->pScriptEngine,
  990. &nScriptState,
  991. pTemplate,
  992. iScriptBlock);
  993. }
  994. if (FAILED(hr))
  995. goto LExit;
  996. // BUG 252: Keep track of how many engines we actually instantiate
  997. ++pEngineInfo->cActiveEngines;
  998. if (nScriptState == SCRIPTSTATE_UNINITIALIZED || fGlobalAsa)
  999. {
  1000. if (FAILED(hr = pScriptInfo->pScriptEngine->AddObjects(!fGlobalAsa)))
  1001. goto LExit;
  1002. }
  1003. if (nScriptState == SCRIPTSTATE_UNINITIALIZED)
  1004. {
  1005. if (FAILED(hr = pScriptInfo->pScriptEngine->AddScriptlet(wstrScript)))
  1006. goto LExit;
  1007. }
  1008. // Add the engine to the scripting namespace
  1009. if (FAILED(hr = pScriptingNamespace->AddEngineToNamespace(
  1010. (CActiveScriptEngine *)pScriptInfo->pScriptEngine)))
  1011. goto LExit;
  1012. // Update locale & code page (in case they are different om this page)
  1013. pScriptInfo->pScriptEngine->UpdateLocaleInfo(hostinfoLocale);
  1014. pScriptInfo->pScriptEngine->UpdateLocaleInfo(hostinfoCodePage);
  1015. }
  1016. // Add the scripting namespace to each script engine. Because all engines might not
  1017. // implement "lazy instantiation", this code requires all
  1018. // engines are pre-instantiated (which means we can't do it in the above loop.)
  1019. // Add the scripting namespace to the hitobj first
  1020. pHitObj->AddScriptingNamespace(pScriptingNamespace);
  1021. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1022. pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddScriptingNamespace();
  1023. /*
  1024. * Bug 735:
  1025. * Bring all engines except the "primary engine" (engine 0) to runnable state
  1026. * in the order in which script for the given language was found in the script file
  1027. */
  1028. for (iEng = 1; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1029. {
  1030. hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->MakeEngineRunnable();
  1031. if (FAILED(hr))
  1032. goto LExit;
  1033. }
  1034. LExit:
  1035. return(hr);
  1036. }
  1037. /*===================================================================
  1038. DeAllocAndFreeEngines
  1039. Deallocate and free any loaded engines
  1040. Parameters:
  1041. pEngineInfo - Engine info to release
  1042. Returns:
  1043. Nothing
  1044. ===================================================================*/
  1045. VOID DeAllocAndFreeEngines
  1046. (
  1047. ActiveEngineInfo *pEngineInfo,
  1048. CAppln *pAppln,
  1049. IASPObjectContextCustom *pTxnScriptContextCustom
  1050. )
  1051. {
  1052. WORD iEng;
  1053. Assert(pEngineInfo != NULL);
  1054. if (pEngineInfo->cActiveEngines > 0) {
  1055. if (pEngineInfo->rgActiveEngines == NULL) {
  1056. Assert(pEngineInfo->rgActiveEngines);
  1057. }
  1058. else {
  1059. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1060. g_ScriptManager.ReturnEngineToCache(&pEngineInfo->rgActiveEngines[iEng].pScriptEngine, pAppln, pTxnScriptContextCustom);
  1061. pEngineInfo->cActiveEngines = 0;
  1062. }
  1063. }
  1064. if (pEngineInfo->cEngines > 1)
  1065. {
  1066. delete pEngineInfo->rgActiveEngines;
  1067. }
  1068. pEngineInfo->cEngines = 0;
  1069. pEngineInfo->rgActiveEngines = NULL;
  1070. }
  1071. /*===================================================================
  1072. GetScriptEngine
  1073. Get a script engine based on index. Return NULL if the index
  1074. is not in range. (this is a callback)
  1075. The AllocAndLoadEngines function will create an array of ScriptingInfo
  1076. structures that are defined here. It contains all the infomation
  1077. needed to 1. set up the MapScript2SourceLine callback,
  1078. 2. merge namespaces, 3. set up this callback.
  1079. Parameters:
  1080. iScriptEngine - the script engine to retrieve
  1081. pvData - instance data for the function
  1082. Returns:
  1083. The requested script engine or NULL if not such engine
  1084. Side effects:
  1085. None
  1086. ===================================================================*/
  1087. CScriptEngine *GetScriptEngine
  1088. (
  1089. INT iScriptEngine,
  1090. VOID *pvData
  1091. )
  1092. {
  1093. ActiveEngineInfo *pInfo = static_cast<ActiveEngineInfo *>(pvData);
  1094. if (unsigned(iScriptEngine) >= unsigned(pInfo->cActiveEngines))
  1095. {
  1096. // Note: the caller has no idea how many script engines there are.
  1097. // if the caller asks for an engine out of range, return NULL so they
  1098. // know they have asked for more than there are
  1099. return NULL;
  1100. }
  1101. return(pInfo->rgActiveEngines[iScriptEngine].pScriptEngine);
  1102. }
  1103. /*===================================================================
  1104. CallScriptFunctionOfEngine
  1105. Calls a script engine to execute one of its functions
  1106. Returns:
  1107. S_OK on success
  1108. Side effects:
  1109. None
  1110. ===================================================================*/
  1111. HRESULT CallScriptFunctionOfEngine
  1112. (
  1113. ActiveEngineInfo &engineInfo,
  1114. short iScriptBlock,
  1115. wchar_t *strFunction,
  1116. IASPObjectContextCustom *pTxnScriptContextCustom,
  1117. BOOLB *pfAborted
  1118. )
  1119. {
  1120. HRESULT hr;
  1121. Assert(engineInfo.rgActiveEngines != NULL);
  1122. Assert(engineInfo.rgActiveEngines[iScriptBlock].pScriptEngine != NULL);
  1123. Assert(pfAborted != NULL);
  1124. *pfAborted = FALSE;
  1125. /*
  1126. * If they want a transaction, then we create a TransactedScript object
  1127. * and tell it to call the engine
  1128. */
  1129. if (pTxnScriptContextCustom)
  1130. {
  1131. hr = pTxnScriptContextCustom->Call(
  1132. #ifdef _WIN64
  1133. // Win64 fix -- use UINT64 instead of LONG_PTR since LONG_PTR is broken for Win64 1/21/2000
  1134. (UINT64)engineInfo.rgActiveEngines[iScriptBlock].pScriptEngine,strFunction, pfAborted);
  1135. #else
  1136. (LONG_PTR)engineInfo.rgActiveEngines[iScriptBlock].pScriptEngine,strFunction, pfAborted);
  1137. #endif
  1138. }
  1139. else
  1140. {
  1141. hr = engineInfo.rgActiveEngines[iScriptBlock].pScriptEngine->Call(strFunction);
  1142. }
  1143. return hr;
  1144. }
  1145. /*===================================================================
  1146. CallScriptFunction
  1147. Calls each script engine in turn to execute a script function;
  1148. exits when an engine succeeds or we run out of engines.
  1149. Returns:
  1150. S_OK on success
  1151. Side effects:
  1152. None
  1153. ===================================================================*/
  1154. HRESULT CallScriptFunction
  1155. (
  1156. ActiveEngineInfo &engineInfo,
  1157. wchar_t *strFunction,
  1158. IASPObjectContextCustom *pTxnScriptContextCustom,
  1159. BOOLB *pfAborted
  1160. )
  1161. {
  1162. HRESULT hr = E_FAIL;
  1163. int i;
  1164. for (i = 0; i < engineInfo.cActiveEngines; i++)
  1165. {
  1166. // if execution succeeds, bail
  1167. if (SUCCEEDED(hr = CallScriptFunctionOfEngine(engineInfo, (SHORT)i, strFunction,
  1168. pTxnScriptContextCustom, pfAborted)))
  1169. goto LExit;
  1170. // if execution fails with exception other then unknown name, bail
  1171. if (hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND)
  1172. goto LExit;
  1173. }
  1174. LExit:
  1175. return hr;
  1176. }
  1177. /*===================================================================
  1178. TestScriptFunction
  1179. Tests each script engine in turn to test [the existance of] a script
  1180. function; exits when an engine succeeds or we run out of engines.
  1181. Parameters
  1182. ActiveEngineInfo &engineInfo
  1183. wchar_t *strFunction functions name
  1184. Returns:
  1185. S_OK if exists
  1186. Side effects:
  1187. None
  1188. ===================================================================*/
  1189. HRESULT TestScriptFunction
  1190. (
  1191. ActiveEngineInfo &engineInfo,
  1192. wchar_t *strFunction
  1193. )
  1194. {
  1195. HRESULT hr = E_FAIL;
  1196. for (int i = 0; i < engineInfo.cActiveEngines; i++)
  1197. {
  1198. hr = engineInfo.rgActiveEngines[i].pScriptEngine->
  1199. CheckEntryPoint(strFunction);
  1200. // if execution succeeds, bail
  1201. if (SUCCEEDED(hr))
  1202. break;
  1203. // if fails with result other then unknown name, bail
  1204. if (hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND)
  1205. break;
  1206. }
  1207. return hr;
  1208. }