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.

2202 lines
57 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-2001 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. #ifndef __ATLPERF_INL__
  11. #define __ATLPERF_INL__
  12. #pragma once
  13. #ifndef __ATLPERF_H__
  14. #error atlperf.inl requires atlperf.h to be included first
  15. #endif
  16. #include <atlsecurity.h>
  17. #pragma warning(push)
  18. #ifndef _CPPUNWIND
  19. #pragma warning(disable: 4702) // unreachable code
  20. #endif
  21. namespace ATL
  22. {
  23. __declspec(selectany) LPCTSTR c_szAtlPerfCounter = _T("Counter");
  24. __declspec(selectany) LPCTSTR c_szAtlPerfFirstCounter = _T("First Counter");
  25. __declspec(selectany) LPCTSTR c_szAtlPerfLastCounter = _T("Last Counter");
  26. __declspec(selectany) LPCTSTR c_szAtlPerfHelp = _T("Help");
  27. __declspec(selectany) LPCTSTR c_szAtlPerfFirstHelp = _T("First Help");
  28. __declspec(selectany) LPCTSTR c_szAtlPerfLastHelp = _T("Last Help");
  29. __declspec(selectany) LPCWSTR c_szAtlPerfGlobal = L"Global";
  30. __declspec(selectany) LPCTSTR c_szAtlPerfLibrary = _T("Library");
  31. __declspec(selectany) LPCTSTR c_szAtlPerfOpen = _T("Open");
  32. __declspec(selectany) LPCTSTR c_szAtlPerfCollect = _T("Collect");
  33. __declspec(selectany) LPCTSTR c_szAtlPerfClose = _T("Close");
  34. __declspec(selectany) LPCTSTR c_szAtlPerfLanguages = _T("Languages");
  35. __declspec(selectany) LPCTSTR c_szAtlPerfMap = _T("Map");
  36. __declspec(selectany) LPCTSTR c_szAtlPerfServicesKey = _T("SYSTEM\\CurrentControlSet\\Services");
  37. __declspec(selectany) LPCTSTR c_szAtlPerfPerformanceKey = _T("SYSTEM\\CurrentControlSet\\Services\\%s\\Performance");
  38. __declspec(selectany) LPCTSTR c_szAtlPerfPerfLibKey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
  39. __declspec(selectany) LPCTSTR c_szAtlPerfPerfLibLangKey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\%3.3x");
  40. inline CPerfMon::~CPerfMon() throw()
  41. {
  42. UnInitialize();
  43. }
  44. inline HRESULT CPerfMon::CreateMap(LANGID language, HINSTANCE hResInstance, UINT* pSampleRes) throw()
  45. {
  46. language; // unused
  47. hResInstance; // unused
  48. pSampleRes; // unused
  49. return S_OK;
  50. }
  51. inline CPerfMapEntry& CPerfMon::_GetMapEntry(UINT nIndex) throw()
  52. {
  53. ATLASSERT(nIndex < _GetNumMapEntries());
  54. return m_map[nIndex];
  55. }
  56. inline UINT CPerfMon::_GetNumMapEntries() throw()
  57. {
  58. return (UINT) m_map.GetCount();
  59. }
  60. inline CPerfObject* CPerfMon::_GetFirstObject(CAtlFileMappingBase* pBlock) throw()
  61. {
  62. ATLASSERT(pBlock != NULL);
  63. // should never happen if Initialize succeeded
  64. // are you checking return codes?
  65. ATLASSERT(pBlock->GetData() != NULL);
  66. return reinterpret_cast<CPerfObject*>(LPBYTE(pBlock->GetData()) + m_nHeaderSize);
  67. }
  68. inline CPerfObject* CPerfMon::_GetNextObject(CPerfObject* pInstance) throw()
  69. {
  70. ATLASSERT(pInstance != NULL);
  71. return reinterpret_cast<CPerfObject*>(LPBYTE(pInstance) + pInstance->m_nAllocSize);
  72. }
  73. inline CAtlFileMappingBase* CPerfMon::_GetNextBlock(CAtlFileMappingBase* pBlock) throw()
  74. {
  75. // calling _GetNextBlock(NULL) will return the first block
  76. DWORD dwNextBlockIndex = 0;
  77. if (pBlock)
  78. {
  79. dwNextBlockIndex= _GetBlockId(pBlock) +1;
  80. if (DWORD(m_aMem.GetCount()) == dwNextBlockIndex)
  81. return NULL;
  82. }
  83. return m_aMem[dwNextBlockIndex];
  84. }
  85. inline CAtlFileMappingBase* CPerfMon::_AllocNewBlock(CAtlFileMappingBase* pPrev, BOOL* pbExisted /* == NULL */) throw()
  86. {
  87. // initialize a security descriptor to give everyone access to objects we create
  88. CSecurityDescriptor sd;
  89. sd.InitializeFromThreadToken();
  90. SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), sd, FALSE };
  91. CAutoPtr<CAtlFileMappingBase> spMem;
  92. CAtlFileMappingBase* pMem = NULL;
  93. ATLTRY(spMem.Attach(new CAtlFileMappingBase));
  94. if (spMem == NULL)
  95. return NULL;
  96. // create a unique name for the shared mem segment based on the index
  97. DWORD dwNextBlockIndex;
  98. if (pPrev != NULL)
  99. dwNextBlockIndex = _GetBlockId(pPrev) +1;
  100. else
  101. {
  102. // use the system allocation granularity (65536 currently. may be different in the future)
  103. SYSTEM_INFO si;
  104. GetSystemInfo(&si);
  105. m_nAllocSize = si.dwAllocationGranularity;
  106. dwNextBlockIndex = 0;
  107. }
  108. BOOL bExisted = FALSE;
  109. _ATLTRY
  110. {
  111. CString strName;
  112. strName.Format(_T("ATLPERF_%s_%3.3d"), GetAppName(), dwNextBlockIndex);
  113. HRESULT hr = spMem->MapSharedMem(m_nAllocSize, strName, &bExisted, &sa);
  114. if (FAILED(hr))
  115. return NULL;
  116. // save the index of this block
  117. // don't for first block since we don't know m_nSchemaSize yet
  118. if (dwNextBlockIndex)
  119. _GetBlockId(spMem) = dwNextBlockIndex;
  120. if (!bExisted)
  121. memset(spMem->GetData(), 0, m_nAllocSize);
  122. if (pbExisted)
  123. *pbExisted = bExisted;
  124. pMem = spMem;
  125. m_aMem.Add(spMem);
  126. OnBlockAlloc(pMem);
  127. }
  128. _ATLCATCHALL()
  129. {
  130. return NULL;
  131. }
  132. return pMem;
  133. }
  134. inline HRESULT CPerfMon::_LoadMap() throw()
  135. {
  136. _ATLTRY
  137. {
  138. HRESULT hr;
  139. ClearMap();
  140. DWORD* pData = LPDWORD(m_aMem[0]->GetData());
  141. DWORD dwDataSize = *pData++; // blob size
  142. DWORD dwNumItems = *pData++; // number of items
  143. // see if we have name data
  144. DWORD* pNameData = NULL;
  145. if (dwDataSize > (2+dwNumItems*9) * sizeof(DWORD))
  146. pNameData = pData + dwNumItems*9; // blob size and item count already skipped. skip item data
  147. for (DWORD i=0; i<dwNumItems; i++)
  148. {
  149. DWORD dwIsObject = *pData++;
  150. DWORD dwPerfId = *pData++;
  151. DWORD dwDetailLevel = *pData++;
  152. CString strName;
  153. if (pNameData)
  154. {
  155. strName = CString(LPWSTR(pNameData+1), *pNameData);
  156. pNameData += AtlAlignUp(sizeof(WCHAR) * *pNameData, sizeof(DWORD))/sizeof(DWORD) + 1;
  157. }
  158. if (dwIsObject)
  159. {
  160. DWORD dwDefaultCounter = *pData++;
  161. DWORD dwInstanceLess = *pData++;
  162. DWORD dwStructSize = *pData++;
  163. DWORD dwMaxInstanceNameLen = *pData++;
  164. hr = AddObjectDefinition(
  165. dwPerfId,
  166. strName,
  167. NULL,
  168. dwDetailLevel,
  169. dwDefaultCounter,
  170. dwInstanceLess,
  171. dwStructSize,
  172. dwMaxInstanceNameLen);
  173. if (FAILED(hr))
  174. {
  175. ClearMap();
  176. return hr;
  177. }
  178. }
  179. else
  180. {
  181. DWORD dwCounterType = *pData++;
  182. DWORD dwMaxCounterSize = *pData++;
  183. DWORD dwDataOffset = *pData++;
  184. DWORD dwDefaultScale = *pData++;
  185. hr = AddCounterDefinition(
  186. dwPerfId,
  187. strName,
  188. NULL,
  189. dwDetailLevel,
  190. dwCounterType,
  191. dwMaxCounterSize,
  192. dwDataOffset,
  193. dwDefaultScale);
  194. if (FAILED(hr))
  195. {
  196. ClearMap();
  197. return hr;
  198. }
  199. }
  200. DWORD dwNameId = *pData++;
  201. DWORD dwHelpId = *pData++;
  202. CPerfMapEntry& entry = _GetMapEntry(_GetNumMapEntries()-1);
  203. entry.m_nNameId = dwNameId;
  204. entry.m_nHelpId = dwHelpId;
  205. }
  206. return S_OK;
  207. }
  208. _ATLCATCHALL()
  209. {
  210. return E_OUTOFMEMORY;
  211. }
  212. }
  213. inline HRESULT CPerfMon::_SaveMap() throw()
  214. {
  215. _ATLTRY
  216. {
  217. // figure out how much memory we need
  218. size_t nSize = (2 + 9*_GetNumMapEntries()) * sizeof(DWORD);
  219. for (UINT i=0; i<_GetNumMapEntries(); i++)
  220. {
  221. // if any of the entries have names, they'd better all have names
  222. CPerfMapEntry& entry = _GetMapEntry(i);
  223. if (!entry.m_strName.IsEmpty())
  224. nSize += sizeof(DWORD) + AtlAlignUp(sizeof(WCHAR) * entry.m_strName.GetLength(), sizeof(DWORD));
  225. }
  226. CHeapPtr<BYTE> blob;
  227. if (!blob.Allocate(nSize))
  228. return E_OUTOFMEMORY;
  229. // start with blob size and number of items in the blob
  230. DWORD* pCurrent = reinterpret_cast<DWORD*>(blob.m_pData);
  231. *pCurrent++ = (DWORD) nSize; // blob size
  232. *pCurrent++ = _GetNumMapEntries(); // number of items
  233. for (UINT i=0; i<_GetNumMapEntries(); i++)
  234. {
  235. // add all the relevant runtime info to the blob for each item
  236. CPerfMapEntry& entry = _GetMapEntry(i);
  237. *pCurrent++ = entry.m_bIsObject;
  238. *pCurrent++ = entry.m_dwPerfId;
  239. *pCurrent++ = entry.m_dwDetailLevel;
  240. if (entry.m_bIsObject)
  241. {
  242. *pCurrent++ = entry.m_nDefaultCounter;
  243. *pCurrent++ = entry.m_nInstanceLess;
  244. *pCurrent++ = entry.m_nStructSize;
  245. *pCurrent++ = entry.m_nMaxInstanceNameLen;
  246. }
  247. else
  248. {
  249. *pCurrent++ = entry.m_dwCounterType;
  250. *pCurrent++ = entry.m_nMaxCounterSize;
  251. *pCurrent++ = entry.m_nDataOffset;
  252. *pCurrent++ = entry.m_nDefaultScale;
  253. }
  254. *pCurrent++ = entry.m_nNameId;
  255. *pCurrent++ = entry.m_nHelpId;
  256. }
  257. // add names to the blob
  258. for (UINT i=0; i<_GetNumMapEntries(); i++)
  259. {
  260. // if any of the entries have names, they'd better all have names
  261. CPerfMapEntry& entry = _GetMapEntry(i);
  262. if (!entry.m_strName.IsEmpty())
  263. {
  264. // copy the len of the string (in characters) then the wide-char version of the string
  265. // pad the string to a dword boundary
  266. int nLen = entry.m_strName.GetLength();
  267. *pCurrent++ = nLen;
  268. memcpy(pCurrent, CT2CW(entry.m_strName), sizeof(WCHAR)*nLen);
  269. pCurrent += AtlAlignUp(sizeof(WCHAR) * nLen, sizeof(DWORD))/sizeof(DWORD);
  270. }
  271. }
  272. CRegKey rkApp;
  273. CString str;
  274. DWORD dwErr;
  275. str.Format(c_szAtlPerfPerformanceKey, GetAppName());
  276. dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
  277. if (dwErr != ERROR_SUCCESS)
  278. return AtlHresultFromWin32(dwErr);
  279. rkApp.SetBinaryValue(c_szAtlPerfMap, blob, *LPDWORD(blob.m_pData));
  280. return S_OK;
  281. }
  282. _ATLCATCHALL()
  283. {
  284. return E_OUTOFMEMORY;
  285. }
  286. }
  287. inline CPerfMapEntry* CPerfMon::_FindObjectInfo(DWORD dwObjectId) throw()
  288. {
  289. for (UINT i=0; i<_GetNumMapEntries(); i += _GetMapEntry(i).m_nNumCounters+1)
  290. {
  291. CPerfMapEntry& object = _GetMapEntry(i);
  292. if (object.m_dwPerfId == dwObjectId)
  293. return &object;
  294. }
  295. return NULL;
  296. }
  297. inline CPerfMapEntry* CPerfMon::_FindCounterInfo(CPerfMapEntry* pObjectEntry, DWORD dwCounterId) throw()
  298. {
  299. ATLASSERT(pObjectEntry != NULL);
  300. for (DWORD i=0; i<pObjectEntry->m_nNumCounters; i++)
  301. {
  302. CPerfMapEntry* pCounter = pObjectEntry+i+1;
  303. if (pCounter->m_dwPerfId == dwCounterId)
  304. return pCounter;
  305. }
  306. return NULL;
  307. }
  308. inline CPerfMapEntry* CPerfMon::_FindCounterInfo(DWORD dwObjectId, DWORD dwCounterId) throw()
  309. {
  310. CPerfMapEntry* pObjectEntry = _FindObjectInfo(dwObjectId);
  311. if (pObjectEntry != NULL)
  312. return _FindCounterInfo(pObjectEntry, dwCounterId);
  313. return NULL;
  314. }
  315. inline BOOL CPerfMon::_WantObjectType(LPWSTR szValue, DWORD dwObjectId) throw(...)
  316. {
  317. ATLASSERT(szValue != NULL);
  318. if (lstrcmpiW(c_szAtlPerfGlobal, szValue) == 0)
  319. return TRUE;
  320. CString strList(szValue);
  321. int nStart = 0;
  322. CString strNum = strList.Tokenize(_T(" "), nStart);
  323. while (!strNum.IsEmpty())
  324. {
  325. if (_ttoi(strNum) == int(dwObjectId))
  326. return TRUE;
  327. strNum = strList.Tokenize(_T(" "), nStart);
  328. }
  329. return FALSE;
  330. }
  331. inline LPBYTE CPerfMon::_AllocData(LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, size_t nBytesNeeded) throw()
  332. {
  333. ATLASSERT(pnBytesUsed != NULL);
  334. if (nBytesAvail < *pnBytesUsed + (ULONG) nBytesNeeded)
  335. return NULL;
  336. LPBYTE p = pData;
  337. pData += nBytesNeeded;
  338. *pnBytesUsed += (ULONG) nBytesNeeded;
  339. return p;
  340. }
  341. inline DWORD& CPerfMon::_GetBlockId(CAtlFileMappingBase* pBlock) throw()
  342. {
  343. ATLASSERT(pBlock != NULL);
  344. return *LPDWORD(LPBYTE(pBlock->GetData()) + m_nSchemaSize);
  345. }
  346. inline void CPerfMon::_FillObjectType(PERF_OBJECT_TYPE* pObjectType, CPerfMapEntry* pObjectEntry) throw()
  347. {
  348. ATLASSERT(pObjectType != NULL);
  349. ATLASSERT(pObjectEntry != NULL);
  350. pObjectType->DefinitionLength = sizeof(PERF_OBJECT_TYPE) + sizeof(PERF_COUNTER_DEFINITION) * pObjectEntry->m_nNumCounters;
  351. pObjectType->TotalByteLength = pObjectType->DefinitionLength; // we will add the instance definitions/counter blocks as we go
  352. pObjectType->HeaderLength = sizeof(PERF_OBJECT_TYPE);
  353. pObjectType->ObjectNameTitleIndex = pObjectEntry->m_nNameId;
  354. pObjectType->ObjectNameTitle = NULL;
  355. pObjectType->ObjectHelpTitleIndex = pObjectEntry->m_nHelpId;
  356. pObjectType->ObjectHelpTitle = NULL;
  357. pObjectType->DetailLevel = pObjectEntry->m_dwDetailLevel;
  358. pObjectType->NumCounters = pObjectEntry->m_nNumCounters;
  359. pObjectType->DefaultCounter = pObjectEntry->m_nDefaultCounter;
  360. if (pObjectEntry->m_nInstanceLess == PERF_NO_INSTANCES)
  361. pObjectType->NumInstances = PERF_NO_INSTANCES;
  362. else
  363. pObjectType->NumInstances = 0; // this will be calculated as we go
  364. pObjectType->CodePage = 0;
  365. pObjectType->PerfTime.QuadPart = 0;
  366. pObjectType->PerfFreq.QuadPart = 0;
  367. }
  368. inline void CPerfMon::_FillCounterDef(
  369. PERF_COUNTER_DEFINITION* pCounterDef,
  370. CPerfMapEntry* pCounterEntry,
  371. ULONG& nCBSize
  372. ) throw()
  373. {
  374. ATLASSERT(pCounterDef != NULL);
  375. ATLASSERT(pCounterEntry != NULL);
  376. pCounterDef->ByteLength = sizeof(PERF_COUNTER_DEFINITION);
  377. pCounterDef->CounterNameTitleIndex = pCounterEntry->m_nNameId;
  378. pCounterDef->CounterNameTitle = NULL;
  379. pCounterDef->CounterHelpTitleIndex = pCounterEntry->m_nHelpId;
  380. pCounterDef->CounterHelpTitle = NULL;
  381. pCounterDef->DefaultScale = pCounterEntry->m_nDefaultScale;
  382. pCounterDef->DetailLevel = pCounterEntry->m_dwDetailLevel;
  383. pCounterDef->CounterType = pCounterEntry->m_dwCounterType;
  384. switch (pCounterEntry->m_dwCounterType & ATLPERF_SIZE_MASK)
  385. {
  386. case PERF_SIZE_DWORD:
  387. pCounterDef->CounterSize = sizeof(DWORD);
  388. break;
  389. case PERF_SIZE_LARGE:
  390. pCounterDef->CounterSize = sizeof(__int64);
  391. break;
  392. case PERF_SIZE_ZERO:
  393. pCounterDef->CounterSize = 0;
  394. break;
  395. case PERF_SIZE_VARIABLE_LEN:
  396. ATLASSERT((pCounterEntry->m_dwCounterType & ATLPERF_TYPE_MASK) == PERF_TYPE_TEXT);
  397. if ((pCounterEntry->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
  398. pCounterDef->CounterSize = (DWORD) AtlAlignUp(pCounterEntry->m_nMaxCounterSize * sizeof(WCHAR), sizeof(DWORD));
  399. else
  400. pCounterDef->CounterSize = (DWORD) AtlAlignUp(pCounterEntry->m_nMaxCounterSize * sizeof(char), sizeof(DWORD));
  401. break;
  402. }
  403. pCounterDef->CounterOffset = sizeof(PERF_COUNTER_BLOCK) + nCBSize;
  404. nCBSize += pCounterDef->CounterSize;
  405. }
  406. inline HRESULT CPerfMon::_CollectObjectType(
  407. CPerfMapEntry* pObjectEntry,
  408. LPBYTE pData,
  409. ULONG nBytesAvail,
  410. ULONG* pnBytesUsed
  411. ) throw()
  412. {
  413. ATLASSERT(pObjectEntry != NULL);
  414. ATLASSERT(pnBytesUsed != NULL);
  415. ATLASSERT(m_aMem.GetCount() != 0);
  416. *pnBytesUsed = 0;
  417. // write the object definition out
  418. PERF_OBJECT_TYPE* pObjectType = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_OBJECT_TYPE*) NULL);
  419. if (pObjectType == NULL)
  420. return E_OUTOFMEMORY;
  421. _FillObjectType(pObjectType, pObjectEntry);
  422. // save a pointer to the first counter entry and counter definition.
  423. // we'll need them when we create the PERF_COUNTER_BLOCK data
  424. CPerfMapEntry* pCounterEntries = pObjectEntry + 1;
  425. PERF_COUNTER_DEFINITION* pCounterDefs = reinterpret_cast<PERF_COUNTER_DEFINITION*>(pData);
  426. ULONG nCBSize = 0; // counter block size
  427. // write the counter definitions out
  428. for (DWORD i=0; i<pObjectEntry->m_nNumCounters; i++)
  429. {
  430. CPerfMapEntry* pCounterEntry = pObjectEntry+i+1;
  431. PERF_COUNTER_DEFINITION* pCounterDef = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_COUNTER_DEFINITION*) NULL);
  432. if (pCounterDef == NULL)
  433. return E_OUTOFMEMORY;
  434. _FillCounterDef(pCounterDef, pCounterEntry, nCBSize);
  435. }
  436. // search for objects of the appropriate type and write out their instance/counter data
  437. CAtlFileMappingBase* pCurrentBlock = m_aMem[0];
  438. CPerfObject* pInstance = _GetFirstObject(pCurrentBlock);
  439. while (pInstance && pInstance->m_nAllocSize != 0)
  440. {
  441. if (pInstance->m_dwObjectId == pObjectEntry->m_dwPerfId)
  442. {
  443. PERF_INSTANCE_DEFINITION* pInstanceDef = NULL;
  444. if (pObjectEntry->m_nInstanceLess == PERF_NO_INSTANCES)
  445. pObjectType->NumInstances = PERF_NO_INSTANCES;
  446. else
  447. {
  448. pObjectType->NumInstances++;
  449. // create an instance definition
  450. pInstanceDef = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_INSTANCE_DEFINITION*) NULL);
  451. if (pInstanceDef == NULL)
  452. return E_OUTOFMEMORY;
  453. pInstanceDef->ParentObjectTitleIndex = 0;
  454. pInstanceDef->ParentObjectInstance = 0;
  455. pInstanceDef->UniqueID = PERF_NO_UNIQUE_ID;
  456. // handle the instance name
  457. LPCWSTR szInstNameSrc = LPCWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset);
  458. pInstanceDef->NameLength = (ULONG)(wcslen(szInstNameSrc)+1)*sizeof(WCHAR);
  459. LPWSTR szInstNameDest = (LPWSTR) _AllocData(pData, nBytesAvail, pnBytesUsed, AtlAlignUp(pInstanceDef->NameLength, sizeof(DWORD)));
  460. if (szInstNameDest == NULL)
  461. return E_OUTOFMEMORY;
  462. memcpy(szInstNameDest, szInstNameSrc, pInstanceDef->NameLength);
  463. pInstanceDef->NameOffset = ULONG(LPBYTE(szInstNameDest) - LPBYTE(pInstanceDef));
  464. pInstanceDef->ByteLength = DWORD(sizeof(PERF_INSTANCE_DEFINITION) + AtlAlignUp(pInstanceDef->NameLength, sizeof(DWORD)));
  465. }
  466. // create the counter block
  467. PERF_COUNTER_BLOCK* pCounterBlock = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_COUNTER_BLOCK*) NULL);
  468. if (pCounterBlock == NULL)
  469. return E_OUTOFMEMORY;
  470. pCounterBlock->ByteLength = sizeof(PERF_COUNTER_BLOCK) + nCBSize;
  471. LPBYTE pCounterData = _AllocData(pData, nBytesAvail, pnBytesUsed, nCBSize);
  472. if (pCounterData == NULL)
  473. return E_OUTOFMEMORY;
  474. for (ULONG i=0; i<pObjectType->NumCounters; i++)
  475. {
  476. switch (pCounterEntries[i].m_dwCounterType & ATLPERF_SIZE_MASK)
  477. {
  478. case PERF_SIZE_DWORD:
  479. *LPDWORD(pCounterData+pCounterDefs[i].CounterOffset-sizeof(PERF_COUNTER_BLOCK)) =
  480. *LPDWORD(LPBYTE(pInstance)+pCounterEntries[i].m_nDataOffset);
  481. break;
  482. case PERF_SIZE_LARGE:
  483. *PULONGLONG(pCounterData+pCounterDefs[i].CounterOffset-sizeof(PERF_COUNTER_BLOCK)) =
  484. *PULONGLONG(LPBYTE(pInstance)+pCounterEntries[i].m_nDataOffset);
  485. break;
  486. case PERF_SIZE_VARIABLE_LEN:
  487. {
  488. LPBYTE pSrc = LPBYTE(pInstance)+pObjectEntry->m_nDataOffset;
  489. LPBYTE pDest = pCounterData+pCounterDefs[i].CounterOffset-sizeof(PERF_COUNTER_BLOCK);
  490. if ((pCounterEntries[i].m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
  491. {
  492. ULONG nLen = (ULONG)wcslen(LPCWSTR(pSrc));
  493. nLen = min(nLen, pCounterEntries[i].m_nMaxCounterSize-1);
  494. wcsncpy(LPWSTR(pDest), LPCWSTR(pSrc), nLen);
  495. ((LPWSTR) pDest)[nLen] = 0;
  496. }
  497. else
  498. {
  499. ULONG nLen = (ULONG)strlen(LPCSTR(pSrc));
  500. nLen = min(nLen, pCounterEntries[i].m_nMaxCounterSize-1);
  501. strncpy(LPSTR(pDest), LPCSTR(pSrc), nLen);
  502. ((LPSTR) pDest)[nLen] = 0;
  503. }
  504. }
  505. break;
  506. }
  507. }
  508. if (pInstanceDef != NULL)
  509. pObjectType->TotalByteLength += pInstanceDef->ByteLength;
  510. pObjectType->TotalByteLength += sizeof(PERF_COUNTER_BLOCK) + nCBSize;
  511. }
  512. pInstance = _GetNextObject(pInstance);
  513. if (pInstance->m_nAllocSize == (ULONG) -1)
  514. {
  515. pCurrentBlock = _GetNextBlock(pCurrentBlock);
  516. if (pCurrentBlock == NULL)
  517. pInstance = NULL;
  518. else
  519. pInstance = _GetFirstObject(pCurrentBlock);
  520. }
  521. }
  522. return S_OK;
  523. }
  524. inline DWORD CPerfMon::Open(LPWSTR szDeviceNames) throw()
  525. {
  526. szDeviceNames; // unused
  527. return Initialize();
  528. }
  529. inline DWORD CPerfMon::Collect(
  530. LPWSTR szValue,
  531. LPVOID* ppData,
  532. LPDWORD pcbBytes,
  533. LPDWORD pcObjectTypes
  534. ) throw()
  535. {
  536. _ATLTRY
  537. {
  538. if (m_aMem.GetCount() == 0 || m_aMem[0]->GetData() == NULL || m_lock.m_h == NULL)
  539. {
  540. *pcbBytes = 0;
  541. *pcObjectTypes = 0;
  542. return ERROR_SUCCESS;
  543. }
  544. // get a lock so that other threads don't corrupt the data we're collecting
  545. CPerfLock lock(this);
  546. if (FAILED(lock.GetStatus()))
  547. {
  548. *pcbBytes = 0;
  549. *pcObjectTypes = 0;
  550. return ERROR_SUCCESS;
  551. }
  552. LPBYTE pData = LPBYTE(*ppData);
  553. ULONG nBytesLeft = *pcbBytes;
  554. ULONG nBytesUsed;
  555. *pcbBytes = 0;
  556. for (UINT i=0; i<_GetNumMapEntries(); i += _GetMapEntry(i).m_nNumCounters+1)
  557. {
  558. CPerfMapEntry* pObjectEntry = &_GetMapEntry(i);
  559. if (_WantObjectType(szValue, pObjectEntry->m_nNameId))
  560. {
  561. if (FAILED(_CollectObjectType(pObjectEntry, pData, nBytesLeft, &nBytesUsed)))
  562. {
  563. *pcbBytes = 0;
  564. *pcObjectTypes = 0;
  565. return ERROR_SUCCESS;
  566. }
  567. (*pcObjectTypes)++;
  568. (*pcbBytes) += nBytesUsed;
  569. nBytesLeft -= nBytesUsed;
  570. pData += nBytesUsed;
  571. }
  572. }
  573. *ppData = pData;
  574. return ERROR_SUCCESS;
  575. }
  576. _ATLCATCHALL()
  577. {
  578. *pcbBytes = 0;
  579. *pcObjectTypes = 0;
  580. return ERROR_SUCCESS;
  581. }
  582. }
  583. inline DWORD CPerfMon::Close() throw()
  584. {
  585. UnInitialize();
  586. return ERROR_SUCCESS;
  587. }
  588. #ifdef _ATL_PERF_REGISTER
  589. inline void CPerfMon::_AppendStrings(
  590. LPTSTR& pszNew,
  591. CAtlArray<CString>& astrStrings,
  592. ULONG iFirstIndex
  593. ) throw()
  594. {
  595. for (UINT iString = 0; iString < astrStrings.GetCount(); iString++)
  596. {
  597. INT nFormatChars = _stprintf(pszNew, _T("%d"), iFirstIndex+2*iString);
  598. pszNew += nFormatChars + 1;
  599. _tcscpy(pszNew, astrStrings[iString]);
  600. pszNew += astrStrings[iString].GetLength() + 1;
  601. }
  602. }
  603. inline HRESULT CPerfMon::_AppendRegStrings(
  604. CRegKey& rkLang,
  605. LPCTSTR szValue,
  606. CAtlArray<CString>& astrStrings,
  607. ULONG nNewStringSize,
  608. ULONG iFirstIndex,
  609. ULONG iLastIndex
  610. ) throw()
  611. {
  612. _ATLTRY
  613. {
  614. // load the existing strings, add the new data, and resave the strings
  615. ULONG nCharsOrig = 0;
  616. ULONG nCharsNew;
  617. DWORD dwErr;
  618. dwErr = rkLang.QueryMultiStringValue(szValue, NULL, &nCharsOrig);
  619. if (dwErr != ERROR_SUCCESS)
  620. return AtlHresultFromWin32(dwErr);
  621. nCharsNew = nCharsOrig + nNewStringSize;
  622. CString strOrig;
  623. dwErr = rkLang.QueryMultiStringValue(szValue, CStrBuf(strOrig, nCharsOrig, CStrBuf::SET_LENGTH), &nCharsOrig);
  624. if (dwErr != ERROR_SUCCESS)
  625. return AtlHresultFromWin32(dwErr);
  626. LPCTSTR pszOrig = strOrig;
  627. CString strNew;
  628. CStrBuf szNew(strNew, nCharsNew, CStrBuf::SET_LENGTH);
  629. LPTSTR pszNew = szNew;
  630. bool bNewStringsAdded = false;
  631. while (*pszOrig != '\0')
  632. {
  633. ULONG iIndex = _ttoi(pszOrig);
  634. int nLen = (int) _tcslen(pszOrig) + 1; // get the length of the index and null
  635. nLen += (int) _tcslen(pszOrig+nLen) + 1; // add the length of the description and null
  636. if (!bNewStringsAdded && iIndex >= iFirstIndex)
  637. {
  638. _AppendStrings(pszNew, astrStrings, iFirstIndex);
  639. bNewStringsAdded = true;
  640. }
  641. if (iIndex < iFirstIndex || iIndex > iLastIndex)
  642. {
  643. memmove(pszNew, pszOrig, nLen*sizeof(TCHAR));
  644. pszNew += nLen;
  645. }
  646. pszOrig += nLen;
  647. }
  648. if (!bNewStringsAdded)
  649. _AppendStrings(pszNew, astrStrings, iFirstIndex);
  650. *pszNew++ = '\0'; // must have 2 null terminators at end of multi_sz
  651. dwErr = rkLang.SetMultiStringValue(szValue, strNew);
  652. if (dwErr != ERROR_SUCCESS)
  653. return AtlHresultFromWin32(dwErr);
  654. return S_OK;
  655. }
  656. _ATLCATCHALL()
  657. {
  658. return E_OUTOFMEMORY;
  659. }
  660. }
  661. inline HRESULT CPerfMon::_RemoveRegStrings(
  662. CRegKey& rkLang,
  663. LPCTSTR szValue,
  664. ULONG iFirstIndex,
  665. ULONG iLastIndex
  666. ) throw()
  667. {
  668. _ATLTRY
  669. {
  670. // load the existing strings, remove the data, and resave the strings
  671. DWORD nChars = 0;
  672. DWORD dwErr;
  673. dwErr = rkLang.QueryMultiStringValue(szValue, NULL, &nChars);
  674. if (dwErr != ERROR_SUCCESS)
  675. return AtlHresultFromWin32(dwErr);
  676. CString str;
  677. CStrBuf szBuf(str, nChars, CStrBuf::SET_LENGTH);
  678. dwErr = rkLang.QueryMultiStringValue(szValue, szBuf, &nChars);
  679. if (dwErr != ERROR_SUCCESS)
  680. return AtlHresultFromWin32(dwErr);
  681. LPCTSTR pszRead = szBuf;
  682. LPTSTR pszWrite = szBuf;
  683. while (*pszRead != '\0')
  684. {
  685. ULONG iIndex = _ttoi(pszRead);
  686. int nLen = (int) _tcslen(pszRead) + 1; // get the length of the index and null
  687. nLen += (int) _tcslen(pszRead+nLen) + 1; // add the length of the description and null
  688. if (iIndex < iFirstIndex || iIndex > iLastIndex)
  689. {
  690. memmove(pszWrite, pszRead, nLen*sizeof(TCHAR));
  691. pszWrite += nLen;
  692. }
  693. pszRead += nLen;
  694. }
  695. *pszWrite++ = '\0'; // must have 2 null terminators at end of multi_sz
  696. dwErr = rkLang.SetMultiStringValue(szValue, szBuf);
  697. if (dwErr != ERROR_SUCCESS)
  698. return AtlHresultFromWin32(dwErr);
  699. return S_OK;
  700. }
  701. _ATLCATCHALL()
  702. {
  703. return E_OUTOFMEMORY;
  704. }
  705. }
  706. inline HRESULT CPerfMon::_ReserveStringRange(DWORD& dwFirstCounter, DWORD& dwFirstHelp) throw()
  707. {
  708. CRegKey rkApp;
  709. CString strAppKey;
  710. DWORD dwErr;
  711. _ATLTRY
  712. {
  713. strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
  714. }
  715. _ATLCATCHALL()
  716. {
  717. return E_OUTOFMEMORY;
  718. }
  719. dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, strAppKey);
  720. if (dwErr == ERROR_SUCCESS)
  721. {
  722. // see if we already have a sufficient range reserved
  723. DWORD dwFirstAppCounter;
  724. DWORD dwFirstAppHelp;
  725. DWORD dwLastAppCounter;
  726. DWORD dwLastAppHelp;
  727. if (rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstAppCounter) == ERROR_SUCCESS &&
  728. rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstAppHelp) == ERROR_SUCCESS &&
  729. rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastAppCounter) == ERROR_SUCCESS &&
  730. rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastAppHelp) == ERROR_SUCCESS &&
  731. dwLastAppCounter-dwFirstAppCounter+2 >= DWORD(2*_GetNumMapEntries()) &&
  732. dwLastAppHelp-dwFirstAppHelp+2 >= DWORD(2*_GetNumMapEntries()))
  733. {
  734. dwFirstCounter = dwFirstAppCounter;
  735. dwFirstHelp = dwFirstAppHelp;
  736. return S_OK;
  737. }
  738. }
  739. CRegKey rkPerfLib;
  740. dwErr = rkPerfLib.Open(HKEY_LOCAL_MACHINE, c_szAtlPerfPerfLibKey);
  741. if (dwErr != ERROR_SUCCESS)
  742. return AtlHresultFromWin32(dwErr);
  743. if (!rkApp)
  744. {
  745. dwErr = rkApp.Create(HKEY_LOCAL_MACHINE, strAppKey);
  746. if (dwErr != ERROR_SUCCESS)
  747. return AtlHresultFromWin32(dwErr);
  748. }
  749. // figure out the counter range
  750. DWORD dwLastCounter;
  751. DWORD dwLastHelp;
  752. dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
  753. if (dwErr != ERROR_SUCCESS)
  754. return AtlHresultFromWin32(dwErr);
  755. dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
  756. if (dwErr != ERROR_SUCCESS)
  757. return AtlHresultFromWin32(dwErr);
  758. dwFirstCounter = dwLastCounter + 2;
  759. dwFirstHelp = dwLastHelp + 2;
  760. dwLastCounter += 2*_GetNumMapEntries();
  761. dwLastHelp += 2*_GetNumMapEntries();
  762. dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
  763. if (dwErr != ERROR_SUCCESS)
  764. return AtlHresultFromWin32(dwErr);
  765. dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
  766. if (dwErr != ERROR_SUCCESS)
  767. return AtlHresultFromWin32(dwErr);
  768. // register the used counter range
  769. dwErr = rkApp.SetDWORDValue(c_szAtlPerfFirstCounter, dwFirstCounter);
  770. if (dwErr != ERROR_SUCCESS)
  771. return AtlHresultFromWin32(dwErr);
  772. dwErr = rkApp.SetDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
  773. if (dwErr != ERROR_SUCCESS)
  774. return AtlHresultFromWin32(dwErr);
  775. dwErr = rkApp.SetDWORDValue(c_szAtlPerfFirstHelp, dwFirstHelp);
  776. if (dwErr != ERROR_SUCCESS)
  777. return AtlHresultFromWin32(dwErr);
  778. dwErr = rkApp.SetDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
  779. if (dwErr != ERROR_SUCCESS)
  780. return AtlHresultFromWin32(dwErr);
  781. return S_OK;
  782. }
  783. inline HRESULT CPerfMon::Register(
  784. LPCTSTR szOpenFunc,
  785. LPCTSTR szCollectFunc,
  786. LPCTSTR szCloseFunc,
  787. HINSTANCE hDllInstance /* == _AtlBaseModule.GetModuleInstance() */
  788. ) throw()
  789. {
  790. ATLASSERT(szOpenFunc != NULL);
  791. ATLASSERT(szCollectFunc != NULL);
  792. ATLASSERT(szCloseFunc != NULL);
  793. CString str;
  794. DWORD dwErr;
  795. HRESULT hr;
  796. hr = CreateMap(LANGIDFROMLCID(GetThreadLocale()), hDllInstance);
  797. if (FAILED(hr))
  798. return hr;
  799. CString strAppKey;
  800. _ATLTRY
  801. {
  802. strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
  803. }
  804. _ATLCATCHALL()
  805. {
  806. return E_OUTOFMEMORY;
  807. }
  808. // if we're already registered, unregister so we can redo registration
  809. _UnregisterStrings();
  810. // reserve a range for our counter and help strings
  811. DWORD dwFirstCounter = 0;
  812. DWORD dwFirstHelp = 0;
  813. _ReserveStringRange(dwFirstCounter, dwFirstHelp);
  814. for (UINT i=0; i<_GetNumMapEntries(); i++)
  815. {
  816. CPerfMapEntry& entry = _GetMapEntry(i);
  817. entry.m_nNameId = dwFirstCounter + i*2;
  818. entry.m_nHelpId = dwFirstHelp + i*2;
  819. }
  820. // register the app entry points
  821. CRegKey rkApp;
  822. dwErr = rkApp.Create(HKEY_LOCAL_MACHINE, strAppKey);
  823. if (dwErr != ERROR_SUCCESS)
  824. return AtlHresultFromWin32(dwErr);
  825. _ATLTRY
  826. {
  827. if (GetModuleFileName(hDllInstance, CStrBuf(str, MAX_PATH), MAX_PATH) == 0)
  828. return AtlHresultFromLastError();
  829. }
  830. _ATLCATCHALL()
  831. {
  832. return E_OUTOFMEMORY;
  833. }
  834. dwErr = rkApp.SetStringValue(c_szAtlPerfLibrary, str);
  835. if (dwErr != ERROR_SUCCESS)
  836. return AtlHresultFromWin32(dwErr);
  837. dwErr = rkApp.SetStringValue(c_szAtlPerfOpen, szOpenFunc);
  838. if (dwErr != ERROR_SUCCESS)
  839. return AtlHresultFromWin32(dwErr);
  840. dwErr = rkApp.SetStringValue(c_szAtlPerfCollect, szCollectFunc);
  841. if (dwErr != ERROR_SUCCESS)
  842. return AtlHresultFromWin32(dwErr);
  843. dwErr = rkApp.SetStringValue(c_szAtlPerfClose, szCloseFunc);
  844. if (dwErr != ERROR_SUCCESS)
  845. return AtlHresultFromWin32(dwErr);
  846. dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, _T(""));
  847. if (dwErr != ERROR_SUCCESS)
  848. return AtlHresultFromWin32(dwErr);
  849. hr = _SaveMap();
  850. if (FAILED(hr))
  851. return hr;
  852. return S_OK;
  853. }
  854. inline HRESULT CPerfMon::RegisterStrings(
  855. LANGID language /* = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) */,
  856. HINSTANCE hResInstance /* = _AtlBaseModule.GetResourceInstance() */
  857. ) throw()
  858. {
  859. _ATLTRY
  860. {
  861. CString str;
  862. DWORD dwErr;
  863. HRESULT hr;
  864. CRegKey rkLang;
  865. CRegKey rkApp;
  866. LANGID wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);
  867. if (language == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL))
  868. {
  869. language = LANGIDFROMLCID(GetThreadLocale());
  870. wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);
  871. }
  872. hr = CreateMap(language, hResInstance);
  873. if (FAILED(hr))
  874. return hr;
  875. str.Format(c_szAtlPerfPerfLibLangKey, wPrimaryLanguage);
  876. dwErr = rkLang.Open(HKEY_LOCAL_MACHINE, str);
  877. if (dwErr == ERROR_FILE_NOT_FOUND)
  878. return S_FALSE; // the language isn't installed on the system
  879. if (dwErr != ERROR_SUCCESS)
  880. return AtlHresultFromWin32(dwErr);
  881. // load list of language strings already registered
  882. str.Format(c_szAtlPerfPerformanceKey, GetAppName());
  883. dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
  884. if (dwErr != ERROR_SUCCESS)
  885. return AtlHresultFromWin32(dwErr);
  886. DWORD dwLangsLen = 0;
  887. CString strLangs;
  888. dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, NULL, &dwLangsLen);
  889. if (dwErr != ERROR_SUCCESS)
  890. return AtlHresultFromWin32(dwErr);
  891. CStrBuf szLangs(strLangs, dwLangsLen+4, CStrBuf::SET_LENGTH); // reserve room for adding new language
  892. dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, szLangs, &dwLangsLen);
  893. if (dwErr != ERROR_SUCCESS)
  894. return AtlHresultFromWin32(dwErr);
  895. dwLangsLen--; // don't count '\0'
  896. // see if this language has already been registered and if so, return
  897. TCHAR szNewLang[5];
  898. _stprintf(szNewLang, _T("%3.3x "), wPrimaryLanguage);
  899. if (strLangs.Find(szNewLang) != -1)
  900. return S_OK;
  901. // load the strings we want to append and figure out how much extra space is needed for them
  902. // (including up to 5-digit index values and 2 null separators)
  903. CAtlArray<CString> astrCounters;
  904. CAtlArray<CString> astrHelp;
  905. ULONG nNewCounterSize = 0;
  906. ULONG nNewHelpSize = 0;
  907. for (UINT i=0; i<_GetNumMapEntries(); i++)
  908. {
  909. CPerfMapEntry& object = _GetMapEntry(i);
  910. astrCounters.Add(object.m_strName);
  911. nNewCounterSize += object.m_strName.GetLength() + 7;
  912. astrHelp.Add(object.m_strHelp);
  913. nNewHelpSize += object.m_strHelp.GetLength() + 7;
  914. }
  915. DWORD dwFirstCounter;
  916. DWORD dwFirstHelp;
  917. DWORD dwLastCounter;
  918. DWORD dwLastHelp;
  919. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstCounter);
  920. if (dwErr != ERROR_SUCCESS)
  921. return AtlHresultFromWin32(dwErr);
  922. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstHelp);
  923. if (dwErr != ERROR_SUCCESS)
  924. return AtlHresultFromWin32(dwErr);
  925. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
  926. if (dwErr != ERROR_SUCCESS)
  927. return AtlHresultFromWin32(dwErr);
  928. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
  929. if (dwErr != ERROR_SUCCESS)
  930. return AtlHresultFromWin32(dwErr);
  931. hr = _AppendRegStrings(rkLang, c_szAtlPerfCounter, astrCounters, nNewCounterSize, dwFirstCounter, dwLastCounter);
  932. if (FAILED(hr))
  933. return hr;
  934. hr = _AppendRegStrings(rkLang, c_szAtlPerfHelp, astrHelp, nNewHelpSize, dwFirstHelp, dwLastHelp);
  935. if (FAILED(hr))
  936. return hr;
  937. // add the language to the list of installed languages
  938. _tcscpy(szLangs+dwLangsLen, szNewLang);
  939. dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, szLangs);
  940. if (dwErr != ERROR_SUCCESS)
  941. return AtlHresultFromWin32(dwErr);
  942. return S_OK;
  943. }
  944. _ATLCATCHALL()
  945. {
  946. return E_OUTOFMEMORY;
  947. }
  948. }
  949. inline BOOL CPerfMon::EnumResLangProc(
  950. HINSTANCE hModule,
  951. LPCTSTR szType,
  952. LPCTSTR szName,
  953. LANGID wIDLanguage,
  954. LPARAM lParam
  955. ) throw()
  956. {
  957. hModule; // unused
  958. szType; // unused
  959. szName; // unused
  960. CAtlArray<LANGID>* pLangs = reinterpret_cast<CAtlArray<LANGID>*>(lParam);
  961. _ATLTRY
  962. {
  963. pLangs->Add(wIDLanguage);
  964. }
  965. _ATLCATCHALL()
  966. {
  967. return E_OUTOFMEMORY;
  968. }
  969. return TRUE;
  970. }
  971. inline HRESULT CPerfMon::RegisterAllStrings(
  972. HINSTANCE hResInstance /* = NULL */
  973. ) throw()
  974. {
  975. HRESULT hrReturn = S_FALSE;
  976. HRESULT hr;
  977. UINT nRes;
  978. hr = CreateMap(0, NULL, &nRes);
  979. if (FAILED(hr))
  980. return hr;
  981. if (nRes == 0)
  982. return RegisterStrings(0, hResInstance);
  983. if (hResInstance != NULL)
  984. return _RegisterAllStrings(nRes, hResInstance);
  985. for (int i = 0; hResInstance = _AtlBaseModule.GetHInstanceAt(i), hResInstance != NULL; i++)
  986. {
  987. hr = _RegisterAllStrings(nRes, hResInstance);
  988. if (FAILED(hr))
  989. return hr;
  990. if (hr == S_OK)
  991. hrReturn = S_OK;
  992. }
  993. return hrReturn;
  994. }
  995. inline HRESULT CPerfMon::_RegisterAllStrings(
  996. UINT nRes,
  997. HINSTANCE hResInstance
  998. ) throw()
  999. {
  1000. HRESULT hrReturn = S_FALSE;
  1001. HRESULT hr;
  1002. CAtlArray<LANGID> langs;
  1003. if (!EnumResourceLanguages(hResInstance, RT_STRING, MAKEINTRESOURCE((nRes>>4)+1), EnumResLangProc, reinterpret_cast<LPARAM>(&langs)))
  1004. return AtlHresultFromLastError();
  1005. for (UINT i=0; i<langs.GetCount(); i++)
  1006. {
  1007. hr = RegisterStrings(langs[i], hResInstance);
  1008. if (FAILED(hr))
  1009. return hr;
  1010. if (hr == S_OK)
  1011. hrReturn = S_OK;
  1012. }
  1013. return hrReturn;
  1014. }
  1015. inline HRESULT CPerfMon::_UnregisterStrings() throw()
  1016. {
  1017. _ATLTRY
  1018. {
  1019. CString str;
  1020. HRESULT hr;
  1021. DWORD dwErr;
  1022. // unregister the PerfMon counter and help strings
  1023. CRegKey rkApp;
  1024. str.Format(c_szAtlPerfPerformanceKey, GetAppName());
  1025. dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
  1026. if (dwErr != ERROR_SUCCESS)
  1027. return AtlHresultFromWin32(dwErr);
  1028. DWORD dwFirstAppCounter;
  1029. DWORD dwFirstAppHelp;
  1030. DWORD dwLastAppCounter;
  1031. DWORD dwLastAppHelp;
  1032. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstAppCounter);
  1033. if (dwErr != ERROR_SUCCESS)
  1034. return AtlHresultFromWin32(dwErr);
  1035. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstAppHelp);
  1036. if (dwErr != ERROR_SUCCESS)
  1037. return AtlHresultFromWin32(dwErr);
  1038. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastAppCounter);
  1039. if (dwErr != ERROR_SUCCESS)
  1040. return AtlHresultFromWin32(dwErr);
  1041. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastAppHelp);
  1042. if (dwErr != ERROR_SUCCESS)
  1043. return AtlHresultFromWin32(dwErr);
  1044. // iterate through the installed languages and delete them all
  1045. DWORD nChars = 0;
  1046. dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, NULL, &nChars);
  1047. if (dwErr != ERROR_SUCCESS)
  1048. return AtlHresultFromWin32(dwErr);
  1049. CString strLangs;
  1050. dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, CStrBuf(strLangs, nChars, CStrBuf::SET_LENGTH), &nChars);
  1051. if (dwErr != ERROR_SUCCESS)
  1052. return AtlHresultFromWin32(dwErr);
  1053. int nIndex = 0;
  1054. CString strLang = strLangs.Tokenize(_T(" "), nIndex);
  1055. while (!strLang.IsEmpty())
  1056. {
  1057. CRegKey rkLang;
  1058. dwErr = rkLang.Open(HKEY_LOCAL_MACHINE, CString(c_szAtlPerfPerfLibKey) + _T("\\") + strLang);
  1059. if (dwErr != ERROR_SUCCESS)
  1060. return AtlHresultFromWin32(dwErr);
  1061. hr = _RemoveRegStrings(rkLang, c_szAtlPerfCounter, dwFirstAppCounter, dwLastAppCounter);
  1062. if (FAILED(hr))
  1063. return hr;
  1064. hr = _RemoveRegStrings(rkLang, c_szAtlPerfHelp, dwFirstAppHelp, dwLastAppHelp);
  1065. if (FAILED(hr))
  1066. return hr;
  1067. strLang = strLangs.Tokenize(_T(" "), nIndex);
  1068. }
  1069. dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, _T(""));
  1070. if (dwErr != ERROR_SUCCESS)
  1071. return AtlHresultFromWin32(dwErr);
  1072. return S_OK;
  1073. }
  1074. _ATLCATCHALL()
  1075. {
  1076. return E_OUTOFMEMORY;
  1077. }
  1078. }
  1079. inline HRESULT CPerfMon::Unregister() throw()
  1080. {
  1081. CString str;
  1082. HRESULT hr;
  1083. DWORD dwErr;
  1084. CRegKey rkPerfLib;
  1085. CRegKey rkApp;
  1086. hr = _UnregisterStrings();
  1087. if (FAILED(hr))
  1088. return hr;
  1089. dwErr = rkPerfLib.Open(HKEY_LOCAL_MACHINE, c_szAtlPerfPerfLibKey);
  1090. if (dwErr != ERROR_SUCCESS)
  1091. return AtlHresultFromWin32(dwErr);
  1092. _ATLTRY
  1093. {
  1094. str.Format(c_szAtlPerfPerformanceKey, GetAppName());
  1095. }
  1096. _ATLCATCHALL()
  1097. {
  1098. return E_OUTOFMEMORY;
  1099. }
  1100. dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
  1101. if (dwErr != ERROR_SUCCESS)
  1102. return AtlHresultFromWin32(dwErr);
  1103. DWORD dwLastCounter;
  1104. DWORD dwLastHelp;
  1105. DWORD dwFirstAppCounter;
  1106. DWORD dwFirstAppHelp;
  1107. DWORD dwLastAppCounter;
  1108. DWORD dwLastAppHelp;
  1109. dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
  1110. if (dwErr != ERROR_SUCCESS)
  1111. return AtlHresultFromWin32(dwErr);
  1112. dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
  1113. if (dwErr != ERROR_SUCCESS)
  1114. return AtlHresultFromWin32(dwErr);
  1115. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstAppCounter);
  1116. if (dwErr != ERROR_SUCCESS)
  1117. return AtlHresultFromWin32(dwErr);
  1118. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstAppHelp);
  1119. if (dwErr != ERROR_SUCCESS)
  1120. return AtlHresultFromWin32(dwErr);
  1121. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastAppCounter);
  1122. if (dwErr != ERROR_SUCCESS)
  1123. return AtlHresultFromWin32(dwErr);
  1124. dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastAppHelp);
  1125. if (dwErr != ERROR_SUCCESS)
  1126. return AtlHresultFromWin32(dwErr);
  1127. // rewind the Last Help/Last Counter values if possible
  1128. if (dwLastCounter == dwLastAppCounter)
  1129. {
  1130. dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastCounter, dwFirstAppCounter-2);
  1131. if (dwErr != ERROR_SUCCESS)
  1132. return AtlHresultFromWin32(dwErr);
  1133. }
  1134. if (dwLastHelp == dwLastAppHelp)
  1135. {
  1136. dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastHelp, dwFirstAppHelp-2);
  1137. if (dwErr != ERROR_SUCCESS)
  1138. return AtlHresultFromWin32(dwErr);
  1139. }
  1140. // delete the app key
  1141. CRegKey rkServices;
  1142. rkApp.Close();
  1143. dwErr = rkServices.Open(HKEY_LOCAL_MACHINE, c_szAtlPerfServicesKey);
  1144. if (dwErr != ERROR_SUCCESS)
  1145. return AtlHresultFromWin32(dwErr);
  1146. dwErr = rkServices.RecurseDeleteKey(GetAppName());
  1147. if (dwErr != ERROR_SUCCESS)
  1148. return AtlHresultFromWin32(dwErr);
  1149. return S_OK;
  1150. }
  1151. #endif
  1152. inline HRESULT CPerfMon::Initialize() throw()
  1153. {
  1154. CMutex tempLock;
  1155. CString strAppName;
  1156. HRESULT hr;
  1157. _ATLTRY
  1158. {
  1159. strAppName = GetAppName();
  1160. ATLASSERT(m_aMem.GetCount() == 0);
  1161. // initialize a security descriptor to give everyone access to objects we create
  1162. CSecurityDescriptor sd;
  1163. sd.InitializeFromThreadToken();
  1164. SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), sd, FALSE };
  1165. // create a mutex to handle syncronizing access to the shared memory area
  1166. CString strMutexName;
  1167. strMutexName.Format(_T("ATLPERF_%s_LOCK"), strAppName);
  1168. tempLock.Create(&sa, FALSE, strMutexName);
  1169. if (tempLock.m_h == NULL)
  1170. return AtlHresultFromLastError();
  1171. // create a shared memory area to share data between the app being measured and the client doing the measuring
  1172. {
  1173. CMutexLock lock(tempLock);
  1174. BOOL bExisted = FALSE;
  1175. CAtlFileMappingBase* pMem;
  1176. pMem = _AllocNewBlock(NULL, &bExisted);
  1177. if (pMem == NULL)
  1178. return E_OUTOFMEMORY;
  1179. if (!bExisted)
  1180. {
  1181. // copy the map from the registry to the shared memory
  1182. CRegKey rkApp;
  1183. DWORD dwErr;
  1184. CString strAppKey;
  1185. strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
  1186. dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, strAppKey, KEY_READ);
  1187. if (dwErr != ERROR_SUCCESS)
  1188. {
  1189. m_aMem.RemoveAll();
  1190. return AtlHresultFromWin32(dwErr);
  1191. }
  1192. ULONG nBytes = m_nAllocSize;
  1193. dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, pMem->GetData(), &nBytes);
  1194. if (dwErr != ERROR_SUCCESS)
  1195. {
  1196. m_aMem.RemoveAll();
  1197. return AtlHresultFromWin32(dwErr);
  1198. }
  1199. }
  1200. hr = _LoadMap();
  1201. if (FAILED(hr))
  1202. {
  1203. m_aMem.RemoveAll();
  1204. return hr;
  1205. }
  1206. m_nSchemaSize = *LPDWORD(pMem->GetData());
  1207. m_nHeaderSize = m_nSchemaSize + sizeof(DWORD);
  1208. }
  1209. m_lock.Attach(tempLock.Detach());
  1210. }
  1211. _ATLCATCHALL()
  1212. {
  1213. m_aMem.RemoveAll();
  1214. return E_OUTOFMEMORY;
  1215. }
  1216. return S_OK;
  1217. }
  1218. inline void CPerfMon::UnInitialize() throw()
  1219. {
  1220. if (m_lock.m_h != NULL)
  1221. m_lock.Close();
  1222. m_aMem.RemoveAll();
  1223. ClearMap();
  1224. }
  1225. inline HRESULT CPerfMon::_CreateInstance(
  1226. DWORD dwObjectId,
  1227. DWORD dwInstance,
  1228. LPCWSTR szInstanceName,
  1229. CPerfObject** ppInstance,
  1230. bool bByName
  1231. ) throw()
  1232. {
  1233. CPerfObject* pEmptyBlock = NULL;
  1234. if (ppInstance == NULL)
  1235. return E_POINTER;
  1236. if (m_aMem.GetCount() == 0 || m_aMem[0]->GetData() == NULL || m_lock.m_h == NULL)
  1237. return E_UNEXPECTED; // Initialize must succeed before calling CreateInstance
  1238. *ppInstance = NULL;
  1239. CPerfMapEntry* pObjectEntry = _FindObjectInfo(dwObjectId);
  1240. if (pObjectEntry == NULL)
  1241. return E_INVALIDARG;
  1242. if (szInstanceName == NULL && bByName)
  1243. return E_INVALIDARG;
  1244. if (pObjectEntry->m_nInstanceLess == PERF_NO_INSTANCES &&
  1245. (dwInstance != 0 || szInstanceName != NULL))
  1246. return E_INVALIDARG;
  1247. CPerfLock lock(this);
  1248. if (FAILED(lock.GetStatus()))
  1249. return lock.GetStatus();
  1250. CAtlFileMappingBase* pCurrentBlock = m_aMem[0];
  1251. CPerfObject* pInstance = _GetFirstObject(pCurrentBlock);
  1252. ULONG nMaxInstance = 0;
  1253. ULONG nUsedSpace = 0;
  1254. // walk all of the existing objects trying to find one that matches the request
  1255. while (pInstance->m_nAllocSize != 0)
  1256. {
  1257. nUsedSpace += pInstance->m_nAllocSize;
  1258. if (pInstance->m_dwObjectId == dwObjectId)
  1259. {
  1260. nMaxInstance = max(nMaxInstance, pInstance->m_dwInstance);
  1261. // check to see if we've found the one the caller wants
  1262. if (!bByName && pInstance->m_dwInstance == dwInstance &&
  1263. (pObjectEntry->m_nInstanceLess == PERF_NO_INSTANCES || dwInstance != 0))
  1264. {
  1265. *ppInstance = pInstance;
  1266. pInstance->m_nRefCount++;
  1267. return S_OK;
  1268. }
  1269. if (bByName)
  1270. {
  1271. LPWSTR szInstName = (LPWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset));
  1272. if (wcsncmp(szInstName, szInstanceName, pObjectEntry->m_nMaxInstanceNameLen-1) == 0)
  1273. {
  1274. *ppInstance = pInstance;
  1275. pInstance->m_nRefCount++;
  1276. return S_OK;
  1277. }
  1278. }
  1279. }
  1280. if (pInstance->m_nAllocSize == pObjectEntry->m_nAllocSize && pInstance->m_dwObjectId == 0)
  1281. pEmptyBlock = pInstance;
  1282. pInstance = _GetNextObject(pInstance);
  1283. if (pInstance->m_nAllocSize == 0 &&
  1284. m_nHeaderSize + nUsedSpace + pObjectEntry->m_nAllocSize + sizeof(CPerfObject) > m_nAllocSize)
  1285. {
  1286. // we've reached the end of the block and have no room to allocate an object of this
  1287. // type. cap the block with a sentinel
  1288. pInstance->m_nAllocSize = (ULONG) -1;
  1289. }
  1290. // check for an end-of-shared-mem sentinel
  1291. if (pInstance->m_nAllocSize == (ULONG) -1)
  1292. {
  1293. nUsedSpace = 0;
  1294. CAtlFileMappingBase* pNextBlock = _GetNextBlock(pCurrentBlock);
  1295. if (pNextBlock == NULL)
  1296. {
  1297. // we've reached the last block of shared mem.
  1298. // the instance hasn't been found, so either use a
  1299. // previously freed instance block (pEmptyBlock) or allocate a new
  1300. // shared mem block to hold the new instance
  1301. if (pEmptyBlock == NULL)
  1302. {
  1303. pNextBlock = _AllocNewBlock(pCurrentBlock);
  1304. if (pNextBlock == NULL)
  1305. return E_OUTOFMEMORY;
  1306. }
  1307. else
  1308. break;
  1309. }
  1310. pCurrentBlock = pNextBlock;
  1311. pInstance = _GetFirstObject(pCurrentBlock);
  1312. }
  1313. }
  1314. // allocate a new object
  1315. if (pEmptyBlock != NULL)
  1316. pInstance = pEmptyBlock;
  1317. else
  1318. pInstance->m_nAllocSize = pObjectEntry->m_nAllocSize;
  1319. pInstance->m_dwObjectId = pObjectEntry->m_dwPerfId;
  1320. if (dwInstance == 0 && pObjectEntry->m_nInstanceLess != PERF_NO_INSTANCES)
  1321. pInstance->m_dwInstance = nMaxInstance + 1;
  1322. else
  1323. pInstance->m_dwInstance = dwInstance;
  1324. pInstance->m_nRefCount = 1;
  1325. // copy the instance name, truncate if necessary
  1326. if (pObjectEntry->m_nInstanceLess != PERF_NO_INSTANCES)
  1327. {
  1328. ULONG nNameLen = (ULONG)min(wcslen(szInstanceName), pObjectEntry->m_nMaxInstanceNameLen-1);
  1329. ULONG nNameBytes = (nNameLen+1) * sizeof(WCHAR);
  1330. pInstance->m_nInstanceNameOffset = pInstance->m_nAllocSize-nNameBytes;
  1331. memcpy(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset, szInstanceName, nNameBytes);
  1332. LPWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset)[nNameLen] = 0;
  1333. }
  1334. *ppInstance = pInstance;
  1335. return S_OK;
  1336. }
  1337. inline HRESULT CPerfMon::CreateInstance(
  1338. DWORD dwObjectId,
  1339. DWORD dwInstance,
  1340. LPCWSTR szInstanceName,
  1341. CPerfObject** ppInstance
  1342. ) throw()
  1343. {
  1344. return _CreateInstance(dwObjectId, dwInstance, szInstanceName, ppInstance, false);
  1345. }
  1346. inline HRESULT CPerfMon::CreateInstanceByName(
  1347. DWORD dwObjectId,
  1348. LPCWSTR szInstanceName,
  1349. CPerfObject** ppInstance
  1350. ) throw()
  1351. {
  1352. return _CreateInstance(dwObjectId, 0, szInstanceName, ppInstance, true);
  1353. }
  1354. inline HRESULT CPerfMon::ReleaseInstance(CPerfObject* pInstance) throw()
  1355. {
  1356. ATLASSERT(pInstance != NULL);
  1357. if (pInstance == NULL)
  1358. return E_INVALIDARG;
  1359. CPerfLock lock(this);
  1360. if (FAILED(lock.GetStatus()))
  1361. return lock.GetStatus();
  1362. if (--pInstance->m_nRefCount == 0)
  1363. {
  1364. pInstance->m_dwInstance = 0;
  1365. pInstance->m_dwObjectId = 0;
  1366. }
  1367. return S_OK;
  1368. }
  1369. inline HRESULT CPerfMon::LockPerf(DWORD dwTimeout /* == INFINITE */) throw()
  1370. {
  1371. if (m_lock.m_h == NULL)
  1372. return E_UNEXPECTED;
  1373. DWORD dwRes = WaitForSingleObject(m_lock.m_h, dwTimeout);
  1374. if (dwRes == WAIT_ABANDONED || dwRes == WAIT_OBJECT_0)
  1375. return S_OK;
  1376. if (dwRes == WAIT_TIMEOUT)
  1377. return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
  1378. return AtlHresultFromLastError();
  1379. }
  1380. inline void CPerfMon::UnlockPerf() throw()
  1381. {
  1382. m_lock.Release();
  1383. }
  1384. // map building routines
  1385. inline HRESULT CPerfMon::AddObjectDefinition(
  1386. DWORD dwObjectId,
  1387. LPCTSTR szObjectName,
  1388. LPCTSTR szHelpString,
  1389. DWORD dwDetailLevel,
  1390. INT nDefaultCounter,
  1391. BOOL bInstanceLess,
  1392. UINT nStructSize,
  1393. UINT nMaxInstanceNameLen) throw()
  1394. {
  1395. // must have one and only one of these
  1396. ATLASSERT(!bInstanceLess ^ !nMaxInstanceNameLen);
  1397. CPerfMapEntry entry;
  1398. entry.m_dwPerfId = dwObjectId;
  1399. _ATLTRY
  1400. {
  1401. entry.m_strName = szObjectName;
  1402. entry.m_strHelp = szHelpString;
  1403. }
  1404. _ATLCATCHALL()
  1405. {
  1406. return E_OUTOFMEMORY;
  1407. }
  1408. entry.m_dwDetailLevel = dwDetailLevel;
  1409. entry.m_bIsObject = TRUE;
  1410. // OBJECT INFO
  1411. entry.m_nNumCounters = 0;
  1412. entry.m_nDefaultCounter = nDefaultCounter;
  1413. entry.m_nInstanceLess = bInstanceLess ? PERF_NO_INSTANCES : 0;
  1414. entry.m_nStructSize = nStructSize;
  1415. entry.m_nMaxInstanceNameLen = nMaxInstanceNameLen;
  1416. entry.m_nAllocSize = nStructSize + nMaxInstanceNameLen*sizeof(WCHAR);
  1417. // COUNTER INFO
  1418. entry.m_dwCounterType = 0;
  1419. entry.m_nDefaultScale = 0;
  1420. entry.m_nMaxCounterSize = 0;
  1421. entry.m_nDataOffset = 0;
  1422. entry.m_nNameId = 0;
  1423. entry.m_nHelpId = 0;
  1424. _ATLTRY
  1425. {
  1426. m_map.Add(entry);
  1427. }
  1428. _ATLCATCHALL()
  1429. {
  1430. return E_OUTOFMEMORY;
  1431. }
  1432. if (_GetNumMapEntries() == 1)
  1433. m_nNumObjectTypes = 1;
  1434. else
  1435. m_nNumObjectTypes++;
  1436. return S_OK;
  1437. }
  1438. inline HRESULT CPerfMon::AddCounterDefinition(
  1439. DWORD dwCounterId,
  1440. LPCTSTR szCounterName,
  1441. LPCTSTR szHelpString,
  1442. DWORD dwDetailLevel,
  1443. DWORD dwCounterType,
  1444. ULONG nMaxCounterSize,
  1445. UINT nOffset,
  1446. INT nDefaultScale) throw()
  1447. {
  1448. for (int i=_GetNumMapEntries()-1; i>=0; i--)
  1449. {
  1450. CPerfMapEntry& object = _GetMapEntry(i);
  1451. if (object.m_bIsObject)
  1452. {
  1453. CPerfMapEntry counter;
  1454. counter.m_dwPerfId = dwCounterId;
  1455. _ATLTRY
  1456. {
  1457. counter.m_strName = szCounterName;
  1458. counter.m_strHelp = szHelpString;
  1459. }
  1460. _ATLCATCHALL()
  1461. {
  1462. return E_OUTOFMEMORY;
  1463. }
  1464. counter.m_dwDetailLevel = dwDetailLevel;
  1465. counter.m_bIsObject = FALSE;
  1466. // OBJECT INFO
  1467. counter.m_nNumCounters = 0;
  1468. counter.m_nDefaultCounter = 0;
  1469. counter.m_nInstanceLess = 0;
  1470. counter.m_nStructSize = 0;
  1471. counter.m_nMaxInstanceNameLen = 0;
  1472. counter.m_nAllocSize = 0;
  1473. // COUNTER INFO
  1474. counter.m_dwCounterType = dwCounterType;
  1475. counter.m_nDefaultScale = nDefaultScale;
  1476. counter.m_nMaxCounterSize = nMaxCounterSize;
  1477. counter.m_nDataOffset = nOffset;
  1478. object.m_nNumCounters++;
  1479. if (counter.m_nMaxCounterSize > 0)
  1480. {
  1481. ATLASSERT(counter.m_dwCounterType & PERF_TYPE_TEXT);
  1482. object.m_nAllocSize += counter.m_nMaxCounterSize * sizeof(WCHAR);
  1483. }
  1484. counter.m_nNameId = 0;
  1485. counter.m_nHelpId = 0;
  1486. _ATLTRY
  1487. {
  1488. m_map.Add(counter);
  1489. }
  1490. _ATLCATCHALL()
  1491. {
  1492. return E_OUTOFMEMORY;
  1493. }
  1494. return S_OK;
  1495. }
  1496. }
  1497. // found no object in map! must add object BEFORE adding counter!
  1498. ATLASSERT(FALSE);
  1499. return E_UNEXPECTED;
  1500. }
  1501. inline void CPerfMon::ClearMap() throw()
  1502. {
  1503. m_map.RemoveAll();
  1504. }
  1505. #ifndef _ATL_PERF_NOXML
  1506. ATL_NOINLINE inline HRESULT CPerfMon::PersistToXML(IStream *pStream, BOOL bFirst/*=TRUE*/, BOOL bLast/*=TRUE*/) throw(...)
  1507. {
  1508. ATLASSERT(pStream != NULL);
  1509. if (pStream == NULL)
  1510. return E_INVALIDARG;
  1511. CPerfLock lock(this);
  1512. if (FAILED(lock.GetStatus()))
  1513. return ERROR_SUCCESS;
  1514. CStringA strXML;
  1515. HRESULT hr = S_OK;
  1516. ULONG nLen = 0;
  1517. if (bFirst)
  1518. {
  1519. strXML = "<?xml version=\"1.0\" ?>\r\n<perfPersist>\r\n";
  1520. hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
  1521. if (hr != S_OK)
  1522. return hr;
  1523. }
  1524. strXML.Format("\t<perfmon name=\"%s\">\r\n", CT2CA(GetAppName()));
  1525. hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
  1526. for (UINT i=0; i<_GetNumMapEntries(); i+= _GetMapEntry(i).m_nNumCounters+1)
  1527. {
  1528. CPerfMapEntry *pObjectEntry = &_GetMapEntry(i);
  1529. CPerfMapEntry *pCounterEntries = pObjectEntry+1;
  1530. CAtlFileMappingBase *pCurrentBlock = _GetNextBlock(NULL);
  1531. CPerfObject *pInstance = _GetFirstObject(pCurrentBlock);
  1532. strXML.Format("\t\t<perfObject perfid=\"%d\">\r\n",
  1533. pObjectEntry->m_dwPerfId, pObjectEntry->m_nNameId, pObjectEntry->m_nHelpId);
  1534. hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
  1535. if (hr != S_OK)
  1536. return E_FAIL;
  1537. while (pInstance && pInstance->m_nAllocSize)
  1538. {
  1539. if (pInstance->m_dwObjectId == pObjectEntry->m_dwPerfId)
  1540. {
  1541. if (pObjectEntry->m_nInstanceLess != PERF_NO_INSTANCES)
  1542. {
  1543. // handle the instance name
  1544. LPCWSTR wszInstNameSrc = LPCWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset);
  1545. int nInstLen = (int) wcslen(wszInstNameSrc);
  1546. // convert to UTF8
  1547. nLen = AtlUnicodeToUTF8(wszInstNameSrc, nInstLen, NULL, 0);
  1548. CHeapPtr<CHAR> szUTF8;
  1549. if (!szUTF8.Allocate(nLen+1))
  1550. return E_OUTOFMEMORY;
  1551. nLen = AtlUnicodeToUTF8(wszInstNameSrc, nInstLen, szUTF8, nLen);
  1552. szUTF8[nLen] = '\0';
  1553. strXML.Format("\t\t\t<instance name=\"%s\">\r\n", szUTF8);
  1554. hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
  1555. if (hr != S_OK)
  1556. return hr;
  1557. }
  1558. for (ULONG j=0; j<pObjectEntry->m_nNumCounters; j++)
  1559. {
  1560. CPerfMapEntry *pCounterEntry = pCounterEntries+j;
  1561. switch (pCounterEntry->m_dwCounterType & ATLPERF_SIZE_MASK)
  1562. {
  1563. case PERF_SIZE_DWORD:
  1564. {
  1565. strXML.Format("\t\t\t\t<counter type=\"perf_size_dword\" value=\"%d\" offset=\"%d\"/>\r\n",
  1566. *LPDWORD(LPBYTE(pInstance)+pCounterEntry->m_nDataOffset),
  1567. pCounterEntry->m_nDataOffset);
  1568. break;
  1569. }
  1570. case PERF_SIZE_LARGE:
  1571. {
  1572. strXML.Format("\t\t\t\t<counter type=\"perf_size_large\" value=\"%d\" offset=\"%d\"/>\r\n",
  1573. *PULONGLONG(LPBYTE(pInstance)+pCounterEntry->m_nDataOffset),
  1574. pCounterEntry->m_nDataOffset);
  1575. break;
  1576. }
  1577. case PERF_SIZE_VARIABLE_LEN:
  1578. {
  1579. CHeapPtr<CHAR> szUTF8;
  1580. LPBYTE pSrc = LPBYTE(pInstance)+pCounterEntry->m_nDataOffset;
  1581. if ((pCounterEntry->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
  1582. {
  1583. ULONG nTextLen = (ULONG)wcslen(LPCWSTR(pSrc));
  1584. // convert to UTF8
  1585. nLen = AtlUnicodeToUTF8(LPCWSTR(pSrc), nTextLen, NULL, 0);
  1586. if (!szUTF8.Allocate(nLen+1))
  1587. return E_OUTOFMEMORY;
  1588. nLen = AtlUnicodeToUTF8(LPCWSTR(pSrc), nTextLen, szUTF8, nLen);
  1589. szUTF8[nLen] = '\0';
  1590. strXML.Format("\t\t\t\t<counter type=\"perf_size_variable_len_unicode\" value=\"%s\" offset=\"%d\"/>\r\n",
  1591. szUTF8,
  1592. pCounterEntry->m_nDataOffset);
  1593. }
  1594. else
  1595. {
  1596. ULONG nTextLen = (ULONG)strlen(LPCSTR(pSrc));
  1597. if (!szUTF8.Allocate(nTextLen+1))
  1598. return E_OUTOFMEMORY;
  1599. strcpy(szUTF8, LPCSTR(pSrc));
  1600. strXML.Format("\t\t\t\t<counter type=\"perf_size_variable_len_ansi\" value=\"%s\" offset=\"%d\"/>\r\n",
  1601. szUTF8,
  1602. pCounterEntry->m_nDataOffset);
  1603. }
  1604. break;
  1605. }
  1606. default:
  1607. // error:
  1608. return E_FAIL;
  1609. }
  1610. hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
  1611. if (hr != S_OK)
  1612. return hr;
  1613. }
  1614. }
  1615. if (pObjectEntry->m_nInstanceLess != PERF_NO_INSTANCES)
  1616. {
  1617. hr = pStream->Write("\t\t\t</instance>\r\n", sizeof("\t\t\t</instance>\r\n")-1, &nLen);
  1618. if (hr != S_OK)
  1619. return hr;
  1620. }
  1621. pInstance = _GetNextObject(pInstance);
  1622. if (pInstance->m_nAllocSize == (ULONG)-1)
  1623. {
  1624. pCurrentBlock = _GetNextBlock(pCurrentBlock);
  1625. if (pCurrentBlock == NULL)
  1626. pInstance = NULL;
  1627. else
  1628. pInstance = _GetFirstObject(pCurrentBlock);
  1629. }
  1630. }
  1631. hr = pStream->Write("\t\t</perfObject>\r\n", sizeof("\t\t</perfObject>\r\n")-1, &nLen);
  1632. if (hr != S_OK)
  1633. return hr;
  1634. }
  1635. hr = pStream->Write("\t</perfmon>\r\n", sizeof("\t</perfmon>\r\n")-1, &nLen);
  1636. if (hr != S_OK)
  1637. return hr;
  1638. if (hr == S_OK && bLast)
  1639. hr = pStream->Write("</perfPersist>", sizeof("</perfPersist>")-1, &nLen);
  1640. return hr;
  1641. }
  1642. // This function is very lenient with inappropriate XML
  1643. ATL_NOINLINE inline HRESULT CPerfMon::LoadFromXML(IStream *pStream) throw(...)
  1644. {
  1645. ATLASSERT(pStream != NULL);
  1646. if (pStream == NULL)
  1647. return E_INVALIDARG;
  1648. // Get a lock
  1649. CPerfLock lock(this);
  1650. if (FAILED(lock.GetStatus()))
  1651. return ERROR_SUCCESS;
  1652. CComPtr<IXMLDOMDocument> spdoc;
  1653. // load the xml
  1654. HRESULT hr = CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC, __uuidof(IXMLDOMDocument), (void **) &spdoc);
  1655. if (FAILED(hr))
  1656. {
  1657. return hr;
  1658. }
  1659. spdoc->put_async(VARIANT_FALSE);
  1660. CComPtr<IPersistStreamInit> spSI;
  1661. hr = spdoc->QueryInterface(&spSI);
  1662. if (hr != S_OK)
  1663. return hr;
  1664. hr = spSI->Load(pStream);
  1665. if (hr != S_OK)
  1666. return hr;
  1667. // validate that it is a perfPersist stream
  1668. CComPtr<IXMLDOMElement> spRoot;
  1669. hr = spdoc->get_documentElement(&spRoot);
  1670. if (hr != S_OK)
  1671. return hr;
  1672. CComBSTR bstrName;
  1673. hr = spRoot->get_baseName(&bstrName);
  1674. if (wcscmp(bstrName, L"perfPersist"))
  1675. return S_FALSE;
  1676. USES_CONVERSION;
  1677. // find the appropriate perfmon node
  1678. CComPtr<IXMLDOMNode> spChild;
  1679. hr = spRoot->get_firstChild(&spChild);
  1680. while (hr == S_OK)
  1681. {
  1682. bstrName.Empty();
  1683. hr = spChild->get_baseName(&bstrName);
  1684. if (hr == S_OK)
  1685. {
  1686. if (!wcscmp(bstrName, L"perfmon"))
  1687. {
  1688. bstrName.Empty();
  1689. hr = _GetAttribute(spChild, L"name", &bstrName);
  1690. if (hr == S_OK)
  1691. {
  1692. if (!_tcscmp(W2CT(bstrName), GetAppName()))
  1693. break;
  1694. }
  1695. }
  1696. }
  1697. CComPtr<IXMLDOMNode> spNext;
  1698. hr = spChild->get_nextSibling(&spNext);
  1699. spChild.Attach(spNext.Detach());
  1700. }
  1701. // there is no perfmon node in the XML for the current CPerfMon class
  1702. if (hr != S_OK)
  1703. return S_FALSE;
  1704. CComPtr<IXMLDOMNode> spPerfRoot;
  1705. spPerfRoot.Attach(spChild.Detach());
  1706. // iterate over the objects in the perfmon subtree
  1707. // this is the loop that does the real work
  1708. hr = spPerfRoot->get_firstChild(&spChild);
  1709. DWORD dwInstance = 1;
  1710. while (hr == S_OK)
  1711. {
  1712. // see if it's a perfObject
  1713. bstrName.Empty();
  1714. hr = spChild->get_baseName(&bstrName);
  1715. if (hr != S_OK || wcscmp(bstrName, L"perfObject"))
  1716. return S_FALSE;
  1717. // get the perfid
  1718. bstrName.Empty();
  1719. hr = _GetAttribute(spChild, L"perfid", &bstrName);
  1720. DWORD dwPerfId = _wtoi(bstrName);
  1721. // iterate over children
  1722. CComPtr<IXMLDOMNode> spInstChild;
  1723. hr = spChild->get_firstChild(&spInstChild);
  1724. while (hr == S_OK)
  1725. {
  1726. // see if it's a instance
  1727. bstrName.Empty();
  1728. hr = spInstChild->get_baseName(&bstrName);
  1729. if (hr != S_OK || wcscmp(bstrName, L"instance"))
  1730. return S_FALSE;
  1731. // get the instance name
  1732. bstrName.Empty();
  1733. hr = _GetAttribute(spInstChild, L"name", &bstrName);
  1734. if (hr != S_OK)
  1735. return S_FALSE;
  1736. // create the instance
  1737. // REVIEW : take a loook at the dwInstance stuff--is it acceptable?
  1738. CPerfObject *pInstance = NULL;
  1739. hr = CreateInstance(dwPerfId, dwInstance++, bstrName, &pInstance);
  1740. if (hr != S_OK)
  1741. return S_FALSE;
  1742. // iterate over the counters and set the data
  1743. CComPtr<IXMLDOMNode> spCntrChild;
  1744. hr = spInstChild->get_firstChild(&spCntrChild);
  1745. while (hr == S_OK)
  1746. {
  1747. // get the base name
  1748. bstrName.Empty();
  1749. hr = spCntrChild->get_baseName(&bstrName);
  1750. if (hr != S_OK || wcscmp(bstrName, L"counter"))
  1751. return S_FALSE;
  1752. // get the type
  1753. bstrName.Empty();
  1754. hr = _GetAttribute(spCntrChild, L"type", &bstrName);
  1755. if (hr != S_OK)
  1756. return S_FALSE;
  1757. DWORD dwType;
  1758. if (!wcscmp(bstrName, L"perf_size_dword"))
  1759. dwType = PERF_SIZE_DWORD;
  1760. else if (!wcscmp(bstrName, L"perf_size_large"))
  1761. dwType = PERF_SIZE_LARGE;
  1762. else if (!wcscmp(bstrName, L"perf_size_variable_len_ansi"))
  1763. dwType = PERF_SIZE_VARIABLE_LEN;
  1764. else if (!wcscmp(bstrName, L"perf_size_variable_len_unicode"))
  1765. dwType = PERF_SIZE_VARIABLE_LEN | PERF_TEXT_UNICODE;
  1766. else
  1767. return S_FALSE;
  1768. // get the value
  1769. bstrName.Empty();
  1770. hr = _GetAttribute(spCntrChild, L"value", &bstrName);
  1771. if (hr != S_OK)
  1772. return S_FALSE;
  1773. CComBSTR bstrOffset;
  1774. hr = _GetAttribute(spCntrChild, L"offset", &bstrOffset);
  1775. if (hr != S_OK)
  1776. return S_FALSE;
  1777. WCHAR *pStop = NULL;
  1778. DWORD dwOffset = wcstoul(bstrOffset, &pStop, 10);
  1779. if (dwType == PERF_SIZE_DWORD) // add it as a DWORD
  1780. {
  1781. DWORD dwVal = wcstoul(bstrName, &pStop, 10);
  1782. *LPDWORD(LPBYTE(pInstance)+dwOffset) = dwVal;
  1783. }
  1784. else if (dwType == PERF_SIZE_LARGE) // add it is a ULONGLONG
  1785. {
  1786. ULONGLONG qwVal = _wcstoui64(bstrName, &pStop, 10);
  1787. *PULONGLONG(LPBYTE(pInstance)+dwOffset) = qwVal;
  1788. }
  1789. else if (dwType == PERF_SIZE_VARIABLE_LEN) // add it as an ansi string
  1790. {
  1791. AtlW2AHelper(LPSTR(LPBYTE(pInstance)+dwOffset), bstrName, bstrName.Length(), ATL::_AtlGetConversionACP());
  1792. }
  1793. else // add it as a unicode string
  1794. {
  1795. memcpy(LPBYTE(pInstance)+dwOffset, bstrName, bstrName.Length()*sizeof(WCHAR));
  1796. }
  1797. CComPtr<IXMLDOMNode> spCntrNext;
  1798. hr = spCntrChild->get_nextSibling(&spCntrNext);
  1799. spCntrChild.Attach(spCntrNext.Detach());
  1800. }
  1801. CComPtr<IXMLDOMNode> spInstNext;
  1802. hr = spInstChild->get_nextSibling(&spInstNext);
  1803. spInstChild.Attach(spInstNext.Detach());
  1804. }
  1805. CComPtr<IXMLDOMNode> spNext;
  1806. hr = spChild->get_nextSibling(&spNext);
  1807. spChild.Attach(spNext.Detach());
  1808. }
  1809. return S_OK;
  1810. }
  1811. // a little utility function to retrieve a named attribute from a node
  1812. ATL_NOINLINE inline HRESULT CPerfMon::_GetAttribute(IXMLDOMNode *pNode, LPCWSTR szAttrName, BSTR *pbstrVal) throw()
  1813. {
  1814. ATLASSERT(pNode != NULL);
  1815. ATLASSERT(szAttrName != NULL);
  1816. ATLASSERT(pbstrVal != NULL);
  1817. *pbstrVal = NULL;
  1818. CComPtr<IXMLDOMNamedNodeMap> spAttrs;
  1819. HRESULT hr = pNode->get_attributes(&spAttrs);
  1820. if (hr != S_OK)
  1821. return hr;
  1822. CComPtr<IXMLDOMNode> spAttr;
  1823. hr = spAttrs->getNamedItem((BSTR) szAttrName, &spAttr);
  1824. if (hr != S_OK)
  1825. return hr;
  1826. CComVariant varVal;
  1827. hr = spAttr->get_nodeValue(&varVal);
  1828. if (hr != S_OK)
  1829. return hr;
  1830. hr = varVal.ChangeType(VT_BSTR);
  1831. if (hr != S_OK)
  1832. return hr;
  1833. *pbstrVal = varVal.bstrVal;
  1834. varVal.vt = VT_EMPTY;
  1835. return S_OK;
  1836. }
  1837. #endif // _ATL_PERF_NOXML
  1838. } // namespace ATL
  1839. #pragma warning(pop)
  1840. #endif // __ATLPERF_INL__