RESOLUTION
To work around this problem, do not to use attributes
for a Unicode build of this kind of project. You must redefine three macros if
you want to use these attributes. To avoid changing the atlperf.h header,
redefine these macros in the header file for the Performance Monitor object of
the project, as follows:
The BEGIN_PERF_MAP macro defines a function
that is named
GetAppName() that directly returns the AppName parameter that is passed to the
macro. To work around this problem, return a created
CString object instead, so that the following line:
return AppName;
is returned as follows:
return CString(AppName);
The following is the full redefinition for BEGIN_PERF_MAP, together
with the #undef for the original code for your reference.
NOTE: However, if you copy and paste from this article, formatting
problems may cause compile errors. Microsoft recommends that you copy these
macros from atlperf.h, paste them into your source file, and then make the
changes as suggested.
#undef BEGIN_PERF_MAP
#define BEGIN_PERF_MAP(AppName) \
private: \
LPCTSTR GetAppName() const throw() { return CString(AppName); } \
HRESULT CreateMap(WORD wLanguage, HINSTANCE hResInstance, UINT* pSampleRes = NULL) throw() \
{ \
CPerfMon* pPerf = this; \
(void)pPerf; \
wLanguage; \
hResInstance; \
if (pSampleRes) \
*pSampleRes = 0; \
CString strName; \
CString strHelp; \
HRESULT hr; \
(void)hr; \
ClearMap();
The DECLARE_PERF_OBJECT_EX macro uses the raw
namestring and
helpstring objects that are passed to the macro. Convert these to Unicode by
wrapping them in
CString objects. The lines that read as follows:
strName = (LPCTSTR) namestring; \
strHelp = (LPCTSTR) helpstring; \
must be changed to the following:
strName = CString(namestring); \
strHelp = CString(helpstring); \
The following is the complete DECLARE_PERF_OBJECT_EX macro:
#undef DECLARE_PERF_OBJECT_EX
#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 \
{ \
__pragma(warning(push)); \
__pragma(warning(disable: 4127)); \
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 = CString(namestring); \
strHelp = CString(helpstring); \
} \
__pragma(warning(pop)); \
} \
_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*(...) */ \
/* You must have this for the code wizards to parse things properly */ \
static const DWORD kObjectId = dwObjectId
The DEFINE_COUNTER_EX macro is similar to DECLARE_PERF_OBJECT_EX, and
the workaround is the same. The following is the complete macro:
#undef DEFINE_COUNTER_EX
#define DEFINE_COUNTER_EX(member, dwCounterId, namestring, helpstring, detail, countertype, maxcountersize, defscale) \
CAssertValidField< (countertype) & ATLPERF_SIZE_MASK >::AssertValidFieldType( &_PerfCounterClass::member ); \
_ATLTRY \
{ \
__pragma(warning(push)); \
__pragma(warning(disable: 4127)); \
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 = CString(namestring); \
strHelp = CString(helpstring); \
} \
__pragma(warning(pop)); \
} \
_ATLCATCHALL() \
{ \
return E_FAIL; \
} \
hr = pPerf->AddCounterDefinition(dwCounterId, strName, strHelp, detail, countertype, maxcountersize, (ULONG) offsetof(_PerfCounterClass, member), defscale); \
if (FAILED(hr)) \
return hr;