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

1804 lines
53 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: class.cxx
  7. //
  8. // Contents: Server table entry implementation
  9. //
  10. // History: VinayKr Created
  11. // 06-Nov-98 TarunA Launch and shutdown logic change
  12. // 24-Feb-99 TarunA Fix custom surrogate launch
  13. // 17-Jun-99 a-sergiv Support for filtering RPCSS event logs
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "act.hxx"
  17. CServerTable * gpClassTable = NULL;
  18. CServerTable * gpProcessTable = NULL;
  19. CSharedLock * gpClassLock = 0;
  20. CSharedLock * gpProcessLock = 0;
  21. CInterlockedInteger gRegisterKey( 1 );
  22. //
  23. // Default number of milliseconds to wait for a server to register its
  24. // class factory before giving up and forcefully terminating it.
  25. //
  26. DWORD gServerStartTimeout = 120000;
  27. //
  28. // Default number of milliseconds to wait for a class factory registration
  29. // after we detect that the launched server has died (for supporting cases
  30. // where the server we launch turns around and launches another, then dies
  31. // immediately)
  32. //
  33. DWORD gServerStartSecondChanceTimeout = 30000;
  34. //
  35. // Default number of milliseconds to wait for an NT service server to register
  36. // before we wake up and query its status. At most we wait for
  37. // gNTServiceMaxTimeouts of these periods (see code in WaitForService below).
  38. //
  39. DWORD gNTServiceInterrogatePeriod = 30000;
  40. DWORD gNTServiceMaxTimeouts = 4;
  41. //
  42. // Default number of milliseconds that we block while waiting for a dllhost
  43. // server to register. There is a startup protocol here - we block for
  44. // thirty seconds, then check the state of the launched process.
  45. //
  46. DWORD gDllhostServerStartTimeout = 30000;
  47. //
  48. // Maxiumum number of milliseconds we will wait while waiting for a dllhost
  49. // server to register. There is a protocol yes, but this is the upper time
  50. // bound no matter what.
  51. //
  52. DWORD gDllhostMaxServerStartTimeout = 90000;
  53. //
  54. // Default number of milliseconds to wait for a dllhost to finish
  55. // long-running initialization.
  56. //
  57. DWORD gDllhostInitializationTimeout = 90000;
  58. void GetSessionIDFromActParams(IActivationPropertiesIn* pActPropsIn, LONG* plSessionID)
  59. {
  60. *plSessionID = INVALID_SESSION_ID;
  61. if (pActPropsIn != NULL)
  62. {
  63. ISpecialSystemProperties *pSp = NULL;
  64. HRESULT hr;
  65. hr = pActPropsIn->QueryInterface(IID_ISpecialSystemProperties, (void**) &pSp);
  66. if (SUCCEEDED(hr) && pSp != NULL)
  67. {
  68. ULONG ulSessionID;
  69. BOOL bUseConsole;
  70. hr = pSp->GetSessionId(&ulSessionID, &bUseConsole);
  71. if (SUCCEEDED(hr))
  72. {
  73. if (!bUseConsole && (ulSessionID != INVALID_SESSION_ID))
  74. {
  75. // Just use whatever was there
  76. *plSessionID = (LONG) ulSessionID;
  77. }
  78. else if (bUseConsole)
  79. {
  80. // Little bit of magic here regarding how to find the
  81. // currently active NT console session ID.
  82. *plSessionID = (USER_SHARED_DATA->ActiveConsoleId);
  83. }
  84. }
  85. pSp->Release();
  86. pSp = NULL;
  87. }
  88. }
  89. }
  90. //+-------------------------------------------------------------------------
  91. //
  92. // CServerTable::GetOrCreate
  93. //
  94. // A somewhat degenerate combination of Lookup and Create -- only creates
  95. // empty entries -- in particular without hooking up process entry if the
  96. // entry being created is a class entry -- used only to create process entries
  97. // and to create class entries for unsolicited CoRegisterClassObject calls
  98. //
  99. //--------------------------------------------------------------------------
  100. CServerTableEntry *
  101. CServerTable::GetOrCreate(
  102. IN GUID & ServerGuid
  103. )
  104. {
  105. CServerTableEntry * pEntry;
  106. pEntry = Lookup( ServerGuid );
  107. if ( pEntry )
  108. return pEntry;
  109. else
  110. return Create(ServerGuid);
  111. }
  112. //+-------------------------------------------------------------------------
  113. //
  114. // CServerTable::Create
  115. //
  116. // Creates a new CServerTableEntry, or returns an existing one.
  117. //
  118. //--------------------------------------------------------------------------
  119. CServerTableEntry *
  120. CServerTable::Create(
  121. IN GUID & ServerGuid
  122. )
  123. {
  124. BOOL fEntryFoundInTable = FALSE;
  125. _pServerTableLock->LockExclusive();
  126. // Must use CGuidTable::Lookup method because it doesn't take
  127. // a shared lock. Already have the exclusive lock.
  128. CServerTableEntry *pNewEntry = (CServerTableEntry *) CGuidTable::Lookup( &ServerGuid );
  129. if (pNewEntry)
  130. {
  131. pNewEntry->Reference(); // Found an entry, take a reference on it
  132. fEntryFoundInTable = TRUE;
  133. }
  134. else
  135. {
  136. LONG Status;
  137. pNewEntry = new CServerTableEntry( Status, &ServerGuid, _EntryType );
  138. if ( ! pNewEntry )
  139. {
  140. _pServerTableLock->UnlockExclusive();
  141. return NULL;
  142. }
  143. if ( Status != ERROR_SUCCESS )
  144. {
  145. _pServerTableLock->UnlockExclusive();
  146. // release using base class method because the entry is not
  147. // in the table yet and we don't want to try to remove it
  148. pNewEntry->CReferencedObject::Release();
  149. return NULL;
  150. }
  151. }
  152. if (!fEntryFoundInTable)
  153. {
  154. Add( pNewEntry );
  155. }
  156. _pServerTableLock->UnlockExclusive();
  157. return pNewEntry;
  158. }
  159. //+-------------------------------------------------------------------------
  160. //
  161. // CServerTable::Lookup
  162. //
  163. //--------------------------------------------------------------------------
  164. CServerTableEntry *
  165. CServerTable::Lookup(
  166. IN GUID & ServerGuid
  167. )
  168. {
  169. CServerTableEntry * pServerTableEntry;
  170. _pServerTableLock->LockShared();
  171. pServerTableEntry = (CServerTableEntry *) CGuidTable::Lookup( &ServerGuid );
  172. if ( pServerTableEntry )
  173. pServerTableEntry->Reference();
  174. _pServerTableLock->UnlockShared();
  175. return pServerTableEntry;
  176. }
  177. //+-------------------------------------------------------------------------
  178. //
  179. // CServerTableEntry::CServerTableEntry
  180. //
  181. //--------------------------------------------------------------------------
  182. CServerTableEntry::CServerTableEntry(
  183. OUT LONG& Status,
  184. IN GUID * pServerGUID,
  185. IN EnumEntryType EntryType
  186. ) :
  187. CGuidTableEntry( pServerGUID ), _EntryType(EntryType)
  188. ,_ServerLock( Status ), _lThreadToken(0), _hProcess(0), _pProcess(NULL)
  189. ,_pvRunAsHandle(NULL), _bSuspendedClsid(FALSE), _bSuspendedApplication(FALSE),
  190. _dwProcessId(0)
  191. {
  192. Status = ERROR_SUCCESS;
  193. switch (_EntryType)
  194. {
  195. case ENTRY_TYPE_CLASS:
  196. _pParentTable = gpClassTable;
  197. break;
  198. case ENTRY_TYPE_PROCESS:
  199. _pParentTable = gpProcessTable;
  200. break;
  201. default:
  202. Status = E_INVALIDARG;
  203. }
  204. if (Status == ERROR_SUCCESS)
  205. {
  206. _pParentTableLock = _pParentTable->_pServerTableLock;
  207. }
  208. }
  209. //+-------------------------------------------------------------------------
  210. //
  211. // CServerTableEntry::~CServerTableEntry
  212. //
  213. //--------------------------------------------------------------------------
  214. CServerTableEntry::~CServerTableEntry()
  215. {
  216. ASSERT(_pParentTableLock->HeldExclusive());
  217. // Remove ourselves from the table
  218. _pParentTable->Remove(this);
  219. if(NULL != _pProcess)
  220. {
  221. ReleaseProcess(_pProcess);
  222. }
  223. ASSERT(_pvRunAsHandle == NULL);
  224. ASSERT(_hProcess == NULL);
  225. }
  226. //+-------------------------------------------------------------------------
  227. //
  228. // CServerTableEntry::Release
  229. //
  230. //--------------------------------------------------------------------------
  231. DWORD
  232. CServerTableEntry::Release()
  233. {
  234. DWORD Refs;
  235. CSharedLock* pParentTableLock = _pParentTableLock;
  236. CairoleDebugOut((DEB_SCM, "Releasing ServerTableEntry at 0x%p\n", this));
  237. pParentTableLock->LockExclusive();
  238. Dereference();
  239. if ( 0 == (Refs = References()) )
  240. {
  241. delete this;
  242. }
  243. pParentTableLock->UnlockExclusive();
  244. return Refs;
  245. }
  246. //+-------------------------------------------------------------------------
  247. //
  248. // CServerTableEntry::RegisterServer
  249. //
  250. //--------------------------------------------------------------------------
  251. HRESULT
  252. CServerTableEntry::RegisterServer(
  253. IN CProcess * pServerProcess,
  254. IN IPID ipid,
  255. IN CClsidData * pClsidData, OPTIONAL
  256. IN CAppidData * pAppidData,
  257. IN UCHAR ServerState,
  258. OUT DWORD * pRegistrationKey )
  259. {
  260. CServerListEntry * pEntry;
  261. CSurrogateListEntry * pSurrogateEntry;
  262. UCHAR Context = 0;
  263. UCHAR SubContext = 0;
  264. if (pClsidData)
  265. {
  266. if ( (pClsidData->ServerType() == SERVERTYPE_SERVICE) ||
  267. (pClsidData->ServerType() == SERVERTYPE_COMPLUS_SVC) )
  268. {
  269. Context = SERVER_SERVICE;
  270. }
  271. else if ( pClsidData->HasRunAs() )
  272. {
  273. Context = SERVER_RUNAS;
  274. if ( pClsidData->IsInteractiveUser() )
  275. SubContext = SUB_CONTEXT_RUNAS_INTERACTIVE;
  276. else
  277. SubContext = SUB_CONTEXT_RUNAS_THIS_USER;
  278. }
  279. // Special case of COM+ library class being loaded by VB for debugging
  280. else if ( pClsidData->ServerType() == SERVERTYPE_COMPLUS && pClsidData->IsInprocClass() )
  281. {
  282. Context = SERVER_RUNAS;
  283. }
  284. }
  285. if ( _EntryType == ENTRY_TYPE_PROCESS )
  286. {
  287. // This is the COM+/COM surrogate case
  288. Win4Assert(NULL == pClsidData && "Process Entry Given Clsid data");
  289. Win4Assert(NULL != pAppidData && "Process Entry Not Given Appid data");
  290. if (pAppidData->Service())
  291. {
  292. Context = SERVER_SERVICE;
  293. }
  294. else if ((pAppidData->IsInteractiveUser()) || pAppidData->RunAsUser())
  295. {
  296. Context = SERVER_RUNAS;
  297. }
  298. }
  299. // If none of the above applied, Context will be zero at this point -- this
  300. // essentially means the server should be treated as an activate-as-activator
  301. // server. However, if Context is zero SubContext had better also be zero,
  302. // and so we assert that here.
  303. if (Context == 0)
  304. {
  305. Context = SERVER_ACTIVATOR;
  306. ASSERT(SubContext == 0);
  307. }
  308. pEntry = new CServerListEntry(
  309. this,
  310. pServerProcess,
  311. ipid,
  312. Context,
  313. ServerState,
  314. SubContext);
  315. if ( ! pEntry )
  316. return E_OUTOFMEMORY;
  317. // Add registration to the process object -- but only if we are a class entry;
  318. // otherwise this is a registration for a surrogate server
  319. if ( _EntryType == ENTRY_TYPE_CLASS )
  320. {
  321. pEntry->AddToProcess( Guid() );
  322. }
  323. //
  324. SetSuspendedFlagOnNewServer(pServerProcess);
  325. //
  326. // NOTE: The entry should be inserted in the lists only after
  327. // all the registration specific stuff has been done. This will
  328. // ensure that anyone outside this procedure sees the complete
  329. // entry and not some half-baked one
  330. //
  331. ServerLock()->LockExclusive();
  332. // Check if process handle exists implying that a
  333. // launch is in progress for this class. Try to
  334. // register runas,process, and threadtoken with
  335. // the newly created entry
  336. // Note that it is essential for the server lock to
  337. // be held since _hProcess can change otherwise.
  338. if (_hProcess || _pProcess)
  339. RegisterHandles(pEntry, pServerProcess);
  340. _ServerList.Insert( pEntry );
  341. ServerLock()->UnlockExclusive();
  342. //
  343. // It's possible that a process could register itself as a surrogate but
  344. // there's no CLSID info in the registry. We might want to disallow
  345. // this kind of register.
  346. //
  347. // Note: We allow class registration if appid is not present but don't
  348. // allow surrogate registration since it'll never be found
  349. // The right thing to do would be to reject the call completely when
  350. // an appid is not present but we will take the path of least resistance
  351. // and preserve legacy
  352. if ( pClsidData && (ServerState & SERVERSTATE_SURROGATE) && pClsidData->AppidString() )
  353. {
  354. pSurrogateEntry = new CSurrogateListEntry( pClsidData->AppidString(), pEntry );
  355. if ( ! pSurrogateEntry )
  356. {
  357. pEntry->CReferencedObject::Release();
  358. return E_OUTOFMEMORY;
  359. }
  360. gpSurrogateList->Insert( pSurrogateEntry );
  361. }
  362. *pRegistrationKey = pEntry->RegistrationKey();
  363. return S_OK;
  364. }
  365. //+-------------------------------------------------------------------------
  366. //
  367. // CServerTableEntry::RevokeServer -- version 1 for class entries
  368. //
  369. // CODE WORK: Consider defining two separate classes for class and
  370. // process entries so we can avoid this sort of thing
  371. //
  372. //--------------------------------------------------------------------------
  373. void
  374. CServerTableEntry::RevokeServer(
  375. IN CProcess * pServerProcess,
  376. IN DWORD RegistrationKey
  377. )
  378. {
  379. Win4Assert(_EntryType == ENTRY_TYPE_CLASS);
  380. ServerLock()->LockExclusive();
  381. CServerListEntry * pEntry = (CServerListEntry *) _ServerList.First();
  382. for ( ; pEntry; pEntry = (CServerListEntry *) pEntry->Next() )
  383. {
  384. if ( (RegistrationKey == pEntry->_RegistrationKey)
  385. #if 1 // #ifndef _CHICAGO_
  386. && (pServerProcess == pEntry->_pServerProcess)
  387. #endif
  388. )
  389. break;
  390. }
  391. if ( pEntry )
  392. _ServerList.Remove( pEntry );
  393. ServerLock()->UnlockExclusive();
  394. if ( pEntry )
  395. {
  396. pEntry->RemoveFromProcess();
  397. pEntry->Release();
  398. }
  399. }
  400. //+-------------------------------------------------------------------------
  401. //
  402. // CServerTableEntry::RevokeServer -- version 2 for process entries
  403. //
  404. //--------------------------------------------------------------------------
  405. void
  406. CServerTableEntry::RevokeServer(
  407. IN ScmProcessReg * pScmProcessReg
  408. )
  409. {
  410. Win4Assert(_EntryType == ENTRY_TYPE_PROCESS);
  411. ServerLock()->LockExclusive();
  412. CServerListEntry * pEntry = (CServerListEntry *) _ServerList.First();
  413. for ( ; pEntry; pEntry = (CServerListEntry *) pEntry->Next() )
  414. {
  415. if ( (pScmProcessReg->RegistrationToken == pEntry->_RegistrationKey)
  416. )
  417. break;
  418. }
  419. if ( pEntry )
  420. _ServerList.Remove( pEntry );
  421. ServerLock()->UnlockExclusive();
  422. if ( pEntry )
  423. {
  424. pEntry->RemoveFromProcess();
  425. pEntry->Release();
  426. }
  427. }
  428. //+-------------------------------------------------------------------------
  429. //
  430. // CServerTableEntry::LookupServer
  431. //
  432. //--------------------------------------------------------------------------
  433. BOOL
  434. CServerTableEntry::LookupServer(
  435. IN CToken * pClientToken,
  436. IN BOOL bRemoteActivation,
  437. IN BOOL bClientImpersonating,
  438. IN WCHAR * pwszWinstaDesktop,
  439. IN DWORD dwFlags,
  440. IN LONG lThreadToken,
  441. IN LONG lSessionID,
  442. IN DWORD pid,
  443. IN DWORD dwProcessReqType,
  444. OUT CServerListEntry ** ppServerListEntry)
  445. {
  446. CServerListEntry * pEntry;
  447. *ppServerListEntry = NULL;
  448. // If we are suspended, no need to go any further
  449. if (IsSuspended())
  450. return FALSE;
  451. ServerLock()->LockShared();
  452. pEntry = (CServerListEntry *) _ServerList.First();
  453. for ( ; pEntry; pEntry = (CServerListEntry *) pEntry->Next() )
  454. {
  455. if ( pEntry->Match( pClientToken,
  456. bRemoteActivation,
  457. bClientImpersonating,
  458. pwszWinstaDesktop,
  459. FALSE,
  460. lThreadToken,
  461. lSessionID,
  462. pid,
  463. dwProcessReqType,
  464. dwFlags ) )
  465. {
  466. pEntry->Reference();
  467. break;
  468. }
  469. }
  470. ServerLock()->UnlockShared();
  471. *ppServerListEntry = pEntry;
  472. return (pEntry != 0);
  473. }
  474. //+-------------------------------------------------------------------------
  475. //
  476. // CServerTableEntry::LookupServer
  477. //
  478. //--------------------------------------------------------------------------
  479. BOOL
  480. CServerTableEntry::LookupServer(
  481. IN DWORD RegistrationKey,
  482. CServerListEntry ** ppServerListEntry )
  483. {
  484. CServerListEntry * pEntry;
  485. ServerLock()->LockShared();
  486. pEntry = (CServerListEntry *) _ServerList.First();
  487. for ( ; pEntry; pEntry = (CServerListEntry *) pEntry->Next() )
  488. {
  489. if ( RegistrationKey == pEntry->_RegistrationKey )
  490. break;
  491. }
  492. if ( pEntry )
  493. pEntry->Reference();
  494. ServerLock()->UnlockShared();
  495. *ppServerListEntry = pEntry;
  496. return (pEntry != 0);
  497. }
  498. //+-------------------------------------------------------------------------
  499. //
  500. // CServerTableEntry::UnsuspendServer
  501. //
  502. //--------------------------------------------------------------------------
  503. void
  504. CServerTableEntry::UnsuspendServer(
  505. IN DWORD RegistrationKey
  506. )
  507. {
  508. CServerListEntry * pEntry;
  509. LookupServer( RegistrationKey, &pEntry );
  510. if ( pEntry )
  511. {
  512. pEntry->_State &= ~SERVERSTATE_SUSPENDED;
  513. pEntry->Release();
  514. }
  515. }
  516. //+-------------------------------------------------------------------------
  517. // CServerTableEntry::ServerExists
  518. //+-------------------------------------------------------------------------
  519. HRESULT
  520. CServerTableEntry::ServerExists(
  521. IN ACTIVATION_PARAMS * pActParams, BOOL *pfExist)
  522. {
  523. LONG lSessionID = INVALID_SESSION_ID;
  524. ServerLock()->LockShared();
  525. GetSessionIDFromActParams(pActParams->pActPropsIn, &lSessionID);
  526. CServerListEntry *pEntry = (CServerListEntry *) _ServerList.First();
  527. for ( ; pEntry; pEntry = (CServerListEntry *) pEntry->Next() )
  528. {
  529. if ( pEntry->Match(
  530. pActParams->pToken,
  531. pActParams->RemoteActivation,
  532. pActParams->bClientImpersonating,
  533. pActParams->pProcess ? pActParams->pProcess->WinstaDesktop() : NULL ,
  534. FALSE,
  535. 0,
  536. lSessionID ))
  537. {
  538. break;
  539. }
  540. }
  541. ServerLock()->UnlockShared();
  542. *pfExist = (pEntry != NULL);
  543. return S_OK;
  544. }
  545. //+-------------------------------------------------------------------------
  546. //
  547. // CServerTableEntry::CallRunningServer
  548. // Synopsis: The behavior of CallRunningServer is best described by this matrix
  549. //
  550. // If the call is made successfully then we return
  551. // If CallServer() returns error then we take the following action
  552. // ----------------------------------------------------------------------------
  553. // | | RPC_E_SERVERFAULT | CO_E_SERVER_STOPPING | Other Errors |
  554. // ----------------------------------------------------------------------------
  555. // | COM | Kill the process | Remove the list entry |Remove the list entry|
  556. // | | Remove the list entry | Try launching another |Try launching another|
  557. // | | Try launching another | process |process |
  558. // | | process | | |
  559. // | | | | |
  560. // -----------------------------------------------------------------------------
  561. // | COM+| Kill the process | Set a timeout period |If process exists |
  562. // | | Remove the list entry | If the server |then |
  563. // | | Return the error | stops before timeout | return error |
  564. // | | | then |else |
  565. // | | | try launching | Remove the entry |
  566. // | | | another process | try launching |
  567. // | | | else | another process |
  568. // | | | return error | |
  569. // -----------------------------------------------------------------------------
  570. //--------------------------------------------------------------------------
  571. BOOL
  572. CServerTableEntry::CallRunningServer(
  573. IN ACTIVATION_PARAMS * pActParams,
  574. IN DWORD dwFlags,
  575. IN LONG lLaunchThreadToken,
  576. IN CClsidData * pClsidData,
  577. OUT HRESULT * phr
  578. )
  579. {
  580. BOOL bStatus;
  581. LONG lSessionID = INVALID_SESSION_ID;
  582. CServerListEntry* pEntry;
  583. GetSessionIDFromActParams(pActParams->pActPropsIn, &lSessionID);
  584. for (;;)
  585. {
  586. BOOL bTerminatedServer;
  587. bStatus = LookupServer(
  588. pActParams->pToken,
  589. pActParams->RemoteActivation,
  590. pActParams->bClientImpersonating,
  591. pActParams->pProcess ? pActParams->pProcess->WinstaDesktop() : NULL ,
  592. dwFlags,
  593. lLaunchThreadToken,
  594. lSessionID,
  595. pActParams->dwPID,
  596. pActParams->dwProcessReqType,
  597. &pEntry);
  598. if (!bStatus)
  599. {
  600. Win4Assert(!pEntry);
  601. return FALSE;
  602. }
  603. *phr = S_OK;
  604. //
  605. // If the entry is "initializing", then it isn't really ready yet.
  606. // Wait for it to become so.
  607. //
  608. if (pEntry->IsInitializing())
  609. {
  610. *phr = WaitForInitCompleted(pEntry, pClsidData);
  611. if (FAILED(*phr))
  612. {
  613. if (*phr == CO_E_SERVER_STOPPING)
  614. bStatus = FALSE;
  615. else
  616. bStatus = TRUE;
  617. }
  618. }
  619. //
  620. // Returns TRUE if we successfully make a call to this server, or
  621. // if an unrecoverable non-server-related error is encountered
  622. // (e.g, an out-of-mem failure while allocating data before or
  623. // after the call).
  624. //
  625. // The final HRESULT is not necessarily S_OK.
  626. //
  627. if (SUCCEEDED(*phr))
  628. bStatus = pEntry->CallServer(pActParams, phr);
  629. if (!bStatus)
  630. {
  631. // We were unable to talk to the server, or got back
  632. // CO_E_SERVER_STOPPING.
  633. // Retrieve the process handle, if we have one
  634. HANDLE hProcess = pEntry->GetProcess()->GetProcessHandle();
  635. bTerminatedServer = FALSE;
  636. // Try to kill the server if it returned RPC_E_SERVERFAULT (this
  637. // means that we caught an unhandled exception somewhere in the
  638. // server, which we don't really appreciate.)
  639. if(*phr == RPC_E_SERVERFAULT)
  640. {
  641. if(hProcess)
  642. {
  643. bTerminatedServer = TerminateProcess(hProcess, 0);
  644. }
  645. // Remember that the server blew up on us. This is mostly
  646. // for debugging purposes
  647. pEntry->IncServerFaults();
  648. }
  649. //
  650. // Determine if we need to remove the server entry. We will do this if
  651. // a) we killed the server process up above; or b) the server returned
  652. // CO_E_SERVER_STOPPING; or c) the server process is dead already.
  653. //
  654. if (bTerminatedServer ||
  655. (*phr == CO_E_SERVER_STOPPING) ||
  656. pEntry->ServerDied())
  657. {
  658. BOOL bRemoved;
  659. //
  660. // Remove this server entry if it's still in the list.
  661. //
  662. ServerLock()->LockExclusive();
  663. bRemoved = _ServerList.InList(pEntry);
  664. if (bRemoved)
  665. _ServerList.Remove(pEntry);
  666. ServerLock()->UnlockExclusive();
  667. if (bRemoved)
  668. {
  669. pEntry->RemoveFromProcess();
  670. pEntry->Release();
  671. }
  672. }
  673. }
  674. // Now allow threads other than launching one to access
  675. // this entry. Exit since we matched launched server
  676. // regardless of result since we know that we will
  677. // not get any more matches.
  678. if (lLaunchThreadToken)
  679. {
  680. pEntry->SetThreadToken(0);
  681. pEntry->Release();
  682. return bStatus;
  683. }
  684. pEntry->Release();
  685. if ( bStatus )
  686. return TRUE;
  687. }
  688. }
  689. //+-------------------------------------------------------------------------
  690. //
  691. // CServerTableEntry::StartServerAndWait
  692. //
  693. //--------------------------------------------------------------------------
  694. HRESULT
  695. CServerTableEntry::StartServerAndWait(
  696. IN ACTIVATION_PARAMS * pActParams,
  697. IN CClsidData * pClsidData,
  698. IN LONG &lLaunchThreadToken
  699. )
  700. {
  701. SC_HANDLE hService;
  702. HRESULT hr;
  703. BOOL bStatus;
  704. BOOL bServiceAlreadyRunning = FALSE;
  705. DWORD dwActvFlags;
  706. if ( ! pClsidData->LaunchAllowed( pActParams->pToken, pActParams->ClsContext ) )
  707. return E_ACCESSDENIED;
  708. // Check CreateProcessMemoryGate
  709. // [a-sergiv (Sergei O. Ivanov) 11/1/99 Implemented Memory Gates in COM Base
  710. if(pActParams->pActPropsIn)
  711. {
  712. BOOL bResult = TRUE;
  713. IClassClassicInfo *pClassicInfo = NULL;
  714. hr = pActParams->pActPropsIn->GetClassInfo(IID_IClassClassicInfo, (void**) &pClassicInfo);
  715. if(SUCCEEDED(hr) && pClassicInfo)
  716. {
  717. IResourceGates *pResGates = NULL;
  718. hr = pClassicInfo->GetProcess(IID_IResourceGates, (void**) &pResGates);
  719. pClassicInfo->Release();
  720. if(SUCCEEDED(hr) && pResGates)
  721. {
  722. hr = pResGates->Test(CreateProcessMemoryGate, &bResult);
  723. pResGates->Release();
  724. if(SUCCEEDED(hr) && !bResult)
  725. {
  726. // The gate said NO!
  727. return E_OUTOFMEMORY;
  728. }
  729. }
  730. }
  731. }
  732. hService = 0;
  733. // NOTE: _hProcess, _dwProcessId, _pProcess and all other process specific
  734. // variables that are part of CServerTableEntry are used only during the
  735. // launch. Once the launch is completed either they are transferred to
  736. // process specific entries or discarded. See CServerTableEntry::RegisterHandles
  737. // for an example.
  738. _dwProcessId = 0;
  739. // _hProcess and _pProcess variables are released and set to
  740. // null whether
  741. // (1) This is the first launch
  742. // OR
  743. // (2) We succeeded in an earlier launch or failed
  744. Win4Assert((0 == _hProcess) && (NULL == _pProcess));
  745. //
  746. // Get the register event for the server we're about to launch. Note
  747. // there exists a problem in that we may launch a server, but another
  748. // server may register the desired clsid\appid at about the same time.
  749. // I think this is just something we have to live with, especially since
  750. // there are servers in the world that don't register with us, but instead
  751. // turn around and launch another process to do the registration. So,
  752. // even if we have a process handle it would be impossible to always
  753. // correlate from register event back to the launching table entry.
  754. //
  755. HANDLE hRegisterEvent = pClsidData->ServerRegisterEvent();
  756. if (!hRegisterEvent)
  757. return E_OUTOFMEMORY;
  758. if (pClsidData->ServerType() == SERVERTYPE_SURROGATE)
  759. {
  760. Win4Assert(_EntryType == ENTRY_TYPE_CLASS);
  761. LPWSTR pwszAppidString = pClsidData->AppidString();
  762. CSurrogateListEntry * pSurrogateListEntry = NULL;
  763. if(pwszAppidString)
  764. {
  765. pSurrogateListEntry = gpSurrogateList->Lookup(
  766. pActParams->pToken,
  767. pActParams->RemoteActivation,
  768. pActParams->bClientImpersonating,
  769. pActParams->pProcess ? pActParams->pProcess->WinstaDesktop() : NULL ,
  770. pwszAppidString );
  771. }
  772. if ( pSurrogateListEntry )
  773. {
  774. // If we find a surrogate entry and we are inside a launch
  775. // server then that implies that a surrogate was launched for
  776. // a different class' activation. We have a process entry for
  777. // this surrogate and we set it here. Later when RegisterServer
  778. // gets called we use the process object to set the state.
  779. // For all other cases, the state is set using the process handle.
  780. _pProcess = pSurrogateListEntry->Process();
  781. Win4Assert(NULL !=_pProcess);
  782. // We will release this on every path below
  783. ReferenceProcess( _pProcess, TRUE );
  784. // Remember the launching thread's token
  785. _lThreadToken = lLaunchThreadToken;
  786. // Load the dll that will service the activation request
  787. bStatus = pSurrogateListEntry->LoadDll( pActParams, &hr );
  788. pSurrogateListEntry->Release();
  789. // A status of TRUE implies that we successfully talked to the
  790. // server
  791. if (bStatus)
  792. {
  793. // A successful hresult implies that the server was able to
  794. // load the dll successfully and hence we expect it to
  795. // register back
  796. if(SUCCEEDED(hr))
  797. {
  798. // Wait for the loaded object server to register back
  799. bStatus = WaitForSingleObject( hRegisterEvent, 30000 );
  800. }
  801. // If the server failed to load the dll or it registered back
  802. // within the timeout then we return immediately
  803. if ( FAILED(hr) || (bStatus == WAIT_OBJECT_0) )
  804. {
  805. ReleaseProcess(_pProcess);
  806. _pProcess = NULL;
  807. CloseHandle(hRegisterEvent);
  808. return hr;
  809. }
  810. }
  811. // If a launched server failed to register back in the given
  812. // timeout or we were not able to talk to the server then we
  813. // continue and try to launch a new process
  814. ReleaseProcess(_pProcess);
  815. _pProcess = NULL;
  816. }
  817. }
  818. if ((pClsidData->ServerType() == SERVERTYPE_SERVICE) ||
  819. (pClsidData->ServerType() == SERVERTYPE_COMPLUS_SVC))
  820. {
  821. #ifndef _CHICAGO_
  822. // Set the token here as service does not register back
  823. // with us and so it cannot be set at registration time
  824. // unlike the activator server case below
  825. hr = pClsidData->LaunchService( pActParams->pToken, pActParams->ClsContext, &hService );
  826. if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING))
  827. {
  828. hr = S_OK;
  829. bServiceAlreadyRunning = TRUE;
  830. }
  831. #endif // _CHICAGO_
  832. }
  833. else
  834. {
  835. //When a "RunAs Interactive User" server is launched from a Hydra session,
  836. //the server runs in the Hydra session of the caller. In this case,
  837. //we want to call LaunchActivator server instead of LaunchRunAsServer
  838. //so that the server runs in the appropriate Hydra session.
  839. //if ( pClsidData->HasRunAs() &&
  840. // (!pClsidData->IsInteractiveUser() || !pActParams->pToken ||!pActParams->pToken->GetSessionId()))
  841. _lThreadToken = lLaunchThreadToken;
  842. if ( pClsidData->HasRunAs())
  843. {
  844. #ifndef _CHICAGO_
  845. hr = pClsidData->LaunchRunAsServer(
  846. pActParams->pToken,
  847. pActParams->RemoteActivation,
  848. pActParams->pActPropsIn,
  849. pActParams->ClsContext,
  850. &_hProcess,
  851. &_dwProcessId,
  852. &_pvRunAsHandle);
  853. #endif // _CHICAGO_
  854. }
  855. else
  856. {
  857. // Check to see if the client requested "protected" activation. If
  858. // so, we refuse to launch a server using their token.
  859. hr = pActParams->pActPropsIn->GetActivationFlags(&dwActvFlags);
  860. if (FAILED(hr) || (dwActvFlags & ACTVFLAGS_DISABLE_AAA))
  861. {
  862. hr = E_ACCESSDENIED;
  863. }
  864. if (SUCCEEDED(hr))
  865. {
  866. hr = pClsidData->LaunchActivatorServer(
  867. pActParams->pToken,
  868. pActParams->pEnvBlock,
  869. pActParams->EnvBlockLength,
  870. pActParams->RemoteActivation,
  871. pActParams->bClientImpersonating,
  872. pActParams->pProcess ? pActParams->pProcess->WinstaDesktop() : NULL,
  873. pActParams->ClsContext,
  874. &_hProcess,
  875. &_dwProcessId);
  876. }
  877. }
  878. }
  879. if (FAILED(hr))
  880. {
  881. #ifndef _CHICAGO_
  882. Win4Assert(_pvRunAsHandle == NULL);
  883. #endif
  884. _lThreadToken = 0;
  885. CloseHandle(hRegisterEvent);
  886. return hr;
  887. }
  888. // we got this far so it is time to wait for the server/service we just
  889. // launched to register itself with us appropriately and in a timely fashion
  890. // Retry once if we fail to get desktop resources the first time
  891. BOOL fSuccessful;
  892. for (int i=0; i<2; i++) {
  893. ULONG winerr=0;
  894. fSuccessful = FALSE;
  895. switch (pClsidData->ServerType())
  896. {
  897. case SERVERTYPE_SERVICE:
  898. case SERVERTYPE_COMPLUS_SVC:
  899. Win4Assert(hService && "Waiting for service with NULL handle");
  900. fSuccessful = WaitForService(hService, hRegisterEvent,
  901. bServiceAlreadyRunning);
  902. CloseServiceHandle( hService );
  903. hService = 0;
  904. break;
  905. case SERVERTYPE_COMPLUS:
  906. case SERVERTYPE_DLLHOST:
  907. fSuccessful = WaitForDllhostServer(hRegisterEvent,
  908. pActParams,
  909. winerr,
  910. lLaunchThreadToken);
  911. break;
  912. default:
  913. fSuccessful = WaitForLocalServer(hRegisterEvent,
  914. winerr);
  915. break;
  916. }
  917. #ifndef _CHICAGO_
  918. if ( (i==0) && _pvRunAsHandle && (!fSuccessful ) &&
  919. (winerr == ERROR_WAIT_NO_CHILDREN))
  920. {
  921. RunAsInvalidateAndRelease(_pvRunAsHandle);
  922. _pvRunAsHandle = NULL;
  923. hr = pClsidData->LaunchRunAsServer(
  924. pActParams->pToken,
  925. pActParams->RemoteActivation,
  926. pActParams->pActPropsIn,
  927. pActParams->ClsContext,
  928. &_hProcess,
  929. &_dwProcessId,
  930. &_pvRunAsHandle);
  931. if (FAILED(hr))
  932. {
  933. Win4Assert(_pvRunAsHandle == NULL);
  934. CloseHandle(hRegisterEvent);
  935. return hr;
  936. }
  937. continue;
  938. }
  939. #endif // _CHICAGO_
  940. break;
  941. }
  942. if ( !fSuccessful )
  943. {
  944. GUID ServerGuid = Guid();
  945. LogRegisterTimeout( &ServerGuid, pActParams->ClsContext, pActParams->pToken );
  946. hr = CO_E_SERVER_EXEC_FAILURE;
  947. }
  948. else
  949. {
  950. hr = S_OK;
  951. }
  952. // Ensure that we are serializing around
  953. // registration which takes an exclusive
  954. // before modifying this and is the only
  955. // one that needs to look at or modify it.
  956. if (_hProcess)
  957. {
  958. ServerLock()->LockShared();
  959. if (_hProcess)
  960. {
  961. CloseHandle(_hProcess);
  962. _hProcess = 0;
  963. }
  964. ServerLock()->UnlockShared();
  965. }
  966. // If we still have the token set the callers also to
  967. // NULL because we might have succeeded the launch but
  968. // the server registering back was different from
  969. // the one launched(this should be very rare).
  970. if (_lThreadToken)
  971. {
  972. _lThreadToken = 0;
  973. lLaunchThreadToken = 0;
  974. }
  975. #ifndef _CHICAGO_
  976. if (_pvRunAsHandle)
  977. {
  978. Win4Assert(pClsidData->HasRunAs());
  979. RunAsRelease(_pvRunAsHandle);
  980. _pvRunAsHandle = NULL;
  981. }
  982. #endif // _CHICAGO_
  983. CloseHandle(hRegisterEvent);
  984. return hr;
  985. }
  986. //+-------------------------------------------------------------------------
  987. //
  988. // CServerTableEntry::RegisterHandles
  989. //
  990. // Synopsis Register either the RunAs or the process handle with the
  991. // CProcess object. Also register Single use Thread token.
  992. //
  993. // NOTE: this is called by RegisterServer
  994. //--------------------------------------------------------------------------
  995. BOOL CServerTableEntry::RegisterHandles(IN CServerListEntry * pEntry,
  996. IN CProcess *pServerProcess)
  997. {
  998. BOOL bStatus = TRUE;
  999. // Are we interested in registering the process handle
  1000. if(_hProcess || _pProcess)
  1001. {
  1002. Win4Assert(pServerProcess);
  1003. // We can have either a process handle if this entry is the one
  1004. // which was the first to launch the server or we can have a process
  1005. // object if the server has already been launched. The two cases are
  1006. // mutually exclusive and we assert that here.
  1007. Win4Assert((_hProcess && (NULL == _pProcess)) ||
  1008. (0 == _hProcess && (NULL != _pProcess)));
  1009. if(_hProcess)
  1010. bStatus = pServerProcess->SetProcessHandle(_hProcess,_dwProcessId);
  1011. // If a FALSE status is returned then the PID of the process launched
  1012. // by us did not match the PID of the process registered.
  1013. // The only cases where this will be FALSE are if a server is
  1014. // started by hand at the same time as a system launch or the
  1015. // process registering was launched by the one we launched.
  1016. // This should almost never happen
  1017. if (!bStatus)
  1018. goto ExitRegisterHandles;
  1019. // If the PID matched then we are sure that this register event
  1020. // matches the server we launched
  1021. // Given process handle away so remove our reference
  1022. _hProcess = 0;
  1023. // If we had a process match save thread token if
  1024. // it was passed since this thread launched the server
  1025. if (_lThreadToken)
  1026. {
  1027. pEntry->SetThreadToken(_lThreadToken);
  1028. _lThreadToken = NULL;
  1029. }
  1030. // Are we interested in registering the RunAs handle ?
  1031. #ifndef _CHICAGO_
  1032. if (_pvRunAsHandle)
  1033. {
  1034. // Pass our winsta reference over to process entry which will
  1035. // release it when it goes away so we can be rid of
  1036. // responsibilities for it.
  1037. RunAsSetWinstaDesktop(_pvRunAsHandle,
  1038. pServerProcess->WinstaDesktop());
  1039. pServerProcess->SetRunAsHandle(_pvRunAsHandle);
  1040. // Given Handle away so remove our reference
  1041. _pvRunAsHandle = NULL;
  1042. }
  1043. #endif
  1044. }
  1045. ExitRegisterHandles:
  1046. return bStatus;
  1047. }
  1048. //+-------------------------------------------------------------------------
  1049. //
  1050. // CServerTableEntry::WaitForLocalServer
  1051. //
  1052. //--------------------------------------------------------------------------
  1053. BOOL
  1054. CServerTableEntry::WaitForLocalServer(
  1055. IN HANDLE hRegisterEvent,
  1056. IN ULONG &winerr
  1057. )
  1058. {
  1059. DWORD Status = WAIT_OBJECT_0+1;
  1060. BOOL bStatus = FALSE;
  1061. HANDLE Handles[2];
  1062. Handles[0] = hRegisterEvent;
  1063. Handles[1] = _hProcess;
  1064. // Wait for process and register events
  1065. Status = WaitForMultipleObjects( 2, Handles, FALSE, gServerStartTimeout );
  1066. if ( Status == (WAIT_OBJECT_0 + 1) )
  1067. {
  1068. // Launched Process went away but this could be the case
  1069. // where we have a launched server that starts another server
  1070. // which registers back(Lotus or something ??)
  1071. // So null the handle and wait for the register event for
  1072. // a much shorter time
  1073. GetExitCodeProcess(_hProcess, &winerr);
  1074. HANDLE hProcess;
  1075. CloseHandle( _hProcess );
  1076. _hProcess = 0;
  1077. Status = WaitForSingleObject( hRegisterEvent, gServerStartSecondChanceTimeout );
  1078. }
  1079. if ( Status != WAIT_OBJECT_0 && _hProcess )
  1080. TerminateProcess( _hProcess, 0 );
  1081. if ( Status == WAIT_OBJECT_0 )
  1082. return TRUE;
  1083. else
  1084. return FALSE;
  1085. }
  1086. //+-------------------------------------------------------------------------
  1087. //
  1088. // CServerTableEntry::WaitForDllhostServer
  1089. //
  1090. //--------------------------------------------------------------------------
  1091. BOOL
  1092. CServerTableEntry::WaitForDllhostServer(
  1093. IN HANDLE hRegisterEvent,
  1094. IN ACTIVATION_PARAMS *pActParams,
  1095. IN ULONG &winerr,
  1096. IN LONG lThreadToken
  1097. )
  1098. {
  1099. DWORD Status = WAIT_OBJECT_0+1;
  1100. DWORD WaitedMilliSecondsToStart = 0;
  1101. CServerListEntry * pEntry = NULL;
  1102. BOOL bStatus;
  1103. CProcess *pProcess=NULL;
  1104. HANDLE Handles[2];
  1105. Handles[0] = hRegisterEvent;
  1106. Handles[1] = _hProcess;
  1107. LONG lSessionID = INVALID_SESSION_ID;
  1108. GetSessionIDFromActParams(pActParams->pActPropsIn, &lSessionID);
  1109. for (;;)
  1110. {
  1111. // Wait for process and register events
  1112. Status = WaitForMultipleObjects( 2, Handles,
  1113. FALSE, gDllhostServerStartTimeout );
  1114. if ( ( Status == WAIT_OBJECT_0 ) ||
  1115. ( Status == (WAIT_OBJECT_0 + 1 )))
  1116. break;
  1117. if (pEntry == NULL)
  1118. {
  1119. bStatus = LookupServer(
  1120. pActParams->pToken,
  1121. pActParams->RemoteActivation,
  1122. pActParams->bClientImpersonating,
  1123. pActParams->pProcess ? pActParams->pProcess->WinstaDesktop() : NULL ,
  1124. MATCHFLAG_ALLOW_SUSPENDED, // Dllhost is suspended now, we still want to find it!
  1125. lThreadToken,
  1126. lSessionID,
  1127. 0, // no need for a pid here
  1128. PRT_IGNORE, // no need for prt here
  1129. &pEntry);
  1130. if (!bStatus)
  1131. pEntry = NULL;
  1132. else
  1133. {
  1134. pProcess = pEntry->_pServerProcess;
  1135. Win4Assert(pProcess != NULL);
  1136. }
  1137. }
  1138. ScmProcessReg *pScmProcessReg=NULL;
  1139. if (pProcess)
  1140. {
  1141. pScmProcessReg = pProcess->GetProcessReg();
  1142. Win4Assert(pScmProcessReg != NULL);
  1143. }
  1144. if (! pScmProcessReg )
  1145. {
  1146. // ProcessActivatorStarted not called yet
  1147. WaitedMilliSecondsToStart += gDllhostServerStartTimeout;
  1148. if (WaitedMilliSecondsToStart >= gDllhostMaxServerStartTimeout)
  1149. break;
  1150. else
  1151. continue;
  1152. }
  1153. // ProcessActivatorStarted has been called, how long since last call from
  1154. // initial process activator?
  1155. // handles wraparound
  1156. CTime CurrentTime;
  1157. DWORD WaitedMilliSecondsToReady = CurrentTime - pScmProcessReg->TimeOfLastPing;
  1158. if (WaitedMilliSecondsToReady >= gDllhostMaxServerStartTimeout)
  1159. break;
  1160. else
  1161. continue;
  1162. }
  1163. if (pEntry)
  1164. pEntry->Release();
  1165. if ( Status == WAIT_OBJECT_0 )
  1166. return TRUE;
  1167. else
  1168. {
  1169. GetExitCodeProcess(_hProcess, &winerr);
  1170. TerminateProcess( _hProcess, 0 );
  1171. return FALSE;
  1172. }
  1173. }
  1174. //+-------------------------------------------------------------------------
  1175. //
  1176. // CServerTableEntry::WaitForService
  1177. //
  1178. //--------------------------------------------------------------------------
  1179. BOOL
  1180. CServerTableEntry::WaitForService(
  1181. IN SC_HANDLE hService,
  1182. IN HANDLE hRegisterEvent,
  1183. IN BOOL bServiceAlreadyRunning
  1184. )
  1185. {
  1186. SERVICE_STATUS ServiceStatus;
  1187. DWORD Status;
  1188. BOOL bStatus;
  1189. BOOL bKeepLooping;
  1190. BOOL bStopService = FALSE;
  1191. for (DWORD i = 0; i < gNTServiceMaxTimeouts; i++)
  1192. {
  1193. Status = WaitForSingleObject( hRegisterEvent, gNTServiceInterrogatePeriod );
  1194. if (Status == WAIT_OBJECT_0)
  1195. {
  1196. // register event was signalled, just return
  1197. break;
  1198. }
  1199. else
  1200. {
  1201. // Assume we are done
  1202. bKeepLooping = FALSE;
  1203. bStatus = ControlService( hService,
  1204. SERVICE_CONTROL_INTERROGATE,
  1205. &ServiceStatus );
  1206. if (bStatus)
  1207. {
  1208. switch ( ServiceStatus.dwCurrentState )
  1209. {
  1210. case SERVICE_STOPPED :
  1211. case SERVICE_STOP_PENDING :
  1212. // weirdness
  1213. break;
  1214. case SERVICE_RUNNING :
  1215. case SERVICE_START_PENDING :
  1216. case SERVICE_CONTINUE_PENDING :
  1217. // the service is taking its own sweet time. Keep
  1218. // looping to give it more time.
  1219. bKeepLooping = TRUE;
  1220. break;
  1221. case SERVICE_PAUSE_PENDING :
  1222. case SERVICE_PAUSED :
  1223. // more weirdness
  1224. if (!bServiceAlreadyRunning)
  1225. bStopService = TRUE;
  1226. break;
  1227. }
  1228. }
  1229. //else quit
  1230. if (!bKeepLooping)
  1231. break;
  1232. }
  1233. }
  1234. if ( bStopService )
  1235. {
  1236. (void) ControlService( hService,
  1237. SERVICE_CONTROL_STOP,
  1238. &ServiceStatus );
  1239. }
  1240. if ( Status == WAIT_OBJECT_0 )
  1241. return TRUE;
  1242. else
  1243. return FALSE;
  1244. }
  1245. //+-------------------------------------------------------------------------
  1246. //
  1247. // CServerTableEntry::WaitForInitCompleted
  1248. //
  1249. // Wait for an initializing server (dllhost) to finish initialization.
  1250. //
  1251. //--------------------------------------------------------------------------
  1252. HRESULT
  1253. CServerTableEntry::WaitForInitCompleted(
  1254. IN CServerListEntry *pEntry,
  1255. IN CClsidData *pClsidData
  1256. )
  1257. {
  1258. Win4Assert(pClsidData); // Should NOT call this without registration info.
  1259. if (NULL == pClsidData)
  1260. {
  1261. // If no clsid data, then we'll just need to return the
  1262. // "I'm initializing still" error code, since we have no
  1263. // way of waiting. I don't think this should ever happen,
  1264. // though.
  1265. return CO_E_SERVER_INIT_TIMEOUT;
  1266. }
  1267. HANDLE hInitEvent = pClsidData->ServerInitializedEvent();
  1268. if (!hInitEvent)
  1269. {
  1270. return E_OUTOFMEMORY;
  1271. }
  1272. HRESULT hr = S_OK;
  1273. if (pEntry->IsInitializing())
  1274. {
  1275. HANDLE hProcess = pEntry->_pServerProcess->GetProcessHandle();
  1276. DWORD dwRet;
  1277. if (hProcess)
  1278. {
  1279. HANDLE handles[2] = {hInitEvent, hProcess};
  1280. dwRet = WaitForMultipleObjects(2, handles, FALSE, gDllhostInitializationTimeout);
  1281. }
  1282. else
  1283. {
  1284. dwRet = WaitForSingleObject(hInitEvent, gDllhostInitializationTimeout);
  1285. }
  1286. if (dwRet == WAIT_TIMEOUT)
  1287. {
  1288. hr = CO_E_SERVER_INIT_TIMEOUT;
  1289. }
  1290. else if (dwRet == WAIT_OBJECT_0)
  1291. {
  1292. hr = S_OK;
  1293. }
  1294. else if (dwRet == WAIT_OBJECT_0+1)
  1295. {
  1296. hr = CO_E_SERVER_STOPPING;
  1297. }
  1298. else
  1299. {
  1300. hr = HRESULT_FROM_WIN32(GetLastError());
  1301. }
  1302. }
  1303. CloseHandle(hInitEvent);
  1304. return hr;
  1305. }
  1306. //+-------------------------------------------------------------------------
  1307. //
  1308. // CServerTableEntry::GetServerListWithLock
  1309. //
  1310. // Returns a pointer to this entry's server list. Takes shared lock before
  1311. // returning. Caller is expected to call ReleaseSharedListLock to release
  1312. // the lock
  1313. //
  1314. //--------------------------------------------------------------------------
  1315. CServerList* CServerTableEntry::GetServerListWithSharedLock()
  1316. {
  1317. ServerLock()->LockShared();
  1318. return &_ServerList;
  1319. }
  1320. //+-------------------------------------------------------------------------
  1321. //
  1322. // CServerTableEntry::ReleaseSharedListLock
  1323. //
  1324. // Releases a shared lock on this entry's list lock.
  1325. //
  1326. //--------------------------------------------------------------------------
  1327. void CServerTableEntry::ReleaseSharedListLock()
  1328. {
  1329. ServerLock()->UnlockShared();
  1330. }
  1331. //
  1332. // CServerTableEntry::SuspendClass
  1333. //
  1334. // Turns on the suspended flag for this entry.
  1335. //
  1336. void CServerTableEntry::SuspendClass()
  1337. {
  1338. ASSERT(!_bSuspendedClsid &&
  1339. !_bSuspendedApplication &&
  1340. _EntryType == ENTRY_TYPE_CLASS);
  1341. _bSuspendedClsid = TRUE;
  1342. SetSuspendOnAllServers(TRUE);
  1343. }
  1344. //
  1345. // CServerTableEntry::UnsuspendClass
  1346. //
  1347. // Turns off the suspended flag for this entry.
  1348. //
  1349. void CServerTableEntry::UnsuspendClass()
  1350. {
  1351. ASSERT(_bSuspendedClsid &&
  1352. !_bSuspendedApplication &&
  1353. _EntryType == ENTRY_TYPE_CLASS);
  1354. _bSuspendedClsid = FALSE;
  1355. SetSuspendOnAllServers(FALSE);
  1356. }
  1357. //
  1358. // CServerTableEntry::RetireClass
  1359. //
  1360. // Retires all currently registered servers for
  1361. // this clsid.
  1362. //
  1363. void CServerTableEntry::RetireClass()
  1364. {
  1365. ASSERT(_EntryType == ENTRY_TYPE_CLASS);
  1366. RetireAllServers();
  1367. }
  1368. //
  1369. // CServerTableEntry::SuspendApplication
  1370. //
  1371. // Turns on the suspended flag for this entry.
  1372. //
  1373. void CServerTableEntry::SuspendApplication()
  1374. {
  1375. ASSERT(!_bSuspendedClsid &&
  1376. !_bSuspendedApplication &&
  1377. _EntryType == ENTRY_TYPE_PROCESS);
  1378. _bSuspendedClsid = TRUE;
  1379. }
  1380. //
  1381. // CServerTableEntry::UnsuspendApplication
  1382. //
  1383. // Turns on the suspended flag for this entry.
  1384. //
  1385. void CServerTableEntry::UnsuspendApplication()
  1386. {
  1387. ASSERT(!_bSuspendedClsid &&
  1388. _bSuspendedApplication &&
  1389. _EntryType == ENTRY_TYPE_PROCESS);
  1390. _bSuspendedClsid = FALSE;
  1391. }
  1392. //
  1393. // CServerTableEntry::RetireApplication
  1394. //
  1395. // Marks as retired all servers registered with
  1396. // this entry.
  1397. //
  1398. void CServerTableEntry::RetireApplication()
  1399. {
  1400. ASSERT(_EntryType == ENTRY_TYPE_PROCESS);
  1401. RetireAllServers();
  1402. }
  1403. //
  1404. // CServerTableEntry::IsSuspended
  1405. //
  1406. // Returns TRUE if servers of this type are
  1407. // currently suspended, FALSE otherwise.
  1408. //
  1409. BOOL CServerTableEntry::IsSuspended()
  1410. {
  1411. ASSERT(_EntryType == ENTRY_TYPE_CLASS ||
  1412. _EntryType == ENTRY_TYPE_PROCESS);
  1413. if (_EntryType == ENTRY_TYPE_CLASS)
  1414. return _bSuspendedClsid;
  1415. else
  1416. return _bSuspendedApplication;
  1417. }
  1418. //
  1419. // CServerTableEntry::SetSuspendOnAllServers
  1420. //
  1421. // Sets the suspended bit on all currently registered servers.
  1422. //
  1423. void CServerTableEntry::SetSuspendOnAllServers(BOOL bSuspended)
  1424. {
  1425. CServerListEntry * pEntry;
  1426. ServerLock()->LockShared();
  1427. for (pEntry = (CServerListEntry *) _ServerList.First();
  1428. pEntry;
  1429. pEntry = (CServerListEntry *) pEntry->Next() )
  1430. {
  1431. if (bSuspended)
  1432. pEntry->Suspend();
  1433. else
  1434. pEntry->Unsuspend();
  1435. }
  1436. ServerLock()->UnlockShared();
  1437. }
  1438. //
  1439. // CServerTableEntry::RetireAllServers
  1440. //
  1441. // Marks as retired all currently registered servers.
  1442. //
  1443. void CServerTableEntry::RetireAllServers()
  1444. {
  1445. CServerListEntry * pEntry;
  1446. ServerLock()->LockShared();
  1447. for (pEntry = (CServerListEntry *) _ServerList.First();
  1448. pEntry;
  1449. pEntry = (CServerListEntry *) pEntry->Next() )
  1450. {
  1451. pEntry->Retire();
  1452. }
  1453. ServerLock()->UnlockShared();
  1454. }
  1455. //
  1456. // CServerTableEntry::SetSuspendedFlagOnNewServer
  1457. //
  1458. // Helper function for when a new class factory registration/app
  1459. // comes along. If we are currently suspended, then we need to
  1460. // pass that state on to the new server. If we're not suspended,
  1461. // then there's nothing to do.
  1462. //
  1463. void CServerTableEntry::SetSuspendedFlagOnNewServer(CProcess* pprocess)
  1464. {
  1465. if ( (_EntryType == ENTRY_TYPE_CLASS) && _bSuspendedClsid)
  1466. {
  1467. pprocess->Suspend();
  1468. }
  1469. else if ( (_EntryType == ENTRY_TYPE_PROCESS) && _bSuspendedApplication)
  1470. {
  1471. pprocess->Suspend();
  1472. }
  1473. }
  1474. //+-------------------------------------------------------------------------
  1475. //
  1476. // SCMRemoveRegistration Version 1: for class entries representing traditional
  1477. // local servers including custom surrogate servers.
  1478. //
  1479. // Called from CProcess::RevokeClassRegs() in the resolver.
  1480. //
  1481. //--------------------------------------------------------------------------
  1482. void
  1483. SCMRemoveRegistration(
  1484. CProcess * pProcess,
  1485. GUID & Guid,
  1486. DWORD Reg
  1487. )
  1488. {
  1489. CServerTableEntry * pClassTableEntry = NULL;
  1490. pClassTableEntry = gpClassTable->Lookup( Guid );
  1491. if ( pClassTableEntry )
  1492. {
  1493. pClassTableEntry->RevokeServer( pProcess, Reg );
  1494. pClassTableEntry->Release();
  1495. }
  1496. }
  1497. //+-------------------------------------------------------------------------
  1498. //
  1499. // SCMRemoveRegistration Version 2: for process entries representing
  1500. // new unified surrogate servers.
  1501. //
  1502. // Called from CProcess::RevokeClassRegs() in the resolver.
  1503. //
  1504. //--------------------------------------------------------------------------
  1505. void
  1506. SCMRemoveRegistration(
  1507. ScmProcessReg * pScmProcessReg
  1508. )
  1509. {
  1510. CServerTableEntry * pProcessTableEntry = NULL;
  1511. pProcessTableEntry = gpProcessTable->Lookup( pScmProcessReg->ProcessGUID );
  1512. if ( pProcessTableEntry )
  1513. {
  1514. pProcessTableEntry->RevokeServer( pScmProcessReg );
  1515. pProcessTableEntry->Release();
  1516. }
  1517. }
  1518. void
  1519. SCMProcessCleanup(
  1520. const CProcess *pProcess
  1521. )
  1522. {
  1523. #ifndef _CHICAGO_
  1524. CSurrogateListEntry *pSurrogateEntry = gpSurrogateList->Lookup(pProcess);
  1525. if (pSurrogateEntry)
  1526. {
  1527. gpSurrogateList->Remove(pSurrogateEntry);
  1528. pSurrogateEntry->Release();
  1529. }
  1530. #endif
  1531. }