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

1301 lines
36 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_) && !defined(_CHICAGO_)
  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;
  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. pSPI->ulNumClasses = pprocess->_ulClasses;
  532. pSPI->pCLSIDs = (CLSID*) (pwszWinSta + ulWinstaStrlen);
  533. CClassReg* pReg = (CClassReg*)pprocess->_listClasses.First();
  534. while (pReg)
  535. {
  536. pSPI->pCLSIDs[ulCLSID] = pReg->_Guid;
  537. pReg = (CClassReg*)pReg->Next();
  538. ulCLSID++;
  539. }
  540. }
  541. ASSERT(ulCLSID == pprocess->_ulClasses);
  542. pSPI->pidProcess = pprocess->GetPID();
  543. // We hold a reference on the CProcess object, which owns the process handle until
  544. // it goes away. So it's safe to store the handle directly like this.
  545. // The handle may be NULL if we didn't launch the process, callers have the responsibility
  546. // of checking for this.
  547. pSPI->hProcess = pprocess->GetProcessHandle();
  548. // We hold a reference on the CProcess object, which holds a reference on it's CToken
  549. // object. So it's safe to store the token directly like this, it won't go away.
  550. pSPI->hImpersonationToken = pprocess->GetToken()->GetToken();
  551. // The process will only have a ScmProcessReg if it is a COM+ app
  552. if (pprocess->_pScmProcessReg)
  553. {
  554. pSPI->dwState |= SPIF_COMPLUS;
  555. pSPI->AppId = pprocess->_pScmProcessReg->ProcessGUID;
  556. // flip the ready bit
  557. if (pprocess->_pScmProcessReg->ReadinessStatus & SERVERSTATE_READY)
  558. {
  559. pSPI->dwState |= SPIF_READY;
  560. }
  561. }
  562. else
  563. {
  564. // Legacy-style server. We consider the process to be "ready" if it's
  565. // not in the midst of doing class registrations. The caller tells us this.
  566. if (bProcessReady)
  567. {
  568. pSPI->dwState |= SPIF_READY;
  569. }
  570. }
  571. if (pprocess->IsSuspended())
  572. pSPI->dwState |= SPIF_SUSPENDED;
  573. if (pprocess->IsRetired())
  574. pSPI->dwState |= SPIF_RETIRED;
  575. if (pprocess->IsPaused())
  576. pSPI->dwState |= SPIF_PAUSED;
  577. pSPI->ftCreated = *(pprocess->GetFileTimeCreated());
  578. // UNDONE: server type and identity. Still working on the exact details of this
  579. //pSPI->ServerType =
  580. //if (pSPI->ServerType != SET_SERVICE_
  581. // pSPI->ServerIdent =
  582. // Before we leave the lock, we need to replace the cached struct in the process object
  583. // with the new one; this also clears the dirty bit on the process
  584. pprocess->SetSCMProcessInfo((void*)pSPI);
  585. // Lastly, make a new copy to return to the caller
  586. hr = CopySCMProcessInfo(pSPI, ppSPI);
  587. gpServerLock->UnlockExclusive();
  588. return hr;
  589. }
  590. //+-------------------------------------------------------------------------
  591. //
  592. // Function: FreeSCMProcessInfoPriv
  593. //
  594. // Synopsis: Method that knows how to free a SCMProcessInfo structure,
  595. // including of course its constituent members.
  596. //
  597. // Arguments: ppSCMProcessInfo -- ptr-ptr to the SCMProcessInfo struct
  598. //
  599. // Returns: S_OK - life is good
  600. // E_INVALIDARG -- bad parameter
  601. //
  602. // Note: refer to the header comments for FillInSCMProcessInfo for info
  603. // on the extended layout of a SCMProcessInfo struct.
  604. //
  605. //--------------------------------------------------------------------------
  606. HRESULT CSCMProcessControl::FreeSCMProcessInfoPriv(SCMProcessInfo** ppSCMProcessInfo)
  607. {
  608. if (!ppSCMProcessInfo)
  609. return E_INVALIDARG;
  610. if (*ppSCMProcessInfo)
  611. {
  612. // Decrement the struct ref count; it will not fall to zero until the CProcess*
  613. // object releases its reference, which will not happen unless it is either
  614. // a) rundown; or b) replacing a previous dirty SPI with a new one
  615. LONG lRefs = InterlockedDecrement(SPI_TO_REFCOUNT(*ppSCMProcessInfo));
  616. if (lRefs == 0)
  617. {
  618. (*SPI_TO_CPROCESS(*ppSCMProcessInfo))->Release();
  619. delete (*ppSCMProcessInfo);
  620. }
  621. *ppSCMProcessInfo = NULL;
  622. }
  623. return S_OK;
  624. }
  625. //+-------------------------------------------------------------------------
  626. //
  627. // Function: CopySCMProcessInfo
  628. //
  629. // Synopsis: Allocates and fills in a SCMProcessInfo structure for the
  630. // given CProcess server.
  631. //
  632. // Arguments: pSPISrc -- ptr to the SCMProcessInfo struct that is to be copied
  633. // ppSPIDest -- ptrptr to store the copied struct
  634. //
  635. // Returns: S_OK - success
  636. // E_OUTOFMEMORY
  637. //
  638. //--------------------------------------------------------------------------
  639. HRESULT CSCMProcessControl::CopySCMProcessInfo(SCMProcessInfo* pSPISrc, SCMProcessInfo** ppSPIDest)
  640. {
  641. ASSERT(pSPISrc && ppSPIDest);
  642. if (!pSPISrc || !ppSPIDest)
  643. return E_INVALIDARG;
  644. LONG lNewRefs = InterlockedIncrement(SPI_TO_REFCOUNT(pSPISrc));
  645. *ppSPIDest = pSPISrc;
  646. return S_OK;
  647. };
  648. //+-------------------------------------------------------------------------
  649. //
  650. // Function: FindAppOrClass
  651. //
  652. // Synopsis: This is a generic helper function used by the FindApplication
  653. // and FindClass methods. The logic is the same for either.
  654. //
  655. // Arguments: rguid -- the appid or clsid to use in the query
  656. // pServerTable - the table to use in the query
  657. // ppESPI -- the place to store the resulting enumerator object
  658. //
  659. // Returns: S_OK - success
  660. // E_OUTOFMEMORY
  661. //
  662. //--------------------------------------------------------------------------
  663. HRESULT CSCMProcessControl::FindAppOrClass(const GUID& rguid, CServerTable* pServerTable, IEnumSCMProcessInfo** ppESPI)
  664. {
  665. HRESULT hr;
  666. CSCMProcessEnumerator* pSPEnum = NULL;
  667. CServerTableEntry* pSTE = NULL;
  668. if (!ppESPI)
  669. return E_INVALIDARG;
  670. *ppESPI = NULL;
  671. pSTE = pServerTable->Lookup((GUID&)rguid);
  672. if (!pSTE)
  673. {
  674. return S_OK;
  675. }
  676. pSPEnum = new CSCMProcessEnumerator();
  677. if (!pSPEnum)
  678. {
  679. pSTE->Release();
  680. return E_OUTOFMEMORY;
  681. }
  682. CServerList* pServerList = pSTE->GetServerListWithSharedLock();
  683. ASSERT(pServerList && "unexpected NULL pServerList");
  684. // For each server that has registered for this appid/clsid, add a
  685. // SCMProcessInfo to the enumerator object
  686. CServerListEntry* pSLE = (CServerListEntry*)pServerList->First();
  687. while (pSLE)
  688. {
  689. SCMProcessInfo* pSPI;
  690. CProcess* pprocess = pSLE->GetProcess(); // not refcounted
  691. ASSERT(pprocess);
  692. hr = FillInSCMProcessInfo(pprocess, pSLE->IsReadyForActivations(), &pSPI);
  693. if (SUCCEEDED(hr))
  694. {
  695. // add it to the enumerator; on success, the enumerator owns it
  696. hr = pSPEnum->AddProcess(pSPI);
  697. if (FAILED(hr))
  698. {
  699. FreeSCMProcessInfoPriv(&pSPI); // we still own it, so free the memory
  700. break;
  701. }
  702. }
  703. else
  704. break;
  705. pSLE = (CServerListEntry*) pSLE->Next();
  706. }
  707. pSTE->ReleaseSharedListLock();
  708. if (SUCCEEDED(hr))
  709. {
  710. hr = pSPEnum->QueryInterface(__uuidof(IEnumSCMProcessInfo), (void**)ppESPI);
  711. }
  712. pSPEnum->Release();
  713. pSTE->Release();
  714. return hr;
  715. }
  716. //+-------------------------------------------------------------------------
  717. //
  718. // Function: InitializeEnumerator
  719. //
  720. // Synopsis: Initializes the aggregated enumerator object for use. Mainly
  721. // this consists of adding SCMProcessInfo's for all known servers
  722. // to the enumerator.
  723. //
  724. // Arguments: none
  725. //
  726. // Returns: S_OK
  727. // E_OUTOFMEMORY
  728. //
  729. //--------------------------------------------------------------------------
  730. HRESULT CSCMProcessControl::InitializeEnumerator()
  731. {
  732. return E_NOTIMPL;
  733. }
  734. // IUnknown implementation for CSCMProcessControl
  735. STDMETHODIMP CSCMProcessControl::QueryInterface(REFIID riid, void** ppv)
  736. {
  737. HRESULT hr = S_OK;
  738. if (!ppv)
  739. return E_POINTER;
  740. *ppv = NULL;
  741. if (riid == IID_IUnknown || riid == IID_ISCMProcessControl)
  742. {
  743. *ppv = (void*)this;
  744. AddRef();
  745. return S_OK;
  746. }
  747. /*
  748. else if (riid == IID_IEnumSCMProcessInfo)
  749. {
  750. if (!_bInitializedEnum)
  751. {
  752. // First time we've been QI'd for this interface; create an
  753. // enumerator object to aggregate over.
  754. hr = InitializeEnumerator();
  755. _bInitializedEnum = TRUE;
  756. }
  757. if (SUCCEEDED(hr))
  758. {
  759. hr = _SPEnum.QueryInterface(riid, ppv);
  760. }
  761. return hr;
  762. }
  763. */
  764. return E_NOINTERFACE;
  765. }
  766. STDMETHODIMP_(ULONG) CSCMProcessControl::AddRef()
  767. {
  768. return InterlockedIncrement(&_lRefs);
  769. }
  770. STDMETHODIMP_(ULONG) CSCMProcessControl::Release()
  771. {
  772. LONG lRefs = InterlockedDecrement(&_lRefs);
  773. if (lRefs == 0)
  774. {
  775. delete this;
  776. }
  777. return lRefs;
  778. }
  779. //+-------------------------------------------------------------------------
  780. //
  781. // Implementation of CSCMProcessEnumerator begins here
  782. //
  783. //--------------------------------------------------------------------------
  784. //
  785. // ctor used by the CSCMProcessControl object
  786. //
  787. CSCMProcessEnumerator::CSCMProcessEnumerator() :
  788. _lRefs(1),
  789. _dwNumSPInfos(0),
  790. _dwMaxSPInfos(SPENUM_INITIAL_SIZE),
  791. _dwCurSPInfo(0),
  792. _ppSPInfos(NULL),
  793. _ppSPInfosForReal(_pSPInfosInitial),
  794. _pOuterUnk(NULL)
  795. {
  796. ZeroMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * SPENUM_INITIAL_SIZE);
  797. }
  798. //
  799. // ctor used by the Clone method to create new copies of an enumerator
  800. //
  801. CSCMProcessEnumerator::CSCMProcessEnumerator(CSCMProcessEnumerator* pCSPEOrig,
  802. HRESULT* phrInit) :
  803. _lRefs(1),
  804. _dwNumSPInfos(0), // this gets adjusted in the loop below
  805. _dwMaxSPInfos(pCSPEOrig->_dwMaxSPInfos),
  806. _dwCurSPInfo(pCSPEOrig->_dwCurSPInfo),
  807. _pOuterUnk(NULL)
  808. {
  809. ZeroMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * SPENUM_INITIAL_SIZE);
  810. if (_dwMaxSPInfos == SPENUM_INITIAL_SIZE)
  811. {
  812. // The src enumerator did not grown beyond SPENUM_INITIAL_SIZE
  813. _ppSPInfosForReal = _pSPInfosInitial;
  814. }
  815. else
  816. {
  817. // The src enumerator did grow, so we need to create an array
  818. // to hold everything
  819. _ppSPInfos = new SCMProcessInfo*[_dwMaxSPInfos];
  820. if (!_ppSPInfos)
  821. {
  822. *phrInit = E_OUTOFMEMORY;
  823. return;
  824. }
  825. ZeroMemory(_ppSPInfos, sizeof(SCMProcessInfo*) * _dwMaxSPInfos);
  826. _ppSPInfosForReal = _ppSPInfos;
  827. }
  828. // Make copies of each of the original enumerator's SCMProcessInfo structs
  829. DWORD dwNumSPInfosInOriginal = pCSPEOrig->_dwNumSPInfos;
  830. for (DWORD i = 0; i < dwNumSPInfosInOriginal; i++)
  831. {
  832. *phrInit = CSCMProcessControl::CopySCMProcessInfo(pCSPEOrig->_ppSPInfos[i], &(_ppSPInfosForReal[i]));
  833. if (FAILED(*phrInit))
  834. return;
  835. _dwNumSPInfos++;
  836. }
  837. }
  838. //
  839. // ctor used when we are aggregated by the CSCMProcessControl object
  840. //
  841. CSCMProcessEnumerator::CSCMProcessEnumerator(CSCMProcessControl* pOuterUnk) :
  842. _lRefs(-1), // don't use refcount when we are aggregated
  843. _dwNumSPInfos(0),
  844. _dwMaxSPInfos(SPENUM_INITIAL_SIZE),
  845. _dwCurSPInfo(0),
  846. _ppSPInfosForReal(_pSPInfosInitial),
  847. _pOuterUnk(pOuterUnk) // not refcounted!
  848. {
  849. }
  850. //
  851. // dtor
  852. //
  853. CSCMProcessEnumerator::~CSCMProcessEnumerator()
  854. {
  855. #ifdef DBG
  856. if (_pOuterUnk)
  857. ASSERT(_lRefs == -1);
  858. else
  859. ASSERT(_lRefs == 0);
  860. #endif
  861. for (DWORD i = 0; i < _dwNumSPInfos; i++)
  862. {
  863. CSCMProcessControl::FreeSCMProcessInfoPriv(&(_ppSPInfosForReal[i]));
  864. }
  865. #ifdef DBG
  866. for (DWORD j = i; j < _dwMaxSPInfos; j++)
  867. {
  868. ASSERT(_ppSPInfosForReal[j] == NULL);
  869. }
  870. #endif
  871. if (_ppSPInfos)
  872. {
  873. ASSERT(_dwMaxSPInfos > SPENUM_INITIAL_SIZE);
  874. delete _ppSPInfos;
  875. }
  876. }
  877. //+-------------------------------------------------------------------------
  878. //
  879. // Function: Next
  880. //
  881. // Synopsis: Returns to the caller the requested # of SCMProcessInfo
  882. // ptrs.
  883. //
  884. // Arguments: cElems -- # of requested structs
  885. // ppSPI -- ptr to an array of size cElems
  886. // pcFetched -- out param containg # of elements actually
  887. // fetched; can be NULL.
  888. //
  889. // Returns: S_OK - the requested # of elements were returned
  890. // S_FALSE -- only some of the requested # of elements were returned
  891. // E_INVALIDARG -- one or more parameters were bogus
  892. //
  893. // Notes: the caller's ppSPI array, on success, will contain ptrs to the
  894. // enumerator's SPI structs. The caller may only use his ptrs while
  895. // he holds a reference on the enumerator.
  896. //
  897. //--------------------------------------------------------------------------
  898. STDMETHODIMP CSCMProcessEnumerator::Next(ULONG cElems, SCMProcessInfo** ppSPI, ULONG* pcFetched)
  899. {
  900. if (!ppSPI)
  901. return E_INVALIDARG;
  902. ZeroMemory(ppSPI, sizeof(SCMProcessInfo*) * cElems);
  903. DWORD dwFetched = 0;
  904. for (DWORD i = _dwCurSPInfo; (i < _dwNumSPInfos) && (dwFetched < cElems); i++, dwFetched++)
  905. {
  906. ppSPI[dwFetched] = _ppSPInfosForReal[i];
  907. }
  908. // tell the caller how many he's getting, if he cared
  909. if (pcFetched)
  910. *pcFetched = dwFetched;
  911. // Advance the cursor
  912. _dwCurSPInfo += dwFetched;
  913. return (dwFetched == cElems) ? S_OK : S_FALSE;
  914. }
  915. //+-------------------------------------------------------------------------
  916. //
  917. // Function: Skip
  918. //
  919. // Synopsis: Advances the enumerator's "cursor"/ptr by the specified #
  920. // of elements
  921. //
  922. // Arguments: cElems -- the # of elements to advance the cursor by
  923. //
  924. // Returns: S_OK - success
  925. // S_FALSE - there were not a sufficient # of elements to advance
  926. // that many by. The cursor now points to the last element.
  927. //
  928. //--------------------------------------------------------------------------
  929. STDMETHODIMP CSCMProcessEnumerator::Skip(ULONG cElems)
  930. {
  931. _dwCurSPInfo += cElems;
  932. if (_dwCurSPInfo > _dwNumSPInfos)
  933. {
  934. _dwCurSPInfo = _dwNumSPInfos;
  935. return S_FALSE;
  936. }
  937. else
  938. return S_OK;
  939. }
  940. //+-------------------------------------------------------------------------
  941. //
  942. // Function: Reset
  943. //
  944. // Synopsis: Resets the enumerator "cursor"/ptr to the initial element
  945. //
  946. // Arguments: none
  947. //
  948. // Returns: S_OK
  949. //
  950. STDMETHODIMP CSCMProcessEnumerator::Reset()
  951. {
  952. _dwCurSPInfo = 0;
  953. return S_OK;
  954. }
  955. //+-------------------------------------------------------------------------
  956. //
  957. // Function: Clone
  958. //
  959. // Synopsis: Creates a copy of this enumerator and returns it.
  960. //
  961. // Arguments: ppESPI -- out-param for newly created copy
  962. //
  963. // Returns: S_OK - life is good
  964. // E_INVALIDARG - bad input parameter
  965. // E_OUTOFMEMORY
  966. //
  967. //--------------------------------------------------------------------------
  968. STDMETHODIMP CSCMProcessEnumerator::Clone(IEnumSCMProcessInfo **ppESPI)
  969. {
  970. HRESULT hr;
  971. if (!ppESPI)
  972. return E_INVALIDARG;
  973. *ppESPI = NULL;
  974. CSCMProcessEnumerator* pNewEnum = new CSCMProcessEnumerator(this, &hr);
  975. if (!pNewEnum)
  976. return E_OUTOFMEMORY;
  977. if (SUCCEEDED(hr))
  978. {
  979. hr = pNewEnum->QueryInterface(IID_IEnumSCMProcessInfo, (void**)ppESPI);
  980. }
  981. pNewEnum->Release();
  982. return hr;
  983. }
  984. //+-------------------------------------------------------------------------
  985. //
  986. // Function: AddProcess
  987. //
  988. // Synopsis: Adds the supplied SCMProcessInfo struct to the list managed
  989. // by this enumerator.
  990. //
  991. // Arguments: pSPI -- SCMProcessInfo struct to be added
  992. //
  993. // Returns: S_OK - new struct was successfully added
  994. // E_OUTOFMEMORY
  995. //
  996. // Notes: the list of SCMProcessInfo's managed by this enumerator is
  997. // implemented as a fixed-size array which is grown on demand.
  998. // This enumerator owns freeing the pSPI struct once added.
  999. //
  1000. //--------------------------------------------------------------------------
  1001. HRESULT CSCMProcessEnumerator::AddProcess(SCMProcessInfo* pSPI)
  1002. {
  1003. ASSERT(pSPI);
  1004. if (!pSPI)
  1005. return E_INVALIDARG;
  1006. // Time to grow the array?
  1007. if (_dwNumSPInfos == _dwMaxSPInfos)
  1008. {
  1009. DWORD dwNewArraySize = _dwMaxSPInfos + SPENUM_GROWTH_SIZEADD; // 10,20,30, etc
  1010. SCMProcessInfo** ppSPInfosNew = new SCMProcessInfo*[dwNewArraySize];
  1011. if (!ppSPInfosNew)
  1012. return E_OUTOFMEMORY;
  1013. // Zero everything out
  1014. ZeroMemory(ppSPInfosNew, sizeof(SCMProcessInfo*) * dwNewArraySize);
  1015. // Copy over the contents of the old array
  1016. CopyMemory(ppSPInfosNew, _ppSPInfosForReal, sizeof(SCMProcessInfo*) * _dwMaxSPInfos);
  1017. #ifdef DBG
  1018. // Fill in the old array with a dummy value
  1019. FillMemory(_pSPInfosInitial, sizeof(SCMProcessInfo*) * _dwMaxSPInfos, 0xba);
  1020. #endif
  1021. if (_dwMaxSPInfos > SPENUM_INITIAL_SIZE)
  1022. {
  1023. // We're growing larger than a previous dynamic array; cleanup
  1024. // the old memory
  1025. ASSERT(_ppSPInfos);
  1026. delete _ppSPInfos;
  1027. }
  1028. _ppSPInfos = ppSPInfosNew;
  1029. _ppSPInfosForReal = _ppSPInfos;
  1030. _dwMaxSPInfos = dwNewArraySize;
  1031. }
  1032. // Store the new SCMProcessInfo struct
  1033. _ppSPInfosForReal[_dwNumSPInfos] = pSPI;
  1034. _dwNumSPInfos++;
  1035. return S_OK;
  1036. }
  1037. // IUnknown implementation for CSCMProcessEnumerator
  1038. STDMETHODIMP CSCMProcessEnumerator::QueryInterface(REFIID riid, void** ppv)
  1039. {
  1040. if (!ppv)
  1041. return E_POINTER;
  1042. if (riid == IID_IUnknown || riid == IID_IEnumSCMProcessInfo)
  1043. {
  1044. if (_pOuterUnk && riid == IID_IUnknown)
  1045. return _pOuterUnk->QueryInterface(riid, ppv);
  1046. *ppv = (void*)this;
  1047. AddRef();
  1048. return S_OK;
  1049. }
  1050. else if (_pOuterUnk)
  1051. {
  1052. // Unknown interface, let punkouter take care of it
  1053. return _pOuterUnk->QueryInterface(riid, ppv);
  1054. }
  1055. return E_NOINTERFACE;
  1056. }
  1057. STDMETHODIMP_(ULONG) CSCMProcessEnumerator::AddRef()
  1058. {
  1059. if (_pOuterUnk)
  1060. return _pOuterUnk->AddRef();
  1061. return InterlockedIncrement(&_lRefs);
  1062. }
  1063. STDMETHODIMP_(ULONG) CSCMProcessEnumerator::Release()
  1064. {
  1065. if (_pOuterUnk)
  1066. return _pOuterUnk->Release();
  1067. LONG lRefs = InterlockedDecrement(&_lRefs);
  1068. if (lRefs == 0)
  1069. {
  1070. delete this;
  1071. }
  1072. return lRefs;
  1073. }
  1074. //+-------------------------------------------------------------------------
  1075. //
  1076. // Function: FreeSPIFromCProcess
  1077. //
  1078. // Synopsis: CProcess's don't know about CSCMProcessControl stuff. This is
  1079. // helper function which CProcess extern's in order to call
  1080. //
  1081. //--------------------------------------------------------------------------
  1082. HRESULT FreeSPIFromCProcess(void** ppSCMProcessInfo)
  1083. {
  1084. return CSCMProcessControl::FreeSCMProcessInfoPriv((SCMProcessInfo**)ppSCMProcessInfo);
  1085. }
  1086. //+-------------------------------------------------------------------------
  1087. //
  1088. // Function: PrivGetRPCSSInfo
  1089. //
  1090. // Synopsis: Activators that call GetRPCSSInfo (exported from rpcss.dll)
  1091. // end up in this function; they call here in order to get an
  1092. // interface on which they can query & adjust the scm activation state.
  1093. //
  1094. // History: 05-Sep-99 JSimmons Created
  1095. //
  1096. //--------------------------------------------------------------------------
  1097. HRESULT PrivGetRPCSSInfo(REFCLSID rclsid, REFIID riid, void** ppv)
  1098. {
  1099. HRESULT hr = E_INVALIDARG;
  1100. if (!ppv)
  1101. return E_POINTER;
  1102. if (rclsid == CLSID_RPCSSInfo)
  1103. {
  1104. CSCMProcessControl* pSPC = NULL;
  1105. pSPC = new CSCMProcessControl();
  1106. if (pSPC)
  1107. {
  1108. hr = pSPC->QueryInterface(riid, ppv);
  1109. if (FAILED(hr))
  1110. delete pSPC;
  1111. }
  1112. else
  1113. {
  1114. hr = E_OUTOFMEMORY;
  1115. }
  1116. }
  1117. return hr;
  1118. };