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.

1521 lines
46 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. #include <iismsg.h>
  19. // Local declarations
  20. HRESULT ExecuteGlobal(CHitObj *pHitObj,
  21. const CIntrinsicObjects &intrinsics,
  22. ActiveEngineInfo *pEngineInfo);
  23. HRESULT ExecuteRequest(CTemplate *pTemplate, CHitObj *pHitObj,
  24. const CIntrinsicObjects &intrinsics,
  25. ActiveEngineInfo *pEngineInfo);
  26. HRESULT ReInitIntrinsics(CHitObj *pHitObj, const CIntrinsicObjects &intrinsics,
  27. ActiveEngineInfo *pEngineInfo, BOOL fPostGlobal);
  28. HRESULT AllocAndLoadEngines(CHitObj *pHitObj, CTemplate *pTemplate, ActiveEngineInfo *pEngineInfo,
  29. CScriptingNamespace *pScriptingNamespace, BOOL fGlobalAsa);
  30. VOID DeAllocAndFreeEngines(ActiveEngineInfo *pEngineInfo, CAppln *pAppln);
  31. CScriptEngine *GetScriptEngine(int iScriptEngine, void *pvData);
  32. HRESULT CallScriptFunctionOfEngine(ActiveEngineInfo &engineInfo, short iScriptBlock, wchar_t *strFunction, CASPObjectContext *pASPObjectContext = NULL);
  33. HRESULT CallScriptFunction(ActiveEngineInfo &engineInfo, wchar_t *strFunction);
  34. HRESULT TestScriptFunction(ActiveEngineInfo &engineInfo, wchar_t *strFunction);
  35. /*===================================================================
  36. Execute
  37. Execute a request:
  38. First determine if Global needs to be called
  39. then invoke actual requested template
  40. Parameters:
  41. pTemplate - pointer to loaded template (could be NULL)
  42. pHitObj - pointer to the hit object
  43. intrinsics - pointers to the intrinsic IUnknown pointers.
  44. fChild - flag: TRUE when child request (Server.Execute())
  45. Returns:
  46. S_OK on success
  47. ===================================================================*/
  48. HRESULT Execute
  49. (
  50. CTemplate *pTemplate,
  51. CHitObj *pHitObj,
  52. const CIntrinsicObjects &intrinsics,
  53. BOOL fChild
  54. )
  55. {
  56. HRESULT hr = S_OK;
  57. ActiveEngineInfo engineInfo;
  58. BOOL fRanGlobal = FALSE;
  59. // The hit obj must be valid
  60. Assert(pHitObj != NULL);
  61. pHitObj->AssertValid();
  62. // Check for valid Session codepage. We do it here, rather than in CSession::Init in
  63. // order to avoid generic "New Session Failed" message.
  64. if (pHitObj->GetCodePage() != CP_ACP && !IsValidCodePage(pHitObj->GetCodePage()))
  65. {
  66. HandleErrorMissingFilename(IDE_BAD_CODEPAGE_IN_MB, pHitObj);
  67. return E_FAIL;
  68. }
  69. // Give the engine list to the hitobject
  70. pHitObj->SetActiveEngineInfo(&engineInfo);
  71. /*
  72. * If there is a Global.ASA, call it
  73. */
  74. if (pHitObj->GlobalAspPath() && !fChild)
  75. {
  76. // Clear out the engine info
  77. engineInfo.cEngines = 0;
  78. engineInfo.cActiveEngines = 0;
  79. engineInfo.rgActiveEngines = NULL;
  80. // Init the intrinsics
  81. hr = ReInitIntrinsics(pHitObj, intrinsics, &engineInfo, /* fPostGlobal*/ FALSE);
  82. if (FAILED(hr))
  83. return(hr);
  84. hr = ExecuteGlobal(pHitObj, intrinsics, &engineInfo);
  85. if (intrinsics.PResponse() && intrinsics.PResponse()->FResponseAborted())
  86. {
  87. hr = S_OK;
  88. goto LExit;
  89. }
  90. if (E_SOURCE_FILE_IS_EMPTY == hr)
  91. // bug 977: silently ignore empty global.asa file
  92. hr = S_OK;
  93. else if (FAILED(hr))
  94. {
  95. // Bug 481: If global.asa fails due to Response.End (or Response.Redirect),
  96. // then halt execution of the calling script. If the
  97. // script fails due to Response.End, then return OK status
  98. //
  99. if (hr == DISP_E_EXCEPTION)
  100. hr = S_OK;
  101. // In any case, blow out of here
  102. goto LExit;
  103. }
  104. // Running Global.asa added the scripting namespace to the hitobj. This will cause us problems
  105. // later, remove it.
  106. pHitObj->RemoveScriptingNamespace();
  107. fRanGlobal = TRUE;
  108. }
  109. /*
  110. * If this is not a browser request, then we are done
  111. * For non-browser requests, we do want to run Global.asa (if any), but there is no real template to run.
  112. */
  113. if (!pHitObj->FIsBrowserRequest())
  114. {
  115. hr = S_OK;
  116. goto LExit;
  117. }
  118. // Clear out (or re-clear out) the engine info
  119. engineInfo.cEngines = 0;
  120. engineInfo.cActiveEngines = 0;
  121. engineInfo.rgActiveEngines = NULL;
  122. // Init or Re-Init the intrinsics
  123. ReInitIntrinsics(pHitObj, intrinsics, &engineInfo, fRanGlobal || fChild);
  124. if (!fChild)
  125. {
  126. // For non-child requests hand new Template to Response object
  127. // (for child requests already done)
  128. intrinsics.PResponse()->ReInitTemplate(pTemplate, pHitObj->PSzNewSessionCookie());
  129. }
  130. else
  131. {
  132. // For child requests hand new engine info to the response object
  133. intrinsics.PResponse()->SwapScriptEngineInfo(&engineInfo);
  134. }
  135. // Run the main template
  136. if (pTemplate->FScriptless() && !pHitObj->PAppln()->FDebuggable())
  137. {
  138. // special case scriptless pages
  139. hr = intrinsics.PResponse()->WriteBlock(0);
  140. }
  141. else
  142. {
  143. hr = ExecuteRequest(pTemplate, pHitObj, intrinsics, &engineInfo);
  144. }
  145. LExit:
  146. intrinsics.PResponse()->SwapScriptEngineInfo(NULL);
  147. pHitObj->SetActiveEngineInfo(NULL);
  148. return hr;
  149. }
  150. /*===================================================================
  151. ExecRequest
  152. Execute a request for an actual template (not Global.asa)
  153. execute a request by
  154. - getting the script name
  155. - loading the script into memory
  156. - interpreting the opcodes
  157. Parameters:
  158. pTemplate - pointer to loaded template
  159. pHitObj - pointer to the hit object
  160. intrinsics - pointers to the intrinsic IUnknown pointers.
  161. pEngineInfo - pointers to engine info
  162. Returns:
  163. S_OK on success
  164. ===================================================================*/
  165. HRESULT ExecuteRequest(CTemplate *pTemplate,
  166. CHitObj *pHitObj,
  167. const CIntrinsicObjects &intrinsics,
  168. ActiveEngineInfo *pEngineInfo)
  169. {
  170. HRESULT hr = S_OK;
  171. BOOL fAborted = FALSE;
  172. BOOLB fDebuggerNotifiedOnStart = FALSE;
  173. BOOL fServiceDomainEnterred = FALSE;
  174. CASPObjectContext *pASPObjectContext = NULL;
  175. CASPObjectContext *pPoppedASPObjectContext = NULL;
  176. #ifndef PERF_DISABLE
  177. BOOLB fPerfTransPending = FALSE;
  178. #endif
  179. // The template must be valid
  180. Assert(pTemplate);
  181. // The hit obj must be valid
  182. Assert(pHitObj != NULL);
  183. pHitObj->AssertValid();
  184. // This function should never be called on a non-browser request
  185. Assert(pHitObj->FIsBrowserRequest());
  186. // Remember template's type library wrapper with the HitObj
  187. if (pTemplate->PTypeLibWrapper())
  188. pHitObj->SetTypeLibWrapper(pTemplate->PTypeLibWrapper());
  189. if (pTemplate->FTransacted()) {
  190. #ifndef PERF_DISABLE
  191. g_PerfData.Incr_TRANSTOTAL();
  192. g_PerfData.Incr_TRANSPENDING();
  193. fPerfTransPending = TRUE;
  194. #endif
  195. pASPObjectContext = new CASPObjectContext();
  196. if (!pASPObjectContext) {
  197. hr = E_OUTOFMEMORY;
  198. goto LExit;
  199. }
  200. pPoppedASPObjectContext = pHitObj->SetASPObjectContext(pASPObjectContext);
  201. }
  202. if (pTemplate->PServicesConfig()) {
  203. hr = CoEnterServiceDomain(pTemplate->PServicesConfig());
  204. if (FAILED(hr)) {
  205. goto LExit;
  206. }
  207. fServiceDomainEnterred = TRUE;
  208. }
  209. // load script engines
  210. hr = AllocAndLoadEngines(pHitObj, pTemplate, pEngineInfo, intrinsics.PScriptingNamespace(), /* fGlobalAsa */FALSE);
  211. if (FAILED(hr)) {
  212. pHitObj->SetCompilationFailed();
  213. goto LExit;
  214. }
  215. // If debugging, notify debugger ONPAGESTART
  216. // BUG 138773: Notify debugger AFTER scripts load
  217. // (script must be in running state when AttachTo() is called because debugger may want a code context)
  218. //
  219. if (pHitObj->PAppln()->FDebuggable()) {
  220. pTemplate->AttachTo(pHitObj->PAppln());
  221. if (SUCCEEDED(pTemplate->NotifyDebuggerOnPageEvent(TRUE)))
  222. fDebuggerNotifiedOnStart = TRUE;
  223. }
  224. // bug 1009: if no script engines, do not attempt to do anything
  225. if(0 == pTemplate->CountScriptEngines())
  226. goto LExit;
  227. // run the script by calling primary script engine's global code
  228. hr = CallScriptFunctionOfEngine(*pEngineInfo, // engine-info
  229. 0, // primary script engine
  230. NULL, // call the engine's global code
  231. pHitObj->PASPObjectContext());
  232. if (fServiceDomainEnterred) {
  233. fServiceDomainEnterred = FALSE;
  234. CoLeaveServiceDomain(static_cast<ITransactionStatus *>(pHitObj->PASPObjectContext()));
  235. }
  236. if (pTemplate->FTransacted()) {
  237. fAborted = pHitObj->PASPObjectContext()->FAborted();
  238. }
  239. if (FAILED(hr)) {
  240. /*
  241. * The cryptically named CONTEXT_E_OLDREF error in this case means that
  242. * we are trying to run a transacted web page, but DTC isnt running.
  243. * CONTEXT_E_TMNOTAVAILABLE means the same thing. God knows why
  244. */
  245. if (hr == CONTEXT_E_OLDREF || hr == CONTEXT_E_TMNOTAVAILABLE) {
  246. HandleErrorMissingFilename(IDE_EXECUTOR_DTC_NOT_RUNNING, pHitObj);
  247. }
  248. // Regardless of the error, exit
  249. goto LExit;
  250. }
  251. /*
  252. * If this is a transacted web page, then run either the OnTransactionCommit
  253. * or OnTransactionAbort method in the script, if any.
  254. *
  255. * If the script writer did an explicit SetAbort, or a component run by the script
  256. * did a SetAbort, then we run OnTransactionAbort, otherwise run OnTransactionCommit
  257. */
  258. if (pTemplate->FTransacted()) {
  259. #ifndef PERF_DISABLE
  260. g_PerfData.Incr_TRANSPERSEC();
  261. #endif
  262. if (fAborted) {
  263. hr = CallScriptFunction(*pEngineInfo, L"OnTransactionAbort");
  264. #ifndef PERF_DISABLE
  265. g_PerfData.Incr_TRANSABORTED();
  266. #endif
  267. }
  268. else {
  269. hr = CallScriptFunction(*pEngineInfo, L"OnTransactionCommit");
  270. #ifndef PERF_DISABLE
  271. g_PerfData.Incr_TRANSCOMMIT();
  272. #endif
  273. }
  274. // Ignore UNKNOWNNAME -- this means the author didnt write the method, which is fine
  275. if (hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND)
  276. hr = S_OK;
  277. if (FAILED(hr))
  278. goto LExit;
  279. }
  280. LExit:
  281. //
  282. // Return the engine(s) to cache. Be sure to do this before leaving the services domain
  283. // after we have deallocated the freed the engines or else the context will leak Variant objects
  284. // as the reset script code will not make it to the various variant allocated during the running of the script.
  285. //
  286. DeAllocAndFreeEngines(pEngineInfo, pHitObj->PAppln());
  287. if (fServiceDomainEnterred) {
  288. CoLeaveServiceDomain(NULL);
  289. }
  290. #ifndef PERF_DISABLE
  291. if (fPerfTransPending)
  292. g_PerfData.Decr_TRANSPENDING();
  293. #endif
  294. // Uninit the scripting namespace
  295. (VOID)intrinsics.PScriptingNamespace()->UnInit();
  296. // If debugging, notify debugger ONPAGEDONE
  297. if (fDebuggerNotifiedOnStart) {
  298. Assert(pHitObj->PAppln()->FDebuggable());
  299. pTemplate->NotifyDebuggerOnPageEvent(FALSE);
  300. }
  301. if (pPoppedASPObjectContext)
  302. pHitObj->SetASPObjectContext(pPoppedASPObjectContext);
  303. if (pASPObjectContext)
  304. pASPObjectContext->Release();
  305. return hr;
  306. }
  307. /*===================================================================
  308. ExecuteGlobal
  309. UNDONE: handle script engine the same manner as mainline script engines
  310. with respect to debugging.
  311. Execute code in Global.ASA as part of application or session start or end.
  312. Parameters:
  313. pHitObj - pointer to the hit object
  314. intrinsics - pointers to the intrinsic IUnknown pointers.
  315. pEngineInfo - pointers to engine info
  316. pfDeleteSession - true if global.asa failed, and therefore the caller should
  317. Returns:
  318. S_OK on success
  319. ===================================================================*/
  320. HRESULT ExecuteGlobal
  321. (
  322. CHitObj *pHitObj,
  323. const CIntrinsicObjects &intrinsics,
  324. ActiveEngineInfo *pEngineInfo
  325. )
  326. {
  327. HRESULT hr = S_OK;
  328. CTemplate *pTemplate = NULL;
  329. WORD iEng;
  330. BOOLB fDebuggerNotifiedOnStart = FALSE;
  331. BOOL fUnHideRequestAndResponse = FALSE;
  332. BOOL fOnStartAppln = FALSE;
  333. BOOL fOnEndAppln = FALSE;
  334. BOOL fOnEndSession = FALSE;
  335. BOOL fGlobalAsaInCache;
  336. BOOL fApplnStarted = FALSE;
  337. BOOL fServiceDomainEnterred = FALSE;
  338. CASPObjectContext *pASPObjectContext = NULL;
  339. CASPObjectContext *pPoppedASPObjectContext = NULL;
  340. UINT savedCodePage = CP_ACP;
  341. UINT loadedCodePage = CP_ACP;
  342. // The hit obj must be there, be valid, & have a global.asa name
  343. Assert(pHitObj != NULL);
  344. pHitObj->AssertValid();
  345. Assert(pHitObj->GlobalAspPath() != NULL && *(pHitObj->GlobalAspPath()) != '\0');
  346. // Other arg's must be right
  347. Assert(pEngineInfo != NULL);
  348. // save the current code page in case LoadTemplate changes it...
  349. savedCodePage = pHitObj->GetCodePage();
  350. // Load the script - cache will AddRef
  351. // bug 1051: load template before possibly removing response object (in switch block, below),
  352. // so error reporting to browser will work
  353. hr = LoadTemplate(pHitObj->GlobalAspPath(), pHitObj, &pTemplate, intrinsics, /* fGlobalAsa */ TRUE, &fGlobalAsaInCache);
  354. if (FAILED(hr))
  355. goto LExit;
  356. // get the codepage again so that we can later compare to see if the initial code
  357. // page should be reverted
  358. loadedCodePage = pHitObj->GetCodePage();
  359. Assert(pTemplate != NULL);
  360. // Remember GLOBAL.ASA's type library wrapper with the application
  361. // on the first request
  362. if (pHitObj->FStartApplication() && pTemplate->PTypeLibWrapper())
  363. {
  364. pHitObj->PAppln()->SetGlobTypeLibWrapper(pTemplate->PTypeLibWrapper());
  365. }
  366. if (pTemplate->FTransacted()) {
  367. pASPObjectContext = new CASPObjectContext();
  368. if (!pASPObjectContext) {
  369. hr = E_OUTOFMEMORY;
  370. goto LExit;
  371. }
  372. pPoppedASPObjectContext = pHitObj->SetASPObjectContext(pASPObjectContext);
  373. }
  374. if (pTemplate->PServicesConfig()) {
  375. hr = CoEnterServiceDomain(pTemplate->PServicesConfig());
  376. if (FAILED(hr)) {
  377. goto LExit;
  378. }
  379. fServiceDomainEnterred = TRUE;
  380. }
  381. Assert(pHitObj->FIsValidRequestType());
  382. // Figure out which events to trigger
  383. if (pHitObj->FIsBrowserRequest())
  384. {
  385. fOnStartAppln = pHitObj->FStartApplication();
  386. if (fOnStartAppln)
  387. {
  388. // Hide response and request intrinsics from namespace
  389. pHitObj->HideRequestAndResponseIntrinsics();
  390. // Flag that intrinsics need to be un-hidden back in.
  391. fUnHideRequestAndResponse = TRUE;
  392. }
  393. }
  394. else if (pHitObj->FIsSessionCleanupRequest())
  395. {
  396. fOnEndSession = TRUE;
  397. }
  398. else if (pHitObj->FIsApplnCleanupRequest())
  399. {
  400. fOnEndAppln = TRUE;
  401. }
  402. // If debugging, notify debugger ONPAGESTART
  403. if (pHitObj->PAppln()->FDebuggable())
  404. {
  405. if (SUCCEEDED(pTemplate->NotifyDebuggerOnPageEvent(TRUE)))
  406. fDebuggerNotifiedOnStart = TRUE;
  407. }
  408. hr = AllocAndLoadEngines(pHitObj, pTemplate, pEngineInfo, intrinsics.PScriptingNamespace(), /* fGlobalAsa */TRUE);
  409. if (FAILED(hr))
  410. goto LExit;
  411. // BUG 93991: Defer registration of new document with debugger until after script engines have
  412. // been loaded
  413. //
  414. if (!fGlobalAsaInCache && pHitObj->PAppln()->FDebuggable())
  415. pTemplate->AttachTo(pHitObj->PAppln());
  416. // bug 975: if no script engines, do not attempt to call event functions
  417. if(0 == pTemplate->CountScriptEngines())
  418. goto LExit;
  419. /*
  420. * Call event functions as required
  421. * bug 459: event functions may be in any script engine
  422. */
  423. // First run Application_OnStart
  424. if (fOnStartAppln)
  425. {
  426. pHitObj->SetEventState(eEventAppOnStart);
  427. hr = CallScriptFunction(*pEngineInfo, L"Application_OnStart");
  428. if (SUCCEEDED(hr) || hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND ||
  429. intrinsics.PResponse()->FResponseAborted())
  430. {
  431. if (fUnHideRequestAndResponse)
  432. {
  433. pHitObj->UnHideRequestAndResponseIntrinsics();
  434. fUnHideRequestAndResponse = FALSE;
  435. }
  436. fApplnStarted = TRUE;
  437. hr = S_OK;
  438. }
  439. else
  440. {
  441. goto LExit;
  442. }
  443. }
  444. if (pHitObj->FStartSession())
  445. {
  446. // If application on start was run, add Response and Request names to script engines
  447. if (fOnStartAppln)
  448. {
  449. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  450. {
  451. if (FAILED(hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddAdditionalObject(WSZ_OBJ_RESPONSE, FALSE)))
  452. goto LExit;
  453. if (FAILED(hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddAdditionalObject(WSZ_OBJ_REQUEST, FALSE)))
  454. goto LExit;
  455. }
  456. }
  457. pHitObj->SetEventState(eEventSesOnStart);
  458. hr = CallScriptFunction(*pEngineInfo, L"Session_OnStart");
  459. if (FAILED(hr) && hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND &&
  460. !intrinsics.PResponse()->FResponseAborted())
  461. {
  462. // Mark session as on-start-failed - to be deleted soon
  463. pHitObj->SessionOnStartFailed();
  464. }
  465. else
  466. {
  467. if (SUCCEEDED(hr))
  468. {
  469. // Mark as on-start-invoked -- need to wait for timeout
  470. pHitObj->SessionOnStartInvoked();
  471. }
  472. // Check if Session_OnEnd Present
  473. if (SUCCEEDED(TestScriptFunction(*pEngineInfo, L"Session_OnEnd")))
  474. {
  475. // Mark as on-end-present -- need to execute OnEnd later
  476. pHitObj->SessionOnEndPresent();
  477. }
  478. hr = S_OK;
  479. }
  480. goto LExit;
  481. }
  482. BOOL fImpersonationSet = FALSE;
  483. BOOL fExecuteOnEnd = TRUE;
  484. // no need to even attempt to run Session_OnEnd if it isn't present
  485. if (fOnEndSession && FAILED(TestScriptFunction(*pEngineInfo, L"Session_OnEnd")))
  486. fOnEndSession = FALSE;
  487. // same for application_onend
  488. if (fOnEndAppln && FAILED(TestScriptFunction(*pEngineInfo, L"Application_OnEnd")))
  489. fOnEndAppln = FALSE;
  490. if (fOnEndSession || fOnEndAppln) {
  491. // Is the OnEnd routine supposed to be executed as the Anonymous user?
  492. if (pHitObj->PAppln()->QueryAppConfig()->fRunOnEndAsAnon()) {
  493. // if so, but we don't have a valid token, then we can't
  494. if (pHitObj->PAppln()->QueryAppConfig()->AnonToken() == INVALID_HANDLE_VALUE) {
  495. MSG_Error(MSG_APPL_ERROR_GETTING_ANON_TOKEN,
  496. pHitObj->PAppln()->GetMetabaseKey());
  497. fExecuteOnEnd = FALSE;
  498. }
  499. else {
  500. fImpersonationSet = ImpersonateLoggedOnUser(pHitObj->PAppln()->QueryAppConfig()->AnonToken());
  501. if (fImpersonationSet == FALSE) {
  502. MSG_Error(MSG_APPL_ERROR_IMPERSONATING_ANON_USER,
  503. pHitObj->PAppln()->GetMetabaseKey());
  504. fExecuteOnEnd = FALSE;
  505. }
  506. else {
  507. fImpersonationSet = TRUE;
  508. }
  509. }
  510. }
  511. }
  512. if (fOnEndSession && fExecuteOnEnd) {
  513. pHitObj->SetEventState(eEventSesOnEnd);
  514. hr = CallScriptFunction(*pEngineInfo, L"Session_OnEnd");
  515. // We are failing silently here, since there is no corrective action we could take
  516. }
  517. if (fOnEndAppln && fExecuteOnEnd) {
  518. pHitObj->SetEventState(eEventAppOnEnd);
  519. hr = CallScriptFunction(*pEngineInfo, L"Application_OnEnd");
  520. // We are failing silently here, since there is no corrective action we could take
  521. }
  522. // need to undo impersonation if it was set when executing the OnEnd
  523. // routines. Note that a RevertToSelf is the right thing to do here
  524. // as there should not have been any impersonation on the thread in
  525. // the OnEnd case.
  526. if (fImpersonationSet)
  527. RevertToSelf();
  528. LExit:
  529. // restore the codepage in the hit object if it changed after loading
  530. // and the session's codepage wasn't explicitly set.
  531. if ((loadedCodePage != savedCodePage)
  532. && (!pHitObj->FHasSession() || !pHitObj->PSession()->FCodePageSet()))
  533. pHitObj->SetCodePage(savedCodePage);
  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());
  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. if (fServiceDomainEnterred)
  561. CoLeaveServiceDomain(NULL);
  562. // It is OK if the event function was not found in global.asa
  563. if (hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND)
  564. {
  565. hr = S_OK;
  566. }
  567. if (pPoppedASPObjectContext)
  568. pHitObj->SetASPObjectContext(pPoppedASPObjectContext);
  569. if (pASPObjectContext)
  570. pASPObjectContext->Release();
  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. DWORD nRetryCount=0;
  821. Assert(pHitObj != NULL);
  822. pHitObj->AssertValid();
  823. Assert(ppTemplate != NULL);
  824. //
  825. // Verify that we are recieving a valid filename. If not there is something seriously broken.
  826. // We cannot have a browser request without a URL?
  827. //
  828. Assert(szFile);
  829. if (_tcslen(szFile) == 0)
  830. {
  831. // Could not obtain the PathTranslated corresponding to this file.
  832. // Report a Server 500 Error
  833. pHitObj->ReportServerError(IDE_500_SERVER_ERROR);
  834. return E_FAIL;
  835. }
  836. Retry:
  837. // Load the script - cache will AddRef
  838. if (FAILED(hr = g_TemplateCache.Load(
  839. fGlobalAsa,
  840. szFile,
  841. pHitObj->DWInstanceID(),
  842. pHitObj,
  843. ppTemplate,
  844. pfTemplateInCache)))
  845. {
  846. // handle the inpage I/O Error.
  847. // if inpage I/O error is returned, retry the Load up to 5 times...
  848. if (hr == STATUS_IN_PAGE_ERROR /*0xc0000006*/) {
  849. if (nRetryCount++ < 5) {
  850. if (*ppTemplate) {
  851. (*ppTemplate)->Release();
  852. *ppTemplate = NULL;
  853. }
  854. goto Retry;
  855. }
  856. else {
  857. // if retried more than 5 times, give up and return error
  858. hr = E_COULDNT_OPEN_SOURCE_FILE;
  859. }
  860. }
  861. // CONSIDER moving this cleanup into Template.Load
  862. if (hr == E_COULDNT_OPEN_SOURCE_FILE)
  863. {
  864. // Load error string from string table
  865. // BUG 731: added if to retrieve the correct header
  866. WCHAR szwErr[128];
  867. CwchLoadStringOfId(IDH_404_OBJECT_NOT_FOUND, szwErr, 128);
  868. intrinsics.PResponse()->put_Status( szwErr );
  869. HandleSysError(404, 0, IDE_404_OBJECT_NOT_FOUND, NULL, NULL, pHitObj);
  870. #ifndef PERF_DISABLE
  871. g_PerfData.Incr_REQNOTFOUND();
  872. #endif
  873. }
  874. // fix for bug 371
  875. if (*ppTemplate)
  876. {
  877. (*ppTemplate)->Release();
  878. *ppTemplate = NULL;
  879. }
  880. if (hr == E_OUTOFMEMORY)
  881. {
  882. DBGPRINTF((DBG_CONTEXT, "Loading template returned E_OUTOFMEMORY. Flushing template & Script Cache.\n"));
  883. g_TemplateCache.FlushAll();
  884. g_ScriptManager.FlushAll();
  885. }
  886. }
  887. return(hr);
  888. }
  889. /*===================================================================
  890. AllocAndLoadEngines
  891. Allocate and load all the engines we need
  892. Parameters:
  893. pHitObj - The hit object
  894. pTemplate - The template we're gonna run
  895. pEngineInfo - Engine info to fill in
  896. pScriptingNamespace - scripting namespace
  897. fGlobalAsa - Are we loading engines to run global.asa?
  898. Returns:
  899. S_OK on success
  900. ===================================================================*/
  901. HRESULT AllocAndLoadEngines
  902. (
  903. CHitObj *pHitObj,
  904. CTemplate *pTemplate,
  905. ActiveEngineInfo *pEngineInfo,
  906. CScriptingNamespace *pScriptingNamespace,
  907. BOOL fGlobalAsa
  908. )
  909. {
  910. HRESULT hr = S_OK;
  911. int iObj;
  912. WORD iEng;
  913. WORD iScriptBlock;
  914. WORD cEngines = pTemplate->CountScriptEngines();
  915. Assert(pHitObj != NULL);
  916. pHitObj->AssertValid();
  917. Assert(pTemplate != NULL);
  918. Assert(pEngineInfo != NULL);
  919. Assert(pScriptingNamespace != NULL);
  920. // Load objects from template into hit object
  921. for (iObj = pTemplate->Count(tcompObjectInfo) - 1; iObj >= 0; --iObj)
  922. {
  923. CHAR *szObjectName = NULL;
  924. CLSID clsid;
  925. CompScope scope;
  926. CompModel model;
  927. CMBCSToWChar convStr;
  928. // get object-info from template and add to hitobj's list of objects
  929. hr = pTemplate->GetObjectInfo(iObj, &szObjectName, &clsid, &scope, &model);
  930. if(FAILED(hr))
  931. goto LExit;
  932. hr = convStr.Init(szObjectName);
  933. if (FAILED(hr))
  934. goto LExit;
  935. // ignore error ?
  936. pHitObj->AddComponent(ctTagged, clsid, scope, model, convStr.GetString());
  937. }
  938. // bug 975: if no script engines, exit now
  939. if(cEngines == 0)
  940. goto LExit;
  941. // Allocate space for script engines
  942. //
  943. // NOTE: There is a timing problem here in that the response object needs to
  944. // be instantiated before we instantiate the script engines, but the
  945. // response object needs to be able to access the list of active script
  946. // engines, because it may need to halt execution. To accomplish this,
  947. // the response object is passed a pointer to the "EngineInfo" structure
  948. // as a pointer, and then we modify the contents of the pointer right under
  949. // its nose. We pass an accessor function via pointer so that response just
  950. // sees a void pointer.
  951. //
  952. if (cEngines == 1)
  953. {
  954. // don't do allocations in case of one engine
  955. pEngineInfo->rgActiveEngines = & (pEngineInfo->siOneActiveEngine);
  956. }
  957. else
  958. {
  959. pEngineInfo->rgActiveEngines = new ScriptingInfo[cEngines];
  960. if (pEngineInfo->rgActiveEngines == NULL)
  961. {
  962. hr = E_OUTOFMEMORY;
  963. goto LExit;
  964. }
  965. }
  966. pEngineInfo->cEngines = cEngines;
  967. pEngineInfo->cActiveEngines = 0; // number of SUCCESSFULLY instantiated engines
  968. // Load all of the script engines in advance.
  969. for (iScriptBlock = 0; iScriptBlock < cEngines; ++iScriptBlock)
  970. {
  971. LPCOLESTR wstrScript;
  972. SCRIPTSTATE nScriptState;
  973. ScriptingInfo *pScriptInfo = &pEngineInfo->rgActiveEngines[iScriptBlock];
  974. pTemplate->GetScriptBlock(
  975. iScriptBlock,
  976. &pScriptInfo->szScriptEngine,
  977. &pScriptInfo->pProgLangId,
  978. &wstrScript);
  979. // Populate information required for the line mapping callback.
  980. //
  981. pScriptInfo->LineMapInfo.iScriptBlock = iScriptBlock;
  982. pScriptInfo->LineMapInfo.pTemplate = pTemplate;
  983. // acquire a script engine by:
  984. //
  985. // getting an engine from the template object (if it has one)
  986. // else from the script manager.
  987. //
  988. // If we are in debug mode, the templates tend to be greedy and hold
  989. // onto script engines. (See notes in scrptmgr.h)
  990. //
  991. pScriptInfo->pScriptEngine = NULL;
  992. if (pHitObj->PAppln()->FDebuggable())
  993. {
  994. pScriptInfo->pScriptEngine = pTemplate->GetActiveScript(iScriptBlock);
  995. if (pScriptInfo->pScriptEngine)
  996. {
  997. // If we got one, we don't need to re-init the engine
  998. nScriptState = SCRIPTSTATE_INITIALIZED;
  999. hr = static_cast<CActiveScriptEngine *>(pScriptInfo->pScriptEngine)->ReuseEngine(pHitObj, NULL, iScriptBlock, pHitObj->DWInstanceID());
  1000. }
  1001. }
  1002. if (pScriptInfo->pScriptEngine == NULL)
  1003. {
  1004. hr = g_ScriptManager.GetEngine(LOCALE_SYSTEM_DEFAULT,
  1005. *(pScriptInfo->pProgLangId),
  1006. pTemplate->GetSourceFileName(),
  1007. pHitObj,
  1008. &pScriptInfo->pScriptEngine,
  1009. &nScriptState,
  1010. pTemplate,
  1011. iScriptBlock);
  1012. }
  1013. if (FAILED(hr))
  1014. goto LExit;
  1015. // BUG 252: Keep track of how many engines we actually instantiate
  1016. ++pEngineInfo->cActiveEngines;
  1017. if (nScriptState == SCRIPTSTATE_UNINITIALIZED || fGlobalAsa)
  1018. {
  1019. if (FAILED(hr = pScriptInfo->pScriptEngine->AddObjects(!fGlobalAsa)))
  1020. goto LExit;
  1021. }
  1022. if (nScriptState == SCRIPTSTATE_UNINITIALIZED)
  1023. {
  1024. if (FAILED(hr = pScriptInfo->pScriptEngine->AddScriptlet(wstrScript)))
  1025. goto LExit;
  1026. }
  1027. // Add the engine to the scripting namespace
  1028. if (FAILED(hr = pScriptingNamespace->AddEngineToNamespace(
  1029. (CActiveScriptEngine *)pScriptInfo->pScriptEngine)))
  1030. goto LExit;
  1031. // Update locale & code page (in case they are different om this page)
  1032. pScriptInfo->pScriptEngine->UpdateLocaleInfo(hostinfoLocale);
  1033. pScriptInfo->pScriptEngine->UpdateLocaleInfo(hostinfoCodePage);
  1034. }
  1035. // Add the scripting namespace to each script engine. Because all engines might not
  1036. // implement "lazy instantiation", this code requires all
  1037. // engines are pre-instantiated (which means we can't do it in the above loop.)
  1038. // Add the scripting namespace to the hitobj first
  1039. pHitObj->AddScriptingNamespace(pScriptingNamespace);
  1040. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1041. pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddScriptingNamespace();
  1042. /*
  1043. * Bring all engines, except the "primary engine" (engine 0) when the template
  1044. * isn't global.asa, to runnable state in the order in which script for the
  1045. * given language was found in the script file.
  1046. */
  1047. for (iEng = fGlobalAsa ? 0 : 1; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1048. {
  1049. hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->MakeEngineRunnable();
  1050. if (FAILED(hr))
  1051. goto LExit;
  1052. }
  1053. LExit:
  1054. return(hr);
  1055. }
  1056. /*===================================================================
  1057. DeAllocAndFreeEngines
  1058. Deallocate and free any loaded engines
  1059. Parameters:
  1060. pEngineInfo - Engine info to release
  1061. Returns:
  1062. Nothing
  1063. ===================================================================*/
  1064. VOID DeAllocAndFreeEngines
  1065. (
  1066. ActiveEngineInfo *pEngineInfo,
  1067. CAppln *pAppln
  1068. )
  1069. {
  1070. WORD iEng;
  1071. Assert(pEngineInfo != NULL);
  1072. if (pEngineInfo->cActiveEngines > 0) {
  1073. if (pEngineInfo->rgActiveEngines == NULL) {
  1074. Assert(pEngineInfo->rgActiveEngines);
  1075. }
  1076. else {
  1077. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1078. g_ScriptManager.ReturnEngineToCache(&pEngineInfo->rgActiveEngines[iEng].pScriptEngine, pAppln);
  1079. pEngineInfo->cActiveEngines = 0;
  1080. }
  1081. }
  1082. if (pEngineInfo->cEngines > 1)
  1083. {
  1084. delete pEngineInfo->rgActiveEngines;
  1085. }
  1086. pEngineInfo->cEngines = 0;
  1087. pEngineInfo->rgActiveEngines = NULL;
  1088. }
  1089. /*===================================================================
  1090. GetScriptEngine
  1091. Get a script engine based on index. Return NULL if the index
  1092. is not in range. (this is a callback)
  1093. The AllocAndLoadEngines function will create an array of ScriptingInfo
  1094. structures that are defined here. It contains all the infomation
  1095. needed to 1. set up the MapScript2SourceLine callback,
  1096. 2. merge namespaces, 3. set up this callback.
  1097. Parameters:
  1098. iScriptEngine - the script engine to retrieve
  1099. pvData - instance data for the function
  1100. Returns:
  1101. The requested script engine or NULL if not such engine
  1102. Side effects:
  1103. None
  1104. ===================================================================*/
  1105. CScriptEngine *GetScriptEngine
  1106. (
  1107. INT iScriptEngine,
  1108. VOID *pvData
  1109. )
  1110. {
  1111. ActiveEngineInfo *pInfo = static_cast<ActiveEngineInfo *>(pvData);
  1112. if (unsigned(iScriptEngine) >= unsigned(pInfo->cActiveEngines))
  1113. {
  1114. // Note: the caller has no idea how many script engines there are.
  1115. // if the caller asks for an engine out of range, return NULL so they
  1116. // know they have asked for more than there are
  1117. return NULL;
  1118. }
  1119. return(pInfo->rgActiveEngines[iScriptEngine].pScriptEngine);
  1120. }
  1121. /*===================================================================
  1122. CallScriptFunctionOfEngine
  1123. Calls a script engine to execute one of its functions
  1124. Returns:
  1125. S_OK on success
  1126. Side effects:
  1127. None
  1128. ===================================================================*/
  1129. HRESULT CallScriptFunctionOfEngine
  1130. (
  1131. ActiveEngineInfo &engineInfo,
  1132. short iScriptBlock,
  1133. wchar_t *strFunction,
  1134. CASPObjectContext *pASPObjectContext /* = NULL */
  1135. )
  1136. {
  1137. HRESULT hr;
  1138. Assert(engineInfo.rgActiveEngines != NULL);
  1139. Assert (iScriptBlock <= engineInfo.cEngines);
  1140. CScriptEngine *pScriptEngine = (CScriptEngine *)engineInfo.rgActiveEngines[iScriptBlock].pScriptEngine;
  1141. Assert(pScriptEngine != NULL);
  1142. hr = pScriptEngine->Call(strFunction);
  1143. // housekeeping for the transacted case...
  1144. if (pASPObjectContext != NULL) {
  1145. // If the script timed out or there was an unhandled error, then autoabort
  1146. if (SUCCEEDED(hr) && (pScriptEngine->FScriptTimedOut() || pScriptEngine->FScriptHadError()))
  1147. {
  1148. hr = pASPObjectContext->SetAbort();
  1149. }
  1150. // If the script author did not do an explicit SetComplete or SetAbort
  1151. // then do a SetComplete here so Viper will return the transaction
  1152. // completion status to the caller
  1153. if (SUCCEEDED(hr) && !pASPObjectContext->FAborted())
  1154. {
  1155. hr = pASPObjectContext->SetComplete();
  1156. }
  1157. }
  1158. return hr;
  1159. }
  1160. /*===================================================================
  1161. CallScriptFunction
  1162. Calls each script engine in turn to execute a script function;
  1163. exits when an engine succeeds or we run out of engines.
  1164. Returns:
  1165. S_OK on success
  1166. Side effects:
  1167. None
  1168. ===================================================================*/
  1169. HRESULT CallScriptFunction
  1170. (
  1171. ActiveEngineInfo &engineInfo,
  1172. wchar_t *strFunction
  1173. )
  1174. {
  1175. HRESULT hr = E_FAIL;
  1176. int i;
  1177. for (i = 0; i < engineInfo.cActiveEngines; i++)
  1178. {
  1179. // if execution succeeds, bail
  1180. if (SUCCEEDED(hr = CallScriptFunctionOfEngine(engineInfo, (SHORT)i, strFunction)))
  1181. goto LExit;
  1182. // if execution fails with exception other then unknown name, bail
  1183. if (hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND)
  1184. goto LExit;
  1185. }
  1186. LExit:
  1187. return hr;
  1188. }
  1189. /*===================================================================
  1190. TestScriptFunction
  1191. Tests each script engine in turn to test [the existance of] a script
  1192. function; exits when an engine succeeds or we run out of engines.
  1193. Parameters
  1194. ActiveEngineInfo &engineInfo
  1195. wchar_t *strFunction functions name
  1196. Returns:
  1197. S_OK if exists
  1198. Side effects:
  1199. None
  1200. ===================================================================*/
  1201. HRESULT TestScriptFunction
  1202. (
  1203. ActiveEngineInfo &engineInfo,
  1204. wchar_t *strFunction
  1205. )
  1206. {
  1207. HRESULT hr = E_FAIL;
  1208. for (int i = 0; i < engineInfo.cActiveEngines; i++)
  1209. {
  1210. hr = engineInfo.rgActiveEngines[i].pScriptEngine->
  1211. CheckEntryPoint(strFunction);
  1212. // if execution succeeds, bail
  1213. if (SUCCEEDED(hr))
  1214. break;
  1215. // if fails with result other then unknown name, bail
  1216. if (hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND)
  1217. break;
  1218. }
  1219. return hr;
  1220. }