Fix(ed) crash issues with NV12/NV21+"Piture Size=>Vertical padding not setting to...
[xy_vsfilter.git] / include / atl / atlperf.inl
blob398fd1b0a0b3610cd51395443fef033ad8c03f00
1 // This is a part of the Active Template Library.\r
2 // Copyright (C) Microsoft Corporation\r
3 // All rights reserved.\r
4 //\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
14 #pragma once\r
15  \r
16 #ifndef __ATLPERF_H__\r
17         #error atlperf.inl requires atlperf.h to be included first\r
18 #endif\r
20 #pragma warning(push)\r
22 #ifndef _CPPUNWIND\r
23 #pragma warning(disable: 4702) // unreachable code\r
24 #endif\r
26 namespace ATL\r
27 {\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
50 {\r
51         ATLASSERT(nIndex < _GetNumCounters());\r
52         return &m_counters[nIndex];\r
53 }\r
55 inline UINT CPerfMon::CategoryInfo::_GetNumCounters() throw()\r
56 {\r
57         return (UINT) m_counters.GetCount();\r
58 }\r
60 inline CPerfMon::~CPerfMon() throw()\r
61 {\r
62         UnInitialize();\r
63 }\r
65 inline HRESULT CPerfMon::CreateMap(LANGID language, HINSTANCE hResInstance, UINT* pSampleRes) throw()\r
66 {\r
67         (language); // unused\r
68         (hResInstance); // unused\r
69         (pSampleRes); // unused\r
70         return S_OK;\r
71 }\r
73 inline UINT CPerfMon::_GetNumCategoriesAndCounters() throw()\r
74 {\r
75         UINT nResult = _GetNumCategories();\r
76         for (UINT i=0; i<_GetNumCategories(); i++)\r
77         {\r
78                 nResult += _GetCategoryInfo(i)->_GetNumCounters();\r
79         }\r
81         return nResult;\r
82 }\r
84 inline CPerfMon::CategoryInfo* CPerfMon::_GetCategoryInfo(UINT nIndex) throw()\r
85 {\r
86         ATLASSERT(nIndex < _GetNumCategories());\r
87         return &m_categories[nIndex];\r
88 }\r
90 inline UINT CPerfMon::_GetNumCategories() throw()\r
91 {\r
92         return (UINT) m_categories.GetCount();\r
93 }\r
95 inline CPerfObject* CPerfMon::_GetFirstInstance(CAtlFileMappingBase* pBlock)\r
96 {\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
120         if (pDw)\r
121         {\r
122                 dwNextBlockIndex = *pDw +1;\r
123         }\r
124         if (m_aMem.GetCount() == dwNextBlockIndex)\r
125                 return NULL;\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
134         if (spMem == NULL)\r
135                 return NULL;\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
140         if (pDw)\r
141         {\r
142                 dwNextBlockIndex = *pDw +1;\r
143         }\r
144         else\r
145         {\r
146                 // use the system allocation granularity (65536 currently. may be different in the future)\r
147                 SYSTEM_INFO si;\r
148                 GetSystemInfo(&si);\r
149                 m_nAllocSize = si.dwAllocationGranularity;\r
151                 dwNextBlockIndex = 0;\r
152         }\r
154         _ATLTRY\r
155         {\r
156                 CString strName;\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
160                 if (FAILED(hr))\r
161                         return NULL;\r
163                 pMem = spMem;\r
164                 m_aMem.Add(spMem);\r
165         }\r
166         _ATLCATCHALL()\r
167         {\r
168                 return NULL;\r
169         }\r
171         return pMem;\r
174 inline CAtlFileMappingBase* CPerfMon::_AllocNewBlock(CAtlFileMappingBase* pPrev, BOOL* pbExisted /* == NULL */) throw()\r
176         CAtlFileMappingBase* pMem = NULL;\r
177         _ATLTRY\r
178         {\r
179                 CSecurityAttributes sa;\r
180                 sa.Set(m_sd);\r
182                 CAutoPtr<CAtlFileMappingBase> spMem;\r
183                 spMem.Attach(new CAtlFileMappingBase);\r
184                 if (spMem == NULL)\r
185                 {\r
186                         return NULL;\r
187                 }\r
189                 // create a unique name for the shared mem segment based on the index\r
190                 DWORD dwNextBlockIndex;\r
191                 if (pPrev != NULL)\r
192                 {\r
193                         dwNextBlockIndex = _GetBlockId(pPrev) +1;\r
194                 }\r
195                 else\r
196                 {\r
197                         // use the system allocation granularity (65536 currently. may be different in the future)\r
198                         SYSTEM_INFO si;\r
199                         GetSystemInfo(&si);\r
200                         m_nAllocSize = si.dwAllocationGranularity;\r
202                         dwNextBlockIndex = 0;\r
203                 }\r
205                 BOOL bExisted = FALSE;\r
206                 CString strName;\r
207                 strName.Format(_T("Global\\ATLPERF_%s_%3.3d"), GetAppName(), dwNextBlockIndex);\r
209                 HRESULT hr = spMem->MapSharedMem(m_nAllocSize, strName, &bExisted, &sa);\r
210                 if (FAILED(hr))\r
211                 {\r
212                         return NULL;\r
213                 }\r
215                 if(!bExisted)\r
216                 {\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
221                         {\r
222                                 _GetBlockId(spMem) = dwNextBlockIndex;\r
223                         }\r
224                 }\r
225                 else\r
226                 {\r
227                         CSid owner;\r
228                         CDacl dacl;\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
237                                         NULL,\r
238                                         const_cast<ACL*>(dacl.GetPACL()),\r
239                                         NULL) != ERROR_SUCCESS)\r
240                         {\r
241                                 return NULL;\r
242                         }\r
243                 }\r
245                 if (pbExisted)\r
246                 {\r
247                         *pbExisted = bExisted;\r
248                 }\r
250                 pMem = spMem;\r
251                 m_aMem.Add(spMem);\r
253                 OnBlockAlloc(pMem);\r
254         }\r
255         _ATLCATCHALL()\r
256         {\r
257                 return NULL;\r
258         }\r
260         return pMem;\r
263 inline HRESULT CPerfMon::_OpenAllBlocks() throw()\r
265         HRESULT hr;\r
267         // if we haven't opened any yet, initialize\r
268         if (m_aMem.GetCount() == 0)\r
269         {\r
270                 CAtlFileMappingBase* pMem = _OpenNextBlock(NULL);\r
271                 if (pMem == NULL)\r
272                         return S_OK;\r
274                 hr = _LoadMap(LPDWORD(pMem->GetData()));\r
275                 if (FAILED(hr))\r
276                 {\r
277                         m_aMem.RemoveAll();\r
278                         return hr;\r
279                 }\r
281                 m_nSchemaSize = *LPDWORD(pMem->GetData());\r
282                 m_nHeaderSize = m_nSchemaSize + sizeof(DWORD);\r
283                 m_nHeaderSize  = AtlAlignUp(m_nHeaderSize,16);\r
284         }\r
286         // open any new blocks\r
287         CAtlFileMappingBase* pMem = m_aMem[m_aMem.GetCount()-1];\r
288         while (pMem)\r
289                 pMem = _OpenNextBlock(pMem);\r
291         return S_OK;\r
294 inline HRESULT CPerfMon::_LoadMap(DWORD* pData) throw()\r
296         _ATLTRY\r
297         {\r
298                 HRESULT hr;\r
300                 ClearMap();\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
311                 {\r
312                         DWORD dwIsObject = *pData++;\r
313                         DWORD dwPerfId = *pData++;\r
314                         DWORD dwDetailLevel = *pData++;\r
316                         CString strName;\r
317                         if (pNameData)\r
318                         {\r
319                                 strName = CString(LPWSTR(pNameData+1), *pNameData);\r
320                                 pNameData += AtlAlignUp(sizeof(WCHAR) * *pNameData, sizeof(DWORD))/sizeof(DWORD) + 1;\r
321                         }\r
323                         if (dwIsObject)\r
324                         {\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
331                                         dwPerfId,\r
332                                         strName,\r
333                                         NULL,\r
334                                         dwDetailLevel,\r
335                                         dwDefaultCounter,\r
336                                         dwInstanceLess,\r
337                                         dwStructSize,\r
338                                         dwMaxInstanceNameLen);\r
339                                 if (FAILED(hr))\r
340                                 {\r
341                                         ClearMap();\r
342                                         return hr;\r
343                                 }\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
350                         }\r
351                         else\r
352                         {\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
359                                         dwPerfId,\r
360                                         strName,\r
361                                         NULL,\r
362                                         dwDetailLevel,\r
363                                         dwCounterType,\r
364                                         dwMaxCounterSize,\r
365                                         dwDataOffset,\r
366                                         dwDefaultScale);\r
367                                 if (FAILED(hr))\r
368                                 {\r
369                                         ClearMap();\r
370                                         return hr;\r
371                                 }\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
379                         }\r
380                 }\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
385                 {\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
392                         {\r
393                                 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);\r
394                                 _FillCounterDef(pCounterInfo, pnCounterBlockSize);\r
395                         }\r
396                         // align at 8 bytes per Q262335\r
397                         pCategoryInfo->m_nCounterBlockSize = (ULONG) AtlAlignUp(pCategoryInfo->m_nCounterBlockSize, 8);\r
398                 }\r
400                 return S_OK;\r
401         }\r
402         _ATLCATCHALL()\r
403         {\r
404                 return E_OUTOFMEMORY;\r
405         }\r
408 inline HRESULT CPerfMon::_SaveMap() throw()\r
410         _ATLTRY\r
411         {\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
415                 {\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
419                         {\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
422                                 {\r
423                                         CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);\r
424                                         nSize += sizeof(DWORD) + AtlAlignUp(sizeof(WCHAR) * pCounterInfo->m_strName.GetLength(), sizeof(DWORD));\r
425                                 }\r
426                         }\r
427                 }\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
443                 {\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
456                         nSizeLast = nSize;\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
461                         {\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
473                                 nSizeLast = nSize;\r
474                                 nSize -= 9 * sizeof(DWORD);\r
475                                 if(nSize > nSizeLast) return E_FAIL;\r
476                         }\r
477                 }\r
479                 // add names to the blob\r
480                 for (UINT i=0; i<_GetNumCategories(); i++)\r
481                 {\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
487                         nSizeLast = nSize;\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
493                         nSizeLast = nSize;\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
498                         {\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
504                                 nSizeLast = nSize;\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
510                                 nSizeLast = nSize;\r
511                                 nSize -= sizeof(WCHAR)*nCounterLen;\r
512                                 if(nSize > nSizeLast) return E_FAIL;\r
513                         }\r
514                 }\r
516                 CRegKey rkApp;\r
517                 CString str;\r
518                 DWORD dwErr;\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
527                 return S_OK;\r
528         }\r
529         _ATLCATCHALL()\r
530         {\r
531                 return E_OUTOFMEMORY;\r
532         }\r
535 inline CPerfMon::CategoryInfo* CPerfMon::_FindCategoryInfo(DWORD dwCategoryId) throw()\r
537         for (UINT i=0; i<_GetNumCategories(); i++)\r
538         {\r
539                 CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);\r
540                 if (pCategoryInfo->m_dwCategoryId == dwCategoryId)\r
541                         return pCategoryInfo;\r
542         }\r
544         return NULL;\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
552         {\r
553                 CounterInfo* pCounter = pCategoryInfo->_GetCounterInfo(i);\r
554                 if (pCounter->m_dwCounterId == dwCounterId)\r
555                         return pCounter;\r
556         }\r
558         return NULL;\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
567         return NULL;\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
575                 return TRUE;\r
577         CString strList(szValue);\r
578         int nStart = 0;\r
580         CString strNum = strList.Tokenize(_T(" "), nStart);\r
581         while (!strNum.IsEmpty())\r
582         {\r
583                 if (_ttoi(strNum) == int(dwCategoryId))\r
584                         return TRUE;\r
586                 strNum = strList.Tokenize(_T(" "), nStart);\r
587         }\r
589         return FALSE;\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
598                 return NULL;\r
600         LPBYTE p = pData;\r
601         pData += nBytesNeeded;\r
602         *pnBytesUsed += (ULONG) nBytesNeeded;\r
604         return p;\r
607 inline DWORD& CPerfMon::_GetBlockId(CAtlFileMappingBase* pBlock) \r
609         DWORD* pDw = _GetBlockId_NoThrow(pBlock);\r
610         ATLENSURE(pDw);\r
611         return *pDw;\r
614 inline DWORD* CPerfMon::_GetBlockId_NoThrow(CAtlFileMappingBase* pBlock) \r
616         if (pBlock == NULL)\r
617                 return 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
637         else\r
638                 type.NumInstances = 0; // this will be calculated as objects are processed\r
639         type.CodePage = 0;\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
658         {\r
659         case PERF_SIZE_DWORD:\r
660                 def.CounterSize = sizeof(DWORD);\r
661                 dwAlignOfCounter = sizeof(DWORD);\r
662                 break;\r
663         case PERF_SIZE_LARGE:\r
664                 def.CounterSize = sizeof(__int64);\r
665                 dwAlignOfCounter = sizeof(__int64);\r
666                 break;\r
667         case PERF_SIZE_ZERO:\r
668                 def.CounterSize = 0;\r
669                 dwAlignOfCounter = 0;\r
670                 break;\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
674                 {\r
675                         def.CounterSize = (DWORD) AtlAlignUp(pCounterInfo->m_nMaxCounterSize * sizeof(WCHAR), sizeof(DWORD));\r
676                 }\r
677                 else\r
678                 {\r
679                         def.CounterSize = (DWORD) AtlAlignUp(pCounterInfo->m_nMaxCounterSize * sizeof(char), sizeof(DWORD));\r
680                 }\r
681                 break;\r
682         }\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
690         LPBYTE& pData,\r
691         ULONG nBytesAvail,\r
692         ULONG* pnBytesUsed,\r
693         CPerfObject* _pInstance,\r
694         PERF_OBJECT_TYPE* pObjectType,\r
695         PERF_COUNTER_DEFINITION* pCounterDefs\r
696         ) throw()\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
704         {\r
705                 return E_OUTOFMEMORY;\r
706         }\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
714                 return S_OK;\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
722         else\r
723         {\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
748         }\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
761         {\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
767                 {\r
768                 case PERF_SIZE_DWORD:\r
769                         *LPDWORD(pDest) = *LPDWORD(pSrc);\r
770                         break;\r
771                 case PERF_SIZE_LARGE:\r
772                          *(ULONGLONG*)(pDest) =  *(ULONGLONG*)(pSrc);\r
773                         break;\r
774                 case PERF_SIZE_VARIABLE_LEN:\r
775                         if ((pCounterInfo->m_dwCounterType & ATLPERF_TEXT_MASK) == PERF_TEXT_UNICODE)\r
776                         {\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
781                                 szDest[nLen] = 0;\r
782                         }\r
783                         else\r
784                         {\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
789                                 szDest[nLen] = 0;\r
790                         }\r
791                         break;\r
792                 }\r
793         }\r
795         if (pInstanceDef != NULL)\r
796                 pObjectType->TotalByteLength += pInstanceDef->ByteLength;\r
797         pObjectType->TotalByteLength += pCounterBlock->ByteLength;\r
799         return S_OK;\r
802 inline HRESULT CPerfMon::_CollectInstance(\r
803         CategoryInfo* pCategoryInfo,\r
804         LPBYTE& pData,\r
805         ULONG nBytesAvail,\r
806         ULONG* pnBytesUsed,\r
807         PERF_OBJECT_TYPE* pObjectType,\r
808         PERF_COUNTER_DEFINITION* pCounterDefs\r
809         ) throw()\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
826         {\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
831                 {\r
832                 case PERF_SIZE_DWORD:\r
833                         *LPDWORD(pDest) = 0;\r
834                         break;\r
835                 case PERF_SIZE_LARGE:\r
836                         *PULONGLONG(pDest) = 0;\r
837                         break;\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
841                         else\r
842                                 memset(pDest, 0, pCounterInfo->m_nMaxCounterSize*sizeof(CHAR));\r
843                         break;\r
844                 }\r
845         }\r
847         pObjectType->TotalByteLength += pCounterBlock->ByteLength;\r
849         return S_OK;\r
852 inline HRESULT CPerfMon::_CollectCategoryType(\r
853         CategoryInfo* pCategoryInfo,\r
854         LPBYTE pData,\r
855         ULONG nBytesAvail,\r
856         ULONG* pnBytesUsed\r
857         ) throw()\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
875         {\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
883                 \r
884                 // set PerfTime and PerfFreq for PERF_ELAPSED_TIME counter.\r
885                 if(pCounterDef->CounterType == PERF_ELAPSED_TIME)\r
886                 {\r
887                         LARGE_INTEGER currTime;\r
888                         if (FALSE != QueryPerformanceCounter(&currTime))\r
889                                 pObjectType->PerfTime = currTime;\r
890                         else\r
891                                 pObjectType->PerfTime.QuadPart = 0;\r
892                         QueryPerformanceFrequency (&(pObjectType->PerfFreq));\r
893                 }\r
894         }\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
901         {\r
902                 CPerfObject* pInstance = _GetFirstInstance(pCurrentBlock);\r
903                 while (pInstance && pInstance->m_nAllocSize != 0)\r
904                 {\r
905                         if (pInstance->m_dwCategoryId == pCategoryInfo->m_dwCategoryId)\r
906                         {\r
907                                 bGotInstance = true;\r
908                                 HRESULT hr = _CollectInstance(pCategoryInfo, pData, nBytesAvail,\r
909                                                 pnBytesUsed, pInstance, pObjectType, pCounterDefs);\r
910                                 if (FAILED(hr))\r
911                                         return hr;\r
912                         }\r
914                         pInstance = _GetNextInstance(pInstance);\r
915                         ATLENSURE_RETURN(pInstance!= NULL);\r
917                         if (pInstance->m_nAllocSize == (ULONG) -1)\r
918                         {\r
919                                 pCurrentBlock = _GetNextBlock(pCurrentBlock);\r
920                                 if (pCurrentBlock == NULL)\r
921                                         pInstance = NULL;\r
922                                 else\r
923                                         pInstance = _GetFirstInstance(pCurrentBlock);\r
924                         }\r
925                 }\r
926         }\r
928         if (pCategoryInfo->m_nInstanceLess == PERF_NO_INSTANCES && !bGotInstance)\r
929         {\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
933                 if (FAILED(hr))\r
934                         return hr;\r
935         }\r
937         return S_OK;\r
940 inline DWORD CPerfMon::Open(LPWSTR szDeviceNames) throw()\r
942         (szDeviceNames); // unused\r
944         return 0;\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
952         ) throw()\r
955  \r
956  \r
959         _ATLTRY\r
960         {\r
961                 if (FAILED(_OpenAllBlocks()))\r
962                 {\r
963                         *pcbBytes = 0;\r
964                         *pcObjectTypes = 0;\r
965                         return ERROR_SUCCESS;\r
966                 }\r
968                 LPBYTE pData = LPBYTE(*ppData);\r
969                 ULONG nBytesLeft = *pcbBytes;\r
970                 *pcbBytes = 0;\r
972                 if (_GetNumCategories() == 0)\r
973                 {\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
976                         CRegKey rkApp;\r
977                         DWORD dwErr;\r
978                         CString strAppKey;\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
984                         {\r
985                                 *pcbBytes = 0;\r
986                                 *pcObjectTypes = 0;\r
987                                 return ERROR_SUCCESS;\r
988                         }\r
990                         ULONG nBytes = 0;\r
991                         dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, NULL, &nBytes);\r
992                         if (dwErr != ERROR_SUCCESS)\r
993                         {\r
994                                 *pcbBytes = 0;\r
995                                 *pcObjectTypes = 0;\r
996                                 return ERROR_SUCCESS;\r
997                         }\r
999                         CHeapPtr<DWORD> buf;\r
1000                         if (!buf.Allocate((nBytes+3)/4))\r
1001                         {\r
1002                                 *pcbBytes = 0;\r
1003                                 *pcObjectTypes = 0;\r
1004                                 return ERROR_SUCCESS;\r
1005                         }\r
1007                         dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, buf, &nBytes);\r
1008                         if (dwErr != ERROR_SUCCESS)\r
1009                         {\r
1010                                 *pcbBytes = 0;\r
1011                                 *pcObjectTypes = 0;\r
1012                                 return ERROR_SUCCESS;\r
1013                         }\r
1015                         if (FAILED(_LoadMap(buf)))\r
1016                         {\r
1017                                 *pcbBytes = 0;\r
1018                                 *pcObjectTypes = 0;\r
1019                                 return ERROR_SUCCESS;\r
1020                         }\r
1021                 }\r
1023                 for (UINT i=0; i<_GetNumCategories(); i++)\r
1024                 {\r
1025                         CategoryInfo* pCategoryInfo = _GetCategoryInfo(i);\r
1026                         if (_WantCategoryType(szValue, pCategoryInfo->m_nNameId))\r
1027                         {\r
1028                                 ULONG nBytesUsed = 0;\r
1029                                 HRESULT hr = _CollectCategoryType(pCategoryInfo, pData, nBytesLeft, &nBytesUsed);\r
1030                                 if (hr == E_OUTOFMEMORY)\r
1031                                 {\r
1032                                         *pcbBytes = 0;\r
1033                                         *pcObjectTypes = 0;\r
1034                                         return ERROR_MORE_DATA;\r
1035                                 }\r
1036                                 else if (FAILED(hr))\r
1037                                 {\r
1038                                         *pcbBytes = 0;\r
1039                                         *pcObjectTypes = 0;\r
1040                                         return ERROR_SUCCESS;\r
1041                                 }\r
1043                                 (*pcObjectTypes)++;\r
1044                                 (*pcbBytes) += nBytesUsed;\r
1045                                 nBytesLeft -= nBytesUsed;\r
1046                                 pData += nBytesUsed;\r
1047                         }\r
1048                 }\r
1050                 *ppData = pData;\r
1051                 return ERROR_SUCCESS;\r
1052         }\r
1053         _ATLCATCHALL()\r
1054         {\r
1055                 *pcbBytes = 0;\r
1056                 *pcObjectTypes = 0;\r
1057                 return ERROR_SUCCESS;\r
1058         }\r
1061 inline DWORD CPerfMon::Close() throw()\r
1063         UnInitialize();\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
1072         LPTSTR& pszNew,\r
1073         CAtlArray<CString>& astrStrings,\r
1074         ULONG iFirstIndex\r
1075         ) throw()\r
1077         for (UINT iString = 0; iString < astrStrings.GetCount(); iString++)\r
1078         {\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
1083         }\r
1086 #pragma warning (pop)\r
1088 inline HRESULT CPerfMon::_AppendRegStrings(\r
1089         CRegKey& rkLang,\r
1090         LPCTSTR szValue,\r
1091         CAtlArray<CString>& astrStrings,\r
1092         ULONG nNewStringSize,\r
1093         ULONG iFirstIndex,\r
1094         ULONG iLastIndex\r
1095         ) throw()\r
1097         _ATLTRY\r
1098         {\r
1099                 // load the existing strings, add the new data, and resave the strings\r
1100                 ULONG nCharsOrig = 0;\r
1101                 ULONG nCharsNew;\r
1102                 DWORD dwErr;\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
1110                 CString strOrig;\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
1116                 CString strNew;\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
1123                 {\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
1129                         {\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
1136                                 {\r
1137                                         return E_FAIL;\r
1138                                 }\r
1139                         }\r
1141                         if (iIndex < iFirstIndex || iIndex > iLastIndex)\r
1142                         {\r
1143                                 Checked::memmove_s(pszNew, nCharsNew, pszOrig, nLen*sizeof(TCHAR));\r
1144                                 pszNew += nLen;\r
1145                         }\r
1146                         pszOrig += nLen;\r
1147                 }\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
1157                 return S_OK;\r
1158         }\r
1159         _ATLCATCHALL()\r
1160         {\r
1161                 return E_OUTOFMEMORY;\r
1162         }\r
1165 inline HRESULT CPerfMon::_RemoveRegStrings(\r
1166         CRegKey& rkLang,\r
1167         LPCTSTR szValue,\r
1168         ULONG iFirstIndex,\r
1169         ULONG iLastIndex\r
1170         ) throw()\r
1172         _ATLTRY\r
1173         {\r
1174                 // load the existing strings, remove the data, and resave the strings\r
1175                 DWORD nChars = 0;\r
1176                 DWORD dwErr;\r
1177                 \r
1178                 dwErr = rkLang.QueryMultiStringValue(szValue, NULL, &nChars);\r
1179                 if (dwErr != ERROR_SUCCESS)\r
1180                         return AtlHresultFromWin32(dwErr);\r
1182                 CString str;\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
1193                 {\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
1198                         {\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
1203                                 pszWrite += nLen;\r
1204                         }\r
1205                         pszRead += nLen;\r
1206                 }\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
1213                 return S_OK;\r
1214         }\r
1215         _ATLCATCHALL()\r
1216         {\r
1217                 return E_OUTOFMEMORY;\r
1218         }\r
1221 inline HRESULT CPerfMon::_ReserveStringRange(DWORD& dwFirstCounter, DWORD& dwFirstHelp) throw()\r
1223         CRegKey rkApp;\r
1224         CString strAppKey;\r
1225         DWORD dwErr;\r
1227         _ATLTRY\r
1228         {\r
1229                 strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());\r
1230         }\r
1231         _ATLCATCHALL()\r
1232         {\r
1233                 return E_OUTOFMEMORY;\r
1234         }\r
1236         DWORD nNumStrings = _GetNumCategoriesAndCounters();\r
1238         dwErr = rkApp.Open(HKEY_LOCAL_MACHINE, strAppKey);\r
1239         if (dwErr == ERROR_SUCCESS)\r
1240         {\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
1253                 {\r
1254                         dwFirstCounter = dwFirstAppCounter;\r
1255                         dwFirstHelp = dwFirstAppHelp;\r
1256                         return S_OK;\r
1257                 }\r
1258         }\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
1266         if (!rkApp)\r
1267         {\r
1268                 dwErr = rkApp.Create(HKEY_LOCAL_MACHINE, strAppKey);\r
1269                 if (dwErr != ERROR_SUCCESS)\r
1270                         return AtlHresultFromWin32(dwErr);\r
1271         }\r
1273         // figure out the counter range\r
1274         DWORD dwLastCounter;\r
1275         DWORD dwLastHelp;\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
1315         return S_OK;\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
1323         ) throw()\r
1325         ATLASSERT(szOpenFunc != NULL);\r
1326         ATLASSERT(szCollectFunc != NULL);\r
1327         ATLASSERT(szCloseFunc != NULL);\r
1329         CString str;\r
1330         DWORD dwErr;\r
1331         HRESULT hr;\r
1332         hr = CreateMap(LANGIDFROMLCID(GetThreadLocale()), hDllInstance);\r
1333         if (FAILED(hr)){\r
1334                 hr = CreateMap(LANGIDFROMLCID(1033), hDllInstance);\r
1335                 if (FAILED(hr))\r
1336                 return hr;\r
1337         }\r
1339         CString strAppKey;\r
1340         _ATLTRY\r
1341         {\r
1342                 strAppKey.Format(c_szAtlPerfPerformanceKey, GetAppName());\r
1343         }\r
1344         _ATLCATCHALL()\r
1345         {\r
1346                 return E_OUTOFMEMORY;\r
1347         }\r
1349         // if we're already registered, unregister so we can redo registration\r
1350         _UnregisterStrings();\r
1351         \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
1356         if (FAILED(hr))\r
1357                 return hr;\r
1359         DWORD dwCurrentName = dwFirstCounter;\r
1360         DWORD dwCurrentHelp = dwFirstHelp;\r
1361         for (UINT i=0; i<_GetNumCategories(); i++)\r
1362         {\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
1371                 {\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
1378                 }\r
1379         }\r
1381         // register the app entry points\r
1382         CRegKey rkApp;\r
1384         dwErr = rkApp.Create(HKEY_LOCAL_MACHINE, strAppKey);\r
1385         if (dwErr != ERROR_SUCCESS)\r
1386                 return AtlHresultFromWin32(dwErr);\r
1388         _ATLTRY\r
1389         {\r
1390                 DWORD dwFLen = GetModuleFileName(hDllInstance, CStrBuf(str, MAX_PATH), MAX_PATH);\r
1391                 if( dwFLen == 0 )\r
1392                         return AtlHresultFromLastError();\r
1393                 else if( dwFLen == MAX_PATH )\r
1394                         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);\r
1395         }\r
1396         _ATLCATCHALL()\r
1397         {\r
1398                 return E_OUTOFMEMORY;\r
1399         }\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
1421         hr = _SaveMap();\r
1422         if (FAILED(hr))\r
1423                 return hr;\r
1425         // if the dll is disabled, reenable it since we just reregistered it\r
1426         rkApp.DeleteValue(_T("Disable Performance Counters"));\r
1428         return S_OK;\r
1431 inline HRESULT CPerfMon::RegisterStrings(\r
1432         LANGID language /* = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) */,\r
1433         HINSTANCE hResInstance /* = _AtlBaseModule.GetResourceInstance() */\r
1434         ) throw()\r
1436         _ATLTRY\r
1437         {\r
1438                 CString str;\r
1439                 DWORD dwErr;\r
1440                 HRESULT hr;\r
1441                 CRegKey rkLang;\r
1442                 CRegKey rkApp;\r
1444                 LANGID wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);\r
1446                 if (language == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL))\r
1447                 {\r
1448                         //First try current thread locale\r
1449                         language = LANGIDFROMLCID(GetThreadLocale());\r
1450                         wPrimaryLanguage = (LANGID) PRIMARYLANGID(language);\r
1451                 }\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
1455                 {\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
1461                 }\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
1468                 if (FAILED(hr))\r
1469                         return hr;\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
1478                 CString strLangs;\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
1495                         return S_OK;\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
1505                 {\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
1512                         {\r
1513                                 CounterInfo* pCounterInfo = pCategoryInfo->_GetCounterInfo(j);\r
1515                                 astrCounters.Add(pCounterInfo->m_strName);\r
1516                                 astrHelp.Add(pCounterInfo->m_strHelp);\r
1517                         }\r
1518                 }\r
1520                 for (size_t i=0; i<astrCounters.GetCount(); i++)\r
1521                 {\r
1522                         nNewCounterSize += astrCounters[i].GetLength() + 7;\r
1523                         nNewHelpSize += astrHelp[i].GetLength() + 7;\r
1524                 }\r
1526                 DWORD dwFirstCounter;\r
1527                 DWORD dwFirstHelp;\r
1528                 DWORD dwLastCounter;\r
1529                 DWORD dwLastHelp;\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
1548                 if (FAILED(hr))\r
1549                         return hr;\r
1551                 hr = _AppendRegStrings(rkLang, c_szAtlPerfHelp, astrHelp, nNewHelpSize, dwFirstHelp, dwLastHelp);\r
1552                 if (FAILED(hr))\r
1553                         return hr;\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
1562                 return S_OK;\r
1563         }\r
1564         _ATLCATCHALL()\r
1565         {\r
1566                 return E_OUTOFMEMORY;\r
1567         }\r
1570 inline BOOL CPerfMon::EnumResLangProc(\r
1571         HINSTANCE hModule,\r
1572         LPCTSTR szType,\r
1573         LPCTSTR szName,\r
1574         LANGID wIDLanguage,\r
1575         LPARAM lParam\r
1576         ) throw()\r
1578         hModule; // unused\r
1579         szType; // unused\r
1580         szName; // unused\r
1582         CAtlArray<LANGID>* pLangs = reinterpret_cast<CAtlArray<LANGID>*>(lParam);\r
1583         _ATLTRY\r
1584         {\r
1585                 pLangs->Add(wIDLanguage);\r
1586         }\r
1587         _ATLCATCHALL()\r
1588         {\r
1589                 return FALSE;\r
1590         }\r
1592         return TRUE;\r
1595 inline HRESULT CPerfMon::RegisterAllStrings(\r
1596         HINSTANCE hResInstance /* = NULL */\r
1597         ) throw()\r
1599         HRESULT hrReturn = S_FALSE;\r
1600         HRESULT hr;\r
1602         UINT nRes;\r
1603         hr = CreateMap(0, hResInstance, &nRes);\r
1604         if (FAILED(hr))\r
1605                 return hr;\r
1607         if (nRes == 0)\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
1614         {\r
1615                 hr = _RegisterAllStrings(nRes, hResInstance);\r
1616                 if (FAILED(hr))\r
1617                         return hr;\r
1618                 if (hr == S_OK)\r
1619                         hrReturn = S_OK;\r
1620         }\r
1622         return hrReturn;\r
1625 inline HRESULT CPerfMon::_RegisterAllStrings(\r
1626         UINT nRes,\r
1627         HINSTANCE hResInstance\r
1628         ) throw()\r
1630         HRESULT hrReturn = S_FALSE;\r
1631         HRESULT hr;\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
1638         {\r
1639                 hr = RegisterStrings(langs[i], hResInstance);\r
1640                 if (FAILED(hr))\r
1641                         return hr;\r
1642                 if (hr == S_OK)\r
1643                         hrReturn = S_OK;\r
1644         }\r
1646         return hrReturn;\r
1649 inline HRESULT CPerfMon::_UnregisterStrings() throw()\r
1651         _ATLTRY\r
1652         {\r
1653                 CString str;\r
1654                 HRESULT hr;\r
1655                 DWORD dwErr;\r
1657                 // unregister the PerfMon counter and help strings\r
1658                 CRegKey rkApp;\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
1664                         return S_OK;\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
1690                 DWORD nChars = 0;\r
1691                 dwErr = rkApp.QueryStringValue(c_szAtlPerfLanguages, NULL, &nChars);\r
1692                 if (dwErr != ERROR_SUCCESS)\r
1693                         return AtlHresultFromWin32(dwErr);\r
1695                 CString strLangs;\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
1700                 int nIndex = 0;\r
1701                 CString strLang = strLangs.Tokenize(_T(" "), nIndex);\r
1702                 while (!strLang.IsEmpty())\r
1703                 {\r
1704                         CRegKey rkLang;\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
1711                         if (FAILED(hr))\r
1712                                 return hr;\r
1714                         hr = _RemoveRegStrings(rkLang, c_szAtlPerfHelp, dwFirstAppHelp, dwLastAppHelp);\r
1715                         if (FAILED(hr))\r
1716                                 return hr;\r
1718                         strLang = strLangs.Tokenize(_T(" "), nIndex);\r
1719                 }\r
1721                 dwErr = rkApp.SetStringValue(c_szAtlPerfLanguages, _T(""));\r
1722                 if (dwErr != ERROR_SUCCESS)\r
1723                         return AtlHresultFromWin32(dwErr);\r
1724                         \r
1725                 return S_OK;\r
1726         }\r
1727         _ATLCATCHALL()\r
1728         {\r
1729                 return E_OUTOFMEMORY;\r
1730         }\r
1733 inline HRESULT CPerfMon::Unregister() throw()\r
1735         CString str;\r
1736         HRESULT hr;\r
1737         DWORD dwErr;\r
1739         CRegKey rkPerfLib;\r
1740         CRegKey rkApp;\r
1742         hr = _UnregisterStrings();\r
1743         if (FAILED(hr))\r
1744                 return hr;\r
1746         dwErr = rkPerfLib.Open(HKEY_LOCAL_MACHINE, c_szAtlPerfPerfLibKey);\r
1747         if (dwErr != ERROR_SUCCESS)\r
1748                 return AtlHresultFromWin32(dwErr);\r
1750         _ATLTRY\r
1751         {\r
1752                 str.Format(c_szAtlPerfPerformanceKey, GetAppName());\r
1753         }\r
1754         _ATLCATCHALL()\r
1755         {\r
1756                 return E_OUTOFMEMORY;\r
1757         }\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
1761                 return S_OK;\r
1762         if (dwErr != ERROR_SUCCESS)\r
1763                 return AtlHresultFromWin32(dwErr);\r
1765         DWORD dwLastCounter;\r
1766         DWORD dwLastHelp;\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
1798         {\r
1799                 dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastCounter, dwFirstAppCounter-2);\r
1800                 if (dwErr != ERROR_SUCCESS)\r
1801                         return AtlHresultFromWin32(dwErr);\r
1802         }\r
1804         if (dwLastHelp == dwLastAppHelp)\r
1805         {\r
1806                 dwErr = rkPerfLib.SetDWORDValue(c_szAtlPerfLastHelp, dwFirstAppHelp-2);\r
1807                 if (dwErr != ERROR_SUCCESS)\r
1808                         return AtlHresultFromWin32(dwErr);\r
1809         }\r
1810         rkApp.Close();\r
1812         // delete the app key\r
1813         CRegKey rkServices;\r
1815         _ATLTRY\r
1816         {\r
1817                 str.Format(c_szAtlPerfServicesKey, GetAppName());\r
1818         }\r
1819         _ATLCATCHALL()\r
1820         {\r
1821                 return E_OUTOFMEMORY;\r
1822         }\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
1831         return S_OK;\r
1833 #endif\r
1835 inline HRESULT CPerfMon::Initialize() throw()\r
1837         CMutex tempLock;\r
1838         CString strAppName;\r
1839         HRESULT hr;\r
1841         _ATLTRY\r
1842         {\r
1843                 strAppName = GetAppName();\r
1845                 ATLASSUME(m_aMem.GetCount() == 0);\r
1847                 CAccessToken at;\r
1848                 if (!at.GetEffectiveToken(TOKEN_QUERY))\r
1849                         return E_FAIL;\r
1851          \r
1852                 CSid self;\r
1853                 if (!at.GetUser(&self))\r
1854                         return E_FAIL;\r
1856                 // set up security information for creating the mutex\r
1857                 CDacl dacl;\r
1858                  \r
1859  \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
1869                 sa.Set(m_sd);\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
1879                 {\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
1884                                         NULL,\r
1885                                         const_cast<ACL*>(dacl.GetPACL()),\r
1886                                         NULL) != ERROR_SUCCESS)\r
1887                                 return E_FAIL;\r
1888                 }\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
1895                 {\r
1896                         CMutexLock lock(tempLock);\r
1898                         BOOL bExisted = FALSE;\r
1900                         CAtlFileMappingBase* pMem;\r
1901                         pMem = _AllocNewBlock(NULL, &bExisted);\r
1902                         if (pMem == NULL)\r
1903                                 return E_OUTOFMEMORY;\r
1905                         if (!bExisted)\r
1906                         {\r
1907                                 // copy the map from the registry to the shared memory\r
1908                                 CRegKey rkApp;\r
1909                                 DWORD dwErr;\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
1916                                 {\r
1917                                         m_aMem.RemoveAll();\r
1918                                         return AtlHresultFromWin32(dwErr);\r
1919                                 }\r
1921                                 ULONG nBytes = m_nAllocSize;\r
1922                                 dwErr = rkApp.QueryBinaryValue(c_szAtlPerfMap, pMem->GetData(), &nBytes);\r
1923                                 if (dwErr != ERROR_SUCCESS)\r
1924                                 {\r
1925                                         m_aMem.RemoveAll();\r
1926                                         return AtlHresultFromWin32(dwErr);\r
1927                                 }\r
1928                         }\r
1930                         hr = _LoadMap(LPDWORD(pMem->GetData()));\r
1931                         if (FAILED(hr))\r
1932                         {\r
1933                                 m_aMem.RemoveAll();\r
1934                                 return hr;\r
1935                         }\r
1937                         m_nSchemaSize = *LPDWORD(pMem->GetData());\r
1938                         m_nHeaderSize = m_nSchemaSize + sizeof(DWORD);\r
1939                         m_nHeaderSize  = AtlAlignUp(m_nHeaderSize,16);\r
1940                 }\r
1942                 m_lock.Attach(tempLock.Detach());\r
1943         }\r
1944         _ATLCATCHALL()\r
1945         {\r
1946                 m_aMem.RemoveAll();\r
1947                 return E_OUTOFMEMORY;\r
1948         }\r
1950         return S_OK;\r
1953 inline void CPerfMon::UnInitialize() throw()\r
1955         if (m_lock.m_h != NULL)\r
1956                 m_lock.Close();\r
1957         m_aMem.RemoveAll();\r
1958         ClearMap();\r
1961 inline HRESULT CPerfMon::_CreateInstance(\r
1962         DWORD dwCategoryId,\r
1963         DWORD dwInstance,\r
1964         LPCWSTR szInstanceName,\r
1965         CPerfObject** ppInstance,\r
1966         bool bByName\r
1967         ) throw()\r
1969         CPerfObject* pEmptyBlock = NULL;\r
1971         if (ppInstance == NULL)\r
1972                 return E_POINTER;\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
1999         {\r
2000                 nUsedSpace += pInstance->m_nAllocSize;\r
2002                 if (pInstance->m_dwCategoryId == dwCategoryId)\r
2003                 {\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
2009                         {\r
2010                                 *ppInstance = pInstance;\r
2011                                 pInstance->m_nRefCount++;\r
2012                                 return S_OK;\r
2013                         }\r
2014                         if (bByName)\r
2015                         {\r
2016                                 LPWSTR szInstName = (LPWSTR(LPBYTE(pInstance)+pInstance->m_nInstanceNameOffset));\r
2017                                 if (wcsncmp(szInstName, szInstanceName, pCategoryInfo->m_nMaxInstanceNameLen-1) == 0)\r
2018                                 {\r
2019                                         *ppInstance = pInstance;\r
2020                                         pInstance->m_nRefCount++;\r
2021                                         return S_OK;\r
2022                                 }\r
2023                         }\r
2024                 }\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
2034                 {\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
2038                 }\r
2040                 // check for an end-of-shared-mem sentinel\r
2041                 if (pInstance->m_nAllocSize == (ULONG) -1)\r
2042                 {\r
2043                         nUsedSpace = 0;\r
2044                         CAtlFileMappingBase* pNextBlock = _GetNextBlock(pCurrentBlock);\r
2045                         if (pNextBlock == NULL)\r
2046                         {\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
2052                                 {\r
2053                                         pNextBlock = _AllocNewBlock(pCurrentBlock);\r
2054                                         if (pNextBlock == NULL)\r
2055                                                 return E_OUTOFMEMORY;\r
2056                                 }\r
2057                                 else\r
2058                                         break;\r
2059                         }\r
2060                         pCurrentBlock = pNextBlock;\r
2061                         pInstance = _GetFirstInstance(pCurrentBlock);\r
2062                 }\r
2063         }\r
2065         // allocate a new object\r
2066         if (pEmptyBlock != NULL)\r
2067                 pInstance = pEmptyBlock;\r
2068         else\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
2073         else\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
2080         {\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
2086         }\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
2093         return S_OK;\r
2096 inline HRESULT CPerfMon::CreateInstance(\r
2097         DWORD dwCategoryId,\r
2098         DWORD dwInstance,\r
2099         LPCWSTR szInstanceName,\r
2100         CPerfObject** ppInstance\r
2101         ) throw()\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
2110         ) throw()\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
2126         {\r
2127                 pInstance->m_dwInstance = 0;\r
2128                 pInstance->m_dwCategoryId = 0;\r
2129         }\r
2131         return S_OK;\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
2141                 return S_OK;\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
2149         m_lock.Release();\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
2160         UINT nStructSize,\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
2167         CString strName;\r
2168         CString strHelp;\r
2169         _ATLTRY\r
2170         {\r
2171                 strName = szCategoryName;\r
2172                 strHelp = szHelpString;\r
2173         }\r
2174         _ATLCATCHALL()\r
2175         {\r
2176                 return E_OUTOFMEMORY;\r
2177         }\r
2179         if (!m_categories.SetCount(m_categories.GetCount()+1))\r
2180         {\r
2181                 return E_OUTOFMEMORY;\r
2182         }\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
2199         return S_OK;\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
2209         UINT nOffset,\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
2218         _ATLTRY\r
2219         {\r
2220                 counter.m_strName = szCounterName;\r
2221                 counter.m_strHelp = szHelpString;\r
2222         }\r
2223         _ATLCATCHALL()\r
2224         {\r
2225                 return E_OUTOFMEMORY;\r
2226         }\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
2238         _ATLTRY\r
2239         {\r
2240                 pCategoryInfo->m_counters.Add(counter);\r
2241         }\r
2242         _ATLCATCHALL()\r
2243         {\r
2244                 return E_OUTOFMEMORY;\r
2245         }\r
2247         if (counter.m_nMaxCounterSize > 0)\r
2248         {\r
2249                 ATLASSERT(counter.m_dwCounterType & PERF_TYPE_TEXT);\r
2250                 pCategoryInfo->m_nAllocSize += counter.m_nMaxCounterSize * sizeof(WCHAR);\r
2251         }\r
2253         return S_OK;\r
2256 inline HRESULT CPerfMon::RegisterCategory(\r
2257         WORD wLanguage,\r
2258         HINSTANCE hResInstance,\r
2259         UINT* pSampleRes,\r
2260         DWORD dwCategoryId,\r
2261         UINT nNameString,\r
2262         UINT nHelpString,\r
2263         DWORD dwDetail,\r
2264         BOOL bInstanceless,\r
2265         UINT nStructSize,\r
2266         UINT nMaxInstanceNameLen,\r
2267         INT nDefaultCounter) throw()\r
2269         if (pSampleRes)\r
2270                 *pSampleRes = nNameString;\r
2271    \r
2272         CString strName;\r
2273         CString strHelp;\r
2274    \r
2275         _ATLTRY\r
2276         {\r
2277                  \r
2278                 if (!strName.LoadString(hResInstance, nNameString, wLanguage) ||\r
2279                         !strHelp.LoadString(hResInstance, nHelpString, wLanguage))\r
2280                 {\r
2281                         return E_FAIL;\r
2282                 }\r
2283         }\r
2284         _ATLCATCHALL()\r
2285         {\r
2286                 return E_OUTOFMEMORY;\r
2287         }\r
2289         return RegisterCategory(\r
2290                 wLanguage,\r
2291                 hResInstance,\r
2292                 pSampleRes,\r
2293                 dwCategoryId,\r
2294                 strName,\r
2295                 strHelp,\r
2296                 dwDetail,\r
2297                 bInstanceless,\r
2298                 nStructSize,\r
2299                 nMaxInstanceNameLen,\r
2300                 nDefaultCounter);\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
2310         DWORD dwDetail,\r
2311         BOOL bInstanceless,\r
2312         UINT nStructSize,\r
2313         UINT nMaxInstanceNameLen,\r
2314         INT nDefaultCounter) throw()\r
2316         return AddCategoryDefinition(\r
2317                 dwCategoryId,\r
2318                 szNameString,\r
2319                 szHelpString,\r
2320                 dwDetail,\r
2321                 nDefaultCounter,\r
2322                 bInstanceless,\r
2323                 nStructSize,\r
2324                 nMaxInstanceNameLen);\r
2327 inline HRESULT CPerfMon::RegisterCounter(\r
2328         WORD wLanguage,\r
2329         HINSTANCE hResInstance,\r
2330         DWORD dwCounterId,\r
2331         UINT nNameString,\r
2332         UINT nHelpString,\r
2333         DWORD dwDetail,\r
2334         DWORD dwCounterType,\r
2335         ULONG nMaxCounterSize,\r
2336         UINT nOffset,\r
2337         INT nDefaultScale) throw()\r
2339         CString strName;\r
2340         CString strHelp;\r
2341   \r
2342         _ATLTRY\r
2343         {\r
2344                  \r
2345                 if (!strName.LoadString(hResInstance, nNameString, wLanguage) ||\r
2346                         !strHelp.LoadString(hResInstance, nHelpString, wLanguage))\r
2347                 {\r
2348                         return E_FAIL;\r
2349                 }\r
2350         }\r
2351         _ATLCATCHALL()\r
2352         {\r
2353                 return E_OUTOFMEMORY;\r
2354         }\r
2356         return RegisterCounter(\r
2357                 wLanguage,\r
2358                 hResInstance,\r
2359                 dwCounterId,\r
2360                 strName,\r
2361                 strHelp,\r
2362                 dwDetail,\r
2363                 dwCounterType,\r
2364                 nMaxCounterSize,\r
2365                 nOffset,\r
2366                 nDefaultScale);\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
2375         DWORD dwDetail,\r
2376         DWORD dwCounterType,\r
2377         ULONG nMaxCounterSize,\r
2378         UINT nOffset,\r
2379         INT nDefaultScale) throw()\r
2381         return AddCounterDefinition(\r
2382                 dwCounterId,\r
2383                 szNameString,\r
2384                 szHelpString,\r
2385                 dwDetail,\r
2386                 dwCounterType,\r
2387                 nMaxCounterSize,\r
2388                 nOffset,\r
2389                 nDefaultScale);\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
2409         CStringA strXML;\r
2410         HRESULT hr = S_OK;\r
2411         ULONG nLen = 0;\r
2412         \r
2413         if (bFirst)\r
2414         {\r
2415                 strXML = "<?xml version=\"1.0\" ?>\r\n<perfPersist>\r\n";\r
2416                 hr = pStream->Write(strXML, strXML.GetLength(), &nLen);\r
2417                 if (hr != S_OK)\r
2418                         return hr;\r
2419         }\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
2425         {\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
2435                 if (hr != S_OK)\r
2436                         return E_FAIL;\r
2438                 while (pInstance && pInstance->m_nAllocSize)\r
2439                 {\r
2440                         if (pInstance->m_dwCategoryId == pCategoryInfo->m_dwCategoryId)\r
2441                         {\r
2442                                 if (pCategoryInfo->m_nInstanceLess != PERF_NO_INSTANCES)\r
2443                                 {\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
2458                                         if (hr != S_OK)\r
2459                                                 return hr;\r
2460                                 }\r
2462                                 for (UINT j=0; j<pCategoryInfo->_GetNumCounters(); j++)\r
2463                                 {\r
2464                                         CounterInfo *pCounterInfo = pCategoryInfo->_GetCounterInfo(j);\r
2465                                         switch (pCounterInfo->m_dwCounterType & ATLPERF_SIZE_MASK)\r
2466                                         {\r
2467                                                 case PERF_SIZE_DWORD:\r
2468                                                 {\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
2472                                                         break;\r
2473                                                 }\r
2474                                                 case PERF_SIZE_LARGE:\r
2475                                                 {\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
2479                                                         break;\r
2480                                                 }\r
2481                                                 case PERF_SIZE_VARIABLE_LEN:\r
2482                                                 {\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
2486                                                         {\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
2496                                                                                 szUTF8,\r
2497                                                                                 pCounterInfo->m_nDataOffset);\r
2498                                                         }\r
2499                                                         else\r
2500                                                         {\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
2506                                                                                 szUTF8,\r
2507                                                                                 pCounterInfo->m_nDataOffset);\r
2508                                                         }\r
2509                                                         break;\r
2510                                                 }\r
2511                                                 default:\r
2512                                                         // error:\r
2513                                                         return E_FAIL;\r
2514                                         }\r
2515                                         hr = pStream->Write(strXML, strXML.GetLength(), &nLen);\r
2516                                         if (hr != S_OK)\r
2517                                                 return hr;\r
2518                                 }\r
2520                                 if (pCategoryInfo->m_nInstanceLess != PERF_NO_INSTANCES)\r
2521                                 {\r
2522                                         hr = pStream->Write("\t\t\t</instance>\r\n", sizeof("\t\t\t</instance>\r\n")-1, &nLen);\r
2523                                         if (hr != S_OK)\r
2524                                                 return hr;\r
2525                                 }\r
2526                         }\r
2528                         pInstance = _GetNextInstance(pInstance);\r
2529                         ATLENSURE_RETURN(pInstance!= NULL);\r
2531                         if (pInstance->m_nAllocSize == (ULONG)-1)\r
2532                         {\r
2533                                 pCurrentBlock = _GetNextBlock(pCurrentBlock);\r
2534                                 if (pCurrentBlock == NULL)\r
2535                                         pInstance = NULL;\r
2536                                 else\r
2537                                         pInstance = _GetFirstInstance(pCurrentBlock);\r
2538                         }\r
2539                 }\r
2541                 hr = pStream->Write("\t\t</perfObject>\r\n", sizeof("\t\t</perfObject>\r\n")-1, &nLen);\r
2542                 if (hr != S_OK)\r
2543                         return hr;\r
2544         }\r
2546         hr = pStream->Write("\t</perfmon>\r\n", sizeof("\t</perfmon>\r\n")-1, &nLen);\r
2547         if (hr != S_OK)\r
2548                 return hr;\r
2550         if (hr == S_OK && bLast)\r
2551                 hr = pStream->Write("</perfPersist>", sizeof("</perfPersist>")-1, &nLen);\r
2553         return hr;\r
2556 // This function is very lenient with inappropriate XML\r
2557 ATL_NOINLINE inline HRESULT CPerfMon::LoadFromXML(IStream *pStream) throw(...)\r
2558 {       \r
2559         ATLASSERT(pStream != NULL);\r
2560         if (pStream == NULL)\r
2561                 return E_INVALIDARG;\r
2563         // Get a lock\r
2564         CPerfLock lock(this);\r
2565         if (FAILED(lock.GetStatus()))\r
2566                 return ERROR_SUCCESS;\r
2568         CComPtr<IXMLDOMDocument> spdoc;\r
2570         // load the xml\r
2571         HRESULT hr = CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC, __uuidof(IXMLDOMDocument), (void **) &spdoc);\r
2572         if (FAILED(hr))\r
2573         {\r
2574                 return hr;\r
2575         }\r
2577         spdoc->put_async(VARIANT_FALSE);\r
2579         CComPtr<IPersistStreamInit> spSI;\r
2580         hr = spdoc->QueryInterface(&spSI);\r
2581         if (hr != S_OK)\r
2582                 return hr;\r
2583         hr = spSI->Load(pStream);\r
2584         if (hr != S_OK)\r
2585                 return hr;\r
2587         // validate that it is a perfPersist stream\r
2588         CComPtr<IXMLDOMElement> spRoot;\r
2590         hr = spdoc->get_documentElement(&spRoot);\r
2591         if (hr != S_OK)\r
2592                 return hr;\r
2594         CComBSTR bstrName;\r
2595         hr = spRoot->get_baseName(&bstrName);\r
2596         if (wcscmp(bstrName, L"perfPersist"))\r
2597                 return S_FALSE;\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
2603         {\r
2604                 bstrName.Empty();\r
2605                 hr = spChild->get_baseName(&bstrName);\r
2606                 if (hr == S_OK)\r
2607                 {\r
2608                         if (!wcscmp(bstrName, L"perfmon"))\r
2609                         {\r
2610                                 bstrName.Empty();\r
2611                                 hr = _GetAttribute(spChild, L"name", &bstrName);\r
2612                                 if (hr == S_OK)\r
2613                                 {\r
2614                                         if (!_tcscmp(CW2CT(bstrName), GetAppName()))\r
2615                                                 break;\r
2616                                 }\r
2617                         }\r
2618                 }\r
2620                 CComPtr<IXMLDOMNode> spNext;\r
2621                 hr = spChild->get_nextSibling(&spNext);\r
2622                 spChild.Attach(spNext.Detach());\r
2623         }\r
2625         // there is no perfmon node in the XML for the current CPerfMon class\r
2626         if (hr != S_OK)\r
2627                 return S_FALSE;\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
2636         {\r
2637                 // see if it's a perfObject\r
2638                 bstrName.Empty();\r
2639                 hr = spChild->get_baseName(&bstrName);\r
2640                 if (hr != S_OK || wcscmp(bstrName, L"perfObject"))\r
2641                         return S_FALSE;\r
2643                 // get the perfid\r
2644                 bstrName.Empty();\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
2652                 {\r
2653                         // see if it's a instance\r
2654                         bstrName.Empty();\r
2655                         hr = spInstChild->get_baseName(&bstrName);\r
2656                         if (hr != S_OK || wcscmp(bstrName, L"instance"))\r
2657                                 return S_FALSE;\r
2659                         // get the instance name\r
2660                         bstrName.Empty();\r
2661                         hr = _GetAttribute(spInstChild, L"name", &bstrName);\r
2662                         if (hr != S_OK)\r
2663                                 return S_FALSE;\r
2665                         // get the instance id\r
2666                         bstrName.Empty();\r
2667                         hr = _GetAttribute(spChild, L"id", &bstrName);\r
2668                         if (hr != S_OK)\r
2669                                 return S_FALSE;\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
2675                         if (hr != S_OK)\r
2676                                 return S_FALSE;\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
2682                         {\r
2683                                 // get the base name\r
2684                                 bstrName.Empty();\r
2685                                 hr = spCntrChild->get_baseName(&bstrName);\r
2686                                 if (hr != S_OK || wcscmp(bstrName, L"counter"))\r
2687                                         return S_FALSE;\r
2689                                 // get the type\r
2690                                 bstrName.Empty();\r
2691                                 hr = _GetAttribute(spCntrChild, L"type", &bstrName);\r
2692                                 if (hr != S_OK)\r
2693                                         return S_FALSE;\r
2695                                 DWORD dwType;\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
2704                                 else\r
2705                                         return S_FALSE;\r
2707                                 // get the value\r
2708                                 bstrName.Empty();\r
2709                                 hr = _GetAttribute(spCntrChild, L"value", &bstrName);\r
2710                                 if (hr != S_OK)\r
2711                                         return S_FALSE;\r
2713                                 CComBSTR bstrOffset;\r
2714                                 hr = _GetAttribute(spCntrChild, L"offset", &bstrOffset);\r
2715                                 if (hr != S_OK)\r
2716                                         return S_FALSE;\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
2722                                 {\r
2723                                         DWORD dwVal = wcstoul(bstrName, &pStop, 10);\r
2724                                         *LPDWORD(LPBYTE(pInstance)+dwOffset) = dwVal;\r
2725                                 }\r
2726                                 else if (dwType == PERF_SIZE_LARGE) // add it is a ULONGLONG\r
2727                                 {\r
2728                                         ULONGLONG qwVal = _wcstoui64(bstrName, &pStop, 10);\r
2729                                         *PULONGLONG(LPBYTE(pInstance)+dwOffset) = qwVal;\r
2730                                 }\r
2731                                 else if (dwType == PERF_SIZE_VARIABLE_LEN) // add it as an ansi string\r
2732                                 {\r
2733                                         AtlW2AHelper(LPSTR(LPBYTE(pInstance)+dwOffset), bstrName, bstrName.Length(), ATL::_AtlGetConversionACP());\r
2734                                 }\r
2735                                 else // add it as a unicode string\r
2736                                 {\r
2737                                         Checked::memcpy_s(LPBYTE(pInstance)+dwOffset, pInstance->m_nAllocSize-dwOffset, bstrName, bstrName.Length()*sizeof(WCHAR));\r
2738                                 }\r
2740                                 CComPtr<IXMLDOMNode> spCntrNext;\r
2741                                 hr = spCntrChild->get_nextSibling(&spCntrNext);\r
2742                                 spCntrChild.Attach(spCntrNext.Detach());\r
2743                         }\r
2745                         CComPtr<IXMLDOMNode> spInstNext;\r
2746                         hr = spInstChild->get_nextSibling(&spInstNext);\r
2747                         spInstChild.Attach(spInstNext.Detach());\r
2748                 }\r
2750                 CComPtr<IXMLDOMNode> spNext;\r
2751                 hr = spChild->get_nextSibling(&spNext);\r
2752                 spChild.Attach(spNext.Detach());\r
2753         }\r
2755         return S_OK;\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
2765         *pbstrVal = NULL;\r
2766         CComPtr<IXMLDOMNamedNodeMap> spAttrs;\r
2768         HRESULT hr = pNode->get_attributes(&spAttrs);\r
2769         if (hr != S_OK)\r
2770                 return hr;\r
2771         \r
2772         CComPtr<IXMLDOMNode> spAttr;\r
2773         \r
2774         hr = spAttrs->getNamedItem((BSTR) szAttrName, &spAttr);\r
2775         if (hr != S_OK)\r
2776                 return hr;\r
2777         \r
2778         CComVariant varVal;\r
2779         hr = spAttr->get_nodeValue(&varVal);\r
2780         if (hr != S_OK)\r
2781                 return hr;\r
2782         \r
2783         hr = varVal.ChangeType(VT_BSTR);\r
2784         if (hr != S_OK)\r
2785                 return hr;\r
2787         *pbstrVal = varVal.bstrVal;\r
2788         varVal.vt = VT_EMPTY;\r
2790         return S_OK;\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
2802         { \r
2803                 if (*ppPerf != NULL) \r
2804                 { \r
2805                         hr = (*ppPerf)->Register(_T( ATLPERF_FUNCID_OPEN ), _T( ATLPERF_FUNCID_COLLECT ), _T( ATLPERF_FUNCID_CLOSE ), hDllInstance);\r
2806                         if (FAILED(hr)) \r
2807                                 return hr; \r
2808                         hr = (*ppPerf)->RegisterAllStrings(hDllInstance);\r
2809                         if (FAILED(hr)) \r
2810                                 return hr; \r
2811                 } \r
2812                 ppPerf++; \r
2813         } \r
2814         return S_OK; \r
2815 \r
2817 ATL_NOINLINE inline HRESULT UnregisterPerfMon() throw() \r
2818 \r
2819         CPerfMon **ppPerf = &__pperfA; \r
2820         HRESULT hr = S_OK; \r
2821         while (ppPerf != &__pperfZ) \r
2822         { \r
2823                 if (*ppPerf != NULL) \r
2824                 { \r
2825                         hr = (*ppPerf)->Unregister(); \r
2826                         if (FAILED(hr)) \r
2827                                 return hr; \r
2828                 } \r
2829                 ppPerf++; \r
2830         } \r
2831         return S_OK; \r
2832 \r
2834 extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI OpenPerfMon(LPWSTR lpDeviceNames) throw()\r
2836         CPerfMon **ppPerf = &__pperfA;\r
2837         DWORD dwErr = 0;\r
2838         while (ppPerf != &__pperfZ)\r
2839         {\r
2840                 if (*ppPerf != NULL)\r
2841                 {\r
2842                         dwErr = (*ppPerf)->Open(lpDeviceNames);\r
2843                         if (dwErr != 0)\r
2844                                 return dwErr;\r
2845                 }\r
2846                 ppPerf++;\r
2847         }\r
2848         return 0;\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
2857         DWORD dwErr = 0;\r
2858         while (ppPerf != &__pperfZ)\r
2859         {\r
2860                 if (*ppPerf != NULL)\r
2861                 {\r
2862                         dwErr = (*ppPerf)->Collect(lpwszValue, lppData, lpcbBytes, lpcObjectTypes);\r
2863                         if (dwErr != 0)\r
2864                                 return dwErr;\r
2865                         dwBytesRemaining -= *lpcbBytes;\r
2866                         *lpcbBytes = dwBytesRemaining;\r
2867                 }\r
2868                 ppPerf++;\r
2869         }\r
2870         *lpcbBytes = dwOrigBytes - dwBytesRemaining;\r
2871         return 0;\r
2874 extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI ClosePerfMon() throw()\r
2876         CPerfMon **ppPerf = &__pperfA;\r
2877         while (ppPerf != &__pperfZ)\r
2878         {\r
2879                 if (*ppPerf != NULL)\r
2880                 {\r
2881                         (*ppPerf)->Close();\r
2882                 }\r
2883                 ppPerf++;\r
2884         }\r
2885         return 0;\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