1 // This is a part of the Active Template Library.
\r
2 // Copyright (C) Microsoft Corporation
\r
3 // All rights reserved.
\r
5 // This source code is only intended as a supplement to the
\r
6 // Active Template Library Reference and related
\r
7 // electronic documentation provided with the library.
\r
8 // See these sources for detailed information regarding the
\r
9 // Active Template Library product.
\r
11 #ifndef __ATLPERF_INL__
\r
12 #define __ATLPERF_INL__
\r
16 #ifndef __ATLPERF_H__
\r
17 #error atlperf.inl requires atlperf.h to be included first
\r
20 #pragma warning(push)
\r
23 #pragma warning(disable: 4702) // unreachable code
\r
29 extern __declspec(selectany) const TCHAR * const c_szAtlPerfCounter = _T("Counter");
\r
30 extern __declspec(selectany) const TCHAR * const c_szAtlPerfFirstCounter = _T("First Counter");
\r
31 extern __declspec(selectany) const TCHAR * const c_szAtlPerfLastCounter = _T("Last Counter");
\r
32 extern __declspec(selectany) const TCHAR * const c_szAtlPerfHelp = _T("Help");
\r
33 extern __declspec(selectany) const TCHAR * const c_szAtlPerfFirstHelp = _T("First Help");
\r
34 extern __declspec(selectany) const TCHAR * const c_szAtlPerfLastHelp = _T("Last Help");
\r
36 extern __declspec(selectany) const WCHAR * const c_szAtlPerfGlobal = L"Global";
\r
37 extern __declspec(selectany) const TCHAR * const c_szAtlPerfLibrary = _T("Library");
\r
38 extern __declspec(selectany) const TCHAR * const c_szAtlPerfOpen = _T("Open");
\r
39 extern __declspec(selectany) const TCHAR * const c_szAtlPerfCollect = _T("Collect");
\r
40 extern __declspec(selectany) const TCHAR * const c_szAtlPerfClose = _T("Close");
\r
41 extern __declspec(selectany) const TCHAR * const c_szAtlPerfLanguages = _T("Languages");
\r
42 extern __declspec(selectany) const TCHAR * const c_szAtlPerfMap = _T("Map");
\r
43 extern __declspec(selectany) const TCHAR * const c_szAtlPerfPerformance = _T("Performance");
\r
44 extern __declspec(selectany) const TCHAR * const c_szAtlPerfServicesKey = _T("SYSTEM\\CurrentControlSet\\Services\\%s");
\r
45 extern __declspec(selectany) const TCHAR * const c_szAtlPerfPerformanceKey = _T("SYSTEM\\CurrentControlSet\\Services\\%s\\Performance");
\r
46 extern __declspec(selectany) const TCHAR * const c_szAtlPerfPerfLibKey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
\r
47 extern __declspec(selectany) const TCHAR * const c_szAtlPerfPerfLibLangKey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\%3.3x");
\r
49 inline CPerfMon::CounterInfo* CPerfMon::CategoryInfo::_GetCounterInfo(UINT nIndex) throw()
\r
51 ATLASSERT(nIndex < _GetNumCounters());
\r
52 return &m_counters[nIndex];
\r
55 inline UINT CPerfMon::CategoryInfo::_GetNumCounters() throw()
\r
57 return (UINT) m_counters.GetCount();
\r
60 inline CPerfMon::~CPerfMon() throw()
\r
65 inline HRESULT CPerfMon::CreateMap(LANGID language, HINSTANCE hResInstance, UINT* pSampleRes) throw()
\r
67 (language); // unused
\r
68 (hResInstance); // unused
\r
69 (pSampleRes); // unused
\r
73 inline UINT CPerfMon::_GetNumCategoriesAndCounters() throw()
\r
75 UINT nResult = _GetNumCategories();
\r
76 for (UINT i=0; i<_GetNumCategories(); i++)
\r
78 nResult += _GetCategoryInfo(i)->_GetNumCounters();
\r
84 inline CPerfMon::CategoryInfo* CPerfMon::_GetCategoryInfo(UINT nIndex) throw()
\r
86 ATLASSERT(nIndex < _GetNumCategories());
\r
87 return &m_categories[nIndex];
\r
90 inline UINT CPerfMon::_GetNumCategories() throw()
\r
92 return (UINT) m_categories.GetCount();
\r
95 inline CPerfObject* CPerfMon::_GetFirstInstance(CAtlFileMappingBase* pBlock)
\r
97 ATLENSURE(pBlock != NULL);
\r
99 // should never happen if Initialize succeeded
\r
100 // are you checking return codes?
\r
101 ATLASSERT(pBlock->GetData() != NULL);
\r
103 return reinterpret_cast<CPerfObject*>(LPBYTE(pBlock->GetData()) + m_nHeaderSize);
\r
106 inline CPerfObject* CPerfMon::_GetNextInstance(CPerfObject* pInstance)
\r
108 ATLENSURE_RETURN_VAL(pInstance != NULL, NULL);
\r
109 ATLENSURE_RETURN_VAL(pInstance->m_nAllocSize != (ULONG)-1, NULL);
\r
110 ATLASSERT(pInstance->m_nAllocSize != (ULONG)0);
\r
112 return reinterpret_cast<CPerfObject*>(LPBYTE(pInstance) + pInstance->m_nAllocSize);
\r
115 inline CAtlFileMappingBase* CPerfMon::_GetNextBlock(CAtlFileMappingBase* pBlock) throw()
\r
117 // calling _GetNextBlock(NULL) will return the first block
\r
118 DWORD dwNextBlockIndex = 0;
\r
119 DWORD* pDw= _GetBlockId_NoThrow(pBlock);
\r
122 dwNextBlockIndex = *pDw +1;
\r
124 if (m_aMem.GetCount() == dwNextBlockIndex)
\r
126 return m_aMem[dwNextBlockIndex];
\r
129 inline CAtlFileMappingBase* CPerfMon::_OpenNextBlock(CAtlFileMappingBase* pPrev) throw()
\r
131 CAutoPtr<CAtlFileMappingBase> spMem;
\r
132 CAtlFileMappingBase* pMem = NULL;
\r
133 ATLTRY(spMem.Attach(new CAtlFileMappingBase));
\r
137 // create a unique name for the shared mem segment based on the index
\r
138 DWORD dwNextBlockIndex;
\r
139 DWORD* pDw= _GetBlockId_NoThrow(pPrev);
\r
142 dwNextBlockIndex = *pDw +1;
\r
146 // use the system allocation granularity (65536 currently. may be different in the future)
\r
148 GetSystemInfo(&si);
\r
149 m_nAllocSize = si.dwAllocationGranularity;
\r
151 dwNextBlockIndex = 0;
\r
157 strName.Format(_T("Global\\ATLPERF_%s_%3.3d"), GetAppName(), dwNextBlockIndex);
\r
159 HRESULT hr = spMem->OpenMapping(strName, m_nAllocSize, 0, FILE_MAP_READ);
\r
174 inline CAtlFileMappingBase* CPerfMon::_AllocNewBlock(CAtlFileMappingBase* pPrev, BOOL* pbExisted /* == NULL */) throw()
\r
176 CAtlFileMappingBase* pMem = NULL;
\r
179 CSecurityAttributes sa;
\r
182 CAutoPtr<CAtlFileMappingBase> spMem;
\r
183 spMem.Attach(new CAtlFileMappingBase);
\r
189 // create a unique name for the shared mem segment based on the index
\r
190 DWORD dwNextBlockIndex;
\r
193 dwNextBlockIndex = _GetBlockId(pPrev) +1;
\r
197 // use the system allocation granularity (65536 currently. may be different in the future)
\r
199 GetSystemInfo(&si);
\r
200 m_nAllocSize = si.dwAllocationGranularity;
\r
202 dwNextBlockIndex = 0;
\r
205 BOOL bExisted = FALSE;
\r
207 strName.Format(_T("Global\\ATLPERF_%s_%3.3d"), GetAppName(), dwNextBlockIndex);
\r
209 HRESULT hr = spMem->MapSharedMem(m_nAllocSize, strName, &bExisted, &sa);
\r
217 memset(spMem->GetData(), 0, m_nAllocSize);
\r
218 // save the index of this block
\r
219 // don't for first block since we don't know m_nSchemaSize yet
\r
220 if (dwNextBlockIndex)
\r
222 _GetBlockId(spMem) = dwNextBlockIndex;
\r
230 m_sd.GetOwner(&owner);
\r
231 m_sd.GetDacl(&dacl);
\r
233 // prevent us from using an object someone else has opened
\r
234 if (::SetSecurityInfo(spMem->GetHandle(), SE_KERNEL_OBJECT,
\r
235 DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
\r
236 const_cast<SID*>(owner.GetPSID()),
\r
238 const_cast<ACL*>(dacl.GetPACL()),
\r
239 NULL) != ERROR_SUCCESS)
\r
247 *pbExisted = bExisted;
\r
253 OnBlockAlloc(pMem);
\r
263 inline HRESULT CPerfMon::_OpenAllBlocks() throw()
\r
267 // if we haven't opened any yet, initialize
\r
268 if (m_aMem.GetCount() == 0)
\r
270 CAtlFileMappingBase* pMem = _OpenNextBlock(NULL);
\r
274 hr = _LoadMap(LPDWORD(pMem->GetData()));
\r
277 m_aMem.RemoveAll();
\r
281 m_nSchemaSize = *LPDWORD(pMem->GetData());
\r
282 m_nHeaderSize = m_nSchemaSize + sizeof(DWORD);
\r
283 m_nHeaderSize = AtlAlignUp(m_nHeaderSize,16);
\r
286 // open any new blocks
\r
287 CAtlFileMappingBase* pMem = m_aMem[m_aMem.GetCount()-1];
\r
289 pMem = _OpenNextBlock(pMem);
\r
294 inline HRESULT CPerfMon::_LoadMap(DWORD* pData) throw()
\r
302 DWORD dwDataSize = *pData++; // blob size
\r
303 DWORD dwNumItems = *pData++; // number of items
\r
305 // see if we have name data
\r
306 DWORD* pNameData = NULL;
\r
307 if (dwDataSize > (2+dwNumItems*9) * sizeof(DWORD))
\r
308 pNameData = pData + dwNumItems*9; // blob size and item count already skipped. skip item data
\r
310 for (DWORD i=0; i<dwNumItems; i++)
\r
312 DWORD dwIsObject = *pData++;
\r
313 DWORD dwPerfId = *pData++;
\r
314 DWORD dwDetailLevel = *pData++;
\r
319 strName = CString(LPWSTR(pNameData+1), *pNameData);
\r
320 pNameData += AtlAlignUp(sizeof(WCHAR) * *pNameData, sizeof(DWORD))/sizeof(DWORD) + 1;
\r
325 DWORD dwDefaultCounter = *pData++;
\r
326 DWORD dwInstanceLess = *pData++;
\r
327 DWORD dwStructSize = *pData++;
\r
328 DWORD dwMaxInstanceNameLen = *pData++;
\r
330 hr = AddCategoryDefinition(
\r
338 dwMaxInstanceNameLen);
\r
345 DWORD dwNameId = *pData++;
\r
346 DWORD dwHelpId = *pData++;
\r
347 CategoryInfo* pCategoryInfo = _GetCategoryInfo(_GetNumCategories()-1);
\r
348 pCategoryInfo->m_nNameId = dwNameId;
\r
349 pCategoryInfo->m_nHelpId = dwHelpId;
\r
353 DWORD dwCounterType = *pData++;
\r
354 DWORD dwMaxCounterSize = *pData++;
\r
355 DWORD dwDataOffset = *pData++;
\r
356 DWORD dwDefaultScale = *pData++;
\r
358 hr = AddCounterDefinition(
\r
373 DWORD dwNameId = *pData++;
\r
374 DWORD dwHelpId = *pData++;
\r
375 CategoryInfo* pCategoryInfo = _GetCategoryInfo(_GetNumCategories()-1);
\r
376 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(pCategoryInfo->_GetNumCounters()-1);
\r
377 pCounterInfo->m_nNameId = dwNameId;
\r
378 pCounterInfo->m_nHelpId = dwHelpId;
\r
382 // fill in cache data
\r
383 ULONG* pnCounterBlockSize = NULL; // pointer to the object's counter block size
\r
384 for (DWORD i=0; i<_GetNumCategories(); i++)
\r
386 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
387 // align at 8 bytes per Q262335
\r
388 pCategoryInfo->m_nCounterBlockSize = (ULONG) AtlAlignUp(sizeof(PERF_COUNTER_BLOCK), 8);
\r
389 pnCounterBlockSize = &pCategoryInfo->m_nCounterBlockSize;
\r
390 _FillCategoryType(pCategoryInfo);
\r
391 for (DWORD j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
393 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
394 _FillCounterDef(pCounterInfo, pnCounterBlockSize);
\r
396 // align at 8 bytes per Q262335
\r
397 pCategoryInfo->m_nCounterBlockSize = (ULONG) AtlAlignUp(pCategoryInfo->m_nCounterBlockSize, 8);
\r
404 return E_OUTOFMEMORY;
\r
408 inline HRESULT CPerfMon::_SaveMap() throw()
\r
412 // figure out how much memory we need
\r
413 size_t nSize = (2 + 9*_GetNumCategoriesAndCounters()) * sizeof(DWORD);
\r
414 for (UINT i=0; i<_GetNumCategories(); i++)
\r
416 // if any of the entries have names, they'd better all have names
\r
417 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
418 if (!pCategoryInfo->m_strName.IsEmpty())
\r
420 nSize += sizeof(DWORD) + AtlAlignUp(sizeof(WCHAR) * pCategoryInfo->m_strName.GetLength(), sizeof(DWORD));
\r
421 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
423 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
424 nSize += sizeof(DWORD) + AtlAlignUp(sizeof(WCHAR) * pCounterInfo->m_strName.GetLength(), sizeof(DWORD));
\r
429 CHeapPtr<BYTE> blob;
\r
430 if (!blob.Allocate(nSize))
\r
431 return E_OUTOFMEMORY;
\r
433 // start with blob size and number of items in the blob
\r
434 DWORD* pCurrent = reinterpret_cast<DWORD*>(blob.m_pData);
\r
435 memset(pCurrent, 0, nSize);
\r
436 *pCurrent++ = (DWORD) nSize; // blob size
\r
437 *pCurrent++ = _GetNumCategoriesAndCounters(); // number of items
\r
438 size_t nSizeLast = nSize;
\r
439 nSize -= 2 * sizeof(DWORD);
\r
440 if(nSize > nSizeLast) return E_FAIL;
\r
442 for (UINT i=0; i<_GetNumCategories(); i++)
\r
444 // add all the relevant runtime info to the blob for each item
\r
445 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
447 *pCurrent++ = TRUE; // is object
\r
448 *pCurrent++ = pCategoryInfo->m_dwCategoryId;
\r
449 *pCurrent++ = pCategoryInfo->m_dwDetailLevel;
\r
450 *pCurrent++ = pCategoryInfo->m_nDefaultCounter;
\r
451 *pCurrent++ = pCategoryInfo->m_nInstanceLess;
\r
452 *pCurrent++ = pCategoryInfo->m_nStructSize;
\r
453 *pCurrent++ = pCategoryInfo->m_nMaxInstanceNameLen;
\r
454 *pCurrent++ = pCategoryInfo->m_nNameId;
\r
455 *pCurrent++ = pCategoryInfo->m_nHelpId;
\r
457 nSize -= 9 * sizeof(DWORD);
\r
458 if(nSize > nSizeLast) return E_FAIL;
\r
460 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
462 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
464 *pCurrent++ = FALSE; // is object
\r
465 *pCurrent++ = pCounterInfo->m_dwCounterId;
\r
466 *pCurrent++ = pCounterInfo->m_dwDetailLevel;
\r
467 *pCurrent++ = pCounterInfo->m_dwCounterType;
\r
468 *pCurrent++ = pCounterInfo->m_nMaxCounterSize;
\r
469 *pCurrent++ = pCounterInfo->m_nDataOffset;
\r
470 *pCurrent++ = pCounterInfo->m_nDefaultScale;
\r
471 *pCurrent++ = pCounterInfo->m_nNameId;
\r
472 *pCurrent++ = pCounterInfo->m_nHelpId;
\r
474 nSize -= 9 * sizeof(DWORD);
\r
475 if(nSize > nSizeLast) return E_FAIL;
\r
479 // add names to the blob
\r
480 for (UINT i=0; i<_GetNumCategories(); i++)
\r
482 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
483 // copy the len of the string (in characters) then the wide-char version of the string
\r
484 // pad the string to a dword boundary
\r
485 int nLen = pCategoryInfo->m_strName.GetLength();
\r
486 *pCurrent++ = nLen;
\r
488 nSize -= sizeof(DWORD);
\r
489 if(nSize > nSizeLast) return E_FAIL;
\r
491 Checked::memcpy_s(pCurrent, nSize, CT2CW(pCategoryInfo->m_strName), sizeof(WCHAR)*nLen);
\r
492 pCurrent += AtlAlignUp(sizeof(WCHAR) * nLen, sizeof(DWORD))/sizeof(DWORD);
\r
494 nSize -= sizeof(WCHAR)*nLen;
\r
495 if(nSize > nSizeLast) return E_FAIL;
\r
497 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
499 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
500 // copy the len of the string (in characters) then the wide-char version of the string
\r
501 // pad the string to a dword boundary
\r
502 int nCounterLen = pCounterInfo->m_strName.GetLength();
\r
503 *pCurrent++ = nCounterLen;
\r
505 nSize -= sizeof(DWORD);
\r
506 if(nSize > nSizeLast) return E_FAIL;
\r
508 Checked::memcpy_s(pCurrent, nSize, CT2CW(pCounterInfo->m_strName), sizeof(WCHAR)*nCounterLen);
\r
509 pCurrent += AtlAlignUp(sizeof(WCHAR) * nCounterLen, sizeof(DWORD))/sizeof(DWORD);
\r
511 nSize -= sizeof(WCHAR)*nCounterLen;
\r
512 if(nSize > nSizeLast) return E_FAIL;
\r
520 str.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
521 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
\r
522 if (dwErr != ERROR_SUCCESS)
\r
523 return AtlHresultFromWin32(dwErr);
\r
525 rkApp.SetBinaryValue(c_szAtlPerfMap, blob, *LPDWORD(blob.m_pData));
\r
531 return E_OUTOFMEMORY;
\r
535 inline CPerfMon::CategoryInfo* CPerfMon::_FindCategoryInfo(DWORD dwCategoryId) throw()
\r
537 for (UINT i=0; i<_GetNumCategories(); i++)
\r
539 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
540 if (pCategoryInfo->m_dwCategoryId == dwCategoryId)
\r
541 return pCategoryInfo;
\r
547 inline CPerfMon::CounterInfo* CPerfMon::_FindCounterInfo(CategoryInfo* pCategoryInfo, DWORD dwCounterId)
\r
549 ATLENSURE_RETURN_VAL(pCategoryInfo != NULL, NULL);
\r
551 for (DWORD i=0; i<pCategoryInfo->_GetNumCounters(); i++)
\r
553 CounterInfo* pCounter = pCategoryInfo->_GetCounterInfo(i);
\r
554 if (pCounter->m_dwCounterId == dwCounterId)
\r
561 inline CPerfMon::CounterInfo* CPerfMon::_FindCounterInfo(DWORD dwCategoryId, DWORD dwCounterId) throw()
\r
563 CategoryInfo* pCategoryInfo = _FindCategoryInfo(dwCategoryId);
\r
564 if (pCategoryInfo != NULL)
\r
565 return _FindCounterInfo(pCategoryInfo, dwCounterId);
\r
570 inline BOOL CPerfMon::_WantCategoryType(__in_z LPWSTR szValue, __in DWORD dwCategoryId) throw(...)
\r
572 ATLASSERT(szValue != NULL);
\r
574 if (lstrcmpiW(c_szAtlPerfGlobal, szValue) == 0)
\r
577 CString strList(szValue);
\r
580 CString strNum = strList.Tokenize(_T(" "), nStart);
\r
581 while (!strNum.IsEmpty())
\r
583 if (_ttoi(strNum) == int(dwCategoryId))
\r
586 strNum = strList.Tokenize(_T(" "), nStart);
\r
592 inline LPBYTE CPerfMon::_AllocData(LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, size_t nBytesNeeded)
\r
594 ATLENSURE_RETURN_VAL(pnBytesUsed != NULL, NULL);
\r
595 ULONG newSize = *pnBytesUsed+static_cast<ULONG>(nBytesNeeded);
\r
597 if ((newSize < *pnBytesUsed) || (newSize < (ULONG) nBytesNeeded) || (nBytesAvail < newSize))
\r
601 pData += nBytesNeeded;
\r
602 *pnBytesUsed += (ULONG) nBytesNeeded;
\r
607 inline DWORD& CPerfMon::_GetBlockId(CAtlFileMappingBase* pBlock)
\r
609 DWORD* pDw = _GetBlockId_NoThrow(pBlock);
\r
614 inline DWORD* CPerfMon::_GetBlockId_NoThrow(CAtlFileMappingBase* pBlock)
\r
616 if (pBlock == NULL)
\r
619 return LPDWORD(LPBYTE(pBlock->GetData()) + m_nSchemaSize);
\r
622 inline void CPerfMon::_FillCategoryType(CategoryInfo* pCategoryInfo) throw()
\r
624 PERF_OBJECT_TYPE& type = pCategoryInfo->m_cache;
\r
625 type.DefinitionLength = sizeof(PERF_OBJECT_TYPE) + sizeof(PERF_COUNTER_DEFINITION) * pCategoryInfo->_GetNumCounters();
\r
626 type.TotalByteLength = type.DefinitionLength; // we will add the instance definitions/counter blocks as we go
\r
627 type.HeaderLength = sizeof(PERF_OBJECT_TYPE);
\r
628 type.ObjectNameTitleIndex = pCategoryInfo->m_nNameId;
\r
629 type.ObjectNameTitle = NULL;
\r
630 type.ObjectHelpTitleIndex = pCategoryInfo->m_nHelpId;
\r
631 type.ObjectHelpTitle = NULL;
\r
632 type.DetailLevel = pCategoryInfo->m_dwDetailLevel;
\r
633 type.NumCounters = pCategoryInfo->_GetNumCounters();
\r
634 type.DefaultCounter = pCategoryInfo->m_nDefaultCounter;
\r
635 if (pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES)
\r
636 type.NumInstances = PERF_NO_INSTANCES;
\r
638 type.NumInstances = 0; // this will be calculated as objects are processed
\r
640 type.PerfTime.QuadPart = 0;
\r
641 QueryPerformanceFrequency (&(type.PerfFreq));
\r
644 inline void CPerfMon::_FillCounterDef(CounterInfo* pCounterInfo, ULONG* pnCounterBlockSize) throw()
\r
646 PERF_COUNTER_DEFINITION& def = pCounterInfo->m_cache;
\r
648 def.ByteLength = sizeof(PERF_COUNTER_DEFINITION);
\r
649 def.CounterNameTitleIndex = pCounterInfo->m_nNameId;
\r
650 def.CounterNameTitle = NULL;
\r
651 def.CounterHelpTitleIndex = pCounterInfo->m_nHelpId;
\r
652 def.CounterHelpTitle = NULL;
\r
653 def.DefaultScale = pCounterInfo->m_nDefaultScale;
\r
654 def.DetailLevel = pCounterInfo->m_dwDetailLevel;
\r
655 def.CounterType = pCounterInfo->m_dwCounterType;
\r
656 DWORD dwAlignOfCounter=0;
\r
657 switch (pCounterInfo->m_dwCounterType & ATLPERF_SIZE_MASK)
\r
659 case PERF_SIZE_DWORD:
\r
660 def.CounterSize = sizeof(DWORD);
\r
661 dwAlignOfCounter = sizeof(DWORD);
\r
663 case PERF_SIZE_LARGE:
\r
664 def.CounterSize = sizeof(__int64);
\r
665 dwAlignOfCounter = sizeof(__int64);
\r
667 case PERF_SIZE_ZERO:
\r
668 def.CounterSize = 0;
\r
669 dwAlignOfCounter = 0;
\r
671 case PERF_SIZE_VARIABLE_LEN:
\r
672 ATLASSERT((pCounterInfo->m_dwCounterType & ATLPERF_TYPE_MASK) == PERF_TYPE_TEXT);
\r
673 if ((pCounterInfo->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
\r
675 def.CounterSize = (DWORD) AtlAlignUp(pCounterInfo->m_nMaxCounterSize * sizeof(WCHAR), sizeof(DWORD));
\r
679 def.CounterSize = (DWORD) AtlAlignUp(pCounterInfo->m_nMaxCounterSize * sizeof(char), sizeof(DWORD));
\r
683 *pnCounterBlockSize = AtlAlignUp(*pnCounterBlockSize, dwAlignOfCounter);
\r
684 def.CounterOffset = *pnCounterBlockSize;
\r
685 *pnCounterBlockSize += def.CounterSize;
\r
688 inline HRESULT CPerfMon::_CollectInstance(
\r
689 CategoryInfo* pCategoryInfo,
\r
692 ULONG* pnBytesUsed,
\r
693 CPerfObject* _pInstance,
\r
694 PERF_OBJECT_TYPE* pObjectType,
\r
695 PERF_COUNTER_DEFINITION* pCounterDefs
\r
698 DWORD dwInstance = _pInstance->m_dwInstance;
\r
700 // grab a snapshot of the object
\r
701 USES_ATL_SAFE_ALLOCA;
\r
702 CPerfObject* pInstance = (CPerfObject*) _ATL_SAFE_ALLOCA(_pInstance->m_nAllocSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD);
\r
703 if (pInstance == NULL)
\r
705 return E_OUTOFMEMORY;
\r
707 Checked::memcpy_s(pInstance, _pInstance->m_nAllocSize, _pInstance, _pInstance->m_nAllocSize);
\r
709 // if it was changed or deleted between when we first saw it and when we copied
\r
710 // it, then forget about whatever happens to be there for this collection period
\r
711 if (pInstance->m_dwCategoryId != pCategoryInfo->m_dwCategoryId ||
\r
712 dwInstance != pInstance->m_dwInstance ||
\r
713 pInstance->m_nRefCount == 0)
\r
716 // we have a copy of something that claims to be the object type we're expecting
\r
717 // put it into the data blob
\r
718 PERF_INSTANCE_DEFINITION* pInstanceDef = NULL;
\r
720 if (pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES)
\r
721 pObjectType->NumInstances = PERF_NO_INSTANCES;
\r
724 pObjectType->NumInstances++;
\r
726 // create an instance definition
\r
727 pInstanceDef = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_INSTANCE_DEFINITION*) NULL);
\r
728 if (pInstanceDef == NULL)
\r
729 return E_OUTOFMEMORY;
\r
731 pInstanceDef->ParentObjectTitleIndex = 0;
\r
732 pInstanceDef->ParentObjectInstance = 0;
\r
733 pInstanceDef->UniqueID = PERF_NO_UNIQUE_ID;
\r
735 // handle the instance name
\r
736 LPCWSTR szInstNameSrc = LPCWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset);
\r
737 pInstanceDef->NameLength = (ULONG)(wcslen(szInstNameSrc)+1)*sizeof(WCHAR);
\r
738 // align at 8 bytes per Q262335
\r
739 ULONG nNameAlloc = (ULONG) AtlAlignUp(pInstanceDef->NameLength, 8);
\r
740 LPWSTR szInstNameDest = (LPWSTR) _AllocData(pData, nBytesAvail, pnBytesUsed, nNameAlloc);
\r
741 if (szInstNameDest == NULL)
\r
742 return E_OUTOFMEMORY;
\r
744 Checked::memcpy_s(szInstNameDest, nNameAlloc, szInstNameSrc, pInstanceDef->NameLength);
\r
745 pInstanceDef->NameOffset = ULONG(LPBYTE(szInstNameDest) - LPBYTE(pInstanceDef));
\r
747 pInstanceDef->ByteLength = DWORD(sizeof(PERF_INSTANCE_DEFINITION) + nNameAlloc);
\r
750 // create the counter block + data
\r
751 LPBYTE pCounterData = _AllocData(pData, nBytesAvail, pnBytesUsed, pCategoryInfo->m_nCounterBlockSize);
\r
752 if (pCounterData == NULL)
\r
753 return E_OUTOFMEMORY;
\r
755 // fill in the counter block header for the data
\r
756 PERF_COUNTER_BLOCK* pCounterBlock = (PERF_COUNTER_BLOCK*) pCounterData;
\r
757 pCounterBlock->ByteLength = pCategoryInfo->m_nCounterBlockSize;
\r
759 // fill in the data
\r
760 for (ULONG i=0; i<pObjectType->NumCounters; i++)
\r
762 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(i);
\r
763 PERF_COUNTER_DEFINITION& def = pCounterDefs[i];
\r
764 LPBYTE pSrc = LPBYTE(pInstance)+pCounterInfo->m_nDataOffset;
\r
765 LPBYTE pDest = pCounterData+def.CounterOffset;
\r
766 switch (pCounterInfo->m_dwCounterType & ATLPERF_SIZE_MASK)
\r
768 case PERF_SIZE_DWORD:
\r
769 *LPDWORD(pDest) = *LPDWORD(pSrc);
\r
771 case PERF_SIZE_LARGE:
\r
772 *(ULONGLONG*)(pDest) = *(ULONGLONG*)(pSrc);
\r
774 case PERF_SIZE_VARIABLE_LEN:
\r
775 if ((pCounterInfo->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
\r
777 LPCWSTR szSrc = reinterpret_cast<LPCWSTR>(pSrc);
\r
778 LPWSTR szDest = reinterpret_cast<LPWSTR>(pDest);
\r
779 size_t nLen = __min(wcslen(szSrc), pCounterInfo->m_nMaxCounterSize-1);
\r
780 Checked::wcsncpy_s(szDest, pCounterInfo->m_nMaxCounterSize-1, szSrc, nLen);
\r
785 LPCSTR szSrc = reinterpret_cast<LPCSTR>(pSrc);
\r
786 LPSTR szDest = reinterpret_cast<LPSTR>(pDest);
\r
787 size_t nLen = __min(strlen(szSrc), pCounterInfo->m_nMaxCounterSize-1);
\r
788 Checked::strncpy_s(szDest, pCounterInfo->m_nMaxCounterSize-1, szSrc, nLen);
\r
795 if (pInstanceDef != NULL)
\r
796 pObjectType->TotalByteLength += pInstanceDef->ByteLength;
\r
797 pObjectType->TotalByteLength += pCounterBlock->ByteLength;
\r
802 inline HRESULT CPerfMon::_CollectInstance(
\r
803 CategoryInfo* pCategoryInfo,
\r
806 ULONG* pnBytesUsed,
\r
807 PERF_OBJECT_TYPE* pObjectType,
\r
808 PERF_COUNTER_DEFINITION* pCounterDefs
\r
811 // specialization to collect an instanceless object with no instance data
\r
812 ATLASSERT(pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES);
\r
813 pObjectType->NumInstances = PERF_NO_INSTANCES;
\r
815 // create the counter block + data
\r
816 LPBYTE pCounterData = _AllocData(pData, nBytesAvail, pnBytesUsed, pCategoryInfo->m_nCounterBlockSize);
\r
817 if (pCounterData == NULL)
\r
818 return E_OUTOFMEMORY;
\r
820 // fill in the counter block header for the data
\r
821 PERF_COUNTER_BLOCK* pCounterBlock = (PERF_COUNTER_BLOCK*) pCounterData;
\r
822 pCounterBlock->ByteLength = pCategoryInfo->m_nCounterBlockSize;
\r
824 // fill in the data
\r
825 for (ULONG i=0; i<pObjectType->NumCounters; i++)
\r
827 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(i);
\r
828 PERF_COUNTER_DEFINITION& def = pCounterDefs[i];
\r
829 LPBYTE pDest = pCounterData+def.CounterOffset;
\r
830 switch (pCounterInfo->m_dwCounterType & ATLPERF_SIZE_MASK)
\r
832 case PERF_SIZE_DWORD:
\r
833 *LPDWORD(pDest) = 0;
\r
835 case PERF_SIZE_LARGE:
\r
836 *PULONGLONG(pDest) = 0;
\r
838 case PERF_SIZE_VARIABLE_LEN:
\r
839 if ((pCounterInfo->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
\r
840 memset(pDest, 0, pCounterInfo->m_nMaxCounterSize*sizeof(WCHAR));
\r
842 memset(pDest, 0, pCounterInfo->m_nMaxCounterSize*sizeof(CHAR));
\r
847 pObjectType->TotalByteLength += pCounterBlock->ByteLength;
\r
852 inline HRESULT CPerfMon::_CollectCategoryType(
\r
853 CategoryInfo* pCategoryInfo,
\r
859 ATLENSURE_RETURN(pCategoryInfo != NULL);
\r
860 ATLASSERT(pnBytesUsed != NULL);
\r
862 // write the object definition out
\r
863 PERF_OBJECT_TYPE* pObjectType = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_OBJECT_TYPE*) NULL);
\r
864 if (pObjectType == NULL)
\r
865 return E_OUTOFMEMORY;
\r
867 Checked::memcpy_s(pObjectType, sizeof(PERF_OBJECT_TYPE), &pCategoryInfo->m_cache, sizeof(PERF_OBJECT_TYPE));
\r
869 // save a pointer to the first counter entry and counter definition.
\r
870 // we'll need them when we create the PERF_COUNTER_BLOCK data
\r
871 PERF_COUNTER_DEFINITION* pCounterDefs = reinterpret_cast<PERF_COUNTER_DEFINITION*>(pData);
\r
873 // write the counter definitions out
\r
874 for (DWORD i=0; i<pCategoryInfo->_GetNumCounters(); i++)
\r
876 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(i);
\r
878 PERF_COUNTER_DEFINITION* pCounterDef = _AllocStruct(pData, nBytesAvail, pnBytesUsed, (PERF_COUNTER_DEFINITION*) NULL);
\r
879 if (pCounterDef == NULL)
\r
880 return E_OUTOFMEMORY;
\r
882 Checked::memcpy_s(pCounterDef, sizeof(PERF_COUNTER_DEFINITION), &pCounterInfo->m_cache, sizeof(PERF_COUNTER_DEFINITION));
\r
884 // set PerfTime and PerfFreq for PERF_ELAPSED_TIME counter.
\r
885 if(pCounterDef->CounterType == PERF_ELAPSED_TIME)
\r
887 LARGE_INTEGER currTime;
\r
888 if (FALSE != QueryPerformanceCounter(&currTime))
\r
889 pObjectType->PerfTime = currTime;
\r
891 pObjectType->PerfTime.QuadPart = 0;
\r
892 QueryPerformanceFrequency (&(pObjectType->PerfFreq));
\r
896 // search for objects of the appropriate type and write out their instance/counter data
\r
897 bool bGotInstance = false;
\r
899 CAtlFileMappingBase* pCurrentBlock = _GetNextBlock(NULL);
\r
900 if (pCurrentBlock != NULL)
\r
902 CPerfObject* pInstance = _GetFirstInstance(pCurrentBlock);
\r
903 while (pInstance && pInstance->m_nAllocSize != 0)
\r
905 if (pInstance->m_dwCategoryId == pCategoryInfo->m_dwCategoryId)
\r
907 bGotInstance = true;
\r
908 HRESULT hr = _CollectInstance(pCategoryInfo, pData, nBytesAvail,
\r
909 pnBytesUsed, pInstance, pObjectType, pCounterDefs);
\r
914 pInstance = _GetNextInstance(pInstance);
\r
915 ATLENSURE_RETURN(pInstance!= NULL);
\r
917 if (pInstance->m_nAllocSize == (ULONG) -1)
\r
919 pCurrentBlock = _GetNextBlock(pCurrentBlock);
\r
920 if (pCurrentBlock == NULL)
\r
923 pInstance = _GetFirstInstance(pCurrentBlock);
\r
928 if (pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES && !bGotInstance)
\r
930 // we have an instanceless (singleton) object with no data. send zeroed data
\r
931 HRESULT hr = _CollectInstance(pCategoryInfo, pData, nBytesAvail,
\r
932 pnBytesUsed, pObjectType, pCounterDefs);
\r
940 inline DWORD CPerfMon::Open(LPWSTR szDeviceNames) throw()
\r
942 (szDeviceNames); // unused
\r
947 inline DWORD CPerfMon::Collect(
\r
948 __in_z LPWSTR szValue,
\r
949 __deref_inout_bcount(*pcbBytes) LPVOID* ppData,
\r
950 __inout LPDWORD pcbBytes,
\r
951 __inout LPDWORD pcObjectTypes
\r
961 if (FAILED(_OpenAllBlocks()))
\r
964 *pcObjectTypes = 0;
\r
965 return ERROR_SUCCESS;
\r
968 LPBYTE pData = LPBYTE(*ppData);
\r
969 ULONG nBytesLeft = *pcbBytes;
\r
972 if (_GetNumCategories() == 0)
\r
974 // nothing is providing data. we need to load the map directly
\r
975 // from the registry in order to provide category/counter data
\r
980 strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
982 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, strAppKey, KEY_READ);
\r
983 if (dwErr != ERROR_SUCCESS)
\r
986 *pcObjectTypes = 0;
\r
987 return ERROR_SUCCESS;
\r
991 dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, NULL, &nBytes);
\r
992 if (dwErr != ERROR_SUCCESS)
\r
995 *pcObjectTypes = 0;
\r
996 return ERROR_SUCCESS;
\r
999 CHeapPtr<DWORD> buf;
\r
1000 if (!buf.Allocate((nBytes+3)/4))
\r
1003 *pcObjectTypes = 0;
\r
1004 return ERROR_SUCCESS;
\r
1007 dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, buf, &nBytes);
\r
1008 if (dwErr != ERROR_SUCCESS)
\r
1011 *pcObjectTypes = 0;
\r
1012 return ERROR_SUCCESS;
\r
1015 if (FAILED(_LoadMap(buf)))
\r
1018 *pcObjectTypes = 0;
\r
1019 return ERROR_SUCCESS;
\r
1023 for (UINT i=0; i<_GetNumCategories(); i++)
\r
1025 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
1026 if (_WantCategoryType(szValue, pCategoryInfo->m_nNameId))
\r
1028 ULONG nBytesUsed = 0;
\r
1029 HRESULT hr = _CollectCategoryType(pCategoryInfo, pData, nBytesLeft, &nBytesUsed);
\r
1030 if (hr == E_OUTOFMEMORY)
\r
1033 *pcObjectTypes = 0;
\r
1034 return ERROR_MORE_DATA;
\r
1036 else if (FAILED(hr))
\r
1039 *pcObjectTypes = 0;
\r
1040 return ERROR_SUCCESS;
\r
1043 (*pcObjectTypes)++;
\r
1044 (*pcbBytes) += nBytesUsed;
\r
1045 nBytesLeft -= nBytesUsed;
\r
1046 pData += nBytesUsed;
\r
1051 return ERROR_SUCCESS;
\r
1056 *pcObjectTypes = 0;
\r
1057 return ERROR_SUCCESS;
\r
1061 inline DWORD CPerfMon::Close() throw()
\r
1064 return ERROR_SUCCESS;
\r
1067 #ifdef _ATL_PERF_REGISTER
\r
1068 #pragma warning (push)
\r
1069 #pragma warning(disable : 4996)
\r
1071 inline void CPerfMon::_AppendStrings(
\r
1073 CAtlArray<CString>& astrStrings,
\r
1077 for (UINT iString = 0; iString < astrStrings.GetCount(); iString++)
\r
1079 INT nFormatChars = _stprintf(pszNew, _T("%d"), iFirstIndex+2*iString);
\r
1080 pszNew += nFormatChars + 1;
\r
1081 _tcscpy(pszNew, astrStrings[iString]);
\r
1082 pszNew += astrStrings[iString].GetLength() + 1;
\r
1086 #pragma warning (pop)
\r
1088 inline HRESULT CPerfMon::_AppendRegStrings(
\r
1091 CAtlArray<CString>& astrStrings,
\r
1092 ULONG nNewStringSize,
\r
1093 ULONG iFirstIndex,
\r
1099 // load the existing strings, add the new data, and resave the strings
\r
1100 ULONG nCharsOrig = 0;
\r
1104 dwErr = rkLang.QueryMultiStringValue(szValue, NULL, &nCharsOrig);
\r
1105 if (dwErr != ERROR_SUCCESS)
\r
1106 return AtlHresultFromWin32(dwErr);
\r
1108 nCharsNew = nCharsOrig + nNewStringSize;
\r
1111 dwErr = rkLang.QueryMultiStringValue(szValue, CStrBuf(strOrig, nCharsOrig, CStrBuf::SET_LENGTH), &nCharsOrig);
\r
1112 if (dwErr != ERROR_SUCCESS)
\r
1113 return AtlHresultFromWin32(dwErr);
\r
1114 LPCTSTR pszOrig = strOrig;
\r
1117 CStrBuf szNew(strNew, nCharsNew, CStrBuf::SET_LENGTH);
\r
1118 LPTSTR pszNew = szNew;
\r
1120 bool bNewStringsAdded = false;
\r
1122 while (*pszOrig != '\0')
\r
1124 ULONG iIndex = _ttoi(pszOrig);
\r
1125 int nLen = (int) _tcslen(pszOrig) + 1; // get the length of the index and null
\r
1126 nLen += (int) _tcslen(pszOrig+nLen) + 1; // add the length of the description and null
\r
1128 if (!bNewStringsAdded && iIndex >= iFirstIndex)
\r
1130 LPTSTR pszOld =pszNew;
\r
1131 _AppendStrings(pszNew, astrStrings, iFirstIndex);
\r
1132 bNewStringsAdded = true;
\r
1133 ULONG nCharsNewLast = nCharsNew;
\r
1134 nCharsNew -= ULONG(pszNew-pszOld);
\r
1135 if(nCharsNew > nCharsNewLast)
\r
1141 if (iIndex < iFirstIndex || iIndex > iLastIndex)
\r
1143 Checked::memmove_s(pszNew, nCharsNew, pszOrig, nLen*sizeof(TCHAR));
\r
1148 if (!bNewStringsAdded)
\r
1149 _AppendStrings(pszNew, astrStrings, iFirstIndex);
\r
1151 *pszNew++ = '\0'; // must have 2 null terminators at end of multi_sz
\r
1153 dwErr = rkLang.SetMultiStringValue(szValue, strNew);
\r
1154 if (dwErr != ERROR_SUCCESS)
\r
1155 return AtlHresultFromWin32(dwErr);
\r
1161 return E_OUTOFMEMORY;
\r
1165 inline HRESULT CPerfMon::_RemoveRegStrings(
\r
1168 ULONG iFirstIndex,
\r
1174 // load the existing strings, remove the data, and resave the strings
\r
1178 dwErr = rkLang.QueryMultiStringValue(szValue, NULL, &nChars);
\r
1179 if (dwErr != ERROR_SUCCESS)
\r
1180 return AtlHresultFromWin32(dwErr);
\r
1183 CStrBuf szBuf(str, nChars, CStrBuf::SET_LENGTH);
\r
1184 DWORD nMaxLen = nChars*sizeof(TCHAR);
\r
1186 dwErr = rkLang.QueryMultiStringValue(szValue, szBuf, &nChars);
\r
1187 if (dwErr != ERROR_SUCCESS)
\r
1188 return AtlHresultFromWin32(dwErr);
\r
1190 LPCTSTR pszRead = szBuf;
\r
1191 LPTSTR pszWrite = szBuf;
\r
1192 while (*pszRead != '\0')
\r
1194 ULONG iIndex = _ttoi(pszRead);
\r
1195 int nLen = (int) _tcslen(pszRead) + 1; // get the length of the index and null
\r
1196 nLen += (int) _tcslen(pszRead+nLen) + 1; // add the length of the description and null
\r
1197 if (iIndex < iFirstIndex || iIndex > iLastIndex)
\r
1199 Checked::memmove_s(pszWrite, nMaxLen , pszRead, nLen*sizeof(TCHAR));
\r
1200 UINT nMaxLenLast = nMaxLen;
\r
1201 nMaxLen -= nLen*sizeof(TCHAR);
\r
1202 if(nMaxLen > nMaxLenLast) return E_FAIL;
\r
1207 *pszWrite++ = '\0'; // must have 2 null terminators at end of multi_sz
\r
1209 dwErr = rkLang.SetMultiStringValue(szValue, szBuf);
\r
1210 if (dwErr != ERROR_SUCCESS)
\r
1211 return AtlHresultFromWin32(dwErr);
\r
1217 return E_OUTOFMEMORY;
\r
1221 inline HRESULT CPerfMon::_ReserveStringRange(DWORD& dwFirstCounter, DWORD& dwFirstHelp) throw()
\r
1224 CString strAppKey;
\r
1229 strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
1233 return E_OUTOFMEMORY;
\r
1236 DWORD nNumStrings = _GetNumCategoriesAndCounters();
\r
1238 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, strAppKey);
\r
1239 if (dwErr == ERROR_SUCCESS)
\r
1241 // see if we already have a sufficient range reserved
\r
1242 DWORD dwFirstAppCounter;
\r
1243 DWORD dwFirstAppHelp;
\r
1244 DWORD dwLastAppCounter;
\r
1245 DWORD dwLastAppHelp;
\r
1247 if (rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstAppCounter) == ERROR_SUCCESS &&
\r
1248 rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstAppHelp) == ERROR_SUCCESS &&
\r
1249 rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastAppCounter) == ERROR_SUCCESS &&
\r
1250 rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastAppHelp) == ERROR_SUCCESS &&
\r
1251 dwLastAppCounter-dwFirstAppCounter+2 >= 2*nNumStrings &&
\r
1252 dwLastAppHelp-dwFirstAppHelp+2 >= 2*nNumStrings)
\r
1254 dwFirstCounter = dwFirstAppCounter;
\r
1255 dwFirstHelp = dwFirstAppHelp;
\r
1260 CRegKey rkPerfLib;
\r
1262 dwErr = rkPerfLib.Open(HKEY_LOCAL_MACHINE, c_szAtlPerfPerfLibKey);
\r
1263 if (dwErr != ERROR_SUCCESS)
\r
1264 return AtlHresultFromWin32(dwErr);
\r
1268 dwErr = rkApp.Create(HKEY_LOCAL_MACHINE, strAppKey);
\r
1269 if (dwErr != ERROR_SUCCESS)
\r
1270 return AtlHresultFromWin32(dwErr);
\r
1273 // figure out the counter range
\r
1274 DWORD dwLastCounter;
\r
1277 dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
\r
1278 if (dwErr != ERROR_SUCCESS)
\r
1279 return AtlHresultFromWin32(dwErr);
\r
1281 dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
\r
1282 if (dwErr != ERROR_SUCCESS)
\r
1283 return AtlHresultFromWin32(dwErr);
\r
1285 dwFirstCounter = dwLastCounter + 2;
\r
1286 dwFirstHelp = dwLastHelp + 2;
\r
1287 dwLastCounter += 2*nNumStrings;
\r
1288 dwLastHelp += 2*nNumStrings;
\r
1290 dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
\r
1291 if (dwErr != ERROR_SUCCESS)
\r
1292 return AtlHresultFromWin32(dwErr);
\r
1294 dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
\r
1295 if (dwErr != ERROR_SUCCESS)
\r
1296 return AtlHresultFromWin32(dwErr);
\r
1298 // register the used counter range
\r
1299 dwErr = rkApp.SetDWORDValue(c_szAtlPerfFirstCounter, dwFirstCounter);
\r
1300 if (dwErr != ERROR_SUCCESS)
\r
1301 return AtlHresultFromWin32(dwErr);
\r
1303 dwErr = rkApp.SetDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
\r
1304 if (dwErr != ERROR_SUCCESS)
\r
1305 return AtlHresultFromWin32(dwErr);
\r
1307 dwErr = rkApp.SetDWORDValue(c_szAtlPerfFirstHelp, dwFirstHelp);
\r
1308 if (dwErr != ERROR_SUCCESS)
\r
1309 return AtlHresultFromWin32(dwErr);
\r
1311 dwErr = rkApp.SetDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
\r
1312 if (dwErr != ERROR_SUCCESS)
\r
1313 return AtlHresultFromWin32(dwErr);
\r
1318 inline HRESULT CPerfMon::Register(
\r
1319 LPCTSTR szOpenFunc,
\r
1320 LPCTSTR szCollectFunc,
\r
1321 LPCTSTR szCloseFunc,
\r
1322 HINSTANCE hDllInstance /* == _AtlBaseModule.GetModuleInstance() */
\r
1325 ATLASSERT(szOpenFunc != NULL);
\r
1326 ATLASSERT(szCollectFunc != NULL);
\r
1327 ATLASSERT(szCloseFunc != NULL);
\r
1332 hr = CreateMap(LANGIDFROMLCID(GetThreadLocale()), hDllInstance);
\r
1334 hr = CreateMap(LANGIDFROMLCID(1033), hDllInstance);
\r
1339 CString strAppKey;
\r
1342 strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
1346 return E_OUTOFMEMORY;
\r
1349 // if we're already registered, unregister so we can redo registration
\r
1350 _UnregisterStrings();
\r
1352 // reserve a range for our counter and help strings
\r
1353 DWORD dwFirstCounter = 0;
\r
1354 DWORD dwFirstHelp = 0;
\r
1355 hr = _ReserveStringRange(dwFirstCounter, dwFirstHelp);
\r
1359 DWORD dwCurrentName = dwFirstCounter;
\r
1360 DWORD dwCurrentHelp = dwFirstHelp;
\r
1361 for (UINT i=0; i<_GetNumCategories(); i++)
\r
1363 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
1365 pCategoryInfo->m_nNameId = dwCurrentName;
\r
1366 dwCurrentName += 2;
\r
1367 pCategoryInfo->m_nHelpId = dwCurrentHelp;
\r
1368 dwCurrentHelp += 2;
\r
1370 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
1372 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
1374 pCounterInfo->m_nNameId = dwCurrentName;
\r
1375 dwCurrentName += 2;
\r
1376 pCounterInfo->m_nHelpId = dwCurrentHelp;
\r
1377 dwCurrentHelp += 2;
\r
1381 // register the app entry points
\r
1384 dwErr = rkApp.Create(HKEY_LOCAL_MACHINE, strAppKey);
\r
1385 if (dwErr != ERROR_SUCCESS)
\r
1386 return AtlHresultFromWin32(dwErr);
\r
1390 DWORD dwFLen = GetModuleFileName(hDllInstance, CStrBuf(str, MAX_PATH), MAX_PATH);
\r
1392 return AtlHresultFromLastError();
\r
1393 else if( dwFLen == MAX_PATH )
\r
1394 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
\r
1398 return E_OUTOFMEMORY;
\r
1401 dwErr = rkApp.SetStringValue(c_szAtlPerfLibrary, str);
\r
1402 if (dwErr != ERROR_SUCCESS)
\r
1403 return AtlHresultFromWin32(dwErr);
\r
1405 dwErr = rkApp.SetStringValue(c_szAtlPerfOpen, szOpenFunc);
\r
1406 if (dwErr != ERROR_SUCCESS)
\r
1407 return AtlHresultFromWin32(dwErr);
\r
1409 dwErr = rkApp.SetStringValue(c_szAtlPerfCollect, szCollectFunc);
\r
1410 if (dwErr != ERROR_SUCCESS)
\r
1411 return AtlHresultFromWin32(dwErr);
\r
1413 dwErr = rkApp.SetStringValue(c_szAtlPerfClose, szCloseFunc);
\r
1414 if (dwErr != ERROR_SUCCESS)
\r
1415 return AtlHresultFromWin32(dwErr);
\r
1417 dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, _T(""));
\r
1418 if (dwErr != ERROR_SUCCESS)
\r
1419 return AtlHresultFromWin32(dwErr);
\r
1425 // if the dll is disabled, reenable it since we just reregistered it
\r
1426 rkApp.DeleteValue(_T("Disable Performance Counters"));
\r
1431 inline HRESULT CPerfMon::RegisterStrings(
\r
1432 LANGID language /* = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) */,
\r
1433 HINSTANCE hResInstance /* = _AtlBaseModule.GetResourceInstance() */
\r
1444 LANGID wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);
\r
1446 if (language == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL))
\r
1448 //First try current thread locale
\r
1449 language = LANGIDFROMLCID(GetThreadLocale());
\r
1450 wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);
\r
1452 str.Format(c_szAtlPerfPerfLibLangKey, wPrimaryLanguage);
\r
1453 dwErr = rkLang.Open(HKEY_LOCAL_MACHINE, str);
\r
1454 if (dwErr == ERROR_FILE_NOT_FOUND)
\r
1456 // failed using current thread, so try default system lcid
\r
1457 language = GetSystemDefaultLangID();
\r
1458 wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);
\r
1459 str.Format(c_szAtlPerfPerfLibLangKey, wPrimaryLanguage);
\r
1460 dwErr = rkLang.Open(HKEY_LOCAL_MACHINE, str);
\r
1462 if (dwErr == ERROR_FILE_NOT_FOUND)
\r
1463 return S_FALSE; // the language isn't installed on the system
\r
1464 if (dwErr != ERROR_SUCCESS)
\r
1465 return AtlHresultFromWin32(dwErr);
\r
1467 hr = CreateMap(language, hResInstance);
\r
1471 // load list of language strings already registered
\r
1472 str.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
1473 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
\r
1474 if (dwErr != ERROR_SUCCESS)
\r
1475 return AtlHresultFromWin32(dwErr);
\r
1477 DWORD dwLangsLen = 0;
\r
1480 dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, NULL, &dwLangsLen);
\r
1481 if (dwErr != ERROR_SUCCESS)
\r
1482 return AtlHresultFromWin32(dwErr);
\r
1484 ULONG nLangsBuffSize = dwLangsLen+4;
\r
1485 CStrBuf szLangs(strLangs, nLangsBuffSize, CStrBuf::SET_LENGTH); // reserve room for adding new language
\r
1486 dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, szLangs, &dwLangsLen);
\r
1487 if (dwErr != ERROR_SUCCESS)
\r
1488 return AtlHresultFromWin32(dwErr);
\r
1489 dwLangsLen--; // don't count '\0'
\r
1491 // see if this language has already been registered and if so, return
\r
1492 TCHAR szNewLang[5];
\r
1493 _sntprintf_s(szNewLang, _countof(szNewLang), _countof(szNewLang)-1, _T("%3.3x "), wPrimaryLanguage);
\r
1494 if (strLangs.Find(szNewLang) != -1)
\r
1497 // load the strings we want to append and figure out how much extra space is needed for them
\r
1498 // (including up to 5-digit index values and 2 null separators)
\r
1499 CAtlArray<CString> astrCounters;
\r
1500 CAtlArray<CString> astrHelp;
\r
1501 ULONG nNewCounterSize = 0;
\r
1502 ULONG nNewHelpSize = 0;
\r
1504 for (UINT i=0; i<_GetNumCategories(); i++)
\r
1506 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
1508 astrCounters.Add(pCategoryInfo->m_strName);
\r
1509 astrHelp.Add(pCategoryInfo->m_strHelp);
\r
1511 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
1513 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
1515 astrCounters.Add(pCounterInfo->m_strName);
\r
1516 astrHelp.Add(pCounterInfo->m_strHelp);
\r
1520 for (size_t i=0; i<astrCounters.GetCount(); i++)
\r
1522 nNewCounterSize += astrCounters[i].GetLength() + 7;
\r
1523 nNewHelpSize += astrHelp[i].GetLength() + 7;
\r
1526 DWORD dwFirstCounter;
\r
1527 DWORD dwFirstHelp;
\r
1528 DWORD dwLastCounter;
\r
1531 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstCounter);
\r
1532 if (dwErr != ERROR_SUCCESS)
\r
1533 return AtlHresultFromWin32(dwErr);
\r
1535 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstHelp);
\r
1536 if (dwErr != ERROR_SUCCESS)
\r
1537 return AtlHresultFromWin32(dwErr);
\r
1539 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
\r
1540 if (dwErr != ERROR_SUCCESS)
\r
1541 return AtlHresultFromWin32(dwErr);
\r
1543 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
\r
1544 if (dwErr != ERROR_SUCCESS)
\r
1545 return AtlHresultFromWin32(dwErr);
\r
1547 hr = _AppendRegStrings(rkLang, c_szAtlPerfCounter, astrCounters, nNewCounterSize, dwFirstCounter, dwLastCounter);
\r
1551 hr = _AppendRegStrings(rkLang, c_szAtlPerfHelp, astrHelp, nNewHelpSize, dwFirstHelp, dwLastHelp);
\r
1555 // add the language to the list of installed languages
\r
1556 Checked::tcscpy_s(szLangs+dwLangsLen, nLangsBuffSize-dwLangsLen, szNewLang);
\r
1558 dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, szLangs);
\r
1559 if (dwErr != ERROR_SUCCESS)
\r
1560 return AtlHresultFromWin32(dwErr);
\r
1566 return E_OUTOFMEMORY;
\r
1570 inline BOOL CPerfMon::EnumResLangProc(
\r
1571 HINSTANCE hModule,
\r
1574 LANGID wIDLanguage,
\r
1578 hModule; // unused
\r
1582 CAtlArray<LANGID>* pLangs = reinterpret_cast<CAtlArray<LANGID>*>(lParam);
\r
1585 pLangs->Add(wIDLanguage);
\r
1595 inline HRESULT CPerfMon::RegisterAllStrings(
\r
1596 HINSTANCE hResInstance /* = NULL */
\r
1599 HRESULT hrReturn = S_FALSE;
\r
1603 hr = CreateMap(0, hResInstance, &nRes);
\r
1608 return RegisterStrings(0, hResInstance);
\r
1610 if (hResInstance != NULL)
\r
1611 return _RegisterAllStrings(nRes, hResInstance);
\r
1613 for (int i = 0; hResInstance = _AtlBaseModule.GetHInstanceAt(i), hResInstance != NULL; i++)
\r
1615 hr = _RegisterAllStrings(nRes, hResInstance);
\r
1625 inline HRESULT CPerfMon::_RegisterAllStrings(
\r
1627 HINSTANCE hResInstance
\r
1630 HRESULT hrReturn = S_FALSE;
\r
1633 CAtlArray<LANGID> langs;
\r
1634 if (!EnumResourceLanguages(hResInstance, RT_STRING, MAKEINTRESOURCE((nRes>>4)+1), EnumResLangProc, reinterpret_cast<LPARAM>(&langs)))
\r
1635 return AtlHresultFromLastError();
\r
1637 for (UINT i=0; i<langs.GetCount(); i++)
\r
1639 hr = RegisterStrings(langs[i], hResInstance);
\r
1649 inline HRESULT CPerfMon::_UnregisterStrings() throw()
\r
1657 // unregister the PerfMon counter and help strings
\r
1660 str.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
1661 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
\r
1662 //The register strings was unregistered.
\r
1663 if (dwErr == ERROR_FILE_NOT_FOUND)
\r
1665 if (dwErr != ERROR_SUCCESS)
\r
1666 return AtlHresultFromWin32(dwErr);
\r
1668 DWORD dwFirstAppCounter;
\r
1669 DWORD dwFirstAppHelp;
\r
1670 DWORD dwLastAppCounter;
\r
1671 DWORD dwLastAppHelp;
\r
1673 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstAppCounter);
\r
1674 if (dwErr != ERROR_SUCCESS)
\r
1675 return AtlHresultFromWin32(dwErr);
\r
1677 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstAppHelp);
\r
1678 if (dwErr != ERROR_SUCCESS)
\r
1679 return AtlHresultFromWin32(dwErr);
\r
1681 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastAppCounter);
\r
1682 if (dwErr != ERROR_SUCCESS)
\r
1683 return AtlHresultFromWin32(dwErr);
\r
1685 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastAppHelp);
\r
1686 if (dwErr != ERROR_SUCCESS)
\r
1687 return AtlHresultFromWin32(dwErr);
\r
1689 // iterate through the installed languages and delete them all
\r
1691 dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, NULL, &nChars);
\r
1692 if (dwErr != ERROR_SUCCESS)
\r
1693 return AtlHresultFromWin32(dwErr);
\r
1696 dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, CStrBuf(strLangs, nChars, CStrBuf::SET_LENGTH), &nChars);
\r
1697 if (dwErr != ERROR_SUCCESS)
\r
1698 return AtlHresultFromWin32(dwErr);
\r
1701 CString strLang = strLangs.Tokenize(_T(" "), nIndex);
\r
1702 while (!strLang.IsEmpty())
\r
1706 dwErr = rkLang.Open(HKEY_LOCAL_MACHINE, CString(c_szAtlPerfPerfLibKey) + _T("\\") + strLang);
\r
1707 if (dwErr != ERROR_SUCCESS)
\r
1708 return AtlHresultFromWin32(dwErr);
\r
1710 hr = _RemoveRegStrings(rkLang, c_szAtlPerfCounter, dwFirstAppCounter, dwLastAppCounter);
\r
1714 hr = _RemoveRegStrings(rkLang, c_szAtlPerfHelp, dwFirstAppHelp, dwLastAppHelp);
\r
1718 strLang = strLangs.Tokenize(_T(" "), nIndex);
\r
1721 dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, _T(""));
\r
1722 if (dwErr != ERROR_SUCCESS)
\r
1723 return AtlHresultFromWin32(dwErr);
\r
1729 return E_OUTOFMEMORY;
\r
1733 inline HRESULT CPerfMon::Unregister() throw()
\r
1739 CRegKey rkPerfLib;
\r
1742 hr = _UnregisterStrings();
\r
1746 dwErr = rkPerfLib.Open(HKEY_LOCAL_MACHINE, c_szAtlPerfPerfLibKey);
\r
1747 if (dwErr != ERROR_SUCCESS)
\r
1748 return AtlHresultFromWin32(dwErr);
\r
1752 str.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
1756 return E_OUTOFMEMORY;
\r
1758 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, str);
\r
1759 // The performance counter was unregistered
\r
1760 if (dwErr == ERROR_FILE_NOT_FOUND)
\r
1762 if (dwErr != ERROR_SUCCESS)
\r
1763 return AtlHresultFromWin32(dwErr);
\r
1765 DWORD dwLastCounter;
\r
1767 DWORD dwFirstAppCounter;
\r
1768 DWORD dwFirstAppHelp;
\r
1769 DWORD dwLastAppCounter;
\r
1770 DWORD dwLastAppHelp;
\r
1772 dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastCounter);
\r
1773 if (dwErr != ERROR_SUCCESS)
\r
1774 return AtlHresultFromWin32(dwErr);
\r
1776 dwErr = rkPerfLib.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastHelp);
\r
1777 if (dwErr != ERROR_SUCCESS)
\r
1778 return AtlHresultFromWin32(dwErr);
\r
1780 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstCounter, dwFirstAppCounter);
\r
1781 if (dwErr != ERROR_SUCCESS)
\r
1782 return AtlHresultFromWin32(dwErr);
\r
1784 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfFirstHelp, dwFirstAppHelp);
\r
1785 if (dwErr != ERROR_SUCCESS)
\r
1786 return AtlHresultFromWin32(dwErr);
\r
1788 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastCounter, dwLastAppCounter);
\r
1789 if (dwErr != ERROR_SUCCESS)
\r
1790 return AtlHresultFromWin32(dwErr);
\r
1792 dwErr = rkApp.QueryDWORDValue(c_szAtlPerfLastHelp, dwLastAppHelp);
\r
1793 if (dwErr != ERROR_SUCCESS)
\r
1794 return AtlHresultFromWin32(dwErr);
\r
1796 // rewind the Last Help/Last Counter values if possible
\r
1797 if (dwLastCounter == dwLastAppCounter)
\r
1799 dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastCounter, dwFirstAppCounter-2);
\r
1800 if (dwErr != ERROR_SUCCESS)
\r
1801 return AtlHresultFromWin32(dwErr);
\r
1804 if (dwLastHelp == dwLastAppHelp)
\r
1806 dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastHelp, dwFirstAppHelp-2);
\r
1807 if (dwErr != ERROR_SUCCESS)
\r
1808 return AtlHresultFromWin32(dwErr);
\r
1812 // delete the app key
\r
1813 CRegKey rkServices;
\r
1817 str.Format(c_szAtlPerfServicesKey, GetAppName());
\r
1821 return E_OUTOFMEMORY;
\r
1823 dwErr = rkServices.Open(HKEY_LOCAL_MACHINE, str);
\r
1824 if (dwErr != ERROR_SUCCESS)
\r
1825 return AtlHresultFromWin32(dwErr);
\r
1827 dwErr = rkServices.RecurseDeleteKey(c_szAtlPerfPerformance);
\r
1828 if (dwErr != ERROR_SUCCESS)
\r
1829 return AtlHresultFromWin32(dwErr);
\r
1835 inline HRESULT CPerfMon::Initialize() throw()
\r
1838 CString strAppName;
\r
1843 strAppName = GetAppName();
\r
1845 ATLASSUME(m_aMem.GetCount() == 0);
\r
1848 if (!at.GetEffectiveToken(TOKEN_QUERY))
\r
1853 if (!at.GetUser(&self))
\r
1856 // set up security information for creating the mutex
\r
1860 dacl.AddAllowedAce(Sids::NetworkService(),GENERIC_READ);
\r
1861 dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL);
\r
1862 dacl.AddAllowedAce(Sids::System(), GENERIC_ALL);
\r
1863 dacl.AddAllowedAce(self, GENERIC_ALL);
\r
1865 m_sd.SetDacl(dacl);
\r
1866 m_sd.SetOwner(self);
\r
1868 CSecurityAttributes sa;
\r
1871 // create a mutex to handle syncronizing access to the shared memory area
\r
1872 CString strMutexName;
\r
1873 strMutexName.Format(_T("Global\\ATLPERF_%s_LOCK"), strAppName);
\r
1874 tempLock.Create(&sa, FALSE, strMutexName);
\r
1875 if (tempLock.m_h == NULL)
\r
1876 return AtlHresultFromLastError();
\r
1878 if (GetLastError() == ERROR_ALREADY_EXISTS)
\r
1880 // prevent us from using an object someone else has opened
\r
1881 if (::SetSecurityInfo(tempLock, SE_KERNEL_OBJECT,
\r
1882 DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
\r
1883 const_cast<SID*>(self.GetPSID()),
\r
1885 const_cast<ACL*>(dacl.GetPACL()),
\r
1886 NULL) != ERROR_SUCCESS)
\r
1890 // now set up the dacl for creating shared memory segments and store it
\r
1891 dacl.AddAllowedAce(Sids::Interactive(), GENERIC_READ);
\r
1892 m_sd.SetDacl(dacl);
\r
1894 // create a shared memory area to share data between the app being measured and the client doing the measuring
\r
1896 CMutexLock lock(tempLock);
\r
1898 BOOL bExisted = FALSE;
\r
1900 CAtlFileMappingBase* pMem;
\r
1901 pMem = _AllocNewBlock(NULL, &bExisted);
\r
1903 return E_OUTOFMEMORY;
\r
1907 // copy the map from the registry to the shared memory
\r
1910 CString strAppKey;
\r
1912 strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());
\r
1914 dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, strAppKey, KEY_READ);
\r
1915 if (dwErr != ERROR_SUCCESS)
\r
1917 m_aMem.RemoveAll();
\r
1918 return AtlHresultFromWin32(dwErr);
\r
1921 ULONG nBytes = m_nAllocSize;
\r
1922 dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, pMem->GetData(), &nBytes);
\r
1923 if (dwErr != ERROR_SUCCESS)
\r
1925 m_aMem.RemoveAll();
\r
1926 return AtlHresultFromWin32(dwErr);
\r
1930 hr = _LoadMap(LPDWORD(pMem->GetData()));
\r
1933 m_aMem.RemoveAll();
\r
1937 m_nSchemaSize = *LPDWORD(pMem->GetData());
\r
1938 m_nHeaderSize = m_nSchemaSize + sizeof(DWORD);
\r
1939 m_nHeaderSize = AtlAlignUp(m_nHeaderSize,16);
\r
1942 m_lock.Attach(tempLock.Detach());
\r
1946 m_aMem.RemoveAll();
\r
1947 return E_OUTOFMEMORY;
\r
1953 inline void CPerfMon::UnInitialize() throw()
\r
1955 if (m_lock.m_h != NULL)
\r
1957 m_aMem.RemoveAll();
\r
1961 inline HRESULT CPerfMon::_CreateInstance(
\r
1962 DWORD dwCategoryId,
\r
1964 LPCWSTR szInstanceName,
\r
1965 CPerfObject** ppInstance,
\r
1969 CPerfObject* pEmptyBlock = NULL;
\r
1971 if (ppInstance == NULL)
\r
1974 CAtlFileMappingBase* pCurrentBlock = _GetNextBlock(NULL);
\r
1975 if (pCurrentBlock == NULL || pCurrentBlock->GetData() == NULL || m_lock.m_h == NULL)
\r
1976 return E_UNEXPECTED; // Initialize must succeed before calling CreateInstance
\r
1978 *ppInstance = NULL;
\r
1980 CategoryInfo* pCategoryInfo = _FindCategoryInfo(dwCategoryId);
\r
1981 if (pCategoryInfo == NULL)
\r
1982 return E_INVALIDARG;
\r
1983 if (szInstanceName == NULL && bByName)
\r
1984 return E_INVALIDARG;
\r
1985 if (pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES &&
\r
1986 (dwInstance != 0 || szInstanceName != NULL))
\r
1987 return E_INVALIDARG;
\r
1989 CPerfLock lock(this);
\r
1990 if (FAILED(lock.GetStatus()))
\r
1991 return lock.GetStatus();
\r
1993 CPerfObject* pInstance = _GetFirstInstance(pCurrentBlock);
\r
1994 ULONG nMaxInstance = 0;
\r
1995 ULONG nUsedSpace = 0;
\r
1997 // walk all of the existing objects trying to find one that matches the request
\r
1998 while (pInstance->m_nAllocSize != 0)
\r
2000 nUsedSpace += pInstance->m_nAllocSize;
\r
2002 if (pInstance->m_dwCategoryId == dwCategoryId)
\r
2004 nMaxInstance = __max(nMaxInstance, pInstance->m_dwInstance);
\r
2006 // check to see if we've found the one the caller wants
\r
2007 if (!bByName && pInstance->m_dwInstance == dwInstance &&
\r
2008 (pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES || dwInstance != 0))
\r
2010 *ppInstance = pInstance;
\r
2011 pInstance->m_nRefCount++;
\r
2016 LPWSTR szInstName = (LPWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset));
\r
2017 if (wcsncmp(szInstName, szInstanceName, pCategoryInfo->m_nMaxInstanceNameLen-1) == 0)
\r
2019 *ppInstance = pInstance;
\r
2020 pInstance->m_nRefCount++;
\r
2026 if (pInstance->m_nAllocSize == pCategoryInfo->m_nAllocSize && pInstance->m_nRefCount == 0)
\r
2027 pEmptyBlock = pInstance;
\r
2029 pInstance = _GetNextInstance(pInstance);
\r
2030 ATLENSURE_RETURN(pInstance!= NULL);
\r
2032 if (pInstance->m_nAllocSize == 0 &&
\r
2033 m_nHeaderSize + nUsedSpace + pCategoryInfo->m_nAllocSize + sizeof(CPerfObject) > m_nAllocSize)
\r
2035 // we've reached the end of the block and have no room to allocate an object of this
\r
2036 // type. cap the block with a sentinel
\r
2037 pInstance->m_nAllocSize = (ULONG) -1;
\r
2040 // check for an end-of-shared-mem sentinel
\r
2041 if (pInstance->m_nAllocSize == (ULONG) -1)
\r
2044 CAtlFileMappingBase* pNextBlock = _GetNextBlock(pCurrentBlock);
\r
2045 if (pNextBlock == NULL)
\r
2047 // we've reached the last block of shared mem.
\r
2048 // the instance hasn't been found, so either use a
\r
2049 // previously freed instance block (pEmptyBlock) or allocate a new
\r
2050 // shared mem block to hold the new instance
\r
2051 if (pEmptyBlock == NULL)
\r
2053 pNextBlock = _AllocNewBlock(pCurrentBlock);
\r
2054 if (pNextBlock == NULL)
\r
2055 return E_OUTOFMEMORY;
\r
2060 pCurrentBlock = pNextBlock;
\r
2061 pInstance = _GetFirstInstance(pCurrentBlock);
\r
2065 // allocate a new object
\r
2066 if (pEmptyBlock != NULL)
\r
2067 pInstance = pEmptyBlock;
\r
2069 pInstance->m_nAllocSize = pCategoryInfo->m_nAllocSize;
\r
2071 if (dwInstance == 0 && pCategoryInfo->m_nInstanceLess != PERF_NO_INSTANCES)
\r
2072 pInstance->m_dwInstance = nMaxInstance + 1;
\r
2074 pInstance->m_dwInstance = dwInstance;
\r
2076 pInstance->m_nRefCount = 1;
\r
2078 // copy the instance name, truncate if necessary
\r
2079 if (pCategoryInfo->m_nInstanceLess != PERF_NO_INSTANCES)
\r
2081 ULONG nNameLen = (ULONG)__min(wcslen(szInstanceName), pCategoryInfo->m_nMaxInstanceNameLen-1);
\r
2082 ULONG nNameBytes = (nNameLen+1) * sizeof(WCHAR);
\r
2083 pInstance->m_nInstanceNameOffset = pInstance->m_nAllocSize-nNameBytes;
\r
2084 Checked::memcpy_s(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset, pInstance->m_nAllocSize-pInstance->m_nInstanceNameOffset, szInstanceName, nNameBytes);
\r
2085 LPWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset)[nNameLen] = 0;
\r
2088 // copy the CategoryId last: it won't be collected until this is set
\r
2089 pInstance->m_dwCategoryId = pCategoryInfo->m_dwCategoryId;
\r
2091 *ppInstance = pInstance;
\r
2096 inline HRESULT CPerfMon::CreateInstance(
\r
2097 DWORD dwCategoryId,
\r
2099 LPCWSTR szInstanceName,
\r
2100 CPerfObject** ppInstance
\r
2103 return _CreateInstance(dwCategoryId, dwInstance, szInstanceName, ppInstance, false);
\r
2106 inline HRESULT CPerfMon::CreateInstanceByName(
\r
2107 DWORD dwCategoryId,
\r
2108 LPCWSTR szInstanceName,
\r
2109 CPerfObject** ppInstance
\r
2112 return _CreateInstance(dwCategoryId, 0, szInstanceName, ppInstance, true);
\r
2115 inline HRESULT CPerfMon::ReleaseInstance(CPerfObject* pInstance) throw()
\r
2117 ATLASSERT(pInstance != NULL);
\r
2118 if (pInstance == NULL)
\r
2119 return E_INVALIDARG;
\r
2121 CPerfLock lock(this);
\r
2122 if (FAILED(lock.GetStatus()))
\r
2123 return lock.GetStatus();
\r
2125 if (--pInstance->m_nRefCount == 0)
\r
2127 pInstance->m_dwInstance = 0;
\r
2128 pInstance->m_dwCategoryId = 0;
\r
2134 inline HRESULT CPerfMon::LockPerf(DWORD dwTimeout /* == INFINITE */) throw()
\r
2136 if (m_lock.m_h == NULL)
\r
2137 return E_UNEXPECTED;
\r
2139 DWORD dwRes = WaitForSingleObject(m_lock.m_h, dwTimeout);
\r
2140 if (dwRes == WAIT_ABANDONED || dwRes == WAIT_OBJECT_0)
\r
2142 if (dwRes == WAIT_TIMEOUT)
\r
2143 return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
\r
2144 return AtlHresultFromLastError();
\r
2147 inline void CPerfMon::UnlockPerf() throw()
\r
2152 // map building routines
\r
2153 inline HRESULT CPerfMon::AddCategoryDefinition(
\r
2154 DWORD dwCategoryId,
\r
2155 LPCTSTR szCategoryName,
\r
2156 LPCTSTR szHelpString,
\r
2157 DWORD dwDetailLevel,
\r
2158 INT nDefaultCounter,
\r
2159 BOOL bInstanceLess,
\r
2161 UINT nMaxInstanceNameLen) throw()
\r
2163 // must have one and only one of these
\r
2164 ATLASSERT(!bInstanceLess ^ !nMaxInstanceNameLen);
\r
2166 // get the things that can fail out of the way first
\r
2171 strName = szCategoryName;
\r
2172 strHelp = szHelpString;
\r
2176 return E_OUTOFMEMORY;
\r
2179 if (!m_categories.SetCount(m_categories.GetCount()+1))
\r
2181 return E_OUTOFMEMORY;
\r
2184 // category has been added, set the data
\r
2185 CategoryInfo* pCategoryInfo = _GetCategoryInfo(_GetNumCategories()-1);
\r
2187 pCategoryInfo->m_dwCategoryId = dwCategoryId;
\r
2188 pCategoryInfo->m_dwDetailLevel = dwDetailLevel;
\r
2189 pCategoryInfo->m_nDefaultCounter = nDefaultCounter;
\r
2190 pCategoryInfo->m_nInstanceLess = bInstanceLess ? PERF_NO_INSTANCES : 0;
\r
2191 pCategoryInfo->m_nStructSize = nStructSize;
\r
2192 pCategoryInfo->m_nMaxInstanceNameLen = nMaxInstanceNameLen;
\r
2193 pCategoryInfo->m_nAllocSize = nStructSize + nMaxInstanceNameLen*sizeof(WCHAR);
\r
2194 pCategoryInfo->m_strName = strName;
\r
2195 pCategoryInfo->m_strHelp = strHelp;
\r
2196 pCategoryInfo->m_nNameId = 0;
\r
2197 pCategoryInfo->m_nHelpId = 0;
\r
2202 inline HRESULT CPerfMon::AddCounterDefinition(
\r
2203 DWORD dwCounterId,
\r
2204 LPCTSTR szCounterName,
\r
2205 LPCTSTR szHelpString,
\r
2206 DWORD dwDetailLevel,
\r
2207 DWORD dwCounterType,
\r
2208 ULONG nMaxCounterSize,
\r
2210 INT nDefaultScale) throw()
\r
2212 // must add category BEFORE adding counter!
\r
2213 ATLASSERT(_GetNumCategories() > 0);
\r
2215 CounterInfo counter;
\r
2217 counter.m_dwCounterId = dwCounterId;
\r
2220 counter.m_strName = szCounterName;
\r
2221 counter.m_strHelp = szHelpString;
\r
2225 return E_OUTOFMEMORY;
\r
2227 counter.m_dwDetailLevel = dwDetailLevel;
\r
2228 counter.m_dwCounterType = dwCounterType;
\r
2229 counter.m_nDefaultScale = nDefaultScale;
\r
2230 counter.m_nMaxCounterSize = nMaxCounterSize;
\r
2231 counter.m_nDataOffset = nOffset;
\r
2233 counter.m_nNameId = 0;
\r
2234 counter.m_nHelpId = 0;
\r
2236 // add the counter to the category
\r
2237 CategoryInfo* pCategoryInfo = _GetCategoryInfo(_GetNumCategories()-1);
\r
2240 pCategoryInfo->m_counters.Add(counter);
\r
2244 return E_OUTOFMEMORY;
\r
2247 if (counter.m_nMaxCounterSize > 0)
\r
2249 ATLASSERT(counter.m_dwCounterType & PERF_TYPE_TEXT);
\r
2250 pCategoryInfo->m_nAllocSize += counter.m_nMaxCounterSize * sizeof(WCHAR);
\r
2256 inline HRESULT CPerfMon::RegisterCategory(
\r
2258 HINSTANCE hResInstance,
\r
2260 DWORD dwCategoryId,
\r
2264 BOOL bInstanceless,
\r
2266 UINT nMaxInstanceNameLen,
\r
2267 INT nDefaultCounter) throw()
\r
2270 *pSampleRes = nNameString;
\r
2278 if (!strName.LoadString(hResInstance, nNameString, wLanguage) ||
\r
2279 !strHelp.LoadString(hResInstance, nHelpString, wLanguage))
\r
2286 return E_OUTOFMEMORY;
\r
2289 return RegisterCategory(
\r
2299 nMaxInstanceNameLen,
\r
2303 inline HRESULT CPerfMon::RegisterCategory(
\r
2304 WORD /* wLanguage */,
\r
2305 HINSTANCE /* hResInstance */,
\r
2306 UINT* /* pSampleRes */,
\r
2307 DWORD dwCategoryId,
\r
2308 LPCTSTR szNameString,
\r
2309 LPCTSTR szHelpString,
\r
2311 BOOL bInstanceless,
\r
2313 UINT nMaxInstanceNameLen,
\r
2314 INT nDefaultCounter) throw()
\r
2316 return AddCategoryDefinition(
\r
2324 nMaxInstanceNameLen);
\r
2327 inline HRESULT CPerfMon::RegisterCounter(
\r
2329 HINSTANCE hResInstance,
\r
2330 DWORD dwCounterId,
\r
2334 DWORD dwCounterType,
\r
2335 ULONG nMaxCounterSize,
\r
2337 INT nDefaultScale) throw()
\r
2345 if (!strName.LoadString(hResInstance, nNameString, wLanguage) ||
\r
2346 !strHelp.LoadString(hResInstance, nHelpString, wLanguage))
\r
2353 return E_OUTOFMEMORY;
\r
2356 return RegisterCounter(
\r
2369 inline HRESULT CPerfMon::RegisterCounter(
\r
2370 WORD /* wLanguage */,
\r
2371 HINSTANCE /* hResInstance */,
\r
2372 DWORD dwCounterId,
\r
2373 LPCTSTR szNameString,
\r
2374 LPCTSTR szHelpString,
\r
2376 DWORD dwCounterType,
\r
2377 ULONG nMaxCounterSize,
\r
2379 INT nDefaultScale) throw()
\r
2381 return AddCounterDefinition(
\r
2392 inline void CPerfMon::ClearMap() throw()
\r
2394 m_categories.RemoveAll();
\r
2397 #ifndef _ATL_PERF_NOXML
\r
2399 ATL_NOINLINE inline HRESULT CPerfMon::PersistToXML(IStream *pStream, BOOL bFirst/*=TRUE*/, BOOL bLast/*=TRUE*/) throw(...)
\r
2401 ATLASSERT(pStream != NULL);
\r
2402 if (pStream == NULL)
\r
2403 return E_INVALIDARG;
\r
2405 CPerfLock lock(this);
\r
2406 if (FAILED(lock.GetStatus()))
\r
2407 return ERROR_SUCCESS;
\r
2410 HRESULT hr = S_OK;
\r
2415 strXML = "<?xml version=\"1.0\" ?>\r\n<perfPersist>\r\n";
\r
2416 hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
\r
2421 strXML.Format("\t<perfmon name=\"%s\">\r\n", CT2CA(GetAppName()));
\r
2422 hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
\r
2424 for (UINT i=0; i<_GetNumCategories(); i++)
\r
2426 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);
\r
2428 CAtlFileMappingBase *pCurrentBlock = _GetNextBlock(NULL);
\r
2429 CPerfObject *pInstance = _GetFirstInstance(pCurrentBlock);
\r
2431 strXML.Format("\t\t<perfObject perfid=\"%d\">\r\n",
\r
2432 pCategoryInfo->m_dwCategoryId, pCategoryInfo->m_nNameId, pCategoryInfo->m_nHelpId);
\r
2434 hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
\r
2438 while (pInstance && pInstance->m_nAllocSize)
\r
2440 if (pInstance->m_dwCategoryId == pCategoryInfo->m_dwCategoryId)
\r
2442 if (pCategoryInfo->m_nInstanceLess != PERF_NO_INSTANCES)
\r
2444 // handle the instance name
\r
2445 LPCWSTR wszInstNameSrc = LPCWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset);
\r
2446 int nInstLen = (int) wcslen(wszInstNameSrc);
\r
2448 // convert to UTF8
\r
2449 int nLength = AtlUnicodeToUTF8(wszInstNameSrc, nInstLen, NULL, 0);
\r
2450 CHeapPtr<CHAR> szUTF8;
\r
2451 if ((nLength < 0) || (nLength+1<nLength) || !szUTF8.Allocate(nLength+1))
\r
2452 return E_OUTOFMEMORY;
\r
2453 nLength = AtlUnicodeToUTF8(wszInstNameSrc, nInstLen, szUTF8, nLength);
\r
2454 szUTF8[nLength] = '\0';
\r
2456 strXML.Format("\t\t\t<instance name=\"%s\" id=\"%d\">\r\n", szUTF8, pInstance->m_dwInstance);
\r
2457 hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
\r
2462 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)
\r
2464 CounterInfo *pCounterInfo = pCategoryInfo->_GetCounterInfo(j);
\r
2465 switch (pCounterInfo->m_dwCounterType & ATLPERF_SIZE_MASK)
\r
2467 case PERF_SIZE_DWORD:
\r
2469 strXML.Format("\t\t\t\t<counter type=\"perf_size_dword\" value=\"%d\" offset=\"%d\"/>\r\n",
\r
2470 *LPDWORD(LPBYTE(pInstance)+pCounterInfo->m_nDataOffset),
\r
2471 pCounterInfo->m_nDataOffset);
\r
2474 case PERF_SIZE_LARGE:
\r
2476 strXML.Format("\t\t\t\t<counter type=\"perf_size_large\" value=\"%d\" offset=\"%d\"/>\r\n",
\r
2477 *PULONGLONG(LPBYTE(pInstance)+pCounterInfo->m_nDataOffset),
\r
2478 pCounterInfo->m_nDataOffset);
\r
2481 case PERF_SIZE_VARIABLE_LEN:
\r
2483 CHeapPtr<CHAR> szUTF8;
\r
2484 LPBYTE pSrc = LPBYTE(pInstance)+pCounterInfo->m_nDataOffset;
\r
2485 if ((pCounterInfo->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)
\r
2487 ULONG nTextLen = (ULONG)wcslen(LPCWSTR(pSrc));
\r
2488 // convert to UTF8
\r
2489 nLen = AtlUnicodeToUTF8(LPCWSTR(pSrc), nTextLen, NULL, 0);
\r
2490 if (!szUTF8.Allocate(nLen+1))
\r
2491 return E_OUTOFMEMORY;
\r
2493 nLen = AtlUnicodeToUTF8(LPCWSTR(pSrc), nTextLen, szUTF8, nLen);
\r
2494 szUTF8[nLen] = '\0';
\r
2495 strXML.Format("\t\t\t\t<counter type=\"perf_size_variable_len_unicode\" value=\"%s\" offset=\"%d\"/>\r\n",
\r
2497 pCounterInfo->m_nDataOffset);
\r
2501 ULONG nTextLen = (ULONG)strlen(LPCSTR(pSrc));
\r
2502 if (!szUTF8.Allocate(nTextLen+1))
\r
2503 return E_OUTOFMEMORY;
\r
2504 Checked::strcpy_s(szUTF8, nTextLen+1, LPCSTR(pSrc));
\r
2505 strXML.Format("\t\t\t\t<counter type=\"perf_size_variable_len_ansi\" value=\"%s\" offset=\"%d\"/>\r\n",
\r
2507 pCounterInfo->m_nDataOffset);
\r
2515 hr = pStream->Write(strXML, strXML.GetLength(), &nLen);
\r
2520 if (pCategoryInfo->m_nInstanceLess != PERF_NO_INSTANCES)
\r
2522 hr = pStream->Write("\t\t\t</instance>\r\n", sizeof("\t\t\t</instance>\r\n")-1, &nLen);
\r
2528 pInstance = _GetNextInstance(pInstance);
\r
2529 ATLENSURE_RETURN(pInstance!= NULL);
\r
2531 if (pInstance->m_nAllocSize == (ULONG)-1)
\r
2533 pCurrentBlock = _GetNextBlock(pCurrentBlock);
\r
2534 if (pCurrentBlock == NULL)
\r
2537 pInstance = _GetFirstInstance(pCurrentBlock);
\r
2541 hr = pStream->Write("\t\t</perfObject>\r\n", sizeof("\t\t</perfObject>\r\n")-1, &nLen);
\r
2546 hr = pStream->Write("\t</perfmon>\r\n", sizeof("\t</perfmon>\r\n")-1, &nLen);
\r
2550 if (hr == S_OK && bLast)
\r
2551 hr = pStream->Write("</perfPersist>", sizeof("</perfPersist>")-1, &nLen);
\r
2556 // This function is very lenient with inappropriate XML
\r
2557 ATL_NOINLINE inline HRESULT CPerfMon::LoadFromXML(IStream *pStream) throw(...)
\r
2559 ATLASSERT(pStream != NULL);
\r
2560 if (pStream == NULL)
\r
2561 return E_INVALIDARG;
\r
2564 CPerfLock lock(this);
\r
2565 if (FAILED(lock.GetStatus()))
\r
2566 return ERROR_SUCCESS;
\r
2568 CComPtr<IXMLDOMDocument> spdoc;
\r
2571 HRESULT hr = CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC, __uuidof(IXMLDOMDocument), (void **) &spdoc);
\r
2577 spdoc->put_async(VARIANT_FALSE);
\r
2579 CComPtr<IPersistStreamInit> spSI;
\r
2580 hr = spdoc->QueryInterface(&spSI);
\r
2583 hr = spSI->Load(pStream);
\r
2587 // validate that it is a perfPersist stream
\r
2588 CComPtr<IXMLDOMElement> spRoot;
\r
2590 hr = spdoc->get_documentElement(&spRoot);
\r
2594 CComBSTR bstrName;
\r
2595 hr = spRoot->get_baseName(&bstrName);
\r
2596 if (wcscmp(bstrName, L"perfPersist"))
\r
2599 // find the appropriate perfmon node
\r
2600 CComPtr<IXMLDOMNode> spChild;
\r
2601 hr = spRoot->get_firstChild(&spChild);
\r
2602 while (hr == S_OK)
\r
2605 hr = spChild->get_baseName(&bstrName);
\r
2608 if (!wcscmp(bstrName, L"perfmon"))
\r
2611 hr = _GetAttribute(spChild, L"name", &bstrName);
\r
2614 if (!_tcscmp(CW2CT(bstrName), GetAppName()))
\r
2620 CComPtr<IXMLDOMNode> spNext;
\r
2621 hr = spChild->get_nextSibling(&spNext);
\r
2622 spChild.Attach(spNext.Detach());
\r
2625 // there is no perfmon node in the XML for the current CPerfMon class
\r
2629 CComPtr<IXMLDOMNode> spPerfRoot;
\r
2630 spPerfRoot.Attach(spChild.Detach());
\r
2632 // iterate over the objects in the perfmon subtree
\r
2633 // this is the loop that does the real work
\r
2634 hr = spPerfRoot->get_firstChild(&spChild);
\r
2635 while (hr == S_OK)
\r
2637 // see if it's a perfObject
\r
2639 hr = spChild->get_baseName(&bstrName);
\r
2640 if (hr != S_OK || wcscmp(bstrName, L"perfObject"))
\r
2645 hr = _GetAttribute(spChild, L"perfid", &bstrName);
\r
2646 DWORD dwPerfId = _wtoi(bstrName);
\r
2648 // iterate over children
\r
2649 CComPtr<IXMLDOMNode> spInstChild;
\r
2650 hr = spChild->get_firstChild(&spInstChild);
\r
2651 while (hr == S_OK)
\r
2653 // see if it's a instance
\r
2655 hr = spInstChild->get_baseName(&bstrName);
\r
2656 if (hr != S_OK || wcscmp(bstrName, L"instance"))
\r
2659 // get the instance name
\r
2661 hr = _GetAttribute(spInstChild, L"name", &bstrName);
\r
2665 // get the instance id
\r
2667 hr = _GetAttribute(spChild, L"id", &bstrName);
\r
2670 DWORD dwInstance = _wtoi(bstrName);
\r
2672 // create the instance
\r
2673 CPerfObject *pInstance = NULL;
\r
2674 hr = CreateInstance(dwPerfId, dwInstance++, bstrName, &pInstance);
\r
2678 // iterate over the counters and set the data
\r
2679 CComPtr<IXMLDOMNode> spCntrChild;
\r
2680 hr = spInstChild->get_firstChild(&spCntrChild);
\r
2681 while (hr == S_OK)
\r
2683 // get the base name
\r
2685 hr = spCntrChild->get_baseName(&bstrName);
\r
2686 if (hr != S_OK || wcscmp(bstrName, L"counter"))
\r
2691 hr = _GetAttribute(spCntrChild, L"type", &bstrName);
\r
2696 if (!wcscmp(bstrName, L"perf_size_dword"))
\r
2697 dwType = PERF_SIZE_DWORD;
\r
2698 else if (!wcscmp(bstrName, L"perf_size_large"))
\r
2699 dwType = PERF_SIZE_LARGE;
\r
2700 else if (!wcscmp(bstrName, L"perf_size_variable_len_ansi"))
\r
2701 dwType = PERF_SIZE_VARIABLE_LEN;
\r
2702 else if (!wcscmp(bstrName, L"perf_size_variable_len_unicode"))
\r
2703 dwType = PERF_SIZE_VARIABLE_LEN | PERF_TEXT_UNICODE;
\r
2709 hr = _GetAttribute(spCntrChild, L"value", &bstrName);
\r
2713 CComBSTR bstrOffset;
\r
2714 hr = _GetAttribute(spCntrChild, L"offset", &bstrOffset);
\r
2718 WCHAR *pStop = NULL;
\r
2719 DWORD dwOffset = wcstoul(bstrOffset, &pStop, 10);
\r
2721 if (dwType == PERF_SIZE_DWORD) // add it as a DWORD
\r
2723 DWORD dwVal = wcstoul(bstrName, &pStop, 10);
\r
2724 *LPDWORD(LPBYTE(pInstance)+dwOffset) = dwVal;
\r
2726 else if (dwType == PERF_SIZE_LARGE) // add it is a ULONGLONG
\r
2728 ULONGLONG qwVal = _wcstoui64(bstrName, &pStop, 10);
\r
2729 *PULONGLONG(LPBYTE(pInstance)+dwOffset) = qwVal;
\r
2731 else if (dwType == PERF_SIZE_VARIABLE_LEN) // add it as an ansi string
\r
2733 AtlW2AHelper(LPSTR(LPBYTE(pInstance)+dwOffset), bstrName, bstrName.Length(), ATL::_AtlGetConversionACP());
\r
2735 else // add it as a unicode string
\r
2737 Checked::memcpy_s(LPBYTE(pInstance)+dwOffset, pInstance->m_nAllocSize-dwOffset, bstrName, bstrName.Length()*sizeof(WCHAR));
\r
2740 CComPtr<IXMLDOMNode> spCntrNext;
\r
2741 hr = spCntrChild->get_nextSibling(&spCntrNext);
\r
2742 spCntrChild.Attach(spCntrNext.Detach());
\r
2745 CComPtr<IXMLDOMNode> spInstNext;
\r
2746 hr = spInstChild->get_nextSibling(&spInstNext);
\r
2747 spInstChild.Attach(spInstNext.Detach());
\r
2750 CComPtr<IXMLDOMNode> spNext;
\r
2751 hr = spChild->get_nextSibling(&spNext);
\r
2752 spChild.Attach(spNext.Detach());
\r
2758 // a little utility function to retrieve a named attribute from a node
\r
2759 ATL_NOINLINE inline HRESULT CPerfMon::_GetAttribute(IXMLDOMNode *pNode, LPCWSTR szAttrName, BSTR *pbstrVal) throw()
\r
2761 ATLENSURE_RETURN(pNode != NULL);
\r
2762 ATLASSERT(szAttrName != NULL);
\r
2763 ATLENSURE_RETURN(pbstrVal != NULL);
\r
2766 CComPtr<IXMLDOMNamedNodeMap> spAttrs;
\r
2768 HRESULT hr = pNode->get_attributes(&spAttrs);
\r
2772 CComPtr<IXMLDOMNode> spAttr;
\r
2774 hr = spAttrs->getNamedItem((BSTR) szAttrName, &spAttr);
\r
2778 CComVariant varVal;
\r
2779 hr = spAttr->get_nodeValue(&varVal);
\r
2783 hr = varVal.ChangeType(VT_BSTR);
\r
2787 *pbstrVal = varVal.bstrVal;
\r
2788 varVal.vt = VT_EMPTY;
\r
2793 #endif // _ATL_PERF_NOXML
\r
2795 #if defined(_ATL_PERF_REGISTER) & !defined(_ATL_PERF_NOEXPORT)
\r
2797 ATL_NOINLINE inline HRESULT RegisterPerfMon(HINSTANCE hDllInstance /* = _AtlBaseModule.GetModuleInstance() */) throw()
\r
2799 CPerfMon **ppPerf = &__pperfA;
\r
2800 HRESULT hr = S_OK;
\r
2801 while (ppPerf != &__pperfZ)
\r
2803 if (*ppPerf != NULL)
\r
2805 hr = (*ppPerf)->Register(_T( ATLPERF_FUNCID_OPEN ), _T( ATLPERF_FUNCID_COLLECT ), _T( ATLPERF_FUNCID_CLOSE ), hDllInstance);
\r
2808 hr = (*ppPerf)->RegisterAllStrings(hDllInstance);
\r
2817 ATL_NOINLINE inline HRESULT UnregisterPerfMon() throw()
\r
2819 CPerfMon **ppPerf = &__pperfA;
\r
2820 HRESULT hr = S_OK;
\r
2821 while (ppPerf != &__pperfZ)
\r
2823 if (*ppPerf != NULL)
\r
2825 hr = (*ppPerf)->Unregister();
\r
2834 extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI OpenPerfMon(LPWSTR lpDeviceNames) throw()
\r
2836 CPerfMon **ppPerf = &__pperfA;
\r
2838 while (ppPerf != &__pperfZ)
\r
2840 if (*ppPerf != NULL)
\r
2842 dwErr = (*ppPerf)->Open(lpDeviceNames);
\r
2851 extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI CollectPerfMon(LPWSTR lpwszValue, LPVOID* lppData,
\r
2852 LPDWORD lpcbBytes, LPDWORD lpcObjectTypes) throw()
\r
2854 DWORD dwOrigBytes = *lpcbBytes;
\r
2855 DWORD dwBytesRemaining = *lpcbBytes;
\r
2856 CPerfMon **ppPerf = &__pperfA;
\r
2858 while (ppPerf != &__pperfZ)
\r
2860 if (*ppPerf != NULL)
\r
2862 dwErr = (*ppPerf)->Collect(lpwszValue, lppData, lpcbBytes, lpcObjectTypes);
\r
2865 dwBytesRemaining -= *lpcbBytes;
\r
2866 *lpcbBytes = dwBytesRemaining;
\r
2870 *lpcbBytes = dwOrigBytes - dwBytesRemaining;
\r
2874 extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI ClosePerfMon() throw()
\r
2876 CPerfMon **ppPerf = &__pperfA;
\r
2877 while (ppPerf != &__pperfZ)
\r
2879 if (*ppPerf != NULL)
\r
2881 (*ppPerf)->Close();
\r
2888 #endif // defined(_ATL_PERF_REGISTER) & !defined(_ATL_PERF_NOEXPORT)
\r
2890 } // namespace ATL
\r
2892 #pragma warning(pop)
\r
2894 #endif // __ATLPERF_INL__
\r