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.

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