// This is a part of the Active Template Library. // Copyright (C) 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 #include #ifndef _ATL_PERF_NOXML #include #include #include /* xmldsodid and mshtmdid both have the same identifiers defined, with differing values. So we are renaming the XML ones since there are less identifiers dependent on those. */ #ifdef DISPID_XOBJ_MIN /* in case the HTM one was included first, we'll undef these first */ #define _ATL_MSHTMDID_INCLUDED_ALREADY #undef DISPID_XOBJ_MIN #undef DISPID_XOBJ_MAX #undef DISPID_XOBJ_BASE #endif #include #include /* re-undef the clashing names, and their direct dependents */ #undef DISPID_XOBJ_MIN #undef DISPID_XOBJ_MAX #undef DISPID_XOBJ_BASE #undef DISPID_XMLDSO #undef DISPID_XMLELEMENTCOLLECTION /* re-def the clashing names, and their direct dependents, with un-clashed values */ #define DISPID_XMLDSO_XOBJ_MIN 0x00010000 #define DISPID_XMLDSO_XOBJ_MAX 0x0001FFFF #define DISPID_XMLDSO_XOBJ_BASE DISPID_XMLDSO_XOBJ_MIN #define DISPID_XMLDSO DISPID_XMLDSO_XOBJ_BASE #define DISPID_XMLELEMENTCOLLECTION DISPID_XMLDSO_XOBJ_BASE #ifdef _ATL_MSHTMDID_INCLUDED_ALREADY /* redef the clashing names to the HTM values */ #define DISPID_XOBJ_MIN 0x80010000 #define DISPID_XOBJ_MAX 0x8001FFFF #define DISPID_XOBJ_BASE DISPID_XOBJ_MIN #endif #include #endif #pragma warning(push) #pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible #pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible #pragma pack(push,_ATL_PACKING) 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 { // implementation ULONG m_nAllocSize; DWORD m_dwCategoryId; DWORD m_dwInstance; ULONG m_nRefCount; ULONG m_nInstanceNameOffset; // byte offset from beginning of PerfObject to LPWSTR szInstanceName }; class CPerfMon { public: virtual ~CPerfMon() 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(); #endif HRESULT Initialize() throw(); void UnInitialize() throw(); HRESULT CreateInstance( DWORD dwCategoryId, DWORD dwInstance, LPCWSTR szInstanceName, CPerfObject** ppInstance) throw(); HRESULT CreateInstanceByName( DWORD dwCategoryId, 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::kCategoryId, dwInstance, szInstanceName, reinterpret_cast(ppInstance) ); } template HRESULT CreateInstanceByName( LPCWSTR szInstanceName, T** ppInstance) throw() { // Ensure T derives from CPerfObject static_cast(*ppInstance); return CreateInstanceByName( T::kCategoryId, szInstanceName, reinterpret_cast(ppInstance) ); } HRESULT ReleaseInstance(CPerfObject* pInstance) throw(); HRESULT LockPerf(DWORD dwTimeout = INFINITE) throw(); void UnlockPerf() throw(); #ifndef _ATL_PERF_NOXML HRESULT PersistToXML(IStream *pStream, BOOL bFirst=TRUE, BOOL bLast=TRUE) throw(...); HRESULT LoadFromXML(IStream *pStream) throw(...); #endif // implementation public: // PerfMon entry point helpers DWORD Open(LPWSTR lpDeviceNames) throw(); DWORD Collect(__in_z LPWSTR lpwszValue, __deref_inout_bcount(*pcbBytes) LPVOID* lppData, __inout LPDWORD lpcbBytes, __inout LPDWORD lpcObjectTypes) throw(); DWORD Close() throw(); // map building routines HRESULT AddCategoryDefinition( DWORD dwCategoryId, LPCTSTR szCategoryName, 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(); // macro helpers HRESULT RegisterCategory( WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes, DWORD dwCategoryId, UINT nNameString, UINT nHelpString, DWORD dwDetail, BOOL bInstanceless, UINT nStructSize, UINT nMaxInstanceNameLen, INT nDefaultCounter) throw(); HRESULT RegisterCategory( WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes, DWORD dwCategoryId, LPCTSTR szNameString, LPCTSTR szHelpString, DWORD dwDetail, BOOL bInstanceless, UINT nStructSize, UINT nMaxInstanceNameLen, INT nDefaultCounter) throw(); HRESULT RegisterCounter( WORD wLanguage, HINSTANCE hResInstance, DWORD dwCounterId, UINT nNameString, UINT nHelpString, DWORD dwDetail, DWORD dwCounterType, ULONG nMaxCounterSize, UINT nOffset, INT nDefaultScale) throw(); HRESULT RegisterCounter( WORD wLanguage, HINSTANCE hResInstance, DWORD dwCounterId, LPCTSTR szNameString, LPCTSTR szHelpString, DWORD dwDetail, DWORD dwCounterType, ULONG nMaxCounterSize, UINT nOffset, INT nDefaultScale) throw(); protected: void ClearMap() throw(); virtual LPCTSTR GetAppName() const throw() = 0; virtual HRESULT CreateMap(WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes = NULL) throw(); virtual void OnBlockAlloc(CAtlFileMappingBase* /*pNewBlock*/) { } #ifdef _ATL_PERF_REGISTER static BOOL CALLBACK EnumResLangProc(HINSTANCE hModule, LPCTSTR szType, LPCTSTR szName, LANGID wIDLanguage, LPARAM lParam); #endif // implementation helpers struct CounterInfo { CounterInfo() : m_dwCounterId(0), m_dwDetailLevel(0), m_nNameId(0), m_nHelpId(0), m_dwCounterType(0), m_nDefaultScale(0), m_nMaxCounterSize(0), m_nDataOffset(0) { ZeroMemory (&m_cache, sizeof(m_cache)); } // implementation DWORD m_dwCounterId; CString m_strName; CString m_strHelp; DWORD m_dwDetailLevel; // the ids that correspond to the name and help strings stored in the registry UINT m_nNameId; UINT m_nHelpId; // counter data 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; // cached data to be copied into request PERF_COUNTER_DEFINITION m_cache; }; struct CategoryInfo { // implementation DWORD m_dwCategoryId; CString m_strName; CString m_strHelp; DWORD m_dwDetailLevel; // the ids that correspond to the name and help strings stored in the registry UINT m_nNameId; UINT m_nHelpId; // category data 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; // cached data to be copied into request PERF_OBJECT_TYPE m_cache; ULONG m_nCounterBlockSize; // counters UINT _GetNumCounters() throw(); CounterInfo* _GetCounterInfo(UINT nIndex) throw(); CAtlArray m_counters; }; 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))); } UINT _GetNumCategoriesAndCounters() throw(); CategoryInfo* _GetCategoryInfo(UINT nIndex) throw(); UINT _GetNumCategories() throw(); CPerfObject* _GetFirstInstance(CAtlFileMappingBase* pBlock) throw(); CPerfObject* _GetNextInstance(CPerfObject* pInstance) throw(); CAtlFileMappingBase* _GetNextBlock(CAtlFileMappingBase* pBlock) throw(); CAtlFileMappingBase* _OpenNextBlock(CAtlFileMappingBase* pPrev) throw(); CAtlFileMappingBase* _AllocNewBlock(CAtlFileMappingBase* pPrev, BOOL* pbExisted = NULL) throw(); HRESULT _OpenAllBlocks() throw(); DWORD& _GetBlockId(CAtlFileMappingBase* pBlock) throw(); CategoryInfo* _FindCategoryInfo(DWORD dwCategoryId) throw(); CounterInfo* _FindCounterInfo(CategoryInfo* pCategoryInfo, DWORD dwCounterId) throw(); CounterInfo* _FindCounterInfo(DWORD dwCategoryId, DWORD dwCounterId) throw(); BOOL _WantCategoryType(__in_z LPWSTR lpwszValue, __in DWORD dwPerfId) throw(...); void _FillCategoryType(CategoryInfo* pCategoryInfo) throw(); void _FillCounterDef(CounterInfo* pCounterInfo, ULONG* pnCounterBlockSize) throw(); HRESULT CPerfMon::_CollectInstance( CategoryInfo* pCategoryInfo, LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, CPerfObject* pInstance, PERF_OBJECT_TYPE* pObjectType, PERF_COUNTER_DEFINITION* pCounterDefs ) throw(); HRESULT _CollectInstance( CategoryInfo* pCategoryInfo, LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, PERF_OBJECT_TYPE* pObjectType, PERF_COUNTER_DEFINITION* pCounterDefs ) throw(); HRESULT _CollectCategoryType( CategoryInfo* pCategoryInfo, LPBYTE pData, ULONG nBytesAvail, ULONG* pnBytesUsed) throw(); HRESULT _LoadMap(DWORD* pData) throw(); HRESULT _SaveMap() throw(); HRESULT _GetAttribute( IXMLDOMNode *pNode, LPCWSTR szAttrName, BSTR *pbstrVal) throw(); HRESULT CPerfMon::_CreateInstance( DWORD dwCategoryId, 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_categories; CAutoPtrArray m_aMem; CMutex m_lock; ULONG m_nAllocSize; ULONG m_nHeaderSize; ULONG m_nSchemaSize; CSecurityDesc m_sd; }; class CPerfLock { public: CPerfLock(CPerfMon* pPerfMon, DWORD dwTimeout = INFINITE) { ATLENSURE(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; }; //////////////////////////////////////////////////////////////////////// // map macros // 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() \ { \ if (pSampleRes) \ *pSampleRes = 0; \ ClearMap(); #define BEGIN_COUNTER_MAP(categoryclass) \ public: \ typedef categoryclass _PerfCounterClass; \ static HRESULT CreateMap(CPerfMon* pPerf, WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes) throw() \ { \ HRESULT hr = RegisterCategory(pPerf, wLanguage, hResInstance, pSampleRes); \ if (FAILED(hr)) \ return hr; #define DECLARE_PERF_CATEGORY_EX(dwCategoryId, namestring, helpstring, detail, instanceless, structsize, maxinstnamelen, defcounter) \ static HRESULT RegisterCategory(CPerfMon* pPerf, WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes) throw() \ { \ return pPerf->RegisterCategory(wLanguage, hResInstance, pSampleRes, dwCategoryId, namestring, helpstring, detail, instanceless, structsize, maxinstnamelen, defcounter); \ } \ /* NOTE: put a semicolon after your call to DECLARE_PERF_CATEGORY*(...) */ \ /* this is needed for the code wizards to parse things properly */ \ static const DWORD kCategoryId = dwCategoryId #define CHAIN_PERF_CATEGORY(categoryclass) \ if (FAILED(categoryclass::CreateMap(this, wLanguage, hResInstance, pSampleRes))) \ return E_FAIL; // 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::* ) throw() { } template< class C > static void AssertValidFieldType( LONGLONG C::* ) throw() { } }; #define DEFINE_COUNTER_EX(member, dwCounterId, namestring, helpstring, detail, countertype, maxcountersize, defscale) \ CAssertValidField< (countertype) & ATLPERF_SIZE_MASK >::AssertValidFieldType( &_PerfCounterClass::member ); \ hr = pPerf->RegisterCounter(wLanguage, hResInstance, dwCounterId, namestring, helpstring, 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; \ } #else // _ATL_PERF_REGISTER #define BEGIN_PERF_MAP(AppName) \ private: \ LPCTSTR GetAppName() const throw() { return AppName; } #define BEGIN_COUNTER_MAP(objectclass) #define DECLARE_PERF_CATEGORY_EX(dwCategoryId, namestring, helpstring, detail, instanceless, structsize, maxinstnamelen, defcounter) \ /* NOTE: put a semicolon after your call to DECLARE_PERF_CATEGORY*(...) */ \ /* this is needed for the code wizards to parse things properly */ \ static const DWORD kCategoryId = dwCategoryId #define CHAIN_PERF_CATEGORY(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_CATEGORY(objectclass, dwCategoryId, namestring, helpstring, defcounter) \ DECLARE_PERF_CATEGORY_EX(dwCategoryId, namestring, helpstring, PERF_DETAIL_NOVICE, 0, sizeof(objectclass), ATLPERF_DEFAULT_MAXINSTNAMELENGTH, defcounter) #define DECLARE_PERF_CATEGORY_NO_INSTANCES(objectclass, dwCategoryId, namestring, helpstring, defcounter) \ DECLARE_PERF_CATEGORY_EX(dwCategoryId, 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) #pragma deprecated( DECLARE_PERF_OBJECT_EX ) #pragma deprecated( DECLARE_PERF_OBJECT ) #pragma deprecated( DECLARE_PERF_OBJECT_NO_INSTANCES ) #pragma deprecated( CHAIN_PERF_OBJECT ) #define DECLARE_PERF_OBJECT_EX DECLARE_PERF_CATEGORY_EX #define DECLARE_PERF_OBJECT DECLARE_PERF_CATEGORY #define DECLARE_PERF_OBJECT_NO_INSTANCES DECLARE_PERF_CATEGORY_NO_INSTANCES #define CHAIN_PERF_OBJECT CHAIN_PERF_CATEGORY //////////////////////////////////////////////////////////////////////// // automagic registration stuff #if defined(_ATL_PERF_REGISTER) & !defined(_ATL_PERF_NOEXPORT) // define _ATL_PERF_NOEXPORT if you don't want to use the PERFREG map and don't want these // functions exported from your DLL // Perf register map stuff // this is for ease of integration with the module attribute and for the // perfmon wizard #pragma section("ATLP$A", read, shared) #pragma section("ATLP$Z", read, shared) #pragma section("ATLP$C", read, shared) extern "C" { __declspec(selectany) __declspec(allocate("ATLP$A")) CPerfMon * __pperfA = NULL; __declspec(selectany) __declspec(allocate("ATLP$Z")) CPerfMon * __pperfZ = NULL; } #if !defined(_M_IA64) #pragma comment(linker, "/merge:ATLP=.rdata") #endif #if defined(_M_IA64) || defined(_M_AMD64) #define ATLPERF_FUNCID_OPEN "OpenPerfMon" #define ATLPERF_FUNCID_COLLECT "CollectPerfMon" #define ATLPERF_FUNCID_CLOSE "ClosePerfMon" #elif defined(_M_IX86) #define ATLPERF_FUNCID_OPEN "_OpenPerfMon@4" #define ATLPERF_FUNCID_COLLECT "_CollectPerfMon@16" #define ATLPERF_FUNCID_CLOSE "_ClosePerfMon@0" #else #if !defined(ATLPERF_FUNCID_OPEN) || !defined(ATLPERF_FUNCID_COLLECT) || !defined (ATLPERF_FUNCID_CLOSE) #error "Unknown platform. Define ATLPERF_FUNCID_OPEN, ATLPERF_FUNCID_COLLECT, ATLPERF_FUNCID_CLOSE" #endif #endif HRESULT RegisterPerfMon(HINSTANCE hDllInstance = _AtlBaseModule.GetModuleInstance()) throw(); HRESULT UnregisterPerfMon() throw(); extern "C" DWORD __declspec(dllexport) WINAPI OpenPerfMon(LPWSTR lpDeviceNames) throw(); extern "C" DWORD __declspec(dllexport) WINAPI CollectPerfMon(LPWSTR lpwszValue, LPVOID* lppData, LPDWORD lpcbBytes, LPDWORD lpcObjectTypes) throw(); extern "C" DWORD __declspec(dllexport) WINAPI ClosePerfMon() throw(); // this class handles integrating the registration with CComModule class _CAtlPerfSetFuncPtr { public: _CAtlPerfSetFuncPtr() { _pPerfRegFunc = RegisterPerfMon; _pPerfUnRegFunc = UnregisterPerfMon; } }; extern "C" { __declspec(selectany) _CAtlPerfSetFuncPtr g_atlperfinit; } #if defined(_M_IX86) #pragma comment(linker, "/INCLUDE:_g_atlperfinit") #elif defined(_M_IA64) || defined(_M_AMD64) #pragma comment(linker, "/INCLUDE:g_atlperfinit") #else #pragma message("Unknown platform. Make sure the linker includes g_atlperfinit") #endif #ifndef PERF_ENTRY_PRAGMA #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)); #elif defined(_M_AMD64) #define PERF_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pperf_" #class)); #else #error Unknown Platform. define PERF_ENTRY_PRAGMA #endif #endif // PERF_ENTRY_PRAGMA #define PERFREG_ENTRY(className) \ __declspec(selectany) className __perf_##className; \ extern "C" __declspec(allocate("ATLP$C")) __declspec(selectany) CPerfMon * const __pperf_##className = \ static_cast(&__perf_##className); \ PERF_ENTRY_PRAGMA(className) #endif // _ATL_PERF_NOEXPORT } // namespace ATL #include #pragma pack(pop) #pragma warning(pop) #endif // __ATLPERF_H__