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.

3627 lines
98 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Application Object Manager
  6. File: Applmgr.cpp
  7. Owner: PramodD
  8. This is the Application Manager source file.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "activdbg.h"
  13. #include "mtacb.h"
  14. #include "debugger.h"
  15. #include "memchk.h"
  16. #include <iismsg.h>
  17. PTRACE_LOG CAppln::gm_pTraceLog = NULL;
  18. CApplnMgr g_ApplnMgr;
  19. CApplnCleanupMgr g_ApplnCleanupMgr;
  20. DWORD g_nApplications = 0;
  21. DWORD g_nApplicationObjectsActive = 0;
  22. DWORD g_nApplicationsRestarting = 0;
  23. DWORD g_nApplicationsRestarted = 0;
  24. LONG g_fProceedWithShutdownAppln = 1;
  25. #define DENALI_FILE_NOTIFY_FILTER 0
  26. #pragma warning (disable: 4355) // ignore: "'this' used in base member init
  27. /*===================================================================
  28. S c r i p t E n g i n e C l e a n u p
  29. Node type for linked list of script engines to cleanup
  30. ===================================================================*/
  31. struct CScriptEngineCleanupElem : CDblLink
  32. {
  33. CActiveScriptEngine *m_pEngine;
  34. CScriptEngineCleanupElem(CActiveScriptEngine *pEngine) : m_pEngine(pEngine)
  35. {
  36. m_pEngine->AddRef();
  37. }
  38. ~CScriptEngineCleanupElem()
  39. {
  40. m_pEngine->FinalRelease();
  41. }
  42. };
  43. /*===================================================================
  44. C A p p l n V a r i a n t s
  45. ===================================================================*/
  46. /*===================================================================
  47. CApplnVariants::CApplnVariants
  48. Constructor
  49. Parameters:
  50. Returns:
  51. ===================================================================*/
  52. CApplnVariants::CApplnVariants()
  53. :
  54. m_cRefs(1),
  55. m_pAppln(NULL),
  56. m_ctColType(ctUnknown),
  57. m_ISupportErrImp(this, this, IID_IVariantDictionary)
  58. {
  59. CDispatch::Init(IID_IVariantDictionary);
  60. }
  61. /*===================================================================
  62. CApplnVariants::~CApplnVariants
  63. Constructor
  64. Parameters:
  65. Returns:
  66. ===================================================================*/
  67. CApplnVariants::~CApplnVariants()
  68. {
  69. Assert(!m_pAppln);
  70. }
  71. /*===================================================================
  72. CApplnVariants::Init
  73. Init ApplnVariants
  74. Parameters:
  75. CAppln *pAppln application
  76. CompType ctColType component collection type
  77. Returns:
  78. HRESULT
  79. ===================================================================*/
  80. HRESULT CApplnVariants::Init
  81. (
  82. CAppln *pAppln,
  83. CompType ctColType
  84. )
  85. {
  86. Assert(pAppln);
  87. pAppln->AddRef();
  88. Assert(!m_pAppln);
  89. m_pAppln = pAppln;
  90. m_ctColType = ctColType;
  91. return S_OK;
  92. }
  93. /*===================================================================
  94. CApplnVariants::UnInit
  95. UnInit ApplnVariants
  96. Parameters:
  97. Returns:
  98. HRESULT
  99. ===================================================================*/
  100. HRESULT CApplnVariants::UnInit()
  101. {
  102. if (m_pAppln)
  103. {
  104. m_pAppln->Release();
  105. m_pAppln = NULL;
  106. }
  107. return S_OK;
  108. }
  109. /*===================================================================
  110. CApplnVariants::QueryInterface
  111. CApplnVariants::AddRef
  112. CApplnVariants::Release
  113. IUnknown members for CApplnVariants object.
  114. ===================================================================*/
  115. STDMETHODIMP CApplnVariants::QueryInterface
  116. (
  117. REFIID iid,
  118. void **ppvObj
  119. )
  120. {
  121. if (iid == IID_IUnknown || iid == IID_IDispatch ||
  122. iid == IID_IVariantDictionary)
  123. {
  124. AddRef();
  125. *ppvObj = this;
  126. return S_OK;
  127. }
  128. else if (iid == IID_ISupportErrorInfo)
  129. {
  130. m_ISupportErrImp.AddRef();
  131. *ppvObj = &m_ISupportErrImp;
  132. return S_OK;
  133. }
  134. *ppvObj = NULL;
  135. return E_NOINTERFACE;
  136. }
  137. STDMETHODIMP_(ULONG) CApplnVariants::AddRef()
  138. {
  139. return InterlockedIncrement((LPLONG)&m_cRefs);
  140. }
  141. STDMETHODIMP_(ULONG) CApplnVariants::Release()
  142. {
  143. ULONG cRef = InterlockedDecrement((LPLONG)&m_cRefs);
  144. if (cRef == 0)
  145. {
  146. delete this;
  147. }
  148. return cRef;
  149. }
  150. /*===================================================================
  151. CApplnVariants::ObjectNameFromVariant
  152. Gets name from variant. Resolves operations by index.
  153. Allocates memory for name.
  154. Parameters:
  155. vKey VARIANT
  156. ppwszName [out] allocated name
  157. fVerify flag - check existance if named
  158. Returns:
  159. HRESULT
  160. ===================================================================*/
  161. HRESULT CApplnVariants::ObjectNameFromVariant
  162. (
  163. VARIANT &vKey,
  164. WCHAR **ppwszName,
  165. BOOL fVerify
  166. )
  167. {
  168. HRESULT hr = S_OK;
  169. *ppwszName = NULL;
  170. if (!m_pAppln->PCompCol())
  171. return E_FAIL;
  172. VARIANT *pvarKey = &vKey;
  173. VARIANT varKeyCopy;
  174. VariantInit(&varKeyCopy);
  175. if (V_VT(pvarKey) != VT_BSTR && V_VT(pvarKey) != VT_I2 && V_VT(pvarKey) != VT_I4)
  176. {
  177. if (FAILED(VariantResolveDispatch(&varKeyCopy, &vKey, IID_IVariantDictionary, IDE_APPLICATION)))
  178. {
  179. ExceptionId(IID_IVariantDictionary, IDE_APPLICATION, IDE_EXPECTING_STR);
  180. VariantClear(&varKeyCopy);
  181. return E_FAIL;
  182. }
  183. pvarKey = &varKeyCopy;
  184. }
  185. LPWSTR pwszName = NULL;
  186. switch (V_VT(pvarKey))
  187. {
  188. case VT_BSTR:
  189. {
  190. pwszName = V_BSTR(pvarKey);
  191. if (fVerify && pwszName)
  192. {
  193. CComponentObject *pObj = NULL;
  194. Assert(m_pAppln);
  195. Assert(m_pAppln->PCompCol());
  196. if (m_ctColType == ctTagged)
  197. m_pAppln->PCompCol()->GetTagged(pwszName, &pObj);
  198. else
  199. m_pAppln->PCompCol()->GetProperty(pwszName, &pObj);
  200. if (!pObj || pObj->GetType() != m_ctColType)
  201. pwszName = NULL; // as if not found
  202. }
  203. break;
  204. }
  205. case VT_I1: case VT_I2: case VT_I8:
  206. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  207. case VT_R4: case VT_R8:
  208. // Coerce all integral types to VT_I4
  209. if (FAILED(VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  210. return E_FAIL;
  211. // fallthru to VT_I4
  212. case VT_I4:
  213. {
  214. int i;
  215. // Look up the object by index
  216. i = V_I4(pvarKey);
  217. if (i > 0)
  218. {
  219. Assert(m_pAppln);
  220. Assert(m_pAppln->PCompCol());
  221. m_pAppln->PCompCol()->GetNameByIndex
  222. (
  223. m_ctColType,
  224. i,
  225. &pwszName
  226. );
  227. }
  228. break;
  229. }
  230. }
  231. if (pwszName)
  232. {
  233. *ppwszName = StringDupW(pwszName);
  234. if (*ppwszName == NULL)
  235. hr = E_OUTOFMEMORY;
  236. }
  237. VariantClear(&varKeyCopy);
  238. return hr;
  239. }
  240. /*===================================================================
  241. CApplnVariants::get_Item
  242. Function called from DispInvoke to get keys from the collection.
  243. Parameters:
  244. vKey VARIANT [in], which parameter to get the value of - integers access collection as an array
  245. pvarReturn VARIANT *, [out] value of the requested parameter
  246. Returns:
  247. S_OK on success, E_FAIL on failure.
  248. ===================================================================*/
  249. HRESULT CApplnVariants::get_Item
  250. (
  251. VARIANT varKey,
  252. VARIANT *pVar
  253. )
  254. {
  255. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  256. return E_FAIL;
  257. // Initialize return value
  258. VariantInit(pVar);
  259. if (!m_pAppln->PCompCol())
  260. return S_OK;
  261. // Get HitObj from Viper if Tagged Variants
  262. CHitObj *pHitObj = NULL;
  263. if (m_ctColType == ctTagged)
  264. {
  265. ViperGetHitObjFromContext(&pHitObj);
  266. if (!pHitObj)
  267. return S_OK; // return emtpy variant
  268. }
  269. m_pAppln->Lock();
  270. // Get name
  271. WCHAR *pwszName = NULL;
  272. HRESULT hr = ObjectNameFromVariant(varKey, &pwszName);
  273. if (!pwszName)
  274. {
  275. m_pAppln->UnLock();
  276. return hr;
  277. }
  278. // Find object by name
  279. CComponentObject *pObj = NULL;
  280. if (m_ctColType == ctTagged)
  281. {
  282. Assert(pHitObj);
  283. // need to go through HitObj for instantiation
  284. pHitObj->GetComponent(csAppln, pwszName, CbWStr(pwszName), &pObj);
  285. if (pObj && (pObj->GetType() != ctTagged))
  286. pObj = NULL;
  287. }
  288. else
  289. {
  290. m_pAppln->PCompCol()->GetProperty(pwszName, &pObj);
  291. }
  292. if (pObj)
  293. pObj->GetVariant(pVar);
  294. m_pAppln->UnLock();
  295. free(pwszName);
  296. return S_OK;
  297. }
  298. /*===================================================================
  299. CApplnVariants::put_Item
  300. OLE automation put for Item property
  301. Parameters:
  302. varKey key
  303. Var value
  304. Returns:
  305. S_OK on success, E_FAIL on failure.
  306. ===================================================================*/
  307. HRESULT CApplnVariants::put_Item
  308. (
  309. VARIANT varKey,
  310. VARIANT Var
  311. )
  312. {
  313. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  314. return E_FAIL;
  315. if (m_ctColType == ctTagged)
  316. {
  317. ExceptionId(IID_IVariantDictionary, IDE_APPLICATION,
  318. IDE_CANT_MOD_STATICOBJECTS);
  319. return E_FAIL;
  320. }
  321. Assert(m_ctColType == ctProperty);
  322. if (!m_pAppln->PCompCol())
  323. return E_FAIL;
  324. m_pAppln->Lock();
  325. // Resolve the variant
  326. VARIANT varResolved;
  327. HRESULT hr = VariantResolveDispatch
  328. (
  329. &varResolved,
  330. &Var,
  331. IID_IApplicationObject,
  332. IDE_APPLICATION
  333. );
  334. if (FAILED(hr))
  335. {
  336. m_pAppln->UnLock();
  337. return hr; // exception already raised
  338. }
  339. // Get name
  340. WCHAR *pwszName = NULL;
  341. hr = ObjectNameFromVariant(varKey, &pwszName);
  342. if (pwszName)
  343. {
  344. // Set the property
  345. if (m_pAppln->PCompCol())
  346. hr = m_pAppln->PCompCol()->AddProperty(pwszName, &varResolved);
  347. else
  348. hr = E_FAIL; // not likely if application not UnInited
  349. }
  350. VariantClear(&varResolved);
  351. m_pAppln->UnLock();
  352. if (hr == RPC_E_WRONG_THREAD)
  353. {
  354. // We use RPC_E_WRONG_THREAD to indicate bad model object
  355. ExceptionId(IID_IApplicationObject,
  356. IDE_APPLICATION, IDE_APPLICATION_CANT_STORE_OBJECT);
  357. hr = E_FAIL;
  358. }
  359. free(pwszName);
  360. return hr;
  361. }
  362. /*===================================================================
  363. CApplnVariants::putref_Item
  364. OLE automation putref for Item property
  365. Parameters:
  366. varKey key
  367. Var value
  368. Returns:
  369. S_OK on success, E_FAIL on failure.
  370. ===================================================================*/
  371. HRESULT CApplnVariants::putref_Item
  372. (
  373. VARIANT varKey,
  374. VARIANT Var
  375. )
  376. {
  377. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  378. return E_FAIL;
  379. if (m_ctColType == ctTagged)
  380. {
  381. ExceptionId(IID_IVariantDictionary, IDE_APPLICATION,
  382. IDE_CANT_MOD_STATICOBJECTS);
  383. return E_FAIL;
  384. }
  385. if (FIsIntrinsic(&Var))
  386. {
  387. ExceptionId(IID_IVariantDictionary, IDE_APPLICATION, IDE_APPLICATION_CANT_STORE_INTRINSIC);
  388. return E_FAIL;
  389. }
  390. Assert(m_ctColType == ctProperty);
  391. if (!m_pAppln->PCompCol())
  392. return E_FAIL;
  393. m_pAppln->Lock();
  394. // Get name
  395. WCHAR *pwszName = NULL;
  396. HRESULT hr = ObjectNameFromVariant(varKey, &pwszName);
  397. if (pwszName)
  398. {
  399. // Set the property
  400. if (m_pAppln->PCompCol())
  401. hr = m_pAppln->PCompCol()->AddProperty(pwszName, &Var);
  402. else
  403. hr = E_FAIL; // not likely if application not UnInited
  404. }
  405. m_pAppln->UnLock();
  406. if (hr == RPC_E_WRONG_THREAD)
  407. {
  408. // We use RPC_E_WRONG_THREAD to indicate bad model object
  409. ExceptionId(IID_IApplicationObject,
  410. IDE_APPLICATION, IDE_APPLICATION_CANT_STORE_OBJECT);
  411. hr = E_FAIL;
  412. }
  413. if (pwszName)
  414. free(pwszName);
  415. return hr;
  416. }
  417. /*===================================================================
  418. CApplnVariants::get_Key
  419. Function called from DispInvoke to get values from the collection.
  420. Parameters:
  421. vKey VARIANT [in], which parameter to get the value of - integers access collection as an array
  422. pvarReturn VARIANT *, [out] value of the requested parameter
  423. Returns:
  424. S_OK on success, E_FAIL on failure.
  425. ===================================================================*/
  426. HRESULT CApplnVariants::get_Key
  427. (
  428. VARIANT varKey,
  429. VARIANT *pVar
  430. )
  431. {
  432. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  433. return E_FAIL;
  434. VariantInit(pVar);
  435. if (!m_pAppln->PCompCol())
  436. return S_OK;
  437. m_pAppln->Lock();
  438. // Get name
  439. WCHAR *pwszName = NULL;
  440. HRESULT hr = ObjectNameFromVariant(varKey, &pwszName, TRUE);
  441. m_pAppln->UnLock();
  442. if (!pwszName)
  443. return hr;
  444. // Return BSTr
  445. BSTR bstrT = SysAllocString(pwszName);
  446. free(pwszName);
  447. if (!bstrT)
  448. return E_OUTOFMEMORY;
  449. V_VT(pVar) = VT_BSTR;
  450. V_BSTR(pVar) = bstrT;
  451. return S_OK;
  452. }
  453. /*===================================================================
  454. CApplnVariants::get_Count
  455. Parameters:
  456. pcValues - count is stored in *pcValues
  457. ===================================================================*/
  458. STDMETHODIMP CApplnVariants::get_Count
  459. (
  460. int *pcValues
  461. )
  462. {
  463. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  464. return E_FAIL;
  465. if (m_ctColType == ctTagged)
  466. *pcValues = m_pAppln->m_pApplCompCol->GetTaggedObjectCount();
  467. else
  468. *pcValues = m_pAppln->m_pApplCompCol->GetPropertyCount();
  469. return S_OK;
  470. }
  471. /*===================================================================
  472. CApplnVariants::get__NewEnum
  473. Return a new enumerator
  474. ===================================================================*/
  475. HRESULT CApplnVariants::get__NewEnum
  476. (
  477. IUnknown **ppEnumReturn
  478. )
  479. {
  480. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  481. return E_FAIL;
  482. *ppEnumReturn = NULL;
  483. CVariantsIterator *pIterator = new CVariantsIterator(m_pAppln, m_ctColType);
  484. if (pIterator == NULL)
  485. {
  486. ExceptionId(IID_IVariantDictionary, IDE_SESSION, IDE_OOM);
  487. return E_OUTOFMEMORY;
  488. }
  489. *ppEnumReturn = pIterator;
  490. return S_OK;
  491. }
  492. /*===================================================================
  493. CApplnVariants::Remove
  494. Remove item
  495. Parameters:
  496. varKey key
  497. Returns:
  498. S_OK on success, E_FAIL on failure.
  499. ===================================================================*/
  500. HRESULT CApplnVariants::Remove
  501. (
  502. VARIANT varKey
  503. )
  504. {
  505. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  506. return E_FAIL;
  507. if (m_ctColType == ctTagged)
  508. {
  509. ExceptionId(IID_IVariantDictionary, IDE_APPLICATION,
  510. IDE_CANT_MOD_STATICOBJECTS);
  511. return E_FAIL;
  512. }
  513. Assert(m_ctColType == ctProperty);
  514. m_pAppln->Lock();
  515. // Get name
  516. WCHAR *pwszName = NULL;
  517. ObjectNameFromVariant(varKey, &pwszName);
  518. if (pwszName)
  519. {
  520. CComponentCollection *pCompCol = m_pAppln->PCompCol();
  521. // Set the property
  522. if (pCompCol)
  523. pCompCol->RemoveProperty(pwszName);
  524. free(pwszName);
  525. }
  526. m_pAppln->UnLock();
  527. return S_OK;
  528. }
  529. /*===================================================================
  530. CApplnVariants::RemoveAll
  531. Remove all items
  532. Parameters:
  533. varKey key
  534. Returns:
  535. S_OK on success, E_FAIL on failure.
  536. ===================================================================*/
  537. HRESULT CApplnVariants::RemoveAll()
  538. {
  539. if (!m_pAppln || FAILED(m_pAppln->CheckForTombstone()))
  540. return E_FAIL;
  541. if (m_ctColType == ctTagged)
  542. {
  543. ExceptionId(IID_IVariantDictionary, IDE_APPLICATION,
  544. IDE_CANT_MOD_STATICOBJECTS);
  545. return E_FAIL;
  546. }
  547. Assert(m_ctColType == ctProperty);
  548. m_pAppln->Lock();
  549. CComponentCollection *pCompCol = m_pAppln->PCompCol();
  550. if (pCompCol)
  551. {
  552. pCompCol->RemoveAllProperties();
  553. }
  554. m_pAppln->UnLock();
  555. return S_OK;
  556. }
  557. /*===================================================================
  558. C A p p l n
  559. ===================================================================*/
  560. /*===================================================================
  561. CAppln::CAppln
  562. Constructor
  563. Parameters:
  564. NONE
  565. Returns:
  566. NONE
  567. ===================================================================*/
  568. CAppln::CAppln()
  569. :
  570. m_fInited(FALSE),
  571. m_fFirstRequestRan(FALSE),
  572. m_fGlobalChanged(FALSE),
  573. m_fDeleteInProgress(FALSE),
  574. m_fTombstone(FALSE),
  575. m_fDebuggable(FALSE),
  576. m_fInternalLockInited(FALSE),
  577. m_fApplnLockInited(FALSE),
  578. m_cRefs(1),
  579. m_pszMetabaseKey(NULL),
  580. m_pszApplnPath(NULL),
  581. m_pszGlobalAsa(NULL),
  582. m_pGlobalTemplate(NULL),
  583. m_cSessions(0),
  584. m_cRequests(0),
  585. m_pSessionMgr(NULL),
  586. m_pApplCompCol(NULL),
  587. m_pProperties(NULL),
  588. m_pTaggedObjects(NULL),
  589. m_pAppRoot(NULL),
  590. m_pActivity(NULL),
  591. m_pUnkFTM(NULL),
  592. m_dwLockThreadID(INVALID_THREADID),
  593. m_cLockRefCount(0),
  594. m_pdispGlobTypeLibWrapper(NULL),
  595. m_pServicesConfig(NULL),
  596. m_fSWC_PartitionAccessDenied(FALSE),
  597. m_fSWC_InvalidPartitionGUID(FALSE)
  598. {
  599. // COM stuff
  600. m_ISuppErrImp.Init(static_cast<IApplicationObject *>(this),
  601. static_cast<IApplicationObject *>(this),
  602. IID_IApplicationObject);
  603. CDispatch::Init(IID_IApplicationObject);
  604. InterlockedIncrement((LPLONG)&g_nApplicationObjectsActive);
  605. IF_DEBUG(APPLICATION) {
  606. WriteRefTraceLog(gm_pTraceLog, m_cRefs, this);
  607. }
  608. }
  609. /*===================================================================
  610. CAppln::~CAppln
  611. Destructor
  612. Parameters:
  613. NONE
  614. Returns:
  615. NONE
  616. ===================================================================*/
  617. CAppln::~CAppln()
  618. {
  619. Assert(m_fTombstone); // must be tombstoned before destructor
  620. Assert(m_cRefs == 0); // must have 0 ref count
  621. #ifdef DBG_NOTIFICATION
  622. DBGPRINTF((DBG_CONTEXT, "Deleting application %p\n", this));
  623. #endif // DBG_NOTIFICATION
  624. if ( m_pUnkFTM != NULL )
  625. {
  626. m_pUnkFTM->Release();
  627. m_pUnkFTM = NULL;
  628. }
  629. }
  630. /*===================================================================
  631. HRESULT CAppln::Init
  632. Initialize object
  633. Parameters:
  634. char *pszApplnKey application's metabase key
  635. char *pszApplnPath application's directory path
  636. CIsapiReqInfo *pIReq Isapi Req Info
  637. Returns:
  638. S_OK Success
  639. E_FAIL Failure
  640. E_OUTOFMEMORY Out of memory failure
  641. ===================================================================*/
  642. HRESULT CAppln::Init
  643. (
  644. TCHAR *pszApplnKey,
  645. TCHAR *pszApplnPath,
  646. CIsapiReqInfo *pIReq
  647. )
  648. {
  649. HRESULT hr = S_OK;
  650. CMBCSToWChar convStr;
  651. InterlockedIncrement((LPLONG)&g_nApplications);
  652. Assert(pszApplnKey);
  653. Assert(pszApplnPath);
  654. void *pHashKey = NULL;
  655. DWORD dwHashKeyLength = 0;
  656. DWORD cch;
  657. // Debugging variables (These are placed here for possible cleanup)
  658. IDebugApplicationNode *pVirtualServerRoot = NULL;
  659. CFileNode *pFileNode = NULL;
  660. // Create the FTM
  661. if (m_pUnkFTM == NULL)
  662. {
  663. hr = CoCreateFreeThreadedMarshaler( (IUnknown*)this, &m_pUnkFTM );
  664. if ( FAILED(hr) )
  665. {
  666. Assert( m_pUnkFTM == NULL );
  667. return (hr);
  668. }
  669. }
  670. Assert( m_pUnkFTM != NULL );
  671. // Critical sections created together --
  672. // they are deleted in the destructor based on m_fInited flag
  673. ErrInitCriticalSection(&m_csInternalLock, hr);
  674. if (SUCCEEDED(hr))
  675. {
  676. ErrInitCriticalSection(&m_csApplnLock, hr);
  677. if (FAILED(hr))
  678. DeleteCriticalSection(&m_csInternalLock);
  679. }
  680. if (FAILED(hr))
  681. {
  682. DBGPRINTF((DBG_CONTEXT, "New Application Failed to acquire Critical Section, hr = %08x\n", hr));
  683. return hr;
  684. }
  685. m_fInternalLockInited = TRUE;
  686. m_fApplnLockInited = TRUE;
  687. // Remember (copy of) metabase key
  688. cch = _tcslen(pszApplnKey);
  689. m_pszMetabaseKey = new TCHAR[(cch+1) * sizeof(TCHAR)];
  690. if (!m_pszMetabaseKey)
  691. goto LCleanupOOM;
  692. memcpy(m_pszMetabaseKey, pszApplnKey, (cch+1)*sizeof(TCHAR));
  693. pHashKey = m_pszMetabaseKey;
  694. dwHashKeyLength = cch * sizeof(TCHAR);
  695. // Remember (copy of) appln path
  696. cch = _tcslen(pszApplnPath);
  697. m_pszApplnPath = new TCHAR[(cch+1) * sizeof(TCHAR)];
  698. if (!m_pszApplnPath)
  699. goto LCleanupOOM;
  700. memcpy(m_pszApplnPath, pszApplnPath, (cch+1)*sizeof(TCHAR));
  701. // Get virtual path of appln & remember what it is
  702. TCHAR szApplnVRoot[MAX_PATH];
  703. if (FAILED(hr = FindApplicationPath(pIReq, szApplnVRoot, sizeof szApplnVRoot)))
  704. {
  705. DBGWARN((DBG_CONTEXT, "New Application Failed to FindApplicationPath(), hr = %#08x\n", hr));
  706. goto LCleanup;
  707. }
  708. if ((m_pszApplnVRoot = new TCHAR [(_tcslen(szApplnVRoot) + 1)*sizeof(TCHAR)]) == NULL)
  709. goto LCleanupOOM;
  710. _tcscpy(m_pszApplnVRoot, szApplnVRoot);
  711. // Get Session cookie names, both secure and non-secure
  712. InitSessionCookieNames();
  713. // Initialize link element with key
  714. Assert(pHashKey);
  715. Assert(dwHashKeyLength);
  716. if (FAILED(CLinkElem::Init(pHashKey, dwHashKeyLength)))
  717. goto LCleanupOOM;
  718. m_cSessions = 0;
  719. m_cRequests = 0;
  720. // Create and init app config
  721. m_pAppConfig = new CAppConfig();
  722. if (!m_pAppConfig)
  723. goto LCleanupOOM;
  724. hr = m_pAppConfig->Init(pIReq, this);
  725. if (FAILED(hr))
  726. {
  727. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Init the AppConfig, hr = %#08x\n", hr));
  728. goto LCleanup;
  729. }
  730. // Create and init application level component collection
  731. m_pApplCompCol = new CComponentCollection;
  732. if (!m_pApplCompCol)
  733. goto LCleanupOOM;
  734. hr = m_pApplCompCol->Init(csAppln,m_pAppConfig->fExecuteInMTA());
  735. if (FAILED(hr))
  736. {
  737. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Init the Component Collection, hr = %#08x\n", hr));
  738. goto LCleanup;
  739. }
  740. // initialize application properties collection
  741. m_pProperties = new CApplnVariants;
  742. if (!m_pProperties)
  743. goto LCleanupOOM;
  744. hr = m_pProperties->Init(this, ctProperty);
  745. if (FAILED(hr))
  746. {
  747. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Init the Application Properties, hr = %#08x\n", hr));
  748. goto LCleanup;
  749. }
  750. // initialize application tagged object collection
  751. m_pTaggedObjects = new CApplnVariants;
  752. if (!m_pTaggedObjects)
  753. goto LCleanupOOM;
  754. hr = m_pTaggedObjects->Init(this, ctTagged);
  755. if (FAILED(hr))
  756. {
  757. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Init the Application Tagged Objects, hr = %#08x\n", hr));
  758. goto LCleanup;
  759. }
  760. // Initialize the CServicesConfig Object
  761. hr = InitServicesConfig();
  762. if (FAILED(hr)) {
  763. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Init ServicesConfig, hr = %#08x\n", hr));
  764. goto LCleanup;
  765. }
  766. // Debugging support - Create an application node
  767. // If PDM does not exist it means debugger not installed or it's Win 95
  768. //
  769. if (g_pPDM)
  770. {
  771. // Debugging directories are shown as:
  772. //
  773. // <virtual web server>
  774. // <application name>
  775. // <path to ASP>
  776. //
  777. // Get a pointer to the document node containing the virtual web server.
  778. if (FAILED(hr = GetServerDebugRoot(pIReq, &pVirtualServerRoot)))
  779. {
  780. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not GetServerDebugRoot(), hr = %#08x\n", hr));
  781. goto LCleanup;
  782. }
  783. // Create a node for this application
  784. if (FAILED(hr = g_pDebugApp->CreateApplicationNode(&m_pAppRoot)))
  785. {
  786. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not CreateApplicationNode(), hr = %#08x\n", hr));
  787. goto LCleanup;
  788. }
  789. // Create a doc provider for the node
  790. if ((pFileNode = new CFileNode) == NULL)
  791. goto LCleanupOOM;
  792. // Name the application
  793. TCHAR szDebugApp[256];
  794. TCHAR *pchEnd = strcpyEx(szDebugApp, m_pszApplnVRoot);
  795. if (! QueryAppConfig()->fAllowDebugging()) {
  796. #if UNICODE
  797. CwchLoadStringOfId(
  798. #else
  799. CchLoadStringOfId(
  800. #endif
  801. IDS_DEBUGGING_DISABLED, pchEnd, DIFF(&szDebugApp[sizeof (szDebugApp)/sizeof(TCHAR)] - pchEnd));
  802. m_fDebuggable = FALSE;
  803. }
  804. else
  805. m_fDebuggable = TRUE;
  806. Assert (_tcslen(szDebugApp) < (sizeof(szDebugApp)/sizeof(TCHAR)));
  807. WCHAR *pswzDebugApp;
  808. #if UNICODE
  809. pswzDebugApp = szDebugApp;
  810. #else
  811. if (FAILED(hr = convStr.Init(szDebugApp))) {
  812. DBGWARN((DBG_CONTEXT, "New Application Failed: Cannot convert szDebugApp to UNICODE, hr = %#08x\n", hr));
  813. goto LCleanup;
  814. }
  815. pswzDebugApp = convStr.GetString();
  816. #endif
  817. if (FAILED(hr = pFileNode->Init(pswzDebugApp)))
  818. {
  819. DBGWARN((DBG_CONTEXT, "New Application Failed: Cannot Init CFileNode, hr = %#08x\n", hr));
  820. goto LCleanup;
  821. }
  822. if (FAILED(hr = m_pAppRoot->SetDocumentProvider(pFileNode)))
  823. {
  824. DBGWARN((DBG_CONTEXT, "New Application Failed: SetDocumentProvider failed, hr = %#08x\n", hr));
  825. goto LCleanup;
  826. }
  827. // Attach to the UI
  828. if (FAILED(hr = m_pAppRoot->Attach(pVirtualServerRoot)))
  829. {
  830. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Attach to debugger, hr = %#08x\n", hr));
  831. goto LCleanup;
  832. }
  833. // If this application had a previous incarnation (changed global.asa
  834. // or debugging being flipped on in midstream), then there may be some
  835. // documents in the cache which should be added to the debugger now.
  836. if (m_fDebuggable)
  837. {
  838. g_TemplateCache.AddApplicationToDebuggerUI(this);
  839. // create the global debug activity if it hasn't been created already
  840. if (g_pDebugActivity == NULL) {
  841. g_pDebugActivity = new CViperActivity;
  842. if (g_pDebugActivity == NULL) {
  843. hr = E_OUTOFMEMORY;
  844. goto LCleanup;
  845. }
  846. if (FAILED(hr = g_pDebugActivity->Init(m_pServicesConfig))) {
  847. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not create global debug activity, hr = %#08x\n", hr));
  848. goto LCleanup;
  849. }
  850. }
  851. // In DEBUG mode: all requests run on the same thread
  852. if (FAILED(hr = BindToActivity(g_pDebugActivity)))
  853. {
  854. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not bind application to debugging activity, hr = %#08x\n", hr));
  855. goto LCleanup;
  856. }
  857. }
  858. }
  859. // Create and init session manager
  860. m_pSessionMgr = new CSessionMgr;
  861. if (!m_pSessionMgr)
  862. goto LCleanupOOM;
  863. hr = m_pSessionMgr->Init(this);
  864. if (FAILED(hr)) {
  865. DBGWARN((DBG_CONTEXT, "New Application Failed: Could not Init session manager, hr = %#08x\n", hr));
  866. goto LCleanup;
  867. }
  868. LCleanup:
  869. // Release interfaces
  870. if (pFileNode)
  871. pFileNode->Release();
  872. if (pVirtualServerRoot)
  873. pVirtualServerRoot->Release();
  874. if (SUCCEEDED(hr))
  875. m_fInited = TRUE;
  876. return hr;
  877. LCleanupOOM:
  878. hr = E_OUTOFMEMORY;
  879. DBGERROR((DBG_CONTEXT, "New Application Failed: E_OUTOFMEMORY\n"));
  880. goto LCleanup;
  881. }
  882. /*===================================================================
  883. CAppln::InitServicesConfig
  884. Initializes the Application scoped CServicesConfig object
  885. ===================================================================*/
  886. HRESULT CAppln::InitServicesConfig()
  887. {
  888. HRESULT hr;
  889. IServiceThreadPoolConfig *pIThreadPool = NULL;
  890. IServiceSynchronizationConfig *pISyncConfig = NULL;
  891. IServicePartitionConfig *pIPartitionConfig = NULL;
  892. IServiceSxsConfig *pISxsConfig = NULL;
  893. hr = CoCreateInstance(CLSID_CServiceConfig,
  894. NULL,
  895. CLSCTX_INPROC_SERVER,
  896. IID_IUnknown,
  897. (void **)&m_pServicesConfig);
  898. if (FAILED(hr)) {
  899. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not CCI ServicesConfig, hr = %#08x\n", hr));
  900. goto LCleanup;
  901. }
  902. hr = m_pServicesConfig->QueryInterface(IID_IServiceThreadPoolConfig, (void **)&pIThreadPool);
  903. if (FAILED(hr)) {
  904. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not QI for IServiceThreadPoolConfig, hr = %#08x\n", hr));
  905. goto LCleanup;
  906. }
  907. if (m_pAppConfig->fExecuteInMTA()) {
  908. hr = ViperConfigureMTA();
  909. if (FAILED(hr)) {
  910. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Failed to Configure MTA, hr = %#08x\n", hr));
  911. goto LCleanup;
  912. }
  913. }
  914. else {
  915. hr = ViperConfigureSTA();
  916. if (FAILED(hr)) {
  917. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Failed to Configure STA, hr = %#08x\n", hr));
  918. goto LCleanup;
  919. }
  920. }
  921. hr = pIThreadPool->SelectThreadPool(m_pAppConfig->fExecuteInMTA() ? CSC_MTAThreadPool : CSC_STAThreadPool);
  922. if (FAILED(hr)) {
  923. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Failed to SelectThreadPool, hr = %#08x\n", hr));
  924. goto LCleanup;
  925. }
  926. hr = m_pServicesConfig->QueryInterface(IID_IServiceSynchronizationConfig, (void **)&pISyncConfig);
  927. if (FAILED(hr)) {
  928. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not QI for IServiceSynchronizationConfig, hr = %#08x\n", hr));
  929. goto LCleanup;
  930. }
  931. hr = pISyncConfig->ConfigureSynchronization (m_pAppConfig->fExecuteInMTA() ? CSC_NewSynchronization : CSC_IfContainerIsSynchronized);
  932. if (FAILED(hr)) {
  933. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not ConfigureSynchronization, hr = %#08x\n", hr));
  934. goto LCleanup;
  935. }
  936. if (m_pAppConfig->fUsePartition()) {
  937. if (m_pAppConfig->PPartitionGUID()) {
  938. hr = m_pServicesConfig->QueryInterface(IID_IServicePartitionConfig, (void **)&pIPartitionConfig);
  939. if (FAILED(hr)) {
  940. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not QI for IServicePartitionConfig, hr = %#08x\n", hr));
  941. goto LCleanup;
  942. }
  943. hr = pIPartitionConfig->PartitionConfig(CSC_NewPartition);
  944. if (FAILED(hr)) {
  945. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not set PartitionConfig, hr = %#08x\n", hr));
  946. goto LCleanup;
  947. }
  948. hr = pIPartitionConfig->PartitionID(*m_pAppConfig->PPartitionGUID());
  949. if (FAILED(hr)) {
  950. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not set PartitionID, hr = %#08x\n", hr));
  951. goto LCleanup;
  952. }
  953. }
  954. else {
  955. LogSWCError(InvalidPartitionGUID);
  956. hr = E_FAIL;
  957. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - fUsePartition Set, but no PartitionID\n", hr));
  958. goto LCleanup;
  959. }
  960. }
  961. if (m_pAppConfig->fSxsEnabled()) {
  962. hr = m_pServicesConfig->QueryInterface(IID_IServiceSxsConfig, (void **)&pISxsConfig);
  963. if (FAILED(hr)) {
  964. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not QI for IServiceSxsConfig, hr = %#08x\n", hr));
  965. goto LCleanup;
  966. }
  967. hr = pISxsConfig->SxsConfig(CSC_NewSxs);
  968. if (FAILED(hr)) {
  969. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not set SxsConfig, hr = %#08x\n", hr));
  970. goto LCleanup;
  971. }
  972. LPWSTR pwszApplnPath;
  973. #if UNICODE
  974. pwszApplnPath = m_pszApplnPath;
  975. #else
  976. CMBCSToWChar convPath;
  977. hr = convPath.Init(m_pszApplnPath);
  978. if (FAILED(hr)) {
  979. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not convert ApplnPath to UNICODE, hr = %#08x\n", hr));
  980. goto LCleanup;
  981. }
  982. pwszApplnPath = convPath.GetString();
  983. #endif
  984. hr = pISxsConfig->SxsDirectory(pwszApplnPath);
  985. if (FAILED(hr)) {
  986. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not set SxsDirectory, hr = %#08x\n", hr));
  987. goto LCleanup;
  988. }
  989. if (m_pAppConfig->szSxsName() && *m_pAppConfig->szSxsName()) {
  990. CMBCSToWChar convName;
  991. hr = convName.Init(m_pAppConfig->szSxsName());
  992. if (FAILED(hr)) {
  993. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not convert SxsName to UNICODE, hr = %#08x\n", hr));
  994. goto LCleanup;
  995. }
  996. hr = pISxsConfig->SxsName(convName.GetString());
  997. if (FAILED(hr)) {
  998. DBGWARN((DBG_CONTEXT, "New Application Failed: InitServicesConfig() - Could not set SxsName, hr = %#08x\n", hr));
  999. goto LCleanup;
  1000. }
  1001. }
  1002. }
  1003. LCleanup:
  1004. if (pIThreadPool)
  1005. pIThreadPool->Release();
  1006. if (pISyncConfig)
  1007. pISyncConfig->Release();
  1008. if (pIPartitionConfig)
  1009. pIPartitionConfig->Release();
  1010. if (pISxsConfig)
  1011. pISxsConfig->Release();
  1012. return hr;
  1013. }
  1014. /*===================================================================
  1015. HRESULT CAppln::InitSessionCookieNames
  1016. Initialize session cookie names. called during CApplin::Init. Introduced in QFE fix 28823 by markzh.
  1017. Every application will have a unique session cookie name assigned by this function. This contrast
  1018. to the pre-28823 behavior where we have one session cookie shared by all applications. (Note
  1019. we still had separate cookies if applications are running in different processes). Sharing session
  1020. cookie requires us to accept cookie values generated for another application. That was ok until
  1021. we introduced KeepSessionIDSecure - cookies generated for other applications are reset by
  1022. current application if the current session is secure.
  1023. Session-id cookie name used to be process-wide. The naming scheme was prefix+processid.
  1024. Here we generate a news one for each application. The naming scheme is expanded to prefix +
  1025. processid + appid. The appid is from a monotonous counter. Appid assignment may change
  1026. when process restarts. But that doesn't matter because the old cookie shouldn't be accepted
  1027. anyway. Instead of increasing string length of cookie name to accomodate appid, we made it
  1028. stay at prefix + 8 chars, by better utilization of each digit. Now we allow 32 different values
  1029. in each of the 8 character positions. That gives us 40 bits of information space. 24 bits are
  1030. used by processid, 15 bits are used by appid, 1 bit is used to distinguish cookies on secure
  1031. and non-secure sessions. Only 24 bits of process id (not all 32 bits) are used, because the
  1032. most significant 8 bits of process id is always 0 on current Windows implementation (see
  1033. ExpLookupHandleTableEntry).
  1034. The above method alone will give the same session-id cookie name from every computer
  1035. as long as process id is 123 and application id is 5. If a browser happened to simultaneously
  1036. visit two different severs with the same process id and application id, they will share the
  1037. same cookie name. However, their cookies should not overwrite each other because the client
  1038. should store them separately for two different servers. Regardless, we still wish to have some
  1039. randomness in cookie name and try to minimize name coincidence by injecting some data unique
  1040. to the system. But this is NOT done perfectly. The way we implement this is by adding the
  1041. system start time (as system signature) to bit 8 to bit 23 of process id. "Add" is a reversable
  1042. operator which will maintain one-to-one mapping given a fixed system signature. That will
  1043. ensure different cookie names are issued if process ids are different.
  1044. Parameters:
  1045. none
  1046. Returns:
  1047. none
  1048. ===================================================================*/
  1049. void CAppln::InitSessionCookieNames()
  1050. {
  1051. DWORD pid = GetCurrentProcessId();
  1052. DWORD aid = g_ApplnMgr.NextApplicationID();
  1053. ASSERT(aid <= 0x7fff); // not likely to have so many applications
  1054. aid <<=1; // last bit for secure flag
  1055. // Avoid name conflict between computers, inject system signature.
  1056. // The API GetTickCount is used to calculate system boot time. It returns a
  1057. // DWORD which will wrap around every 49 days. But that's fine because we
  1058. // only care about some bits of the result. Those are not affected by the
  1059. // wrap around. We avoided querying perf data for precise boot up time,
  1060. // as we may run into permission problems.
  1061. time_t curtime;
  1062. time(&curtime);
  1063. DWORD tic = GetTickCount();
  1064. // uptime is what time() would return when system booted, it will:
  1065. // - stay same (within accuracy) as time passes
  1066. // - stay same when tic wraps around 4G
  1067. // - be process independent
  1068. DWORD uptime = curtime*1000 - tic;
  1069. // set signature to uptime devided by accuracy (4 seconds). max ushort= 3 days
  1070. USHORT localSignature = (USHORT)(uptime / 4096);
  1071. // blend in system signature to process id.
  1072. pid += ((DWORD)localSignature) << 8;
  1073. // Encode the Non-secure version of th cookie
  1074. EncodeCookie(m_szSessionCookieName, pid, aid, FALSE);
  1075. // Encode the Secure version of the cookie
  1076. EncodeCookie(m_szSessionCookieNameSecure, pid, aid, TRUE);
  1077. return;
  1078. }
  1079. /*===================================================================
  1080. HRESULT CAppln::EncodeCookie
  1081. Dependingon the fIsSecure flag. we will either encode the cookie from numbers to a string.
  1082. Parameters:
  1083. pszCookie - pointer to the string to be returned
  1084. pid - Process ID
  1085. aid - Application ID
  1086. fIsSecure - Should this be encoded as a secure cookie.
  1087. Returns:
  1088. String filled with the Cookie
  1089. ===================================================================*/
  1090. void CAppln::EncodeCookie (char *pszCookie, DWORD pid, DWORD aid, BOOL fIsSecure)
  1091. {
  1092. strcpy(pszCookie, SZ_SESSION_ID_COOKIE_PREFIX);
  1093. pszCookie += CCH_SESSION_ID_COOKIE_PREFIX;
  1094. // the number of digits is hard coded to 8 here.
  1095. // it doesn't scale by simply adjusting a macro. sorry
  1096. // set cookie value to zero - we'll "bit or" 1's into it
  1097. memset(pszCookie, 0, 8+1); // +1 for null terminator
  1098. //
  1099. // Recommended for all versions of IIS except new products.
  1100. // This limits our behavior change to secure connections only.
  1101. // It may be lifted if someone request this later. When we'll
  1102. // have more confidence on this feature change.
  1103. //
  1104. USHORT wCookieSerial[3]; // cookie name in three words format
  1105. wCookieSerial[0] = (USHORT)pid;
  1106. wCookieSerial[1] = fIsSecure ? (USHORT)aid : 0;
  1107. wCookieSerial[2] = (USHORT)(pid>>16) & 0xFF;
  1108. // redistribute bits in w0-w2 (8*5) to pszCookie (5*8)
  1109. USHORT val; // keeps the sack of bits from wCookieSerial[], then seed them into pszCookie
  1110. for (int bit=0; bit<5; bit++)
  1111. {
  1112. //
  1113. // load value from wCookieSerial[]
  1114. //
  1115. if (bit%2==0)
  1116. {
  1117. val = wCookieSerial[bit/2];
  1118. }
  1119. //
  1120. // fill in the same bit for all 8 digits
  1121. //
  1122. for (int digit=0; digit<8; digit++)
  1123. {
  1124. pszCookie[digit] |= (char)((val & 1) << bit);
  1125. val >>= 1;
  1126. }
  1127. //
  1128. // advance to next bit
  1129. //
  1130. }
  1131. //
  1132. // encode numbers to string
  1133. //
  1134. static char EncodingTable[]=
  1135. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  1136. "012345"; // 32 token characters
  1137. //
  1138. // Replace numbers by characters
  1139. //
  1140. for (int i=0; i<8; i++)
  1141. {
  1142. pszCookie[i] = EncodingTable[pszCookie[i]];
  1143. }
  1144. return;
  1145. }
  1146. /*===================================================================
  1147. CAppln::Restart
  1148. Restart an application. (used for when global.asa changes or
  1149. debugging enable metabase key changes)
  1150. ===================================================================*/
  1151. HRESULT CAppln::Restart(BOOL fForceRestart /* = FALSE*/)
  1152. {
  1153. AddRef(); // keep addref'd while restarting
  1154. DBGPRINTF((DBG_CONTEXT, "Restarting application %S, %p\n", m_pszMetabaseKey, this));
  1155. g_ApplnMgr.Lock();
  1156. // If already restarted or
  1157. // in the tombstone state or
  1158. // restart not allowed
  1159. // shutting down -> don't restart
  1160. if (m_fGlobalChanged ||
  1161. m_fTombstone ||
  1162. (!m_pAppConfig->fEnableApplicationRestart() && !fForceRestart) ||
  1163. IsShutDownInProgress())
  1164. {
  1165. // Give back the lock and refcount
  1166. // since we don't need them
  1167. g_ApplnMgr.UnLock();
  1168. Release();
  1169. return S_OK;
  1170. }
  1171. // remove the application from the global hash
  1172. CLinkElem *pLinkElem = g_ApplnMgr.DeleteElem
  1173. (
  1174. m_pszMetabaseKey,
  1175. _tcslen(m_pszMetabaseKey) * sizeof(TCHAR)
  1176. );
  1177. Assert(pLinkElem);
  1178. Assert(static_cast<CAppln *>(pLinkElem) == this);
  1179. //
  1180. // Indicate to Delete All Sessions.
  1181. // This also doubles up as a flag to indicate that this application has been placed on the application cleanup queue.
  1182. //
  1183. m_fGlobalChanged = TRUE;
  1184. // Unlock
  1185. g_ApplnMgr.UnLock();
  1186. // Increment the count of restarting applications
  1187. InterlockedIncrement((LPLONG)&g_nApplicationsRestarting);
  1188. // Increment the count of restarted applications
  1189. InterlockedIncrement((LPLONG)&g_nApplicationsRestarted);
  1190. m_pSessionMgr->UnScheduleSessionKiller();
  1191. // cleanup the directory monitor entries
  1192. Lock(); // Place critical Section around access to m_rgpvDME
  1193. while (m_rgpvDME.Count())
  1194. {
  1195. static_cast<CDirMonitorEntry *>(m_rgpvDME[0])->Release();
  1196. m_rgpvDME.Remove(0);
  1197. }
  1198. m_rgpvDME.Clear();
  1199. UnLock();
  1200. // add this application to the CleanupManager...
  1201. g_ApplnCleanupMgr.AddAppln(this);
  1202. return S_OK;
  1203. }
  1204. /*===================================================================
  1205. CAppln::ApplnCleanupProc
  1206. Called by the g_ApplnCleanupMgr thread to complete cleanup
  1207. ===================================================================*/
  1208. DWORD __stdcall CAppln::ApplnCleanupProc(VOID *pArg)
  1209. {
  1210. CAppln *pAppln = (CAppln *)pArg;
  1211. DBGPRINTF((DBG_CONTEXT, "[ApplnCleanupProc] enterred for %S, %p\n", pAppln->m_pszMetabaseKey, pArg));
  1212. // Let the requests to drain while trying to delete sessions
  1213. while ((pAppln->m_cRequests || pAppln->m_cSessions))
  1214. {
  1215. if (pAppln->m_cSessions)
  1216. pAppln->m_pSessionMgr->DeleteAllSessions(FALSE);
  1217. if (pAppln->m_cSessions || pAppln->m_cRequests)
  1218. Sleep(200);
  1219. }
  1220. g_ApplnMgr.DeleteApplicationIfExpired(pAppln);
  1221. // Decrement the count of restarting applications
  1222. InterlockedDecrement((LPLONG)&g_nApplicationsRestarting);
  1223. // Wake up the thread so that other threads can run.
  1224. g_ApplnCleanupMgr.Wakeup();
  1225. //
  1226. // Corresponds to the Addref in Restart.
  1227. // Once the request has been queued to COM we can release its reference
  1228. //
  1229. pAppln->Release();
  1230. return 0;
  1231. }
  1232. /*===================================================================
  1233. CAppln::UnInit
  1234. Convert to tombstone state
  1235. Parameters:
  1236. NONE
  1237. Returns:
  1238. HRESULT (S_OK)
  1239. ===================================================================*/
  1240. HRESULT CAppln::UnInit()
  1241. {
  1242. Assert(!m_fTombstone); // don't do it twice
  1243. #ifdef DBG_NOTIFICATION
  1244. #if UNICODE
  1245. DBGPRINTF((DBG_CONTEXT, "Uniniting application %S, %p\n", m_pszApplnPath, this));
  1246. #else
  1247. DBGPRINTF((DBG_CONTEXT, "Uniniting application %s, %p\n", m_pszApplnPath, this));
  1248. #endif
  1249. #endif // DBG_NOTIFICATION
  1250. // Flush the global.asa from the script engine cache
  1251. if (m_pszGlobalAsa)
  1252. {
  1253. g_ScriptManager.FlushCache(m_pszGlobalAsa);
  1254. }
  1255. if (m_pGlobalTemplate)
  1256. {
  1257. // Keep template (and inc file) cache locked while releasing
  1258. // GLOBAL.ASA template so that it wouldn't step onto Flush logic
  1259. //
  1260. // NOTE: CTemplate::End potentially queues global.asa for cleanup on
  1261. // our thread! CleanupEngines() must therefore be called
  1262. // *after* this step.
  1263. //
  1264. LockTemplateAndIncFileCaches();
  1265. m_pGlobalTemplate->End();
  1266. UnLockTemplateAndIncFileCaches();
  1267. m_pGlobalTemplate = NULL;
  1268. }
  1269. //If NT, remove this app from any file/appln mappings it may be in
  1270. g_FileAppMap.Lock();
  1271. int i = m_rgpvFileAppln.Count();
  1272. while (i > 0)
  1273. {
  1274. #ifdef DBG_NOTIFICATION
  1275. DBGPRINTF((DBG_CONTEXT, "Removing application from File/App mapping\n"));
  1276. #endif // DBG_NOTIFICATION
  1277. static_cast<CFileApplnList *>(m_rgpvFileAppln[0])->RemoveApplication(this);
  1278. m_rgpvFileAppln.Remove(0);
  1279. i--;
  1280. }
  1281. g_FileAppMap.UnLock();
  1282. m_rgpvFileAppln.Clear();
  1283. Lock(); // Protecting m_rqpvDME with a critical section
  1284. //
  1285. // In case there are some DME's left around then release them.
  1286. //
  1287. while (m_rgpvDME.Count())
  1288. {
  1289. static_cast<CDirMonitorEntry *>(m_rgpvDME[0])->Release();
  1290. m_rgpvDME.Remove(0);
  1291. }
  1292. //
  1293. // Safe to free the array now.
  1294. //
  1295. m_rgpvDME.Clear();
  1296. UnLock();
  1297. // If debuggable application, clean up pending scripts
  1298. if (m_fDebuggable)
  1299. g_ApplnMgr.CleanupEngines();
  1300. // Free the properties collection
  1301. if (m_pProperties)
  1302. {
  1303. m_pProperties->UnInit();
  1304. m_pProperties->Release();
  1305. m_pProperties = NULL;
  1306. }
  1307. // Free the tagged objects collection
  1308. if (m_pTaggedObjects)
  1309. {
  1310. m_pTaggedObjects->UnInit();
  1311. m_pTaggedObjects->Release();
  1312. m_pTaggedObjects = NULL;
  1313. }
  1314. // Before we close down, debuggable templates need to be made non-debuggable
  1315. if (m_fDebuggable)
  1316. g_TemplateCache.RemoveApplicationFromDebuggerUI(this);
  1317. if (m_pAppRoot)
  1318. {
  1319. m_pAppRoot->Detach();
  1320. m_pAppRoot->Close();
  1321. m_pAppRoot->Release();
  1322. m_pAppRoot = NULL;
  1323. }
  1324. if (m_pApplCompCol)
  1325. {
  1326. delete m_pApplCompCol;
  1327. m_pApplCompCol = NULL;
  1328. }
  1329. if (m_pActivity)
  1330. {
  1331. delete m_pActivity;
  1332. m_pActivity = NULL;
  1333. }
  1334. if (m_pSessionMgr)
  1335. {
  1336. delete m_pSessionMgr;
  1337. m_pSessionMgr = NULL;
  1338. }
  1339. if (m_pAppConfig)
  1340. {
  1341. m_pAppConfig->UnInit();
  1342. // Using Reference counting on the CAppConfig object.
  1343. m_pAppConfig->Release();
  1344. m_pAppConfig = NULL;
  1345. }
  1346. if (m_pdispGlobTypeLibWrapper)
  1347. {
  1348. m_pdispGlobTypeLibWrapper->Release();
  1349. m_pdispGlobTypeLibWrapper = NULL;
  1350. }
  1351. if (m_pszGlobalAsa)
  1352. {
  1353. // If there was a change notification on global.asa
  1354. // then flush the template now.
  1355. // UNDONE: flush correct global.asa
  1356. if (m_fGlobalChanged)
  1357. g_TemplateCache.Flush(m_pszGlobalAsa, MATCH_ALL_INSTANCE_IDS);
  1358. delete [] m_pszGlobalAsa;
  1359. m_pszGlobalAsa = NULL;
  1360. }
  1361. if (m_pszMetabaseKey)
  1362. {
  1363. delete [] m_pszMetabaseKey;
  1364. m_pszMetabaseKey = NULL;
  1365. }
  1366. if (m_pszApplnPath)
  1367. {
  1368. delete [] m_pszApplnPath;
  1369. m_pszApplnPath = NULL;
  1370. }
  1371. if (m_pszApplnVRoot)
  1372. {
  1373. delete [] m_pszApplnVRoot;
  1374. m_pszApplnVRoot = NULL;
  1375. }
  1376. if (m_fInternalLockInited)
  1377. DeleteCriticalSection(&m_csInternalLock);
  1378. if (m_fApplnLockInited)
  1379. DeleteCriticalSection(&m_csApplnLock);
  1380. if (m_pServicesConfig)
  1381. {
  1382. m_pServicesConfig->Release();
  1383. m_pServicesConfig = NULL;
  1384. }
  1385. // Mark this application as Tombstone
  1386. m_fTombstone = TRUE;
  1387. InterlockedDecrement((LPLONG)&g_nApplications);
  1388. // Disconnennect from proxies (in case we are shutting down or will shortly shut down)
  1389. CoDisconnectObject(static_cast<IApplicationObject *>(this), 0);
  1390. return S_OK;
  1391. }
  1392. /*===================================================================
  1393. CAppln::BindToActivity
  1394. Creates application level activity either
  1395. as a clone of the given activity or
  1396. as a brand new activity
  1397. Must be called within critical section. Does not lock itself.
  1398. Parameters:
  1399. CViperActivity *pActivity activity to clone (could be NULL)
  1400. Returns:
  1401. NONE
  1402. ===================================================================*/
  1403. HRESULT CAppln::BindToActivity
  1404. (
  1405. CViperActivity *pActivity
  1406. )
  1407. {
  1408. if (m_pActivity)
  1409. {
  1410. // multiple requests to bind to new activity are ok
  1411. if (!pActivity)
  1412. return S_OK;
  1413. // but not to clone from an existing activity
  1414. Assert(FALSE);
  1415. return E_FAIL;
  1416. }
  1417. m_pActivity = new CViperActivity;
  1418. if (!m_pActivity)
  1419. return E_OUTOFMEMORY;
  1420. HRESULT hr;
  1421. if (pActivity)
  1422. hr = m_pActivity->InitClone(pActivity);
  1423. else
  1424. hr = m_pActivity->Init(m_pServicesConfig);
  1425. if (FAILED(hr))
  1426. {
  1427. delete m_pActivity;
  1428. m_pActivity = NULL;
  1429. }
  1430. return hr;
  1431. }
  1432. /*===================================================================
  1433. CAppln::SetGlobalAsa
  1434. Remembers GLOBAL.ASA file path for this application
  1435. Parameters:
  1436. const char *pszGlobalAsa path to (copy and) remember
  1437. Returns:
  1438. HRESULT
  1439. ===================================================================*/
  1440. HRESULT CAppln::SetGlobalAsa
  1441. (
  1442. const TCHAR *pszGlobalAsa
  1443. )
  1444. {
  1445. // remove existing
  1446. if (m_pszGlobalAsa)
  1447. {
  1448. delete [] m_pszGlobalAsa;
  1449. m_pszGlobalAsa = NULL;
  1450. }
  1451. // store new
  1452. if (pszGlobalAsa)
  1453. {
  1454. DWORD cch = _tcslen(pszGlobalAsa);
  1455. DWORD cb = (cch + 1) * sizeof(TCHAR);
  1456. m_pszGlobalAsa = new TCHAR[cch+1];
  1457. if (!m_pszGlobalAsa)
  1458. return E_OUTOFMEMORY;
  1459. memcpy(m_pszGlobalAsa, pszGlobalAsa, cb);
  1460. }
  1461. return S_OK;
  1462. }
  1463. /*===================================================================
  1464. CAppln::AddDirMonitorEntry
  1465. Remembers change notifcation monitor entries for this application
  1466. Parameters:
  1467. pDirMonitorEntry pointer to DME
  1468. Returns:
  1469. S_OK if the monitor entry was added to the list
  1470. ===================================================================*/
  1471. HRESULT CAppln::AddDirMonitorEntry(CDirMonitorEntry *pDirMonitorEntry)
  1472. {
  1473. DBG_ASSERT(m_fInited);
  1474. DBG_ASSERT(pDirMonitorEntry);
  1475. HRESULT hr = S_OK;
  1476. // Add the DME to the list
  1477. Lock(); // Protect m_rgpvDME by critical section
  1478. if (FAILED(hr = m_rgpvDME.Append(pDirMonitorEntry)))
  1479. {
  1480. pDirMonitorEntry->Release();
  1481. }
  1482. UnLock();
  1483. return hr;
  1484. }
  1485. /*===================================================================
  1486. CAppln::AddFileApplnEntry
  1487. Remembers change notifcation monitor entries for this application
  1488. Parameters:
  1489. pFileAppln pointer to FileApplnEntry
  1490. Returns:
  1491. S_OK if the monitor entry was added to the list
  1492. S_FALSE if the monitor entry was alread in the list
  1493. ===================================================================*/
  1494. HRESULT CAppln::AddFileApplnEntry(CFileApplnList *pFileAppln)
  1495. {
  1496. DBG_ASSERT(m_fInited);
  1497. DBG_ASSERT(pFileAppln);
  1498. HRESULT hr = S_OK;
  1499. int index;
  1500. // See if the file/application entry is alreay in the list
  1501. hr = m_rgpvFileAppln.Find(pFileAppln, &index);
  1502. if (hr == S_FALSE)
  1503. {
  1504. // Add the file/application entry to the list
  1505. hr = m_rgpvFileAppln.Append(pFileAppln);
  1506. }
  1507. else
  1508. {
  1509. // The file/application entry was already in the list
  1510. hr = S_FALSE;
  1511. }
  1512. return hr;
  1513. }
  1514. /*===================================================================
  1515. CAppln::LogSWCError
  1516. Logs an error to the NT Event log for any config errors that arise
  1517. in using COM+ Services Without Components.
  1518. Parameters:
  1519. REFIID riid
  1520. void **ppv
  1521. Returns:
  1522. HRESULT
  1523. ===================================================================*/
  1524. void CAppln::LogSWCError(enum eSWCERRORS error)
  1525. {
  1526. LPCSTR szStrings[4];
  1527. LPCWSTR szwStrings[4];
  1528. WORD cStrings = 0;
  1529. DWORD dwEventID = 0;
  1530. BOOL fUnicode = FALSE;
  1531. switch(error) {
  1532. case PartitionAccessDenied : {
  1533. if (m_fSWC_PartitionAccessDenied == FALSE) {
  1534. m_fSWC_PartitionAccessDenied = TRUE;
  1535. dwEventID = MSG_SWC_PARTITION_ACCESS_DENIED;
  1536. szStrings[0] = m_pAppConfig->szPartition();
  1537. cStrings = 1;
  1538. }
  1539. break;
  1540. }
  1541. case InvalidPartitionGUID: {
  1542. if (m_fSWC_InvalidPartitionGUID == FALSE) {
  1543. m_fSWC_InvalidPartitionGUID = TRUE;
  1544. dwEventID = MSG_SWC_INVALID_PARTITION_GUID;
  1545. szwStrings[0] = m_pszApplnVRoot;
  1546. cStrings = 1;
  1547. fUnicode = TRUE;
  1548. }
  1549. break;
  1550. }
  1551. }
  1552. if (dwEventID) {
  1553. if (fUnicode)
  1554. ReportAnEventW(dwEventID, (WORD) EVENTLOG_ERROR_TYPE, cStrings, szwStrings);
  1555. else
  1556. ReportAnEvent(dwEventID, (WORD) EVENTLOG_ERROR_TYPE, cStrings, szStrings);
  1557. }
  1558. }
  1559. /*===================================================================
  1560. CAppln::QueryInterface
  1561. QueryInterface() -- IApplicationObject implementation.
  1562. Parameters:
  1563. REFIID riid
  1564. void **ppv
  1565. Returns:
  1566. HRESULT
  1567. ===================================================================*/
  1568. STDMETHODIMP CAppln::QueryInterface
  1569. (
  1570. REFIID riid,
  1571. void **ppv
  1572. )
  1573. {
  1574. *ppv = NULL;
  1575. if (IID_IUnknown == riid ||
  1576. IID_IDispatch == riid ||
  1577. IID_IApplicationObject == riid ||
  1578. IID_IDenaliIntrinsic == riid)
  1579. {
  1580. *ppv = static_cast<IApplicationObject *>(this);
  1581. }
  1582. else if (IID_ISupportErrorInfo == riid)
  1583. {
  1584. *ppv = &m_ISuppErrImp;
  1585. }
  1586. else if (IID_IMarshal == riid)
  1587. {
  1588. Assert( m_pUnkFTM != NULL );
  1589. if ( m_pUnkFTM == NULL )
  1590. {
  1591. return E_UNEXPECTED;
  1592. }
  1593. return m_pUnkFTM->QueryInterface( riid, ppv );
  1594. }
  1595. if (*ppv)
  1596. {
  1597. ((LPUNKNOWN)*ppv)->AddRef();
  1598. return S_OK;
  1599. }
  1600. return E_NOINTERFACE;
  1601. }
  1602. /*===================================================================
  1603. CAppln::AddRef
  1604. AddRef() -- IUnknown implementation.
  1605. Parameters:
  1606. Returns:
  1607. Ref count
  1608. ===================================================================*/
  1609. STDMETHODIMP_(ULONG) CAppln::AddRef()
  1610. {
  1611. DWORD cRefs = InterlockedIncrement((LPLONG)&m_cRefs);
  1612. IF_DEBUG(APPLICATION) {
  1613. WriteRefTraceLog(gm_pTraceLog, cRefs, this);
  1614. }
  1615. return cRefs;
  1616. }
  1617. /*===================================================================
  1618. CAppln::Release
  1619. Release() -- IUnknown implementation.
  1620. Parameters:
  1621. Returns:
  1622. Ref count
  1623. ===================================================================*/
  1624. STDMETHODIMP_(ULONG) CAppln::Release()
  1625. {
  1626. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  1627. IF_DEBUG(APPLICATION) {
  1628. WriteRefTraceLog(gm_pTraceLog, cRefs, this);
  1629. }
  1630. if (cRefs)
  1631. return cRefs;
  1632. delete this;
  1633. InterlockedDecrement((LPLONG)&g_nApplicationObjectsActive);
  1634. return 0;
  1635. }
  1636. /*===================================================================
  1637. CAppln::CheckForTombstone
  1638. Tombstone stub for IApplicationObject methods. If the object is
  1639. tombstone, does ExceptionId and fails.
  1640. Parameters:
  1641. Returns:
  1642. HRESULT E_FAIL if Tombstone
  1643. S_OK if not
  1644. ===================================================================*/
  1645. HRESULT CAppln::CheckForTombstone()
  1646. {
  1647. if (!m_fTombstone)
  1648. return S_OK;
  1649. ExceptionId
  1650. (
  1651. IID_IApplicationObject,
  1652. IDE_APPLICATION,
  1653. IDE_INTRINSIC_OUT_OF_SCOPE
  1654. );
  1655. return E_FAIL;
  1656. }
  1657. /*===================================================================
  1658. CAppln::Lock
  1659. IApplicationObject method.
  1660. Will allow the user to lock the application intrinsic for the
  1661. purpose of adding/deleting values.
  1662. Parameters:
  1663. NONE
  1664. Returns:
  1665. HRESULT S_OK on success
  1666. E_FAIL otherwise
  1667. ===================================================================*/
  1668. STDMETHODIMP CAppln::Lock()
  1669. {
  1670. if (FAILED(CheckForTombstone()))
  1671. return E_FAIL;
  1672. Assert(m_fApplnLockInited);
  1673. DWORD dwId = GetCurrentThreadId();
  1674. // If this thread already has the lock, increment lock ref count
  1675. if (m_dwLockThreadID == dwId)
  1676. {
  1677. m_cLockRefCount++;
  1678. }
  1679. else
  1680. {
  1681. EnterCriticalSection(&m_csApplnLock);
  1682. m_cLockRefCount = 1;
  1683. m_dwLockThreadID = dwId;
  1684. }
  1685. return S_OK;
  1686. }
  1687. /*===================================================================
  1688. CAppln::UnLock
  1689. IApplicationObject method.
  1690. Will allow the user to unlock the application intrinsic only
  1691. if it has been locked by this user.
  1692. Parameters:
  1693. NONE
  1694. Returns:
  1695. HRESULT S_OK
  1696. ===================================================================*/
  1697. STDMETHODIMP CAppln::UnLock()
  1698. {
  1699. if (FAILED(CheckForTombstone()))
  1700. return E_FAIL;
  1701. if (m_dwLockThreadID == GetCurrentThreadId())
  1702. {
  1703. if (--m_cLockRefCount == 0)
  1704. {
  1705. // Unlock the application
  1706. m_dwLockThreadID = INVALID_THREADID;
  1707. LeaveCriticalSection(&m_csApplnLock);
  1708. }
  1709. }
  1710. return S_OK;
  1711. }
  1712. /*===================================================================
  1713. CAppln::UnLockAfterRequest
  1714. Remove any application locks left by the user script
  1715. Parameters:
  1716. NONE
  1717. Returns:
  1718. HRESULT S_OK
  1719. ===================================================================*/
  1720. HRESULT CAppln::UnLockAfterRequest()
  1721. {
  1722. Assert(!m_fTombstone);
  1723. if (m_cLockRefCount > 0 && m_dwLockThreadID == GetCurrentThreadId())
  1724. {
  1725. m_cLockRefCount = 0;
  1726. m_dwLockThreadID = INVALID_THREADID;
  1727. LeaveCriticalSection(&m_csApplnLock);
  1728. }
  1729. return S_OK;
  1730. }
  1731. /*===================================================================
  1732. CAppln::get_Value
  1733. IApplicationObject method.
  1734. Will allow the user to retreive a application state variable,
  1735. the variable will come as a named pair, bstr is the name and
  1736. var is the value or object to be returned for that name
  1737. Parameters:
  1738. BSTR FAR * bstrName Name of the variable to get
  1739. VARIANT * pVar Value/object to get for the variable
  1740. Returns:
  1741. HRESULT S_OK on success
  1742. ===================================================================*/
  1743. STDMETHODIMP CAppln::get_Value
  1744. (
  1745. BSTR bstrName,
  1746. VARIANT *pVar
  1747. )
  1748. {
  1749. if (FAILED(CheckForTombstone()))
  1750. return E_FAIL;
  1751. if (bstrName == NULL)
  1752. {
  1753. ExceptionId(IID_IApplicationObject,
  1754. IDE_APPLICATION, IDE_EXPECTING_STR);
  1755. return E_FAIL;
  1756. }
  1757. VariantInit(pVar); // default variant empty
  1758. WCHAR *pwszName;
  1759. STACK_BUFFER(rgbName, 42);
  1760. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1761. if (pwszName == NULL)
  1762. return S_OK; // no name - no value - no error
  1763. //_wcsupr(pwszName);
  1764. Assert(m_pApplCompCol);
  1765. HRESULT hr = S_OK;
  1766. CComponentObject *pObj = NULL;
  1767. // Lock the application
  1768. Lock();
  1769. hr = m_pApplCompCol->GetProperty(pwszName, &pObj);
  1770. if (SUCCEEDED(hr))
  1771. {
  1772. Assert(pObj);
  1773. hr = pObj->GetVariant(pVar);
  1774. }
  1775. // UnLock the application
  1776. UnLock();
  1777. return S_OK;
  1778. }
  1779. /*===================================================================
  1780. CAppln::putref_Value
  1781. IApplicationObject method.
  1782. Will allow the user to assign a application state variable to be saved
  1783. the variable will come as a named pair, bstr is the name and
  1784. var is the value or object to be stored for that name
  1785. Parameters:
  1786. BSTR bstrName Name of the variable to set
  1787. VARIANT Var Value/object to set for the variable
  1788. Returns:
  1789. HRESULT S_OK on success
  1790. ===================================================================*/
  1791. STDMETHODIMP CAppln::putref_Value
  1792. (
  1793. BSTR bstrName,
  1794. VARIANT Var
  1795. )
  1796. {
  1797. if (FAILED(CheckForTombstone()))
  1798. return E_FAIL;
  1799. if (FIsIntrinsic(&Var))
  1800. {
  1801. ExceptionId(IID_IApplicationObject, IDE_APPLICATION,
  1802. IDE_APPLICATION_CANT_STORE_INTRINSIC);
  1803. return E_FAIL;
  1804. }
  1805. if (bstrName == NULL)
  1806. {
  1807. ExceptionId(IID_IApplicationObject,
  1808. IDE_APPLICATION, IDE_EXPECTING_STR);
  1809. return E_FAIL;
  1810. }
  1811. HRESULT hr;
  1812. Assert(m_pApplCompCol);
  1813. // Prepare property name
  1814. WCHAR *pwszName;
  1815. STACK_BUFFER(rgbName, 42);
  1816. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1817. if (pwszName == NULL)
  1818. {
  1819. ExceptionId(IID_IApplicationObject,
  1820. IDE_APPLICATION, IDE_EXPECTING_STR);
  1821. return E_FAIL;
  1822. }
  1823. //_wcsupr(pwszName);
  1824. // Lock the application
  1825. Lock();
  1826. hr = m_pApplCompCol->AddProperty(pwszName, &Var);
  1827. // Unlock the application
  1828. UnLock();
  1829. if (hr == RPC_E_WRONG_THREAD)
  1830. {
  1831. // We use RPC_E_WRONG_THREAD to indicate bad model object
  1832. ExceptionId(IID_IApplicationObject,
  1833. IDE_APPLICATION, IDE_APPLICATION_CANT_STORE_OBJECT);
  1834. hr = E_FAIL;
  1835. }
  1836. return hr;
  1837. }
  1838. /*===================================================================
  1839. CAppln::put_Value
  1840. IApplicationObject method.
  1841. Implement property put by dereferencing variants before
  1842. calling putref.
  1843. Parameters:
  1844. BSTR FAR * bstrName Name of the variable to set
  1845. VARIANT Var Value/object to set for the variable
  1846. Returns:
  1847. HRESULT S_OK on success
  1848. ===================================================================*/
  1849. STDMETHODIMP CAppln::put_Value
  1850. (
  1851. BSTR bstrName,
  1852. VARIANT Var
  1853. )
  1854. {
  1855. if (FAILED(CheckForTombstone()))
  1856. return E_FAIL;
  1857. if (bstrName == NULL)
  1858. {
  1859. ExceptionId(IID_IApplicationObject,
  1860. IDE_APPLICATION, IDE_EXPECTING_STR);
  1861. return E_FAIL;
  1862. }
  1863. HRESULT hr;
  1864. Assert(m_pApplCompCol);
  1865. // Prepare property name
  1866. WCHAR *pwszName;
  1867. STACK_BUFFER(rgbName, 42);
  1868. WSTR_STACK_DUP(bstrName, &rgbName, &pwszName);
  1869. if (pwszName == NULL)
  1870. {
  1871. ExceptionId(IID_IApplicationObject,
  1872. IDE_APPLICATION, IDE_EXPECTING_STR);
  1873. return E_FAIL;
  1874. }
  1875. //_wcsupr(pwszName);
  1876. // Lock the application
  1877. Lock();
  1878. VARIANT varResolved;
  1879. hr = VariantResolveDispatch(&varResolved, &Var,
  1880. IID_IApplicationObject,
  1881. IDE_APPLICATION);
  1882. if (SUCCEEDED(hr))
  1883. {
  1884. hr = m_pApplCompCol->AddProperty(pwszName, &varResolved);
  1885. VariantClear(&varResolved);
  1886. }
  1887. // Unlock the application
  1888. UnLock();
  1889. if (hr == RPC_E_WRONG_THREAD)
  1890. {
  1891. // We use RPC_E_WRONG_THREAD to indicate bad model object
  1892. ExceptionId(IID_IApplicationObject,
  1893. IDE_APPLICATION, IDE_APPLICATION_CANT_STORE_OBJECT);
  1894. hr = E_FAIL;
  1895. }
  1896. return hr;
  1897. }
  1898. /*===================================================================
  1899. CAppln::get_Contents
  1900. Return the application contents dictionary
  1901. ===================================================================*/
  1902. STDMETHODIMP CAppln::get_Contents(IVariantDictionary **ppDictReturn)
  1903. {
  1904. if (FAILED(CheckForTombstone()) || !m_pProperties)
  1905. return E_FAIL;
  1906. return m_pProperties->QueryInterface(IID_IVariantDictionary, reinterpret_cast<void **>(ppDictReturn));
  1907. }
  1908. /*===================================================================
  1909. CAppln::get_StaticObjects
  1910. Return the application static objects dictionary
  1911. ===================================================================*/
  1912. STDMETHODIMP CAppln::get_StaticObjects(IVariantDictionary **ppDictReturn)
  1913. {
  1914. if (FAILED(CheckForTombstone()) || !m_pTaggedObjects)
  1915. return E_FAIL;
  1916. return m_pTaggedObjects->QueryInterface(IID_IVariantDictionary, reinterpret_cast<void **>(ppDictReturn));
  1917. }
  1918. /*===================================================================
  1919. CAppln::UpdateConfig
  1920. Updates configuration from metabase if needed
  1921. ===================================================================*/
  1922. HRESULT CAppln::UpdateConfig(CIsapiReqInfo *pIReq, BOOL *pfRestart, BOOL *pfFlushAll)
  1923. {
  1924. BOOL fRestart = FALSE;
  1925. BOOL fFlushAll = FALSE;
  1926. if (m_pAppConfig->fNeedUpdate())
  1927. {
  1928. InternalLock();
  1929. if (m_pAppConfig->fNeedUpdate()) // still need update?
  1930. {
  1931. char lastPartitionGUID[64];
  1932. lastPartitionGUID[0] = '\0';
  1933. BOOL fAllowedDebugging = m_pAppConfig->fAllowDebugging();
  1934. BOOL fAllowedClientDebug = m_pAppConfig->fAllowClientDebug();
  1935. BOOL fAllowedRestart = m_pAppConfig->fEnableApplicationRestart();
  1936. BOOL fParentPathsEnabled = m_pAppConfig->fEnableParentPaths();
  1937. UINT uLastCodePage = m_pAppConfig->uCodePage();
  1938. LCID uLastLCID = m_pAppConfig->uLCID();
  1939. BOOL fPrevSxsEnabled = m_pAppConfig->fSxsEnabled();
  1940. BOOL fPrevUsePartition = m_pAppConfig->fUsePartition();
  1941. BOOL fPrevUseTracker = m_pAppConfig->fTrackerEnabled();
  1942. BOOL fPrevKeepSessionIDSecure = m_pAppConfig->fKeepSessionIDSecure();
  1943. BOOL fPrevCalcLineNumber = m_pAppConfig->fCalcLineNumber();
  1944. if (m_pAppConfig->fUsePartition() && m_pAppConfig->szPartition()) {
  1945. strncpy(lastPartitionGUID, m_pAppConfig->szPartition(), sizeof(lastPartitionGUID));
  1946. lastPartitionGUID[sizeof(lastPartitionGUID)-1] = '\0';
  1947. }
  1948. BOOL fRestartEnabledUpdated = m_pAppConfig->fRestartEnabledUpdated();
  1949. char szLastDefaultEngine[64];
  1950. strncpy(szLastDefaultEngine, m_pAppConfig->szScriptLanguage(), sizeof szLastDefaultEngine);
  1951. szLastDefaultEngine[sizeof(szLastDefaultEngine) - 1] = '\0';
  1952. m_pAppConfig->Update(pIReq);
  1953. BOOL fAllowDebugging = m_pAppConfig->fAllowDebugging();
  1954. BOOL fAllowClientDebug = m_pAppConfig->fAllowClientDebug();
  1955. BOOL fAllowRestart = m_pAppConfig->fEnableApplicationRestart();
  1956. BOOL fEnableParentPaths = m_pAppConfig->fEnableParentPaths();
  1957. UINT uCodePage = m_pAppConfig->uCodePage();
  1958. LCID uLCID = m_pAppConfig->uLCID();
  1959. BOOL fCurSxsEnabled = m_pAppConfig->fSxsEnabled();
  1960. BOOL fCurUsePartition = m_pAppConfig->fUsePartition();
  1961. BOOL fCurUseTracker = m_pAppConfig->fTrackerEnabled();
  1962. BOOL fCurKeepSessionIDSecure = m_pAppConfig->fKeepSessionIDSecure();
  1963. BOOL fCurCalcLineNumber = m_pAppConfig->fCalcLineNumber();
  1964. const char *szNewDefaultEngine = m_pAppConfig->szScriptLanguage();
  1965. fFlushAll = strcmpi(szLastDefaultEngine, szNewDefaultEngine) != 0
  1966. || (fParentPathsEnabled != fEnableParentPaths)
  1967. || (uLastCodePage != uCodePage)
  1968. || (uLastLCID != uLCID);
  1969. fRestart = (fAllowDebugging != fAllowedDebugging) ||
  1970. (fAllowClientDebug != fAllowedClientDebug) ||
  1971. ((fAllowRestart != fAllowedRestart) && fAllowRestart) ||
  1972. ((fAllowRestart == fAllowedRestart) && fRestartEnabledUpdated) ||
  1973. (fCurSxsEnabled != fPrevSxsEnabled) ||
  1974. (fCurUsePartition != fPrevUsePartition) ||
  1975. (fCurUseTracker != fPrevUseTracker) ||
  1976. (fCurKeepSessionIDSecure != fPrevKeepSessionIDSecure) ||
  1977. (fCurCalcLineNumber != fPrevCalcLineNumber) ||
  1978. (fCurUsePartition
  1979. && fPrevUsePartition
  1980. && ((m_pAppConfig->szPartition() == NULL)
  1981. || (strcmpi(lastPartitionGUID, m_pAppConfig->szPartition()) != 0))) ||
  1982. fFlushAll;
  1983. }
  1984. InternalUnLock();
  1985. }
  1986. if (pfRestart)
  1987. *pfRestart = fRestart;
  1988. if (pfFlushAll)
  1989. *pfFlushAll = fFlushAll;
  1990. return S_OK;
  1991. }
  1992. /*===================================================================
  1993. CAppln::FPathMonitored()
  1994. Checks the list of DMEs in application to see if the specified path
  1995. is already being monitored.
  1996. ===================================================================*/
  1997. CASPDirMonitorEntry *CAppln::FPathMonitored(LPCTSTR pszPath)
  1998. {
  1999. int i;
  2000. Lock(); // Protect m_rqpvDME by a critical section
  2001. int cDMEs = m_rgpvDME.Count();
  2002. for (i=0; i < cDMEs; i++) {
  2003. CASPDirMonitorEntry *pDME = static_cast<CASPDirMonitorEntry *>(m_rgpvDME[i]);
  2004. if (pDME == NULL)
  2005. break;
  2006. if (pDME->FPathMonitored(pszPath))
  2007. {
  2008. UnLock();
  2009. return pDME;
  2010. }
  2011. }
  2012. UnLock();
  2013. return NULL;
  2014. }
  2015. #ifdef DBG
  2016. /*===================================================================
  2017. CAppln::AssertValid
  2018. Test to make sure that the CAppln object is currently correctly
  2019. formed and assert if it is not.
  2020. Returns:
  2021. Nothing
  2022. Side effects:
  2023. None.
  2024. ===================================================================*/
  2025. void CAppln::AssertValid() const
  2026. {
  2027. Assert(m_fInited);
  2028. Assert(m_pSessionMgr);
  2029. Assert(m_pApplCompCol);
  2030. m_pApplCompCol->AssertValid();
  2031. }
  2032. #endif // DBG
  2033. /*===================================================================
  2034. C A p p l n M g r
  2035. ===================================================================*/
  2036. /*===================================================================
  2037. CApplnMgr::CApplnMgr
  2038. Application Manager constructor.
  2039. Parameters:
  2040. NONE
  2041. Returns:
  2042. NONE
  2043. ===================================================================*/
  2044. CApplnMgr::CApplnMgr()
  2045. : m_fInited(FALSE),
  2046. m_fHashTableInited(FALSE),
  2047. m_fCriticalSectionInited(FALSE),
  2048. m_cntApp(0),
  2049. m_pMetabase(NULL),
  2050. m_pMetabaseSink(NULL),
  2051. m_dwMDSinkCookie(0)
  2052. {
  2053. }
  2054. /*===================================================================
  2055. CApplnMgr::~CApplnMgr
  2056. Application Manager destructor.
  2057. Parameters:
  2058. NONE
  2059. Returns:
  2060. NONE
  2061. ===================================================================*/
  2062. CApplnMgr::~CApplnMgr()
  2063. {
  2064. if (!m_fInited)
  2065. UnInit();
  2066. }
  2067. /*===================================================================
  2068. HRESULT CApplnMgr::Init
  2069. Initializes the Appln Manager.
  2070. Parameters:
  2071. NONE
  2072. Returns:
  2073. S_OK Success
  2074. E_FAIL Failure
  2075. E_OUTOFMEMORY Out of memory
  2076. ===================================================================*/
  2077. HRESULT CApplnMgr::Init( void )
  2078. {
  2079. HRESULT hr = S_OK;
  2080. Assert(!m_fInited);
  2081. // Init hash table
  2082. hr = CHashTable::Init(NUM_APPLMGR_HASHING_BUCKETS);
  2083. if (FAILED(hr))
  2084. return hr;
  2085. m_fHashTableInited = TRUE;
  2086. // Init critical section
  2087. ErrInitCriticalSection(&m_csLock, hr);
  2088. if (FAILED(hr))
  2089. return(hr);
  2090. m_fCriticalSectionInited = TRUE;
  2091. m_fInited = TRUE;
  2092. return g_ApplnCleanupMgr.Init();
  2093. }
  2094. /*===================================================================
  2095. HRESULT CApplnMgr::UnInit
  2096. UnInitializes the Appln Manager.
  2097. Parameters:
  2098. NONE
  2099. Returns:
  2100. S_OK Success
  2101. E_FAIL Failure
  2102. ===================================================================*/
  2103. HRESULT CApplnMgr::UnInit( void )
  2104. {
  2105. //
  2106. // release the metabase change notification. Ignore return value as it is always S_OK
  2107. //
  2108. UnInitMBListener();
  2109. //
  2110. // Wait for COM to release all Sinks
  2111. //
  2112. while (!g_fProceedWithShutdownAppln)
  2113. Sleep (100);
  2114. if (m_fHashTableInited)
  2115. {
  2116. CHashTable::UnInit();
  2117. m_fHashTableInited = FALSE;
  2118. }
  2119. if (m_fCriticalSectionInited)
  2120. {
  2121. DeleteCriticalSection(&m_csLock);
  2122. m_fCriticalSectionInited = FALSE;
  2123. }
  2124. m_fInited = FALSE;
  2125. return g_ApplnCleanupMgr.UnInit();
  2126. }
  2127. /*===================================================================
  2128. HRESULT CApplnMgr::InitMBListener
  2129. Registers the CMDAppConfigSink object to listen to sink notifications. Performs an Advise on the ABO
  2130. Parameters:
  2131. NONE
  2132. Returns:
  2133. S_OK Success
  2134. E_FAIL Failure
  2135. E_OUTOFMEMORY Out of memory
  2136. ===================================================================*/
  2137. HRESULT CApplnMgr::InitMBListener( )
  2138. {
  2139. HRESULT hr = S_OK;
  2140. IConnectionPointContainer *pConnPointContainer = NULL;
  2141. IConnectionPoint *pConnPoint = NULL;
  2142. IClassFactory *pcsfFactory = NULL;
  2143. HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
  2144. //
  2145. // Get a pointer to the Metabase
  2146. //
  2147. AspDoRevertHack (&hCurrentUser);
  2148. hr = GetMetabaseIF(&m_pMetabase);
  2149. if (FAILED(hr))
  2150. {
  2151. AspUndoRevertHack (&hCurrentUser);
  2152. return hr;
  2153. }
  2154. //
  2155. // Register to get notifications on the Sink
  2156. //
  2157. m_pMetabaseSink = new CMDAppConfigSink(this);
  2158. if (!m_pMetabaseSink)
  2159. {
  2160. hr = E_OUTOFMEMORY;
  2161. goto LExit;
  2162. }
  2163. m_dwMDSinkCookie = 0;
  2164. if (SUCCEEDED(hr))
  2165. {
  2166. //Advise Metabase about SinkNotify().
  2167. hr = m_pMetabase->QueryInterface(IID_IConnectionPointContainer, (void **)&pConnPointContainer);
  2168. if (pConnPointContainer != NULL)
  2169. {
  2170. //Find the requested Connection Point. This AddRef's the return pointer.
  2171. hr = pConnPointContainer->FindConnectionPoint(IID_IMSAdminBaseSink, &pConnPoint);
  2172. pConnPointContainer->Release();
  2173. if (pConnPoint != NULL)
  2174. {
  2175. hr = pConnPoint->Advise((IUnknown *)m_pMetabaseSink, &m_dwMDSinkCookie);
  2176. pConnPoint->Release();
  2177. }
  2178. }
  2179. }
  2180. LExit:
  2181. if (FAILED(hr))
  2182. {
  2183. m_pMetabase->Release();
  2184. m_pMetabase = NULL;
  2185. }
  2186. AspUndoRevertHack(&hCurrentUser);
  2187. return hr;
  2188. }
  2189. /*===================================================================
  2190. HRESULT CApplnMgr::UnInitMBListener
  2191. Unregisters the Application manager from receiving sink notifications. Performs an UnAdvise on the ABO
  2192. Parameters:
  2193. NONE
  2194. Returns:
  2195. S_OK Success
  2196. E_FAIL Failure
  2197. E_OUTOFMEMORY Out of memory
  2198. ===================================================================*/
  2199. HRESULT CApplnMgr::UnInitMBListener( )
  2200. {
  2201. HRESULT hr = S_OK;
  2202. IConnectionPointContainer *pConnPointContainer = NULL;
  2203. IConnectionPoint *pConnPoint = NULL;
  2204. CHAR szErr[256];
  2205. HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
  2206. AspDoRevertHack (&hCurrentUser);
  2207. if (m_pMetabase) {
  2208. //Advise Metabase about SinkNotify().
  2209. hr = m_pMetabase->QueryInterface(IID_IConnectionPointContainer, (void **)&pConnPointContainer);
  2210. if (pConnPointContainer != NULL)
  2211. {
  2212. //Find the requested Connection Point. This AddRef's the return pointer.
  2213. hr = pConnPointContainer->FindConnectionPoint(IID_IMSAdminBaseSink, &pConnPoint);
  2214. if (FAILED(hr))
  2215. {
  2216. DBGPRINTF((DBG_CONTEXT, "FindConnectionPoint failed. hr = %08x\n", hr));
  2217. }
  2218. pConnPointContainer->Release();
  2219. if (pConnPoint != NULL)
  2220. {
  2221. hr = pConnPoint->Unadvise(m_dwMDSinkCookie);
  2222. if (FAILED(hr))
  2223. {
  2224. DBGPRINTF((DBG_CONTEXT, "UnAdvise App Config Change Notify failed. hr = %08x\n", hr));
  2225. }
  2226. hr = S_OK; // benign failure if Advise was not called (happens with unknown script lang)
  2227. pConnPoint->Release();
  2228. m_dwMDSinkCookie = 0;
  2229. }
  2230. }
  2231. else
  2232. {
  2233. DBGPRINTF((DBG_CONTEXT, "QueryInterface failed. hr = %08x\n", hr));
  2234. }
  2235. m_pMetabase->Release();
  2236. m_pMetabase = NULL;
  2237. }
  2238. if (m_pMetabaseSink) {
  2239. m_pMetabaseSink->Release();
  2240. m_pMetabaseSink = NULL;
  2241. }
  2242. AspUndoRevertHack (&hCurrentUser);
  2243. //
  2244. // Always return S_OK. In the new world, the metabase may have gone away
  2245. // because of a WAS recycle. So, it can happen that even the QI's above will fail.
  2246. //
  2247. return S_OK;
  2248. }
  2249. /*===================================================================
  2250. HRESULT CApplnMgr::NotifyAllMBListeners
  2251. When the RPC thread calls the CMDAppConfigSink objects SinkNotify method. This method is called
  2252. which will iterate through all the applications and call each applications appconfig object to update thier
  2253. config information
  2254. Parameters:
  2255. dwMDNumElements - number of elements in the change list.
  2256. pcoChangeList - The list of changes
  2257. Returns:
  2258. S_OK Success
  2259. E_FAIL Failure
  2260. E_OUTOFMEMORY Out of memory
  2261. ===================================================================*/
  2262. HRESULT CApplnMgr::NotifyAllMBListeners( DWORD dwMDNumElements, MD_CHANGE_OBJECT_W __RPC_FAR pcoChangeList [ ] )
  2263. {
  2264. HRESULT hr = S_OK;
  2265. Lock();
  2266. CLinkElem *pLink = CHashTable::Head();
  2267. while (pLink)
  2268. {
  2269. CAppln *pAppln = static_cast<CAppln *>(pLink);
  2270. pLink = pLink->m_pNext;
  2271. if (pAppln->m_fDeleteInProgress)
  2272. continue;
  2273. hr = pAppln->QueryAppConfig()->SinkNotify(dwMDNumElements, pcoChangeList);
  2274. if (FAILED(hr))
  2275. break;
  2276. }
  2277. UnLock();
  2278. return hr;
  2279. }
  2280. /*===================================================================
  2281. CApplnMgr::AddAppln
  2282. Adds a CAppln element to link list / hash table.
  2283. User has to check if Appln already exists before calling this.
  2284. Critical sectioning is in CHitObj::BrowserRequestInit().
  2285. Parameters:
  2286. char *pszApplnKey Application metabase key
  2287. char *pszApplnPath Application directory path
  2288. CIsapiReqInfo *pIReq
  2289. CAppln **ppAppln [out] Application created
  2290. Returns:
  2291. HRESULT
  2292. ===================================================================*/
  2293. HRESULT CApplnMgr::AddAppln
  2294. (
  2295. TCHAR *pszApplnKey,
  2296. TCHAR *pszApplnPath,
  2297. CIsapiReqInfo *pIReq,
  2298. CAppln **ppAppln
  2299. )
  2300. {
  2301. *ppAppln = NULL; // return NULL if failed
  2302. // Create CAppln object
  2303. CAppln *pAppln = new CAppln;
  2304. if (!pAppln)
  2305. return E_OUTOFMEMORY;
  2306. // Init CAppln object
  2307. HRESULT hr;
  2308. hr = pAppln->Init
  2309. (
  2310. pszApplnKey,
  2311. pszApplnPath,
  2312. pIReq
  2313. );
  2314. if (FAILED(hr))
  2315. {
  2316. pAppln->UnInit();
  2317. pAppln->Release();
  2318. return hr;
  2319. }
  2320. // Add to hash table
  2321. if (!CHashTable::AddElem(pAppln))
  2322. {
  2323. pAppln->UnInit();
  2324. pAppln->Release();
  2325. return E_FAIL;
  2326. }
  2327. *ppAppln = pAppln;
  2328. return S_OK;
  2329. }
  2330. /*===================================================================
  2331. CApplnMgr::FindAppln
  2332. Finds CAppln in hash table
  2333. Critical sectioning must be done outside
  2334. Parameters:
  2335. char *pszApplnKey Application metabase key
  2336. CAppln **ppAppln [out] Application found
  2337. Returns:
  2338. S_OK if found
  2339. S_FALSE if not found
  2340. ===================================================================*/
  2341. HRESULT CApplnMgr::FindAppln
  2342. (
  2343. TCHAR *pszApplnKey,
  2344. CAppln **ppAppln
  2345. )
  2346. {
  2347. CLinkElem *pLinkElem = CHashTable::FindElem
  2348. (
  2349. pszApplnKey,
  2350. _tcslen(pszApplnKey)*sizeof(TCHAR)
  2351. );
  2352. if (!pLinkElem)
  2353. {
  2354. *ppAppln = NULL;
  2355. return S_FALSE;
  2356. }
  2357. *ppAppln = static_cast<CAppln *>(pLinkElem);
  2358. return S_OK;
  2359. }
  2360. /*===================================================================
  2361. CApplnMgr::AddEngine
  2362. When a change notification occurs for a file being debugged,
  2363. we need to delete its associated scripting engine. The naive
  2364. approach of Releasing the engine during notification won't work
  2365. because the engine is on the wrong thread. Instead of marshaling
  2366. to the thread (which raises possibilities of deadlock or starving
  2367. the notification thread if debugging is happening on the debug
  2368. thread), the engines are added to a queue in the application.
  2369. When a request is serviced for debugging (which is now in the
  2370. correct thread context), the application object first flushes
  2371. this list by releasing the engines
  2372. ===================================================================*/
  2373. HRESULT CApplnMgr::AddEngine(CActiveScriptEngine *pEngine)
  2374. {
  2375. CScriptEngineCleanupElem *pScriptElem = new CScriptEngineCleanupElem(pEngine);
  2376. if (pScriptElem == NULL)
  2377. return E_OUTOFMEMORY;
  2378. pScriptElem->AppendTo(m_listEngineCleanup);
  2379. return S_OK;
  2380. }
  2381. /*===================================================================
  2382. CApplnMgr::CleanupEngines()
  2383. Call Release all engine cleanup list.
  2384. ===================================================================*/
  2385. void CApplnMgr::CleanupEngines()
  2386. {
  2387. while (! m_listEngineCleanup.FIsEmpty())
  2388. delete m_listEngineCleanup.PNext();
  2389. }
  2390. /*===================================================================
  2391. CApplnMgr::DeleteApplicationIfExpired
  2392. Removes CAppln object if exprired
  2393. Critical sectioning must be done outside
  2394. Parameters:
  2395. CAppln *pAppln application to delete
  2396. Returns:
  2397. NONE
  2398. ===================================================================*/
  2399. HRESULT CApplnMgr::DeleteApplicationIfExpired
  2400. (
  2401. CAppln *pAppln
  2402. )
  2403. {
  2404. if (!pAppln->m_fGlobalChanged)
  2405. return S_OK;
  2406. if (pAppln->m_cSessions || pAppln->m_cRequests)
  2407. return S_OK;
  2408. if (pAppln->m_fDeleteInProgress)
  2409. return S_OK;
  2410. pAppln->m_fDeleteInProgress = TRUE;
  2411. HRESULT hr = S_OK;
  2412. // Queue it up for deletion
  2413. CHitObj *pHitObj = new CHitObj;
  2414. if (!pHitObj)
  2415. hr = E_OUTOFMEMORY;
  2416. if (SUCCEEDED(hr))
  2417. {
  2418. pHitObj->ApplicationCleanupInit(pAppln);
  2419. // Ask Viper to queue this request
  2420. hr = pHitObj->PostViperAsyncCall();
  2421. }
  2422. // cleanup
  2423. if (FAILED(hr) && pHitObj) {
  2424. pAppln->UnInit();
  2425. pAppln->Release();
  2426. delete pHitObj;
  2427. }
  2428. return hr;
  2429. }
  2430. /*===================================================================
  2431. CApplnMgr::DeleteAllApplications
  2432. Removes CAppln objects from the application manager link list
  2433. and hash table.
  2434. Parameters:
  2435. Returns:
  2436. HRESULT
  2437. ===================================================================*/
  2438. HRESULT CApplnMgr::DeleteAllApplications()
  2439. {
  2440. HRESULT hr = S_OK;
  2441. Lock();
  2442. CLinkElem *pLink = CHashTable::Head();
  2443. CHashTable::ReInit();
  2444. while (pLink)
  2445. {
  2446. CAppln *pAppln = static_cast<CAppln *>(pLink);
  2447. pLink = pLink->m_pNext;
  2448. if (pAppln->m_fDeleteInProgress)
  2449. continue;
  2450. pAppln->m_fDeleteInProgress = TRUE;
  2451. // Queue it up for deletion
  2452. CHitObj *pHitObj = new CHitObj;
  2453. if (!pHitObj)
  2454. {
  2455. hr = E_OUTOFMEMORY;
  2456. break;
  2457. }
  2458. // If NT, Unregister for notifications
  2459. while ((pAppln->m_rgpvDME).Count())
  2460. {
  2461. static_cast<CDirMonitorEntry *>(pAppln->m_rgpvDME[0])->Release();
  2462. (pAppln->m_rgpvDME).Remove(0);
  2463. }
  2464. pAppln->m_rgpvDME.Clear();
  2465. pHitObj->ApplicationCleanupInit(pAppln);
  2466. // Ask Viper to queue this request
  2467. hr = pHitObj->PostViperAsyncCall();
  2468. if (FAILED(hr))
  2469. {
  2470. pAppln->UnInit();
  2471. pAppln->Release();
  2472. delete pHitObj;
  2473. break;
  2474. }
  2475. }
  2476. UnLock();
  2477. return hr;
  2478. }
  2479. /*===================================================================
  2480. CApplnMgr::RestartAllChagnedApplications
  2481. Restarts CAppln objects from the application manager link list
  2482. We walk the list recording which applications are dependent
  2483. on files that have changed since they were compiled. Once we
  2484. have the list, we restart each of the applications.
  2485. This is a fall back when we may have missed a change notification,
  2486. for instance when we had insufficient buffer to record all the changes
  2487. that occured.
  2488. Parameters:
  2489. Returns:
  2490. HRESULT
  2491. ===================================================================*/
  2492. HRESULT CApplnMgr::RestartApplications(BOOL fRestartAllApplications)
  2493. {
  2494. HRESULT hr = S_OK;
  2495. Lock();
  2496. CLinkElem *pLink = CHashTable::Head();
  2497. // Find out which applications need restarting
  2498. while (pLink)
  2499. {
  2500. CAppln *pAppln = static_cast<CAppln *>(pLink);
  2501. pLink = pLink->m_pNext;
  2502. if (!pAppln->FTombstone() && (fRestartAllApplications || (pAppln->m_pGlobalTemplate != NULL && pAppln->m_pGlobalTemplate->FTemplateObsolete())))
  2503. {
  2504. pAppln->Restart();
  2505. }
  2506. }
  2507. UnLock();
  2508. return hr;
  2509. }
  2510. /*===================================================================
  2511. C A p p l n C l e a n u p M g r
  2512. ===================================================================*/
  2513. /*===================================================================
  2514. CApplnMgr::CApplnCleanupMgr
  2515. Application Cleanup Manager constructor.
  2516. Parameters:
  2517. NONE
  2518. Returns:
  2519. NONE
  2520. ===================================================================*/
  2521. CApplnCleanupMgr::CApplnCleanupMgr()
  2522. : m_fInited(FALSE),
  2523. m_fCriticalSectionInited(FALSE),
  2524. m_hThreadAlive(NULL),
  2525. m_cCleanupThreads(0),
  2526. m_hAppToCleanup(INVALID_HANDLE_VALUE)
  2527. {
  2528. m_List.m_pPrev = &m_List;
  2529. m_List.m_pNext = &m_List;
  2530. // Clean out the thread count
  2531. ZeroMemory(&m_hCleanupThreads, sizeof (m_hCleanupThreads));
  2532. }
  2533. /*===================================================================
  2534. CApplnCleanupMgr::~CApplnCleanupMgr
  2535. Application Cleanup Manager destructor.
  2536. Parameters:
  2537. NONE
  2538. Returns:
  2539. NONE
  2540. ===================================================================*/
  2541. CApplnCleanupMgr::~CApplnCleanupMgr()
  2542. {
  2543. // safety measure to prevent UnInit() from calling Sleep()
  2544. UnInit();
  2545. }
  2546. /*===================================================================
  2547. HRESULT CApplnCleanupMgr::Init
  2548. Initializes the Appln Cleanup Manager.
  2549. Parameters:
  2550. NONE
  2551. Returns:
  2552. S_OK Success
  2553. E_FAIL Failure
  2554. E_OUTOFMEMORY Out of memory
  2555. ===================================================================*/
  2556. HRESULT CApplnCleanupMgr::Init( void )
  2557. {
  2558. HRESULT hr = S_OK;
  2559. Assert(!m_fInited);
  2560. // Create delete app event
  2561. m_hAppToCleanup = IIS_CREATE_EVENT(
  2562. "CApplnCleanupMgr::m_hAppToCleanup",
  2563. this,
  2564. FALSE,
  2565. FALSE
  2566. );
  2567. if (!m_hAppToCleanup)
  2568. return E_FAIL;
  2569. // Init critical section
  2570. ErrInitCriticalSection(&m_csLock, hr);
  2571. if (FAILED(hr))
  2572. return(hr);
  2573. m_fCriticalSectionInited = TRUE;
  2574. m_hThreadAlive = CreateThread(NULL, 0, CApplnCleanupMgr::ApplnCleanupThread, NULL , CREATE_SUSPENDED , NULL);
  2575. if (!m_hThreadAlive)
  2576. {
  2577. return HRESULT_FROM_WIN32(GetLastError());
  2578. }
  2579. m_fInited = TRUE;
  2580. if (ResumeThread (m_hThreadAlive) == (DWORD) -1)
  2581. {
  2582. return HRESULT_FROM_WIN32(GetLastError());
  2583. }
  2584. return S_OK;
  2585. }
  2586. /*===================================================================
  2587. HRESULT CApplnCleanupMgr::UnInit
  2588. UnInitializes the Appln Cleanup Manager.
  2589. Parameters:
  2590. NONE
  2591. Returns:
  2592. S_OK Success
  2593. E_FAIL Failure
  2594. ===================================================================*/
  2595. HRESULT CApplnCleanupMgr::UnInit( void )
  2596. {
  2597. HRESULT hr = S_OK;
  2598. // set fInited to FALSE here so that the cleanup thread
  2599. // can safely detect that we're shutting down.
  2600. m_fInited = FALSE;
  2601. if (m_hAppToCleanup != INVALID_HANDLE_VALUE) {
  2602. // Set the event one last time so that the thread
  2603. // wakes up, sees that shutdown is occurring and
  2604. // exits.
  2605. SetEvent(m_hAppToCleanup);
  2606. CloseHandle(m_hAppToCleanup);
  2607. m_hAppToCleanup = INVALID_HANDLE_VALUE;
  2608. }
  2609. // we'll wait for the thread to finish its work
  2610. if (m_hThreadAlive)
  2611. {
  2612. if (WaitForSingleObject(m_hThreadAlive, INFINITE) == WAIT_FAILED)
  2613. {
  2614. hr = HRESULT_FROM_WIN32(GetLastError());
  2615. }
  2616. CloseHandle (m_hThreadAlive);
  2617. m_hThreadAlive = NULL;
  2618. }
  2619. if (m_fCriticalSectionInited) {
  2620. DeleteCriticalSection(&m_csLock);
  2621. m_fCriticalSectionInited = FALSE;
  2622. }
  2623. return hr;
  2624. }
  2625. /*===================================================================
  2626. CApplnCleanupMgr::AddAppln
  2627. Adds a CAppln element to link list / hash table.
  2628. Parameters:
  2629. CAppln *pAppln Application to cleanup
  2630. Returns:
  2631. HRESULT
  2632. ===================================================================*/
  2633. HRESULT CApplnCleanupMgr::AddAppln
  2634. (
  2635. CAppln *pAppln
  2636. )
  2637. {
  2638. HRESULT hr = S_OK;
  2639. #if UNICODE
  2640. DBGPRINTF((DBG_CONTEXT, "[CApplnCleanupMgr] Adding App (%S)\n",pAppln->GetApplnPath(SOURCEPATHTYPE_VIRTUAL)));
  2641. #else
  2642. DBGPRINTF((DBG_CONTEXT, "[CApplnCleanupMgr] Adding App (%s)\n",pAppln->GetApplnPath(SOURCEPATHTYPE_VIRTUAL)));
  2643. #endif
  2644. Lock();
  2645. AddElem(pAppln);
  2646. UnLock();
  2647. if (SUCCEEDED(hr)) {
  2648. Wakeup();
  2649. }
  2650. return hr;
  2651. }
  2652. /*===================================================================
  2653. CApplnCleanupMgr::ApplnCleanupThread
  2654. The thread that does the work to cleanup applications
  2655. Parameters:
  2656. Returns:
  2657. HRESULT
  2658. ===================================================================*/
  2659. DWORD __stdcall CApplnCleanupMgr::ApplnCleanupThread(VOID *pArg)
  2660. {
  2661. g_ApplnCleanupMgr.ApplnCleanupDoWork();
  2662. return 0;
  2663. }
  2664. /*===================================================================
  2665. CApplnCleanupMgr::ApplnCleanupDoWork
  2666. Proc that actually does the work
  2667. Parameters:
  2668. Returns:
  2669. HRESULT
  2670. ===================================================================*/
  2671. void CApplnCleanupMgr::ApplnCleanupDoWork()
  2672. {
  2673. CAppln *pAppln = NULL;
  2674. DWORD nThreadIndex = 0;
  2675. HANDLE hThread = NULL;
  2676. // this thread will be in a constant loop checking for work
  2677. while(1)
  2678. {
  2679. if (m_fInited)
  2680. WaitForSingleObject(m_hAppToCleanup, INFINITE);
  2681. if (Head() == NULL && m_fInited)
  2682. continue;
  2683. // hold the lock while in this loop. This shouldn't hold it
  2684. // for long as there are no long running operations in this loop.
  2685. // If a thread can't be created and the application cleanup
  2686. // must occur on this thread, then the lock is released.
  2687. //
  2688. // Rely on Head() returning NULL to break out of this loop in case of shutdown.
  2689. // In the shutdown case we will not wait
  2690. //
  2691. Lock();
  2692. pAppln = static_cast<CAppln *>(Head());
  2693. if (!pAppln && !m_fInited)
  2694. {
  2695. UnLock();
  2696. break;
  2697. }
  2698. RemoveElem(Head());
  2699. UnLock();
  2700. //
  2701. // This loop will execute while there is work and there aren't too many
  2702. // threads active or we're in shutdown. The theory here is that in the
  2703. // non-shutdown case, let's not spin up more than 4 threads at a time to
  2704. // do the cleanup. If in shutdown, create as many threads as necessary.
  2705. // if no threads started yet, use the first slot
  2706. //
  2707. if ((m_cCleanupThreads < 4) || (IsShutDownInProgress() && (m_cCleanupThreads < MAX_CLEANUP_THREADS)))
  2708. {
  2709. //
  2710. // just get the next index
  2711. //
  2712. nThreadIndex = m_cCleanupThreads;
  2713. }
  2714. else
  2715. {
  2716. //
  2717. // At full capacity. So wait till one of the threads returns / terminated
  2718. //
  2719. nThreadIndex = WaitForMultipleObjects( m_cCleanupThreads,
  2720. m_hCleanupThreads,
  2721. FALSE, // wait for any event
  2722. INFINITE); // return immediately
  2723. Assert(nThreadIndex != WAIT_TIMEOUT);
  2724. }
  2725. DBGPRINTF((DBG_CONTEXT, "[CApplnCleanupMgr] Cleanup Thread working on (%S)\n",pAppln->GetApplnPath(SOURCEPATHTYPE_VIRTUAL)));
  2726. hThread = CreateThread(NULL, 0, CAppln::ApplnCleanupProc, pAppln, 0, NULL);
  2727. // failed to create a thread to do the work. Cleanup the app right here.
  2728. // Unlock the cleanup manager while we are doing this.
  2729. if (hThread == NULL)
  2730. {
  2731. pAppln->ApplnCleanupProc(pAppln);
  2732. }
  2733. else
  2734. {
  2735. //
  2736. // close the previous handle if we are reusing an entry
  2737. //
  2738. if (nThreadIndex < m_cCleanupThreads)
  2739. {
  2740. //
  2741. // we are reusing a slot from a terminated thread
  2742. //
  2743. CloseHandle(m_hCleanupThreads[ nThreadIndex ]);
  2744. }
  2745. else
  2746. {
  2747. //
  2748. // we are using a new slot
  2749. //
  2750. Assert(nThreadIndex == m_cCleanupThreads);
  2751. m_cCleanupThreads++;
  2752. }
  2753. m_hCleanupThreads[ nThreadIndex ] = hThread;
  2754. }
  2755. }
  2756. if (m_cCleanupThreads)
  2757. {
  2758. WaitForMultipleObjects(
  2759. m_cCleanupThreads,
  2760. m_hCleanupThreads,
  2761. TRUE, // wait for ALL event
  2762. INFINITE); // wait for as long as it takes.
  2763. while( m_cCleanupThreads )
  2764. {
  2765. CloseHandle(m_hCleanupThreads[ --m_cCleanupThreads ]);
  2766. }
  2767. }
  2768. }
  2769. #define WSTR_NULL L"\0"
  2770. /*===================================================================
  2771. C A p p l n I t e r a t o r
  2772. ===================================================================*/
  2773. /*===================================================================
  2774. CApplnIterator::CApplnIterator
  2775. Constructor
  2776. Parameters:
  2777. NONE
  2778. Returns:
  2779. NONE
  2780. ===================================================================*/
  2781. CApplnIterator::CApplnIterator()
  2782. : m_pApplnMgr(NULL), m_pCurr(NULL), m_fEnded(FALSE)
  2783. {
  2784. }
  2785. /*===================================================================
  2786. CApplnIterator::~CApplnIterator
  2787. Destructor.
  2788. Parameters:
  2789. NONE
  2790. Returns:
  2791. NONE
  2792. ===================================================================*/
  2793. CApplnIterator::~CApplnIterator( void )
  2794. {
  2795. if (m_pApplnMgr != NULL)
  2796. Stop();
  2797. }
  2798. /*===================================================================
  2799. HRESULT CApplnIterator::Start
  2800. Starts iterator on the Appln Manager.
  2801. Parameters:
  2802. CApplnMgr * pApplnMgr Appln Manager
  2803. (if NULL g_ApplnManager is assumed)
  2804. Returns:
  2805. S_OK Success
  2806. E_FAIL Failure
  2807. ===================================================================*/
  2808. HRESULT CApplnIterator::Start
  2809. (
  2810. CApplnMgr *pApplnMgr
  2811. )
  2812. {
  2813. m_pApplnMgr = pApplnMgr ? m_pApplnMgr : &g_ApplnMgr;
  2814. m_pApplnMgr->Lock();
  2815. m_pCurr = NULL;
  2816. m_fEnded = FALSE;
  2817. return S_OK;
  2818. }
  2819. /*===================================================================
  2820. HRESULT CApplnIterator::Stop
  2821. Stops iterator on the Appln Manager.
  2822. Parameters:
  2823. NONE
  2824. Returns:
  2825. S_OK Success
  2826. E_FAIL Failure
  2827. ===================================================================*/
  2828. HRESULT CApplnIterator::Stop()
  2829. {
  2830. if (m_pApplnMgr)
  2831. {
  2832. m_pApplnMgr->UnLock();
  2833. m_pApplnMgr = NULL;
  2834. }
  2835. m_pCurr = NULL;
  2836. m_fEnded = FALSE;
  2837. return S_OK;
  2838. }
  2839. /*===================================================================
  2840. HRESULT CApplnIterator::Next
  2841. Iterates to the next Appln.
  2842. Parameters:
  2843. NONE
  2844. Returns:
  2845. Appln * or NULL
  2846. ===================================================================*/
  2847. CAppln *CApplnIterator::Next( void )
  2848. {
  2849. if (m_pApplnMgr == NULL || m_fEnded)
  2850. return NULL; // didn't start or already ended
  2851. CLinkElem *pT = m_pCurr ? m_pCurr->m_pNext : m_pApplnMgr->Head();
  2852. if (pT)
  2853. {
  2854. m_pCurr = static_cast<CAppln *>(pT);
  2855. return m_pCurr;
  2856. }
  2857. m_fEnded = TRUE;
  2858. return NULL;
  2859. }