// This is a part of the Active Template Library. // Copyright (C) 1996-2001 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #ifndef __ATLPERF_H__ #define __ATLPERF_H__ #pragma once #ifndef __cplusplus #error ATL requires C++ compilation (use a .cpp suffix) #endif #include #include #include #include #include #include #include #ifndef _ATL_PERF_NOXML #include #include #include #include #include #include #endif namespace ATL { const DWORD ATLPERF_SIZE_MASK = 0x00000300; const DWORD ATLPERF_TYPE_MASK = 0x00000C00; const DWORD ATLPERF_TEXT_MASK = 0x00010000; #ifndef ATLPERF_DEFAULT_MAXINSTNAMELENGTH #define ATLPERF_DEFAULT_MAXINSTNAMELENGTH 64 #endif // base class for user-defined perf objects struct CPerfObject { ULONG m_nAllocSize; DWORD m_dwObjectId; DWORD m_dwInstance; ULONG m_nRefCount; ULONG m_nInstanceNameOffset; // byte offset from beginning of PerfObject to LPWSTR szInstanceName }; struct CPerfMapEntry { DWORD m_dwPerfId; CString m_strName; CString m_strHelp; DWORD m_dwDetailLevel; BOOL m_bIsObject; // OBJECT INFO ULONG m_nNumCounters; LONG m_nDefaultCounter; LONG m_nInstanceLess; // PERF_NO_INSTANCES if instanceless // the size of the struct not counting the name and string counters ULONG m_nStructSize; // in characters including the null terminator ULONG m_nMaxInstanceNameLen; ULONG m_nAllocSize; // COUNTER INFO DWORD m_dwCounterType; LONG m_nDefaultScale; // the maximum size of the string counter data in characters, including the null terminator // ignored if not a string counter ULONG m_nMaxCounterSize; ULONG m_nDataOffset; // the ids that correspond to the name and help strings stored in the registry UINT m_nNameId; UINT m_nHelpId; }; class CPerfMon { public: ~CPerfMon() throw(); // PerfMon entry point helpers DWORD Open(LPWSTR lpDeviceNames) throw(); DWORD Collect(LPWSTR lpwszValue, LPVOID* lppData, LPDWORD lpcbBytes, LPDWORD lpcObjectTypes) throw(); DWORD Close() throw(); #ifdef _ATL_PERF_REGISTER // registration HRESULT Register( LPCTSTR szOpenFunc, LPCTSTR szCollectFunc, LPCTSTR szCloseFunc, HINSTANCE hDllInstance = _AtlBaseModule.GetModuleInstance()) throw(); HRESULT RegisterStrings( LANGID wLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), HINSTANCE hResInstance = _AtlBaseModule.GetResourceInstance()) throw(); HRESULT RegisterAllStrings(HINSTANCE hResInstance = NULL) throw(); HRESULT Unregister() throw(); static BOOL CALLBACK EnumResLangProc(HINSTANCE hModule, LPCTSTR szType, LPCTSTR szName, LANGID wIDLanguage, LPARAM lParam); #endif HRESULT Initialize() throw(); void UnInitialize() throw(); HRESULT CreateInstance( DWORD dwObjectId, DWORD dwInstance, LPCWSTR szInstanceName, CPerfObject** ppInstance) throw(); HRESULT CreateInstanceByName( DWORD dwObjectId, LPCWSTR szInstanceName, CPerfObject** ppInstance) throw(); template HRESULT CreateInstance( DWORD dwInstance, LPCWSTR szInstanceName, T** ppInstance) throw() { // Ensure T derives from CPerfObject static_cast(*ppInstance); return CreateInstance( T::kObjectId, dwInstance, szInstanceName, reinterpret_cast(ppInstance) ); } template HRESULT CreateInstanceByName( LPCWSTR szInstanceName, T** ppInstance) throw() { // Ensure T derives from CPerfObject static_cast(*ppInstance); return CreateInstanceByName( T::kObjectId, szInstanceName, reinterpret_cast(ppInstance) ); } HRESULT ReleaseInstance(CPerfObject* pInstance) throw(); HRESULT LockPerf(DWORD dwTimeout = INFINITE) throw(); void UnlockPerf() throw(); // map building routines HRESULT AddObjectDefinition( DWORD dwObjectId, LPCTSTR szObjectName, LPCTSTR szHelpString, DWORD dwDetailLevel, INT nDefaultCounter, BOOL bInstanceLess, UINT nStructSize, UINT nMaxInstanceNameLen = ATLPERF_DEFAULT_MAXINSTNAMELENGTH) throw(); HRESULT AddCounterDefinition( DWORD dwCounterId, LPCTSTR szCounterName, LPCTSTR szHelpString, DWORD dwDetailLevel, DWORD dwCounterType, ULONG nMaxCounterSize, UINT nOffset, INT nDefaultScale) throw(); void ClearMap() throw(); #ifndef _ATL_PERF_NOXML HRESULT PersistToXML(IStream *pStream, BOOL bFirst=TRUE, BOOL bLast=TRUE) throw(...); HRESULT LoadFromXML(IStream *pStream) throw(...); #endif protected: virtual LPCTSTR GetAppName() const throw() = 0; virtual HRESULT CreateMap(WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes = NULL) throw(); virtual void OnBlockAlloc(CAtlFileMappingBase* /*pNewBlock*/) { } // implementation helpers LPBYTE _AllocData(LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, size_t nBytesNeeded) throw(); template T* _AllocStruct(LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, T*) throw() { return reinterpret_cast(_AllocData(pData, nBytesAvail, pnBytesUsed, sizeof(T))); } CPerfMapEntry& _GetMapEntry(UINT nIndex) throw(); UINT _GetNumMapEntries() throw(); CPerfObject* _GetFirstObject(CAtlFileMappingBase* pBlock) throw(); CPerfObject* _GetNextObject(CPerfObject* pInstance) throw(); CAtlFileMappingBase* _GetNextBlock(CAtlFileMappingBase* pBlock) throw(); CAtlFileMappingBase* _AllocNewBlock(CAtlFileMappingBase* pPrev, BOOL* pbExisted = NULL) throw(); DWORD& _GetBlockId(CAtlFileMappingBase* pBlock) throw(); CPerfMapEntry* _FindObjectInfo(DWORD dwObjectId) throw(); CPerfMapEntry* _FindCounterInfo(CPerfMapEntry* pObjectEntry, DWORD dwCounterId) throw(); CPerfMapEntry* _FindCounterInfo(DWORD dwObjectId, DWORD dwCounterId) throw(); BOOL _WantObjectType(LPWSTR lpwszValue, DWORD dwPerfId) throw(...); void _FillObjectType(PERF_OBJECT_TYPE* pObjectType, CPerfMapEntry* pObjectEntry) throw(); void _FillCounterDef( PERF_COUNTER_DEFINITION* pCounterDef, CPerfMapEntry* pCounterEntry, ULONG& nCBSize) throw(); HRESULT _CollectObjectType( CPerfMapEntry* pObjectEntry, LPBYTE pData, ULONG nBytesAvail, ULONG* pnBytesUsed) throw(); HRESULT _LoadMap() throw(); HRESULT _SaveMap() throw(); HRESULT _GetAttribute( IXMLDOMNode *pNode, LPCWSTR szAttrName, BSTR *pbstrVal) throw(); HRESULT CPerfMon::_CreateInstance( DWORD dwObjectId, DWORD dwInstance, LPCWSTR szInstanceName, CPerfObject** ppInstance, bool bByName) throw(); #ifdef _ATL_PERF_REGISTER void _AppendStrings( LPTSTR& pszNew, CAtlArray& astrStrings, ULONG iFirstIndex ) throw(); HRESULT _AppendRegStrings( CRegKey& rkLang, LPCTSTR szValue, CAtlArray& astrStrings, ULONG nNewStringSize, ULONG iFirstIndex, ULONG iLastIndex) throw(); HRESULT _RemoveRegStrings( CRegKey& rkLang, LPCTSTR szValue, ULONG iFirstIndex, ULONG iLastIndex) throw(); HRESULT _ReserveStringRange(DWORD& dwFirstCounter, DWORD& dwFirstHelp) throw(); HRESULT _UnregisterStrings() throw(); HRESULT _RegisterAllStrings(UINT nRes, HINSTANCE hResInstance) throw(); #endif private: CAtlArray m_map; CAutoPtrArray m_aMem; CMutex m_lock; ULONG m_nAllocSize; ULONG m_nHeaderSize; ULONG m_nSchemaSize; ULONG m_nNumObjectTypes; }; class CPerfLock { public: CPerfLock(CPerfMon* pPerfMon, DWORD dwTimeout = INFINITE) throw() { ATLASSERT(pPerfMon != NULL); m_pPerfMon = pPerfMon; m_hrStatus = m_pPerfMon->LockPerf(dwTimeout); } ~CPerfLock() throw() { if (SUCCEEDED(m_hrStatus)) m_pPerfMon->UnlockPerf(); } HRESULT GetStatus() const throw() { return m_hrStatus; } private: CPerfMon* m_pPerfMon; HRESULT m_hrStatus; }; // empty definition just for ease of use with code wizards, etc. #define BEGIN_PERFREG_MAP() // empty definition just for ease of use with code wizards, etc. #define END_PERFREG_MAP() #if !defined(_ATL_PERF_REGISTER) | defined(_ATL_PERF_NOEXPORT) #define PERFREG_ENTRY(className) #endif #ifdef _ATL_PERF_REGISTER #define BEGIN_PERF_MAP(AppName) \ private: \ LPCTSTR GetAppName() const throw() { return AppName; } \ HRESULT CreateMap(WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes = NULL) throw() \ { \ CPerfMon* pPerf = this; \ wLanguage; \ hResInstance; \ if (pSampleRes) \ *pSampleRes = 0; \ CString strName; \ CString strHelp; \ HRESULT hr; \ ClearMap(); #define BEGIN_COUNTER_MAP(objectclass) \ public: \ typedef objectclass _PerfCounterClass; \ static HRESULT CreateMap(CPerfMon* pPerf, WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes) throw() \ { \ wLanguage; \ hResInstance; \ pSampleRes; \ CString strName; \ CString strHelp; \ HRESULT hr; \ hr = RegisterObject(pPerf, wLanguage, hResInstance, pSampleRes); \ if (FAILED(hr)) \ return hr; #define DECLARE_PERF_OBJECT_EX(dwObjectId, namestring, helpstring, detail, instanceless, structsize, maxinstnamelen, defcounter) \ static HRESULT RegisterObject(CPerfMon* pPerf, WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes) throw() \ { \ CString strName; \ CString strHelp; \ HRESULT hr; \ _ATLTRY \ { \ if (IS_INTRESOURCE(namestring)) \ { \ ATLASSERT(IS_INTRESOURCE(helpstring)); \ if (pSampleRes) \ *pSampleRes = (UINT) (UINT_PTR) namestring; \ if (hResInstance && !strName.LoadString(hResInstance, (UINT) (UINT_PTR) namestring, wLanguage)) \ return E_FAIL; \ if (hResInstance && !strHelp.LoadString(hResInstance, (UINT) (UINT_PTR) helpstring, wLanguage)) \ return E_FAIL; \ } \ else \ { \ ATLASSERT(!IS_INTRESOURCE(helpstring)); \ strName = (LPCTSTR) namestring; \ strHelp = (LPCTSTR) helpstring; \ } \ } \ _ATLCATCHALL() \ { \ return E_FAIL; \ } \ hr = pPerf->AddObjectDefinition(dwObjectId, strName, strHelp, detail, defcounter, instanceless, (ULONG) structsize, maxinstnamelen); \ if (FAILED(hr)) \ return hr; \ return S_OK; \ } \ /* NOTE: put a semicolon after your call to DECLARE_PERF_OBJECT*(...) */ \ /* this is needed for the code wizards to parse things properly */ \ static const DWORD kObjectId = dwObjectId #define CHAIN_PERF_OBJECT(objectclass) \ hr = objectclass::CreateMap(pPerf, wLanguage, hResInstance, pSampleRes); \ if (FAILED(hr)) \ return hr; // CAssertValidField ensures that the member variable that's being passed to // DEFINE_COUNTER[_EX] is the proper type. only 32-bit integral types can be used with // PERF_SIZE_DWORD and only 64-bit integral types can be used with PERF_SIZE_LARGE template< DWORD t_dwSize > class CAssertValidField { }; template<> class CAssertValidField< PERF_SIZE_DWORD > { public: template< class C > static void AssertValidFieldType( ULONG C::* ) throw() { } template< class C > static void AssertValidFieldType( LONG C::* ) throw() { } }; template<> class CAssertValidField< PERF_SIZE_LARGE > { public: template< class C > static void AssertValidFieldType( ULONGLONG C::* p ) throw() { } template< class C > static void AssertValidFieldType( LONGLONG C::* p ) throw() { } }; #define DEFINE_COUNTER_EX(member, dwCounterId, namestring, helpstring, detail, countertype, maxcountersize, defscale) \ CAssertValidField< (countertype) & ATLPERF_SIZE_MASK >::AssertValidFieldType( &_PerfCounterClass::member ); \ _ATLTRY \ { \ if (IS_INTRESOURCE(namestring)) \ { \ ATLASSERT(IS_INTRESOURCE(helpstring)); \ if (hResInstance && !strName.LoadString(hResInstance, (UINT) (UINT_PTR) namestring, wLanguage)) \ return E_FAIL; \ if (hResInstance && !strHelp.LoadString(hResInstance, (UINT) (UINT_PTR) helpstring, wLanguage)) \ return E_FAIL; \ } \ else \ { \ ATLASSERT(!IS_INTRESOURCE(helpstring)); \ strName = (LPCTSTR) namestring; \ strHelp = (LPCTSTR) helpstring; \ } \ } \ _ATLCATCHALL() \ { \ return E_FAIL; \ } \ hr = pPerf->AddCounterDefinition(dwCounterId, strName, strHelp, detail, countertype, maxcountersize, (ULONG) offsetof(_PerfCounterClass, member), defscale); \ if (FAILED(hr)) \ return hr; #define END_PERF_MAP() \ return S_OK; \ } #define END_COUNTER_MAP() \ return S_OK; \ } // define _ATL_PERF_NOEXPORT if you don't want to use the PERFREG map and don't want these // functions exported from your DLL #ifndef _ATL_PERF_NOEXPORT // Perf register map stuff // this is for ease of integration with the module attribute and for the // perfmon wizard #pragma data_seg(push) #pragma data_seg("ATLP$A") __declspec(selectany) CPerfMon * __pperfA = NULL; #pragma data_seg("ATLP$Z") __declspec(selectany) CPerfMon * __pperfZ = NULL; #pragma data_seg("ATLP$C") #pragma data_seg(pop) ATL_NOINLINE inline HRESULT RegisterPerfMon(HINSTANCE hDllInstance = _AtlBaseModule.GetModuleInstance()) throw() { CPerfMon **ppPerf = &__pperfA; HRESULT hr = S_OK; while (ppPerf != &__pperfZ) { if (*ppPerf != NULL) { hr = (*ppPerf)->Register(_T("_OpenPerfMon"), _T("_CollectPerfMon"), _T("_ClosePerfMon"), hDllInstance); if (FAILED(hr)) return hr; hr = (*ppPerf)->RegisterAllStrings(hDllInstance); if (FAILED(hr)) return hr; } ppPerf++; } return S_OK; } ATL_NOINLINE inline HRESULT UnregisterPerfMon() throw() { CPerfMon **ppPerf = &__pperfA; HRESULT hr = S_OK; while (ppPerf != &__pperfZ) { if (*ppPerf != NULL) { hr = (*ppPerf)->Unregister(); if (FAILED(hr)) return hr; } ppPerf++; } return S_OK; } extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI OpenPerfMon(LPWSTR lpDeviceNames) throw() { CPerfMon **ppPerf = &__pperfA; DWORD dwErr = 0; while (ppPerf != &__pperfZ) { if (*ppPerf != NULL) { dwErr = (*ppPerf)->Open(lpDeviceNames); if (dwErr != 0) return dwErr; } ppPerf++; } return 0; } extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI CollectPerfMon(LPWSTR lpwszValue, LPVOID* lppData, LPDWORD lpcbBytes, LPDWORD lpcObjectTypes) throw() { DWORD dwOrigBytes = *lpcbBytes; DWORD dwBytesRemaining = *lpcbBytes; CPerfMon **ppPerf = &__pperfA; DWORD dwErr = 0; while (ppPerf != &__pperfZ) { if (*ppPerf != NULL) { dwErr = (*ppPerf)->Collect(lpwszValue, lppData, lpcbBytes, lpcObjectTypes); if (dwErr != 0) return dwErr; dwBytesRemaining -= *lpcbBytes; *lpcbBytes = dwBytesRemaining; } ppPerf++; } *lpcbBytes = dwOrigBytes - dwBytesRemaining; return 0; } extern "C" ATL_NOINLINE inline DWORD __declspec(dllexport) WINAPI ClosePerfMon() throw() { CPerfMon **ppPerf = &__pperfA; while (ppPerf != &__pperfZ) { if (*ppPerf != NULL) { (*ppPerf)->Close(); } ppPerf++; } return 0; } // this class handles integrating the registration with CComModule class _CAtlPerfSetFuncPtr { public: _CAtlPerfSetFuncPtr() { _pPerfRegFunc = RegisterPerfMon; _pPerfUnRegFunc = UnregisterPerfMon; } }; extern "C" { __declspec(selectany) _CAtlPerfSetFuncPtr g_atlperfinit; } #pragma comment(linker, "/INCLUDE:_g_atlperfinit") #if defined(_M_IX86) #define PERF_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:___pperf_" #class)) #elif defined(_M_IA64) #define PERF_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pperf_" #class)) #else #error Unknown Platform. define PERF_ENTRY_PRAGMA #endif #define PERFREG_ENTRY(className) \ className __perf_##className; \ extern "C" __declspec(allocate("ATLP$C")) CPerfMon * __pperf_##className = \ static_cast(&__perf_##className); \ PERF_ENTRY_PRAGMA(className) #endif // _ATL_PERF_NOEXPORT #else // _ATL_PERF_REGISTER #define BEGIN_PERF_MAP(AppName) \ private: \ LPCTSTR GetAppName() const throw() { return AppName; } #define BEGIN_COUNTER_MAP(objectclass) #define DECLARE_PERF_OBJECT_EX(dwObjectId, namestring, helpstring, detail, instanceless, structsize, maxinstnamelen, defcounter) \ /* NOTE: put a semicolon after your call to DECLARE_PERF_OBJECT*(...) */ \ /* this is needed for the code wizards to parse things properly */ \ static const DWORD kObjectId = dwObjectId #define CHAIN_PERF_OBJECT(objectclass) #define DEFINE_COUNTER_EX(member, dwCounterId, namestring, helpstring, detail, countertype, maxcountersize, defscale) #define END_PERF_MAP() #define END_COUNTER_MAP() #endif // _ATL_PERF_REGISTER #define DECLARE_PERF_OBJECT(objectclass, dwObjectId, namestring, helpstring, defcounter) \ DECLARE_PERF_OBJECT_EX(dwObjectId, namestring, helpstring, PERF_DETAIL_NOVICE, 0, sizeof(objectclass), ATLPERF_DEFAULT_MAXINSTNAMELENGTH, defcounter) #define DECLARE_PERF_OBJECT_NO_INSTANCES(objectclass, dwObjectId, namestring, helpstring, defcounter) \ DECLARE_PERF_OBJECT_EX(dwObjectId, namestring, helpstring, PERF_DETAIL_NOVICE, PERF_NO_INSTANCES, sizeof(objectclass), 0, defcounter) #define DEFINE_COUNTER(member, namestring, helpstring, countertype, defscale) \ DEFINE_COUNTER_EX(member, 0, namestring, helpstring, PERF_DETAIL_NOVICE, countertype, 0, defscale) } // namespace ATL #include #endif // __ATLPERF_H__