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.

1303 lines
37 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999.
  5. //
  6. // File: scminfo.cxx
  7. //
  8. // Contents: Definitions/objects for use by scm-level activators
  9. //
  10. // History: 05-Sep-99 JSimmons Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "act.hxx"
  14. #include "scminfo.hxx"
  15. #include "initguid.h"
  16. // Macros to index into special members of the SCMProcessInfo struct
  17. #define SPI_TO_SIZE(pSPI) (ULONG*)(((BYTE*)pSPI) + sizeof(SCMProcessInfo))
  18. #define SPI_TO_REFCOUNT(pSPI) (LONG*)(((BYTE*)pSPI) + sizeof(SCMProcessInfo) + sizeof(ULONG))
  19. #define SPI_TO_CPROCESS(pSPI) (CProcess**)(((BYTE*)pSPI) + sizeof(SCMProcessInfo) + sizeof(ULONG) + sizeof(ULONG))
  20. #define SPI_TO_WINSTA(pSPI) (WCHAR*)(((BYTE*)pSPI) + sizeof(SCMProcessInfo) + sizeof(ULONG) + sizeof(ULONG) + sizeof(CProcess*))
  21. // Rounding constant for ptr sizes
  22. #if defined(_X86_)
  23. #define MEM_ALIGN_SIZE 4
  24. #else
  25. #ifdef _WIN64
  26. #define MEM_ALIGN_SIZE 16
  27. #else
  28. #define MEM_ALIGN_SIZE 8
  29. #endif
  30. #endif
  31. //+-------------------------------------------------------------------------
  32. //
  33. // Implementation of CSCMProcessControl begins here
  34. //
  35. //--------------------------------------------------------------------------
  36. // Constructor
  37. CSCMProcessControl::CSCMProcessControl() :
  38. _lRefs(0),
  39. _bInitializedEnum(FALSE)
  40. {
  41. }
  42. // Destructor
  43. CSCMProcessControl::~CSCMProcessControl()
  44. {
  45. ASSERT(_lRefs == 0);
  46. }
  47. //+-------------------------------------------------------------------------
  48. //
  49. // Function: FindApplication
  50. //
  51. // Synopsis: Creates an enumerator for enumerating over all running com+
  52. // processes that have registered for the specified application.
  53. //
  54. // Arguments: rappid -- the appid they want to know about
  55. // ppESPI -- out param to store the resulting IEnumSCMProcessInfo
  56. //
  57. // Returns: S_OK - life is good; *ppESPI will be non-NULL if at least
  58. // one suitable server was found
  59. // E_INVALIDARG -- one or more parameters was incorrect
  60. // E_OUTOFMEMORY
  61. //
  62. //--------------------------------------------------------------------------
  63. STDMETHODIMP CSCMProcessControl::FindApplication(REFGUID rappid, IEnumSCMProcessInfo** ppESPI)
  64. {
  65. return FindAppOrClass(rappid, gpProcessTable, ppESPI);
  66. }
  67. //+-------------------------------------------------------------------------
  68. //
  69. // Function: FindClass
  70. //
  71. // Synopsis: Creates an enumerator for enumerating over all running
  72. // processes that have registered a class factory for the
  73. // specified clsid.
  74. //
  75. // Arguments: rclsid -- the clsid they want to know about
  76. // ppESPI -- out param to store the resulting IEnumSCMProcessInfo
  77. //
  78. // Returns: S_OK - life is good; *ppESPI will be non-NULL if at least
  79. // one suitable server was found
  80. // E_INVALIDARG -- one or more parameters was incorrect
  81. // E_OUTOFMEMORY
  82. //
  83. //--------------------------------------------------------------------------
  84. STDMETHODIMP CSCMProcessControl::FindClass(REFCLSID rclsid, IEnumSCMProcessInfo **ppESPI)
  85. {
  86. return FindAppOrClass((GUID&)rclsid, gpClassTable, ppESPI);
  87. }
  88. //+-------------------------------------------------------------------------
  89. //
  90. // Function: FindProcess
  91. //
  92. // Synopsis: Tries to find the specified process (by pid) in the the process
  93. // list; if found, then calls FillInSCMProcessInfo.
  94. //
  95. // Arguments: pid -- process id of the process they're interested in
  96. // ppSPI -- out param to store a ptr to new SCMProcessInfo struct
  97. //
  98. // Returns: S_OK - life is good; *ppSPI will be non-NULL if the process was found
  99. // E_INVALIDARG -- didn't find that pid
  100. // E_OUTOFMEMORY
  101. //
  102. //--------------------------------------------------------------------------
  103. STDMETHODIMP CSCMProcessControl::FindProcess(DWORD pid, SCMProcessInfo** ppSPI)
  104. {
  105. HRESULT hr = S_OK;
  106. if (!ppSPI)
  107. return E_INVALIDARG;
  108. *ppSPI = NULL;
  109. //if (pid == gRPCSSPid) // we don't talk about ourselves?
  110. //return E_INVALIDARG;
  111. gpProcessListLock->LockShared();
  112. // look through list of processes
  113. CBListIterator all_procs(gpProcessList);
  114. CProcess* pprocess;
  115. while (pprocess = (CProcess*)all_procs.Next())
  116. {
  117. if (pprocess->GetPID() == pid)
  118. {
  119. // found it
  120. pprocess->ClientReference();
  121. break;
  122. }
  123. }
  124. gpProcessListLock->UnlockShared();
  125. if (pprocess)
  126. {
  127. // REVIEW: we assume blindly here that the process in question has
  128. // finished all registration activities. However, it is possible I
  129. // guess for an activator to query about a process before it had
  130. // finished registration. This would not be a very smart activator.
  131. hr = FillInSCMProcessInfo(pprocess, TRUE, ppSPI);
  132. ReleaseProcess(pprocess);
  133. }
  134. return hr;
  135. }
  136. //+-------------------------------------------------------------------------
  137. //
  138. // Function: SuspendApplication
  139. //
  140. // Synopsis: Marks as suspended all applications that match the specified
  141. // appid. No other applications of this type will be started
  142. // by RPCSS. If any applications of this type are started
  143. // manually, they also will be marked as suspended.
  144. //
  145. // Arguments: rappid -- appid to suspend
  146. //
  147. // Returns: S_OK
  148. //
  149. //--------------------------------------------------------------------------
  150. STDMETHODIMP CSCMProcessControl::SuspendApplication(REFGUID rappid)
  151. {
  152. CServerTableEntry *pProcessEntry;
  153. pProcessEntry = gpProcessTable->Lookup( (GUID&)rappid );
  154. if (pProcessEntry)
  155. {
  156. pProcessEntry->SuspendApplication();
  157. pProcessEntry->Release();
  158. }
  159. return S_OK;
  160. }
  161. //+-------------------------------------------------------------------------
  162. //
  163. // Function: SuspendClass
  164. //
  165. // Synopsis: Marks as suspended all class factories that have been
  166. // registered for the specified clsid. If any new class
  167. // factory registrations are encountered after the suspend has
  168. // been issued, the new registrations will also be suspended.
  169. // No new servers will be launched by RPCSS on behalf of this
  170. // clsid.
  171. //
  172. // Arguments: rclsid -- clsid to suspend
  173. //
  174. // Returns: S_OK
  175. // E_INVALIDARG
  176. //
  177. //--------------------------------------------------------------------------
  178. STDMETHODIMP CSCMProcessControl::SuspendClass(REFCLSID rclsid)
  179. {
  180. CServerTableEntry *pClassEntry;
  181. pClassEntry = gpClassTable->Lookup( (GUID&)rclsid );
  182. if (pClassEntry)
  183. {
  184. pClassEntry->SuspendClass();
  185. pClassEntry->Release();
  186. }
  187. return S_OK;
  188. }
  189. //+-------------------------------------------------------------------------
  190. //
  191. // Function: SuspendProcess
  192. //
  193. // Synopsis: Tries to find the specified process (by pid) in the the process
  194. // list; if found, then marks that process as suspended (unavailable
  195. // for further activations).
  196. //
  197. // Arguments: pid -- process id of the process callers wants to suspend
  198. //
  199. // Returns: S_OK - process was suspended
  200. // E_INVALIDARG -- didn't find that pid
  201. //
  202. //--------------------------------------------------------------------------
  203. STDMETHODIMP CSCMProcessControl::SuspendProcess(DWORD pid)
  204. {
  205. HRESULT hr = E_INVALIDARG;
  206. //if (pid == gRPCSSPid) // we don't talk about ourselves?
  207. //return E_INVALIDARG;
  208. gpProcessListLock->LockShared();
  209. // look through list of processes
  210. CBListIterator all_procs(gpProcessList);
  211. CProcess* pprocess;
  212. while (pprocess = (CProcess*)all_procs.Next())
  213. {
  214. if (pprocess->GetPID() == pid)
  215. {
  216. // found it
  217. pprocess->Suspend();
  218. hr = S_OK;
  219. break;
  220. }
  221. }
  222. gpProcessListLock->UnlockShared();
  223. return hr;
  224. }
  225. //+-------------------------------------------------------------------------
  226. //
  227. // Function: ResumeApplication
  228. //
  229. // Synopsis: Marks as available for activations all applications previously
  230. // suspended.
  231. //
  232. // Arguments: rappid -- application id the caller wants to un-suspend
  233. //
  234. // Returns: S_OK
  235. //
  236. //--------------------------------------------------------------------------
  237. STDMETHODIMP CSCMProcessControl::ResumeApplication(REFGUID rappid)
  238. {
  239. CServerTableEntry *pProcessEntry;
  240. pProcessEntry = gpProcessTable->Lookup( (GUID&)rappid );
  241. if (pProcessEntry)
  242. {
  243. pProcessEntry->UnsuspendApplication();
  244. pProcessEntry->Release();
  245. }
  246. return S_OK;
  247. }
  248. //+-------------------------------------------------------------------------
  249. //
  250. // Function: ResumeClass
  251. //
  252. // Synopsis: Marks all servers supporting the specified clsid as available
  253. // for activation.
  254. //
  255. // Arguments: rclsid -- clsid of the object the caller wants to un-suspend
  256. //
  257. // Returns: S_OK
  258. //
  259. //--------------------------------------------------------------------------
  260. STDMETHODIMP CSCMProcessControl::ResumeClass(REFCLSID rclsid)
  261. {
  262. CServerTableEntry *pClassEntry;
  263. pClassEntry = gpClassTable->Lookup( (GUID&)rclsid );
  264. if (pClassEntry)
  265. {
  266. pClassEntry->UnsuspendClass();
  267. pClassEntry->Release();
  268. }
  269. return S_OK;
  270. }
  271. //+-------------------------------------------------------------------------
  272. //
  273. // Function: ResumeProcess
  274. //
  275. // Synopsis: Tries to find the specified process (by pid) in the the process
  276. // list; if found, then marks that process as unsuspended (ie,
  277. // available for further activations).
  278. //
  279. // Arguments: pid -- process id of the process callers wants to suspend
  280. //
  281. // Returns: S_OK - process was suspended
  282. // E_INVALIDARG -- didn't find that pid
  283. //
  284. //--------------------------------------------------------------------------
  285. STDMETHODIMP CSCMProcessControl::ResumeProcess(DWORD pid)
  286. {
  287. HRESULT hr = E_INVALIDARG;
  288. //if (pid == gRPCSSPid) // we don't talk about ourselves?
  289. //return E_INVALIDARG;
  290. gpProcessListLock->LockShared();
  291. // look through list of processes
  292. CBListIterator all_procs(gpProcessList);
  293. CProcess* pprocess;
  294. while (pprocess = (CProcess*)all_procs.Next())
  295. {
  296. if (pprocess->GetPID() == pid)
  297. {
  298. // found it
  299. pprocess->ClientReference();
  300. break;
  301. }
  302. }
  303. gpProcessListLock->UnlockShared();
  304. if (pprocess)
  305. {
  306. pprocess->Unsuspend();
  307. ReleaseProcess(pprocess);
  308. hr = S_OK;
  309. }
  310. return hr;
  311. }
  312. //+-------------------------------------------------------------------------
  313. //
  314. // Function: RetireApplication
  315. //
  316. // Synopsis: Marks as "retired" all currently running applications with
  317. // the specified appid.
  318. //
  319. // Arguments: appid -- appid to retire
  320. //
  321. // Returns: S_OK - all running applications that matched the appid were
  322. // retired
  323. // E_INVALIDARG
  324. //
  325. //--------------------------------------------------------------------------
  326. STDMETHODIMP CSCMProcessControl::RetireApplication(REFGUID rappid)
  327. {
  328. CServerTableEntry *pProcessEntry;
  329. pProcessEntry = gpProcessTable->Lookup( (GUID&)rappid );
  330. if (pProcessEntry)
  331. {
  332. pProcessEntry->RetireApplication();
  333. pProcessEntry->Release();
  334. }
  335. return S_OK;
  336. }
  337. //+-------------------------------------------------------------------------
  338. //
  339. // Function: RetireClass
  340. //
  341. // Synopsis: Marks as "retired" all currently running processes which
  342. // have registered a class factory for the specified clsid.
  343. //
  344. // Arguments: rclsid -- clsid to retire
  345. //
  346. // Returns: S_OK
  347. // E_INVALIDARG
  348. //
  349. //--------------------------------------------------------------------------
  350. STDMETHODIMP CSCMProcessControl::RetireClass(REFCLSID rclsid)
  351. {
  352. CServerTableEntry *pClassEntry;
  353. pClassEntry = gpClassTable->Lookup( (GUID&)rclsid );
  354. if (pClassEntry)
  355. {
  356. pClassEntry->RetireClass();
  357. pClassEntry->Release();
  358. }
  359. return S_OK;
  360. }
  361. //+-------------------------------------------------------------------------
  362. //
  363. // Function: RetireProcess
  364. //
  365. // Synopsis: Tries to find the specified process (by pid) in the the process
  366. // list; if found, then marks that process as retired (ie,
  367. // unavailable for further activations until the end of time).
  368. //
  369. // Arguments: pid -- process id of the process callers wants to retire
  370. //
  371. // Returns: S_OK - process was suspended
  372. // E_INVALIDARG -- didn't find that pid
  373. //
  374. //--------------------------------------------------------------------------
  375. STDMETHODIMP CSCMProcessControl::RetireProcess(DWORD pid)
  376. {
  377. HRESULT hr = E_INVALIDARG;
  378. //if (pid == gRPCSSPid) // we don't talk about ourselves
  379. //return E_INVALIDARG;
  380. gpProcessListLock->LockShared();
  381. // look through list of processes
  382. CBListIterator all_procs(gpProcessList);
  383. CProcess* pprocess;
  384. while (pprocess = (CProcess*)all_procs.Next())
  385. {
  386. if (pprocess->GetPID() == pid)
  387. {
  388. // found it
  389. pprocess->Retire();
  390. hr = S_OK;
  391. break;
  392. }
  393. }
  394. gpProcessListLock->UnlockShared();
  395. return hr;
  396. }
  397. //+-------------------------------------------------------------------------
  398. //
  399. // Function: FreeSCMProcessInfo
  400. //
  401. // Synopsis: Method that knows how to free a SCMProcessInfo structure,
  402. // including of course its constituent members.
  403. //
  404. // Arguments: ppSPI -- ptr-ptr to the SCMProcessInfo struct
  405. //
  406. // Returns: S_OK - life is good
  407. // E_INVALIDARG -- bad parameter
  408. //
  409. //--------------------------------------------------------------------------
  410. STDMETHODIMP CSCMProcessControl::FreeSCMProcessInfo(SCMProcessInfo** ppSPI)
  411. {
  412. return CSCMProcessControl::FreeSCMProcessInfoPriv(ppSPI);
  413. }
  414. //+-------------------------------------------------------------------------
  415. //
  416. // Private CSCMProcessControl methods below here
  417. //
  418. //--------------------------------------------------------------------------
  419. //+-------------------------------------------------------------------------
  420. //
  421. // Function: FillInSCMProcessInfo
  422. //
  423. // Synopsis: Allocates and fills in a SCMProcessInfo structure for the
  424. // given CProcess object.
  425. //
  426. // Arguments: pprocess -- ptr to the CProcess object
  427. // bProcessReady -- whether the process in question is ready to
  428. // receive activations
  429. // ppSPI -- out param to store a ptr to new SCMProcessInfo struct
  430. //
  431. // Returns: S_OK - life is good
  432. // E_OUTOFMEMORY
  433. //
  434. // Notes: assumes that at least a read lock is held by the caller for
  435. // the duration of the call.
  436. //
  437. // The SCMProcessInfo memory is layed out as follows:
  438. //
  439. // <SCMProcessInfo>
  440. // <size of entire allocation>
  441. // <ref count on this struct>
  442. // <CProcess*>
  443. // <winsta string if any>
  444. // <array of clsids if any>
  445. //
  446. // (note that the size and refcount combined make 8 bytes, thus maintaining ptr alignment on Win64)
  447. // (the winsta string is also padded out to a multiple of the platform ptr size)
  448. //
  449. // The pointer members of the SCMProcessInfo struct point beyond the
  450. // SCMProcessInfo struct proper to the appropriate data. The saved CProcess*
  451. // object has an added refcount. The # of users using the struct is counted
  452. // by the ref count field. We don't free the struct until this falls to zero
  453. // (done in FreeSCMProcessInfoPriv below). Use the macros in scminfo.hxx to
  454. // access these undoc'd members.
  455. //
  456. // If you modify this layout watch out for Win64 alignment issues.
  457. //
  458. HRESULT CSCMProcessControl::FillInSCMProcessInfo(CProcess* pprocess, BOOL bProcessReady, SCMProcessInfo** ppSPI)
  459. {
  460. HRESULT hr = S_OK;
  461. ULONG ulWinstaStrlen = 0;
  462. SCMProcessInfo* pSPI = NULL;
  463. ASSERT(pprocess);
  464. ASSERT(ppSPI);
  465. *ppSPI = NULL;
  466. // Try to take fast path. We can do this if the process in question has not added or
  467. // removed any class registrations.
  468. gpServerLock->LockShared();
  469. if (!pprocess->SPIDirty())
  470. {
  471. // great; make a copy of the struct that we previously cached in the process
  472. // object; this struct won't be messed with while we're holding the read lock
  473. hr = CopySCMProcessInfo((SCMProcessInfo*)pprocess->GetSCMProcessInfo(), ppSPI);
  474. gpServerLock->UnlockShared();
  475. return hr;
  476. }
  477. gpServerLock->UnlockShared();
  478. // Darn, the process changed its set of registrations, or this is the first time we've ever
  479. // done this. Take a write lock and do it the hard way
  480. gpServerLock->LockExclusive();
  481. if (!pprocess->SPIDirty())
  482. {
  483. // we got beat to the lock
  484. hr = CopySCMProcessInfo((SCMProcessInfo*)pprocess->GetSCMProcessInfo(), ppSPI);
  485. gpServerLock->UnlockExclusive();
  486. return hr;
  487. }
  488. // Find length of the winsta string
  489. if (pprocess->_pwszWinstaDesktop)
  490. {
  491. ulWinstaStrlen = lstrlenW(pprocess->_pwszWinstaDesktop) + sizeof(WCHAR);
  492. // Need for the string buffer to be a even multiple of the ptr size
  493. ulWinstaStrlen = (ulWinstaStrlen + MEM_ALIGN_SIZE - 1) & ~(MEM_ALIGN_SIZE - 1);
  494. }
  495. // Allocate one buffer to hold the struct, the winsta string, and the CLSIDs:
  496. ULONG ulBufSizeNeeded = sizeof(SCMProcessInfo) +
  497. sizeof(ULONG) +
  498. sizeof(ULONG) +
  499. sizeof(CProcess*) +
  500. (ulWinstaStrlen * sizeof(WCHAR)) +
  501. (pprocess->_ulClasses * sizeof(CLSID));
  502. pSPI = (SCMProcessInfo*) new BYTE[ ulBufSizeNeeded ];
  503. if (!pSPI)
  504. {
  505. gpServerLock->UnlockExclusive();
  506. return E_OUTOFMEMORY;
  507. }
  508. ZeroMemory(pSPI, ulBufSizeNeeded);
  509. // Store the allocation size. This takes up an extra dword , but saves
  510. // a lot of time when we have to copy the struct
  511. *SPI_TO_SIZE(pSPI)= ulBufSizeNeeded;
  512. // Store a pointer to the CProcess* object itself and take a reference on it
  513. *SPI_TO_CPROCESS(pSPI) = pprocess;
  514. pprocess->Reference();
  515. // Mark the initial refcount as one. This refcount belongs to the CProcess object
  516. // when we cache it below
  517. *SPI_TO_REFCOUNT(pSPI) = 1;
  518. CLSID* pCLSIDs;
  519. WCHAR* pwszWinSta = NULL;
  520. // Copy the winsta string
  521. if (ulWinstaStrlen > 0)
  522. {
  523. pwszWinSta = SPI_TO_WINSTA(pSPI);
  524. lstrcpyW(pwszWinSta, pprocess->_pwszWinstaDesktop);
  525. pSPI->pwszWinstaDesktop = pwszWinSta;
  526. }
  527. // Copy the clsids
  528. ULONG ulCLSID = 0;
  529. if (pprocess->_ulClasses > 0)
  530. {
  531. Assert (pwszWinSta);
  532. pSPI->ulNumClasses = pprocess->_ulClasses;
  533. pSPI->pCLSIDs = (CLSID*) (pwszWinSta + ulWinstaStrlen);
  534. CClassReg* pReg = (CClassReg*)pprocess->_listClasses.First();
  535. while (pReg)
  536. {
  537. pSPI->pCLSIDs[ulCLSID] = pReg->_Guid;
  538. pReg = (CClassReg*)pReg->Next();
  539. ulCLSID++;
  540. }
  541. }
  542. ASSERT(ulCLSID == pprocess->_ulClasses);
  543. pSPI->pidProcess = pprocess->GetPID();
  544. // We hold a reference on the CProcess object, which owns the process handle until
  545. // it goes away. So it's safe to store the handle directly like this.
  546. // The handle may be NULL if we didn't launch the process, callers have the responsibility
  547. // of checking for this.
  548. pSPI->hProcess = pprocess->GetProcessHandle();
  549. // We hold a reference on the CProcess object, which holds a reference on it's CToken
  550. // object. So it's safe to store the token directly like this, it won't go away.
  551. pSPI->hImpersonationToken = pprocess->GetToken()->GetToken();
  552. // The process will only have a ScmProcessReg if it is a COM+ app
  553. if (pprocess->_pScmProcessReg)
  554. {
  555. pSPI->dwState |= SPIF_COMPLUS;
  556. pSPI->AppId = pprocess->_pScmProcessReg->ProcessGUID;
  557. // flip the ready bit
  558. if (pprocess->_pScmProcessReg->ReadinessStatus & SERVERSTATE_READY)
  559. {
  560. pSPI->dwState |= SPIF_READY;
  561. }
  562. }
  563. else
  564. {
  565. // Legacy-style server. We consider the process to be "ready" if it's
  566. // not in the midst of doing class registrations. The caller tells us this.
  567. if (bProcessReady)
  568. {
  569. pSPI->dwState |= SPIF_READY;
  570. }
  571. }
  572. if (pprocess->IsSuspended())
  573. pSPI->dwState |= SPIF_SUSPENDED;
  574. if (pprocess->IsRetired())
  575. pSPI->dwState |= SPIF_RETIRED;
  576. if (pprocess->IsPaused())
  577. pSPI->dwState |= SPIF_PAUSED;
  578. pSPI->ftCreated = *(pprocess->GetFileTimeCreated());
  579. // UNDONE: server type and identity. Still working on the exact details of this
  580. //pSPI->ServerType =
  581. //if (pSPI->ServerType != SET_SERVICE_
  582. // pSPI->ServerIdent =
  583. // Before we leave the lock, we need to replace the cached struct in the process object
  584. // with the new one; this also clears the dirty bit on the process
  585. pprocess->SetSCMProcessInfo((void*)pSPI);
  586. // Lastly, make a new copy to return to the caller
  587. hr = CopySCMProcessInfo(pSPI, ppSPI);
  588. gpServerLock->UnlockExclusive();
  589. return hr;
  590. }
  591. //+-------------------------------------------------------------------------
  592. //
  593. // Function: FreeSCMProcessInfoPriv
  594. //
  595. // Synopsis: Method that knows how to free a SCMProcessInfo structure,
  596. // including of course its constituent members.
  597. //
  598. // Arguments: ppSCMProcessInfo -- ptr-ptr to the SCMProcessInfo struct
  599. //
  600. // Returns: S_OK - life is good
  601. // E_INVALIDARG -- bad parameter
  602. //
  603. // Note: refer to the header comments for FillInSCMProcessInfo for info
  604. // on the extended layout of a SCMProcessInfo struct.
  605. //
  606. //--------------------------------------------------------------------------
  607. HRESULT CSCMProcessControl::FreeSCMProcessInfoPriv(SCMProcessInfo** ppSCMProcessInfo)
  608. {
  609. if (!ppSCMProcessInfo)
  610. return E_INVALIDARG;
  611. if (*ppSCMProcessInfo)
  612. {
  613. // Decrement the struct ref count; it will not fall to zero until the CProcess*
  614. // object releases its reference, which will not happen unless it is either
  615. // a) rundown; or b) replacing a previous dirty SPI with a new one
  616. LONG lRefs = InterlockedDecrement(SPI_TO_REFCOUNT(*ppSCMProcessInfo));
  617. if (lRefs == 0)
  618. {
  619. (*SPI_TO_CPROCESS(*ppSCMProcessInfo))->Release();
  620. delete (*ppSCMProcessInfo);
  621. }
  622. *ppSCMProcessInfo = NULL;
  623. }
  624. return S_OK;
  625. }
  626. //+-------------------------------------------------------------------------
  627. //
  628. // Function: CopySCMProcessInfo
  629. //
  630. // Synopsis: Allocates and fills in a SCMProcessInfo structure for the
  631. // given CProcess server.
  632. //
  633. // Arguments: pSPISrc -- ptr to the SCMProcessInfo struct that is to be copied
  634. // ppSPIDest -- ptrptr to store the copied struct
  635. //
  636. // Returns: S_OK - success
  637. // E_OUTOFMEMORY
  638. //
  639. //--------------------------------------------------------------------------
  640. HRESULT CSCMProcessControl::CopySCMProcessInfo(SCMProcessInfo* pSPISrc, SCMProcessInfo** ppSPIDest)
  641. {
  642. ASSERT(pSPISrc && ppSPIDest);
  643. if (!pSPISrc || !ppSPIDest)
  644. return E_INVALIDARG;
  645. LONG lNewRefs = InterlockedIncrement(SPI_TO_REFCOUNT(pSPISrc));
  646. *ppSPIDest = pSPISrc;
  647. return S_OK;
  648. };
  649. //+-------------------------------------------------------------------------
  650. //
  651. // Function: FindAppOrClass
  652. //
  653. // Synopsis: This is a generic helper function used by the FindApplication
  654. // and FindClass methods. The logic is the same for either.
  655. //
  656. // Arguments: rguid -- the appid or clsid to use in the query
  657. // pServerTable - the table to use in the query
  658. // ppESPI -- the place to store the resulting enumerator object
  659. //
  660. // Returns: S_OK - success
  661. // E_OUTOFMEMORY
  662. //
  663. //--------------------------------------------------------------------------
  664. HRESULT CSCMProcessControl::FindAppOrClass(const GUID& rguid, CServerTable* pServerTable, IEnumSCMProcessInfo** ppESPI)
  665. {
  666. HRESULT hr = S_OK;
  667. CSCMProcessEnumerator* pSPEnum = NULL;
  668. CServerTableEntry* pSTE = NULL;
  669. if (!ppESPI)
  670. return E_INVALIDARG;
  671. *ppESPI = NULL;
  672. pSTE = pServerTable->Lookup((GUID&)rguid);
  673. if (!pSTE)
  674. {
  675. return S_OK;
  676. }
  677. pSPEnum = new CSCMProcessEnumerator();
  678. if (!pSPEnum)
  679. {
  680. pSTE->Release();
  681. return E_OUTOFMEMORY;
  682. }
  683. CServerList* pServerList = pSTE->GetServerListWithSharedLock();
  684. ASSERT(pServerList && "unexpected NULL pServerList");
  685. // For each server that has registered for this appid/clsid, add a
  686. // SCMProcessInfo to the enumerator object
  687. CServerListEntry* pSLE = (CServerListEntry*)pServerList->First();
  688. while (pSLE)
  689. {
  690. SCMProcessInfo* pSPI;
  691. CProcess* pprocess = pSLE->GetProcess(); // not refcounted
  692. ASSERT(pprocess);
  693. hr = FillInSCMProcessInfo(pprocess, pSLE->IsReadyForActivations(), &pSPI);
  694. if (SUCCEEDED(hr))
  695. {
  696. // add it to the enumerator; on success, the enumerator owns it
  697. hr = pSPEnum->AddProcess(pSPI);
  698. if (FAILED(hr))
  699. {
  700. FreeSCMProcessInfoPriv(&pSPI); // we still own it, so free the memory
  701. break;
  702. }
  703. }
  704. else
  705. break;
  706. pSLE = (CServerListEntry*) pSLE->Next();
  707. }
  708. pSTE->ReleaseSharedListLock();
  709. if (SUCCEEDED(hr))
  710. {
  711. hr = pSPEnum->QueryInterface(__uuidof(IEnumSCMProcessInfo), (void**)ppESPI);
  712. }
  713. pSPEnum->Release();
  714. pSTE->Release();
  715. return hr;
  716. }
  717. //+-------------------------------------------------------------------------
  718. //
  719. // Function: InitializeEnumerator
  720. //
  721. // Synopsis: Initializes the aggregated enumerator object for use. Mainly
  722. // this consists of adding SCMProcessInfo's for all known servers
  723. // to the enumerator.
  724. //
  725. // Arguments: none
  726. //
  727. // Returns: S_OK
  728. // E_OUTOFMEMORY
  729. //
  730. //--------------------------------------------------------------------------
  731. HRESULT CSCMProcessControl::InitializeEnumerator()
  732. {
  733. return E_NOTIMPL;
  734. }
  735. // IUnknown implementation for CSCMProcessControl
  736. STDMETHODIMP CSCMProcessControl::QueryInterface(REFIID riid, void** ppv)
  737. {
  738. HRESULT hr = S_OK;
  739. if (!ppv)
  740. return E_POINTER;
  741. *ppv = NULL;
  742. if (riid == IID_IUnknown || riid == IID_ISCMProcessControl)
  743. {
  744. *ppv = (void*)this;
  745. AddRef();
  746. return S_OK;
  747. }
  748. /*
  749. else if (riid == IID_IEnumSCMProcessInfo)
  750. {
  751. if (!_bInitializedEnum)
  752. {
  753. // First time we've been QI'd for this interface; create an
  754. // enumerator object to aggregate over.
  755. hr = InitializeEnumerator();
  756. _bInitializedEnum = TRUE;
  757. }
  758. if (SUCCEEDED(hr))
  759. {
  760. hr = _SPEnum.QueryInterface(riid, ppv);
  761. }
  762. return hr;
  763. }
  764. */
  765. return E_NOINTERFACE;
  766. }
  767. STDMETHODIMP_(ULONG) CSCMProcessControl::AddRef()
  768. {
  769. return InterlockedIncrement(&_lRefs);
  770. }
  771. STDMETHODIMP_(ULONG) CSCMProcessControl::Release()
  772. {
  773. LONG lRefs = InterlockedDecrement(&_lRefs);
  774. if (lRefs == 0)
  775. {
  776. delete this;
  777. }
  778. return lRefs;
  779. }
  780. //+-------------------------------------------------------------------------
  781. //
  782. // Implementation of CSCMProcessEnumerator begins here
  783. //
  784. //--------------------------------------------------------------------------
  785. //
  786. // ctor used by the CSCMProcessControl object
  787. //
  788. CSCMProcessEnumerator::CSCMProcessEnumerator() :
  789. _lRefs(1),
  790. _dwNumSPInfos(0),
  791. _dwMaxSPInfos(SPENUM_INITIAL_SIZE),
  792. _dwCurSPInfo(0),
  793. _ppSPInfos(NULL),
  794. _ppSPInfosForReal(_pSPInfosInitial),
  795. _pOuterUnk(NULL)
  796. {
  797. ZeroMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * SPENUM_INITIAL_SIZE);
  798. }
  799. //
  800. // ctor used by the Clone method to create new copies of an enumerator
  801. //
  802. CSCMProcessEnumerator::CSCMProcessEnumerator(CSCMProcessEnumerator* pCSPEOrig,
  803. HRESULT* phrInit) :
  804. _lRefs(1),
  805. _dwNumSPInfos(0), // this gets adjusted in the loop below
  806. _dwMaxSPInfos(pCSPEOrig->_dwMaxSPInfos),
  807. _dwCurSPInfo(pCSPEOrig->_dwCurSPInfo),
  808. _pOuterUnk(NULL)
  809. {
  810. ZeroMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * SPENUM_INITIAL_SIZE);
  811. if (_dwMaxSPInfos == SPENUM_INITIAL_SIZE)
  812. {
  813. // The src enumerator did not grown beyond SPENUM_INITIAL_SIZE
  814. _ppSPInfosForReal = _pSPInfosInitial;
  815. }
  816. else
  817. {
  818. // The src enumerator did grow, so we need to create an array
  819. // to hold everything
  820. _ppSPInfos = new SCMProcessInfo*[_dwMaxSPInfos];
  821. if (!_ppSPInfos)
  822. {
  823. *phrInit = E_OUTOFMEMORY;
  824. return;
  825. }
  826. ZeroMemory(_ppSPInfos, sizeof(SCMProcessInfo*) * _dwMaxSPInfos);
  827. _ppSPInfosForReal = _ppSPInfos;
  828. }
  829. // Make copies of each of the original enumerator's SCMProcessInfo structs
  830. DWORD dwNumSPInfosInOriginal = pCSPEOrig->_dwNumSPInfos;
  831. for (DWORD i = 0; i < dwNumSPInfosInOriginal; i++)
  832. {
  833. *phrInit = CSCMProcessControl::CopySCMProcessInfo(pCSPEOrig->_ppSPInfos[i], &(_ppSPInfosForReal[i]));
  834. if (FAILED(*phrInit))
  835. return;
  836. _dwNumSPInfos++;
  837. }
  838. }
  839. //
  840. // ctor used when we are aggregated by the CSCMProcessControl object
  841. //
  842. CSCMProcessEnumerator::CSCMProcessEnumerator(CSCMProcessControl* pOuterUnk) :
  843. _lRefs(-1), // don't use refcount when we are aggregated
  844. _dwNumSPInfos(0),
  845. _dwMaxSPInfos(SPENUM_INITIAL_SIZE),
  846. _dwCurSPInfo(0),
  847. _ppSPInfosForReal(_pSPInfosInitial),
  848. _pOuterUnk(pOuterUnk) // not refcounted!
  849. {
  850. }
  851. //
  852. // dtor
  853. //
  854. CSCMProcessEnumerator::~CSCMProcessEnumerator()
  855. {
  856. #ifdef DBG
  857. if (_pOuterUnk)
  858. ASSERT(_lRefs == -1);
  859. else
  860. ASSERT(_lRefs == 0);
  861. #endif
  862. for (DWORD i = 0; i < _dwNumSPInfos; i++)
  863. {
  864. CSCMProcessControl::FreeSCMProcessInfoPriv(&(_ppSPInfosForReal[i]));
  865. }
  866. #ifdef DBG
  867. for (DWORD j = i; j < _dwMaxSPInfos; j++)
  868. {
  869. ASSERT(_ppSPInfosForReal[j] == NULL);
  870. }
  871. #endif
  872. if (_ppSPInfos)
  873. {
  874. ASSERT(_dwMaxSPInfos > SPENUM_INITIAL_SIZE);
  875. delete _ppSPInfos;
  876. }
  877. }
  878. //+-------------------------------------------------------------------------
  879. //
  880. // Function: Next
  881. //
  882. // Synopsis: Returns to the caller the requested # of SCMProcessInfo
  883. // ptrs.
  884. //
  885. // Arguments: cElems -- # of requested structs
  886. // ppSPI -- ptr to an array of size cElems
  887. // pcFetched -- out param containg # of elements actually
  888. // fetched; can be NULL.
  889. //
  890. // Returns: S_OK - the requested # of elements were returned
  891. // S_FALSE -- only some of the requested # of elements were returned
  892. // E_INVALIDARG -- one or more parameters were bogus
  893. //
  894. // Notes: the caller's ppSPI array, on success, will contain ptrs to the
  895. // enumerator's SPI structs. The caller may only use his ptrs while
  896. // he holds a reference on the enumerator.
  897. //
  898. //--------------------------------------------------------------------------
  899. STDMETHODIMP CSCMProcessEnumerator::Next(ULONG cElems, SCMProcessInfo** ppSPI, ULONG* pcFetched)
  900. {
  901. if (!ppSPI)
  902. return E_INVALIDARG;
  903. ZeroMemory(ppSPI, sizeof(SCMProcessInfo*) * cElems);
  904. DWORD dwFetched = 0;
  905. for (DWORD i = _dwCurSPInfo; (i < _dwNumSPInfos) && (dwFetched < cElems); i++, dwFetched++)
  906. {
  907. ppSPI[dwFetched] = _ppSPInfosForReal[i];
  908. }
  909. // tell the caller how many he's getting, if he cared
  910. if (pcFetched)
  911. *pcFetched = dwFetched;
  912. // Advance the cursor
  913. _dwCurSPInfo += dwFetched;
  914. return (dwFetched == cElems) ? S_OK : S_FALSE;
  915. }
  916. //+-------------------------------------------------------------------------
  917. //
  918. // Function: Skip
  919. //
  920. // Synopsis: Advances the enumerator's "cursor"/ptr by the specified #
  921. // of elements
  922. //
  923. // Arguments: cElems -- the # of elements to advance the cursor by
  924. //
  925. // Returns: S_OK - success
  926. // S_FALSE - there were not a sufficient # of elements to advance
  927. // that many by. The cursor now points to the last element.
  928. //
  929. //--------------------------------------------------------------------------
  930. STDMETHODIMP CSCMProcessEnumerator::Skip(ULONG cElems)
  931. {
  932. _dwCurSPInfo += cElems;
  933. if (_dwCurSPInfo > _dwNumSPInfos)
  934. {
  935. _dwCurSPInfo = _dwNumSPInfos;
  936. return S_FALSE;
  937. }
  938. else
  939. return S_OK;
  940. }
  941. //+-------------------------------------------------------------------------
  942. //
  943. // Function: Reset
  944. //
  945. // Synopsis: Resets the enumerator "cursor"/ptr to the initial element
  946. //
  947. // Arguments: none
  948. //
  949. // Returns: S_OK
  950. //
  951. STDMETHODIMP CSCMProcessEnumerator::Reset()
  952. {
  953. _dwCurSPInfo = 0;
  954. return S_OK;
  955. }
  956. //+-------------------------------------------------------------------------
  957. //
  958. // Function: Clone
  959. //
  960. // Synopsis: Creates a copy of this enumerator and returns it.
  961. //
  962. // Arguments: ppESPI -- out-param for newly created copy
  963. //
  964. // Returns: S_OK - life is good
  965. // E_INVALIDARG - bad input parameter
  966. // E_OUTOFMEMORY
  967. //
  968. //--------------------------------------------------------------------------
  969. STDMETHODIMP CSCMProcessEnumerator::Clone(IEnumSCMProcessInfo **ppESPI)
  970. {
  971. HRESULT hr = S_OK;
  972. if (!ppESPI)
  973. return E_INVALIDARG;
  974. *ppESPI = NULL;
  975. CSCMProcessEnumerator* pNewEnum = new CSCMProcessEnumerator(this, &hr);
  976. if (!pNewEnum)
  977. return E_OUTOFMEMORY;
  978. if (SUCCEEDED(hr))
  979. {
  980. hr = pNewEnum->QueryInterface(IID_IEnumSCMProcessInfo, (void**)ppESPI);
  981. }
  982. pNewEnum->Release();
  983. return hr;
  984. }
  985. //+-------------------------------------------------------------------------
  986. //
  987. // Function: AddProcess
  988. //
  989. // Synopsis: Adds the supplied SCMProcessInfo struct to the list managed
  990. // by this enumerator.
  991. //
  992. // Arguments: pSPI -- SCMProcessInfo struct to be added
  993. //
  994. // Returns: S_OK - new struct was successfully added
  995. // E_OUTOFMEMORY
  996. //
  997. // Notes: the list of SCMProcessInfo's managed by this enumerator is
  998. // implemented as a fixed-size array which is grown on demand.
  999. // This enumerator owns freeing the pSPI struct once added.
  1000. //
  1001. //--------------------------------------------------------------------------
  1002. HRESULT CSCMProcessEnumerator::AddProcess(SCMProcessInfo* pSPI)
  1003. {
  1004. ASSERT(pSPI);
  1005. if (!pSPI)
  1006. return E_INVALIDARG;
  1007. // Time to grow the array?
  1008. if (_dwNumSPInfos == _dwMaxSPInfos)
  1009. {
  1010. DWORD dwNewArraySize = _dwMaxSPInfos + SPENUM_GROWTH_SIZEADD; // 10,20,30, etc
  1011. SCMProcessInfo** ppSPInfosNew = new SCMProcessInfo*[dwNewArraySize];
  1012. if (!ppSPInfosNew)
  1013. return E_OUTOFMEMORY;
  1014. // Zero everything out
  1015. ZeroMemory(ppSPInfosNew, sizeof(SCMProcessInfo*) * dwNewArraySize);
  1016. // Copy over the contents of the old array
  1017. CopyMemory(ppSPInfosNew, _ppSPInfosForReal, sizeof(SCMProcessInfo*) * _dwMaxSPInfos);
  1018. #ifdef DBG
  1019. // Fill in the old array with a dummy value
  1020. FillMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * _dwMaxSPInfos, 0xba);
  1021. #endif
  1022. if (_dwMaxSPInfos > SPENUM_INITIAL_SIZE)
  1023. {
  1024. // We're growing larger than a previous dynamic array; cleanup
  1025. // the old memory
  1026. ASSERT(_ppSPInfos);
  1027. delete _ppSPInfos;
  1028. }
  1029. _ppSPInfos = ppSPInfosNew;
  1030. _ppSPInfosForReal = _ppSPInfos;
  1031. _dwMaxSPInfos = dwNewArraySize;
  1032. }
  1033. // Store the new SCMProcessInfo struct
  1034. _ppSPInfosForReal[_dwNumSPInfos] = pSPI;
  1035. _dwNumSPInfos++;
  1036. return S_OK;
  1037. }
  1038. // IUnknown implementation for CSCMProcessEnumerator
  1039. STDMETHODIMP CSCMProcessEnumerator::QueryInterface(REFIID riid, void** ppv)
  1040. {
  1041. if (!ppv)
  1042. return E_POINTER;
  1043. if (riid == IID_IUnknown || riid == IID_IEnumSCMProcessInfo)
  1044. {
  1045. if (_pOuterUnk && riid == IID_IUnknown)
  1046. return _pOuterUnk->QueryInterface(riid, ppv);
  1047. *ppv = (void*)this;
  1048. AddRef();
  1049. return S_OK;
  1050. }
  1051. else if (_pOuterUnk)
  1052. {
  1053. // Unknown interface, let punkouter take care of it
  1054. return _pOuterUnk->QueryInterface(riid, ppv);
  1055. }
  1056. return E_NOINTERFACE;
  1057. }
  1058. STDMETHODIMP_(ULONG) CSCMProcessEnumerator::AddRef()
  1059. {
  1060. if (_pOuterUnk)
  1061. return _pOuterUnk->AddRef();
  1062. return InterlockedIncrement(&_lRefs);
  1063. }
  1064. STDMETHODIMP_(ULONG) CSCMProcessEnumerator::Release()
  1065. {
  1066. if (_pOuterUnk)
  1067. return _pOuterUnk->Release();
  1068. LONG lRefs = InterlockedDecrement(&_lRefs);
  1069. if (lRefs == 0)
  1070. {
  1071. delete this;
  1072. }
  1073. return lRefs;
  1074. }
  1075. //+-------------------------------------------------------------------------
  1076. //
  1077. // Function: FreeSPIFromCProcess
  1078. //
  1079. // Synopsis: CProcess's don't know about CSCMProcessControl stuff. This is
  1080. // helper function which CProcess extern's in order to call
  1081. //
  1082. //--------------------------------------------------------------------------
  1083. HRESULT FreeSPIFromCProcess(void** ppSCMProcessInfo)
  1084. {
  1085. return CSCMProcessControl::FreeSCMProcessInfoPriv((SCMProcessInfo**)ppSCMProcessInfo);
  1086. }
  1087. //+-------------------------------------------------------------------------
  1088. //
  1089. // Function: PrivGetRPCSSInfo
  1090. //
  1091. // Synopsis: Activators that call GetRPCSSInfo (exported from rpcss.dll)
  1092. // end up in this function; they call here in order to get an
  1093. // interface on which they can query & adjust the scm activation state.
  1094. //
  1095. // History: 05-Sep-99 JSimmons Created
  1096. //
  1097. //--------------------------------------------------------------------------
  1098. HRESULT PrivGetRPCSSInfo(REFCLSID rclsid, REFIID riid, void** ppv)
  1099. {
  1100. HRESULT hr = E_INVALIDARG;
  1101. if (!ppv)
  1102. return E_POINTER;
  1103. if (rclsid == CLSID_RPCSSInfo)
  1104. {
  1105. CSCMProcessControl* pSPC = NULL;
  1106. pSPC = new CSCMProcessControl();
  1107. if (pSPC)
  1108. {
  1109. hr = pSPC->QueryInterface(riid, ppv);
  1110. if (FAILED(hr))
  1111. delete pSPC;
  1112. }
  1113. else
  1114. {
  1115. hr = E_OUTOFMEMORY;
  1116. }
  1117. }
  1118. return hr;
  1119. };