Files
Slnkdwf/ATL90/include/atlperf.h
Jos Groot Lipman 0e37d774d2 Merge SLNKDWF64 branch
svn path=/Slnkdwf/trunk/; revision=23911
2015-01-21 12:09:31 +00:00

664 lines
21 KiB
C++

// 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 <atlbase.h>
#include <atlcom.h>
#include <atlstr.h>
#include <atlfile.h>
#include <atlsync.h>
#include <winperf.h>
#include <atlcoll.h>
#include <atlsecurity.h>
#ifndef _ATL_PERF_NOXML
#include <atlenc.h>
#include <oaidl.h>
#include <xmldomdid.h>
/* 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 <xmldsodid.h>
#include <msxmldid.h>
/* 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 <msxml.h>
#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 <class T>
HRESULT CreateInstance(
DWORD dwInstance,
LPCWSTR szInstanceName,
T** ppInstance) throw()
{
// Ensure T derives from CPerfObject
static_cast<CPerfObject*>(*ppInstance);
return CreateInstance(
T::kCategoryId,
dwInstance,
szInstanceName,
reinterpret_cast<CPerfObject**>(ppInstance)
);
}
template <class T>
HRESULT CreateInstanceByName(
LPCWSTR szInstanceName,
T** ppInstance) throw()
{
// Ensure T derives from CPerfObject
static_cast<CPerfObject*>(*ppInstance);
return CreateInstanceByName(
T::kCategoryId,
szInstanceName,
reinterpret_cast<CPerfObject**>(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<CounterInfo> m_counters;
};
LPBYTE _AllocData(LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, size_t nBytesNeeded) throw();
template<typename T> T* _AllocStruct(LPBYTE& pData, ULONG nBytesAvail, ULONG* pnBytesUsed, T*) throw()
{
return reinterpret_cast<T*>(_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(...);
DWORD* _GetBlockId_NoThrow(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<CString>& astrStrings,
ULONG iFirstIndex
) throw();
HRESULT _AppendRegStrings(
CRegKey& rkLang,
LPCTSTR szValue,
CAtlArray<CString>& 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<CategoryInfo> m_categories;
CAutoPtrArray<CAtlFileMappingBase> 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<CPerfMon*>(&__perf_##className); \
PERF_ENTRY_PRAGMA(className)
#endif // _ATL_PERF_NOEXPORT
} // namespace ATL
#include <atlperf.inl>
#pragma pack(pop)
#pragma warning(pop)
#endif // __ATLPERF_H__