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.

829 lines
20 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Main
  6. File: perfdef.h
  7. Owner: DmitryR
  8. Data definitions shared between asp.dll and aspperf.dll
  9. ===================================================================*/
  10. #ifndef _ASP_PERFDEF_H
  11. #define _ASP_PERFDEF_H
  12. #include <pudebug.h>
  13. /*===================================================================
  14. Definitions of names, sizes and mapped data block structures
  15. ===================================================================*/
  16. // Mutex name to access the main file map
  17. #define SZ_PERF_MUTEX "Global\\ASP_PERFMON_MUTEX"
  18. // WaitForSingleObject arg (how long to wait for mutext before failing)
  19. #define PERM_MUTEX_WAIT 1000
  20. // Main shared file map name
  21. #define SZ_PERF_MAIN_FILEMAP "Global\\ASP_PERFMON_MAIN_BLOCK"
  22. // Max number of registered (ASP) processes in main file map
  23. #define C_PERF_PROC_MAX 1024
  24. // Structure that defines main file map
  25. struct CPerfMainBlockData
  26. {
  27. DWORD m_dwTimestamp; // time (GetTickCount()) of the last change
  28. DWORD m_cItems; // number of registred processes
  29. // array of process WAM CLS IDs
  30. CLSID m_rgClsIds[C_PERF_PROC_MAX];
  31. };
  32. #define CB_PERF_MAIN_BLOCK (sizeof(struct CPerfMainBlockData))
  33. // Name for per-process file map
  34. #define SZ_PERF_PROC_FILEMAP_PREFIX "Global\\ASP_PERFMON_BLOCK_"
  35. #define CCH_PERF_PROC_FILEMAP_PREFIX 25
  36. // Number of counters in per-process file map
  37. #define C_PERF_PROC_COUNTERS 37
  38. struct CPerfProcBlockData
  39. {
  40. CLSID m_ClsId; // process CLS ID
  41. DWORD m_rgdwCounters[C_PERF_PROC_COUNTERS]; // array counters
  42. };
  43. #define CB_PERF_PROC_BLOCK (sizeof(struct CPerfProcBlockData))
  44. #define CB_COUNTERS (sizeof(DWORD) * C_PERF_PROC_COUNTERS)
  45. /*===================================================================
  46. CSharedMemBlock -- generic shared memory block
  47. ===================================================================*/
  48. class CSharedMemBlock
  49. {
  50. private:
  51. HANDLE m_hMemory;
  52. void *m_pMemory;
  53. protected:
  54. SECURITY_ATTRIBUTES m_sa;
  55. public:
  56. inline CSharedMemBlock() : m_hMemory(NULL), m_pMemory(NULL) {
  57. m_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  58. m_sa.lpSecurityDescriptor = NULL;
  59. m_sa.bInheritHandle = FALSE;
  60. }
  61. inline ~CSharedMemBlock() {
  62. UnInitMap();
  63. if (m_sa.lpSecurityDescriptor)
  64. free(m_sa.lpSecurityDescriptor);
  65. }
  66. inline void *PMemory() { return m_pMemory; }
  67. HRESULT InitSD();
  68. HRESULT InitMap(LPCSTR szName, DWORD dwSize);
  69. HRESULT UnInitMap();
  70. private:
  71. HRESULT CreateSids( PSID *ppBuiltInAdministrators,
  72. PSID *ppPowerUsers,
  73. PSID *ppAuthenticatedUsers);
  74. };
  75. //
  76. // CreateSids
  77. //
  78. // Create 3 Security IDs
  79. //
  80. // Caller must free memory allocated to SIDs on success.
  81. //
  82. // Returns: HRESULT indicating SUCCESS or FAILURE
  83. //
  84. inline HRESULT CSharedMemBlock::CreateSids(
  85. PSID *ppBuiltInAdministrators,
  86. PSID *ppPowerUsers,
  87. PSID *ppAuthenticatedUsers
  88. )
  89. {
  90. HRESULT hr = S_OK;
  91. *ppBuiltInAdministrators = NULL;
  92. *ppPowerUsers = NULL;
  93. *ppAuthenticatedUsers = NULL;
  94. //
  95. // An SID is built from an Identifier Authority and a set of Relative IDs
  96. // (RIDs). The Authority of interest to us SECURITY_NT_AUTHORITY.
  97. //
  98. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  99. //
  100. // Each RID represents a sub-unit of the authority. Two of the SIDs we
  101. // want to build, Local Administrators, and Power Users, are in the "built
  102. // in" domain. The other SID, for Authenticated users, is based directly
  103. // off of the authority.
  104. //
  105. // For examples of other useful SIDs consult the list in
  106. // \nt\public\sdk\inc\ntseapi.h.
  107. //
  108. if (!AllocateAndInitializeSid(&NtAuthority,
  109. 2, // 2 sub-authorities
  110. SECURITY_BUILTIN_DOMAIN_RID,
  111. DOMAIN_ALIAS_RID_ADMINS,
  112. 0,0,0,0,0,0,
  113. ppBuiltInAdministrators)) {
  114. hr = HRESULT_FROM_WIN32(GetLastError());
  115. } else if (!AllocateAndInitializeSid(&NtAuthority,
  116. 2, // 2 sub-authorities
  117. SECURITY_BUILTIN_DOMAIN_RID,
  118. DOMAIN_ALIAS_RID_POWER_USERS,
  119. 0,0,0,0,0,0,
  120. ppPowerUsers)) {
  121. hr = HRESULT_FROM_WIN32(GetLastError());
  122. } else if (!AllocateAndInitializeSid(&NtAuthority,
  123. 1, // 1 sub-authority
  124. SECURITY_AUTHENTICATED_USER_RID,
  125. 0,0,0,0,0,0,0,
  126. ppAuthenticatedUsers)) {
  127. hr = HRESULT_FROM_WIN32(GetLastError());
  128. }
  129. if (FAILED(hr)) {
  130. if (*ppBuiltInAdministrators) {
  131. FreeSid(*ppBuiltInAdministrators);
  132. *ppBuiltInAdministrators = NULL;
  133. }
  134. if (*ppPowerUsers) {
  135. FreeSid(*ppPowerUsers);
  136. *ppPowerUsers = NULL;
  137. }
  138. if (*ppAuthenticatedUsers) {
  139. FreeSid(*ppAuthenticatedUsers);
  140. *ppAuthenticatedUsers = NULL;
  141. }
  142. }
  143. return hr;
  144. }
  145. //
  146. // InitSD
  147. //
  148. // Creates a SECURITY_DESCRIPTOR with specific DACLs.
  149. //
  150. inline HRESULT CSharedMemBlock::InitSD()
  151. {
  152. HRESULT hr = S_OK;
  153. PSID pAuthenticatedUsers = NULL;
  154. PSID pBuiltInAdministrators = NULL;
  155. PSID pPowerUsers = NULL;
  156. PSECURITY_DESCRIPTOR pSD = NULL;
  157. if (m_sa.lpSecurityDescriptor != NULL) {
  158. return S_OK;
  159. }
  160. if (FAILED(hr = CreateSids(&pBuiltInAdministrators,
  161. &pPowerUsers,
  162. &pAuthenticatedUsers)));
  163. else {
  164. //
  165. // Calculate the size of and allocate a buffer for the DACL, we need
  166. // this value independently of the total alloc size for ACL init.
  167. //
  168. ULONG AclSize;
  169. //
  170. // "- sizeof (ULONG)" represents the SidStart field of the
  171. // ACCESS_ALLOWED_ACE. Since we're adding the entire length of the
  172. // SID, this field is counted twice.
  173. //
  174. AclSize = sizeof (ACL) +
  175. (3 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) +
  176. GetLengthSid(pAuthenticatedUsers) +
  177. GetLengthSid(pBuiltInAdministrators) +
  178. GetLengthSid(pPowerUsers);
  179. pSD = malloc(SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize);
  180. if (!pSD) {
  181. hr = E_OUTOFMEMORY;
  182. } else {
  183. ACL *Acl;
  184. Acl = (ACL *)((BYTE *)pSD + SECURITY_DESCRIPTOR_MIN_LENGTH);
  185. if (!InitializeAcl(Acl,
  186. AclSize,
  187. ACL_REVISION)) {
  188. hr = HRESULT_FROM_WIN32(GetLastError());
  189. } else if (!AddAccessAllowedAce(Acl,
  190. ACL_REVISION,
  191. SYNCHRONIZE | GENERIC_ALL,
  192. pAuthenticatedUsers)) {
  193. hr = HRESULT_FROM_WIN32(GetLastError());
  194. } else if (!AddAccessAllowedAce(Acl,
  195. ACL_REVISION,
  196. SYNCHRONIZE | GENERIC_ALL,
  197. pPowerUsers)) {
  198. hr = HRESULT_FROM_WIN32(GetLastError());
  199. } else if (!AddAccessAllowedAce(Acl,
  200. ACL_REVISION,
  201. SYNCHRONIZE | GENERIC_ALL,
  202. pBuiltInAdministrators)) {
  203. hr = HRESULT_FROM_WIN32(GetLastError());
  204. } else if (!InitializeSecurityDescriptor(pSD,
  205. SECURITY_DESCRIPTOR_REVISION)) {
  206. hr = HRESULT_FROM_WIN32(GetLastError());
  207. } else if (!SetSecurityDescriptorDacl(pSD,
  208. TRUE,
  209. Acl,
  210. FALSE)) {
  211. hr = HRESULT_FROM_WIN32(GetLastError());
  212. }
  213. }
  214. }
  215. if (pAuthenticatedUsers)
  216. FreeSid(pAuthenticatedUsers);
  217. if (pBuiltInAdministrators)
  218. FreeSid(pBuiltInAdministrators);
  219. if (pPowerUsers)
  220. FreeSid(pPowerUsers);
  221. if (FAILED(hr) && pSD) {
  222. free(pSD);
  223. pSD = NULL;
  224. }
  225. m_sa.lpSecurityDescriptor = pSD;
  226. return hr;
  227. }
  228. inline HRESULT CSharedMemBlock::InitMap
  229. (
  230. LPCSTR szName,
  231. DWORD dwSize
  232. )
  233. {
  234. BOOL fNew = FALSE;
  235. HRESULT hr = S_OK;
  236. if (FAILED(hr = InitSD())) {
  237. return hr;
  238. }
  239. // Try to open existing
  240. m_hMemory = OpenFileMappingA
  241. (
  242. FILE_MAP_ALL_ACCESS,
  243. FALSE,
  244. szName
  245. );
  246. if (!m_hMemory)
  247. {
  248. m_hMemory = CreateFileMappingA
  249. (
  250. INVALID_HANDLE_VALUE,
  251. &m_sa,
  252. PAGE_READWRITE,
  253. 0,
  254. dwSize,
  255. szName
  256. );
  257. fNew = TRUE;
  258. }
  259. if (!m_hMemory)
  260. return E_FAIL;
  261. m_pMemory = MapViewOfFile
  262. (
  263. m_hMemory,
  264. FILE_MAP_ALL_ACCESS,
  265. 0,
  266. 0,
  267. 0
  268. );
  269. if (!m_pMemory)
  270. {
  271. UnInitMap();
  272. return E_FAIL;
  273. }
  274. if (fNew)
  275. memset(m_pMemory, 0, dwSize);
  276. return S_OK;
  277. }
  278. inline HRESULT CSharedMemBlock::UnInitMap()
  279. {
  280. if (m_pMemory)
  281. {
  282. UnmapViewOfFile(m_pMemory);
  283. m_pMemory = NULL;
  284. }
  285. if (m_hMemory)
  286. {
  287. CloseHandle(m_hMemory);
  288. m_hMemory = NULL;
  289. }
  290. return S_OK;
  291. }
  292. /*===================================================================
  293. CPerfProcBlock - class representing pref data for a single process
  294. ===================================================================*/
  295. class CPerfProcBlock : public CSharedMemBlock
  296. {
  297. friend class CPerfMainBlock;
  298. protected:
  299. DWORD m_fInited : 1;
  300. DWORD m_fMemCSInited : 1;
  301. DWORD m_fReqCSInited : 1;
  302. // critical sections (only used in ASP.DLL)
  303. CRITICAL_SECTION m_csMemLock; // CS for memory counters
  304. CRITICAL_SECTION m_csReqLock; // CS for per-request counters
  305. // block of counters
  306. CPerfProcBlockData *m_pData;
  307. // next process data (used in ASPPERF.DLL)
  308. CPerfProcBlock *m_pNext;
  309. // access shared memory
  310. HRESULT MapMemory(const CLSID &ClsId);
  311. public:
  312. inline CPerfProcBlock()
  313. : m_fInited(FALSE),
  314. m_fMemCSInited(FALSE), m_fReqCSInited(FALSE),
  315. m_pData(NULL), m_pNext(NULL)
  316. {}
  317. inline ~CPerfProcBlock() { UnInit(); }
  318. HRESULT InitCriticalSections();
  319. HRESULT InitExternal(const CLSID &ClsId); // from ASPPERF.DLL
  320. HRESULT InitForThisProcess // from ASP.DLL
  321. (
  322. const CLSID &ClsId,
  323. DWORD *pdwInitCounters = NULL
  324. );
  325. HRESULT UnInit();
  326. };
  327. inline HRESULT CPerfProcBlock::MapMemory
  328. (
  329. const CLSID &ClsId
  330. )
  331. {
  332. // Construct unique map name with CLSID
  333. char szMapName[CCH_PERF_PROC_FILEMAP_PREFIX+32+1];
  334. strcpy(szMapName, SZ_PERF_PROC_FILEMAP_PREFIX);
  335. char *pszHex = szMapName + CCH_PERF_PROC_FILEMAP_PREFIX;
  336. DWORD *pdwHex = (DWORD *)&ClsId;
  337. for (int i = 0; i < 4; i++, pszHex += 8, pdwHex++)
  338. sprintf(pszHex, "%08x", *pdwHex);
  339. // create or open the map
  340. HRESULT hr = InitMap(szMapName, CB_PERF_PROC_BLOCK);
  341. if (SUCCEEDED(hr))
  342. {
  343. m_pData = (CPerfProcBlockData *)PMemory();
  344. if (m_pData->m_ClsId == CLSID_NULL)
  345. m_pData->m_ClsId = ClsId;
  346. else if (m_pData->m_ClsId != ClsId)
  347. hr = E_FAIL; // cls id mismatch
  348. }
  349. return hr;
  350. }
  351. inline HRESULT CPerfProcBlock::InitCriticalSections()
  352. {
  353. HRESULT hr = S_OK;
  354. if (!m_fMemCSInited)
  355. {
  356. __try { INITIALIZE_CRITICAL_SECTION(&m_csMemLock); }
  357. __except(1) { hr = E_UNEXPECTED; }
  358. if (SUCCEEDED(hr))
  359. m_fMemCSInited = TRUE;
  360. else
  361. return hr;
  362. }
  363. if (!m_fReqCSInited)
  364. {
  365. __try { INITIALIZE_CRITICAL_SECTION(&m_csReqLock); }
  366. __except(1) { hr = E_UNEXPECTED; }
  367. if (SUCCEEDED(hr))
  368. m_fReqCSInited = TRUE;
  369. else
  370. return hr;
  371. }
  372. return S_OK;
  373. }
  374. inline HRESULT CPerfProcBlock::InitExternal
  375. (
  376. const CLSID &ClsId
  377. )
  378. {
  379. HRESULT hr = MapMemory(ClsId);
  380. if (SUCCEEDED(hr))
  381. m_fInited = TRUE;
  382. else
  383. UnInit();
  384. return hr;
  385. }
  386. inline HRESULT CPerfProcBlock::InitForThisProcess
  387. (
  388. const CLSID &ClsId,
  389. DWORD *pdwInitCounters
  390. )
  391. {
  392. HRESULT hr = S_OK;
  393. // Map the shared memory
  394. if (SUCCEEDED(hr))
  395. hr = MapMemory(ClsId);
  396. if (SUCCEEDED(hr))
  397. {
  398. // init the counters
  399. if (pdwInitCounters)
  400. memcpy(m_pData->m_rgdwCounters, pdwInitCounters, CB_COUNTERS);
  401. else
  402. memset(m_pData->m_rgdwCounters, 0, CB_COUNTERS);
  403. m_fInited = TRUE;
  404. }
  405. else
  406. {
  407. UnInit();
  408. }
  409. return hr;
  410. }
  411. inline HRESULT CPerfProcBlock::UnInit()
  412. {
  413. if (m_fMemCSInited)
  414. {
  415. DeleteCriticalSection(&m_csMemLock);
  416. m_fMemCSInited = FALSE;
  417. }
  418. if (m_fReqCSInited)
  419. {
  420. DeleteCriticalSection(&m_csReqLock);
  421. m_fReqCSInited = FALSE;
  422. }
  423. UnInitMap();
  424. m_pData = NULL;
  425. m_pNext = NULL;
  426. m_fInited = FALSE;
  427. return S_OK;
  428. }
  429. /*===================================================================
  430. CPerfMainBlock - class representing the main perf data
  431. ===================================================================*/
  432. class CPerfMainBlock : public CSharedMemBlock
  433. {
  434. private:
  435. DWORD m_fInited : 1;
  436. // the process block directory
  437. CPerfMainBlockData *m_pData;
  438. // mutex to access the process block directory
  439. HANDLE m_hMutex;
  440. // first process data (used in ASPPERF.DLL)
  441. CPerfProcBlock *m_pProcBlock;
  442. // timestamp of main block when the list of process blocks
  443. // last loaded -- to make decide to reload (ASPPREF.DLL only)
  444. DWORD m_dwTimestamp;
  445. public:
  446. inline CPerfMainBlock()
  447. : m_fInited(FALSE),
  448. m_pData(NULL), m_hMutex(NULL),
  449. m_pProcBlock(NULL), m_dwTimestamp(NULL)
  450. {}
  451. inline ~CPerfMainBlock() { UnInit(); }
  452. HRESULT Init();
  453. HRESULT UnInit();
  454. // lock / unlock using mutex
  455. HRESULT Lock();
  456. HRESULT UnLock();
  457. // add/remove process record to the main block (used from ASP.DLL)
  458. HRESULT AddProcess(const CLSID &ClsId);
  459. HRESULT RemoveProcess(const CLSID &ClsId);
  460. // load CPerfProcBlock blocks from the main block into
  461. // objects (used from APPPREF.DLL)
  462. HRESULT Load();
  463. // gather (sum-up) the statistics from each proc block
  464. HRESULT GetStats(DWORD *pdwCounters);
  465. };
  466. inline HRESULT CPerfMainBlock::Init()
  467. {
  468. HRESULT hr = S_OK;
  469. if (FAILED(hr = InitSD())) {
  470. return hr;
  471. }
  472. m_hMutex = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, SZ_PERF_MUTEX);
  473. if (!m_hMutex)
  474. {
  475. m_hMutex = CreateMutexA(&m_sa, FALSE, SZ_PERF_MUTEX);
  476. }
  477. if (!m_hMutex)
  478. hr = E_FAIL;
  479. if (SUCCEEDED(hr))
  480. {
  481. hr = InitMap(SZ_PERF_MAIN_FILEMAP, CB_PERF_MAIN_BLOCK);
  482. if (SUCCEEDED(hr))
  483. m_pData = (CPerfMainBlockData *)PMemory();
  484. }
  485. if (SUCCEEDED(hr))
  486. m_fInited = TRUE;
  487. else
  488. UnInit();
  489. return hr;
  490. }
  491. inline HRESULT CPerfMainBlock::UnInit()
  492. {
  493. while (m_pProcBlock)
  494. {
  495. CPerfProcBlock *pNext = m_pProcBlock->m_pNext;
  496. m_pProcBlock->UnInit();
  497. delete m_pProcBlock;
  498. m_pProcBlock = pNext;
  499. }
  500. if (m_hMutex)
  501. {
  502. CloseHandle(m_hMutex);
  503. m_hMutex = NULL;
  504. }
  505. UnInitMap();
  506. m_dwTimestamp = 0;
  507. m_pData = NULL;
  508. m_pProcBlock = NULL;
  509. m_fInited = FALSE;
  510. return S_OK;
  511. }
  512. inline HRESULT CPerfMainBlock::Lock()
  513. {
  514. if (!m_hMutex)
  515. return E_FAIL;
  516. if (WaitForSingleObject(m_hMutex, PERM_MUTEX_WAIT) == WAIT_TIMEOUT)
  517. return E_FAIL;
  518. return S_OK;
  519. }
  520. inline HRESULT CPerfMainBlock::UnLock()
  521. {
  522. if (m_hMutex)
  523. ReleaseMutex(m_hMutex);
  524. return S_OK;
  525. }
  526. inline HRESULT CPerfMainBlock::AddProcess
  527. (
  528. const CLSID &ClsId
  529. )
  530. {
  531. if (!m_fInited)
  532. return E_FAIL;
  533. if (FAILED(Lock())) // lock mutex
  534. return E_FAIL;
  535. HRESULT hr = S_OK;
  536. BOOL fFound = FALSE;
  537. // find
  538. for (DWORD i = 0; i < m_pData->m_cItems; i++)
  539. {
  540. if (m_pData->m_rgClsIds[i] == ClsId)
  541. {
  542. fFound = TRUE;
  543. break;
  544. }
  545. }
  546. // add only if not already there
  547. if (!fFound)
  548. {
  549. if (m_pData->m_cItems < C_PERF_PROC_MAX)
  550. {
  551. m_pData->m_rgClsIds[m_pData->m_cItems] = ClsId;
  552. m_pData->m_cItems++;
  553. m_pData->m_dwTimestamp = GetTickCount();
  554. }
  555. else
  556. {
  557. hr = E_OUTOFMEMORY;
  558. }
  559. }
  560. UnLock(); // unlock mutex
  561. return hr;
  562. }
  563. inline HRESULT CPerfMainBlock::RemoveProcess
  564. (
  565. const CLSID &ClsId
  566. )
  567. {
  568. if (!m_fInited)
  569. return E_FAIL;
  570. if (FAILED(Lock())) // lock mutex
  571. return E_FAIL;
  572. HRESULT hr = S_OK;
  573. int iFound = -1;
  574. // find
  575. for (DWORD i = 0; i < m_pData->m_cItems; i++)
  576. {
  577. if (m_pData->m_rgClsIds[i] == ClsId)
  578. {
  579. iFound = i;
  580. break;
  581. }
  582. }
  583. // remove
  584. if (iFound >= 0)
  585. {
  586. for (i = iFound; i < m_pData->m_cItems-1; i++)
  587. m_pData->m_rgClsIds[i] = m_pData->m_rgClsIds[i+1];
  588. m_pData->m_cItems--;
  589. m_pData->m_dwTimestamp = GetTickCount();
  590. }
  591. UnLock(); // unlock mutex
  592. return hr;
  593. }
  594. inline HRESULT CPerfMainBlock::Load()
  595. {
  596. if (!m_fInited)
  597. return E_FAIL;
  598. if (m_dwTimestamp == m_pData->m_dwTimestamp)
  599. return S_OK; // already up-to-date
  600. // clear out what we have
  601. while (m_pProcBlock)
  602. {
  603. CPerfProcBlock *pNext = m_pProcBlock->m_pNext;
  604. m_pProcBlock->UnInit();
  605. delete m_pProcBlock;
  606. m_pProcBlock = pNext;
  607. }
  608. if (FAILED(Lock())) // lock mutex
  609. return E_FAIL;
  610. HRESULT hr = S_OK;
  611. // populate new objects for blocks
  612. for (DWORD i = 0; i < m_pData->m_cItems; i++)
  613. {
  614. CPerfProcBlock *pBlock = new CPerfProcBlock;
  615. if (!pBlock)
  616. {
  617. hr = E_OUTOFMEMORY;
  618. break;
  619. }
  620. hr = pBlock->InitExternal(m_pData->m_rgClsIds[i]);
  621. if (FAILED(hr))
  622. {
  623. delete pBlock;
  624. continue;
  625. }
  626. pBlock->m_pNext = m_pProcBlock;
  627. m_pProcBlock = pBlock;
  628. }
  629. // remember timestamp
  630. m_dwTimestamp = SUCCEEDED(hr) ? m_pData->m_dwTimestamp : 0;
  631. UnLock(); // unlock mutex
  632. return hr;
  633. }
  634. inline HRESULT CPerfMainBlock::GetStats
  635. (
  636. DWORD *pdwCounters
  637. )
  638. {
  639. if (!m_fInited)
  640. return E_FAIL;
  641. // reload if needed
  642. if (FAILED(Load()))
  643. return E_FAIL;
  644. // init
  645. memset(pdwCounters, 0, CB_COUNTERS);
  646. // gather
  647. CPerfProcBlock *pBlock = m_pProcBlock;
  648. while (pBlock)
  649. {
  650. for (int i = 0; i < C_PERF_PROC_COUNTERS; i++)
  651. pdwCounters[i] += pBlock->m_pData->m_rgdwCounters[i];
  652. pBlock = pBlock->m_pNext;
  653. }
  654. return S_OK;
  655. }
  656. #endif // _ASP_PERFDEF_H