Несколько лет назад мне нужно схожая функциональность, так что я починил следующий код. Просто сохраните его в файле, например. rtrace.h, включите его в конец вашего stdafx.h и добавьте _RTRACE в режим освобождения, заданный препроцессором.
Может быть кто-то найдет применение для него :-)
Джон
#pragma once
//------------------------------------------------------------------------------------------------
//
// Author: John Cullen
// Date: 2006/04/12
// Based On: MSDN examples for variable argument lists and ATL implementation of TRACE.
//
// Description: Allows the use of TRACE statements in RELEASE builds, by overriding the
// TRACE macro definition and redefining in terms of the RTRACE class and overloaded
// operator(). Trace output is generated by calling OutputDebugString() directly.
//
//
// Usage: Add to the end of stdafx.h and add _RTRACE to the preprocessor defines (typically
// for RELEASE builds, although the flag will be ignored for DEBUG builds.
//
//------------------------------------------------------------------------------------------------
#ifdef _DEBUG
// NL defined as a shortcut for writing FTRACE(_T("\n")); for example, instead write FTRACE(NL);
#define NL _T("\n")
#define LTRACE TRACE(_T("%s(%d): "), __FILE__, __LINE__); TRACE
#define FTRACE TRACE(_T("%s(%d): %s: "), __FILE__, __LINE__, __FUNCTION__); TRACE
#else // _DEBUG
#ifdef _RTRACE
#undef TRACE
#define TRACE RTRACE()
#define LTRACE RTRACE(__FILE__, __LINE__)
#define FTRACE RTRACE(__FILE__, __LINE__, __FUNCTION__)
#define NL _T("\n")
class RTRACE
{
public:
// default constructor, no params
RTRACE(void) : m_pszFileName(NULL), m_nLineNo(0), m_pszFuncName(NULL) {};
// overloaded constructor, filename and lineno
RTRACE(PCTSTR const pszFileName, int nLineNo) :
m_pszFileName(pszFileName), m_nLineNo(nLineNo), m_pszFuncName(NULL) {};
// overloaded constructor, filename, lineno, and function name
RTRACE(PCTSTR const pszFileName, int nLineNo, PCTSTR const pszFuncName) :
m_pszFileName(pszFileName), m_nLineNo(nLineNo), m_pszFuncName(pszFuncName) {};
virtual ~RTRACE(void) {};
// no arguments passed, e.g. RTRACE()()
void operator()() const
{
// no arguments passed, just dump the file, line and function if requested
OutputFileAndLine();
OutputFunction();
}
// format string and parameters passed, e.g. RTRACE()(_T("%s\n"), someStringVar)
void operator()(const PTCHAR pszFmt, ...) const
{
// dump the file, line and function if requested, followed by the TRACE arguments
OutputFileAndLine();
OutputFunction();
// perform the standard TRACE output processing
va_list ptr; va_start(ptr, pszFmt);
INT len = _vsctprintf(pszFmt, ptr) + 1;
TCHAR* buffer = (PTCHAR) malloc(len * sizeof(TCHAR));
_vstprintf(buffer, pszFmt, ptr);
OutputDebugString(buffer);
free(buffer);
}
private:
// output the current file and line
inline void OutputFileAndLine() const
{
if (m_pszFileName && _tcslen(m_pszFileName) > 0)
{
INT len = _sctprintf(_T("%s(%d): "), m_pszFileName, m_nLineNo) + 1;
PTCHAR buffer = (PTCHAR) malloc(len * sizeof(TCHAR));
_stprintf(buffer, _T("%s(%d): "), m_pszFileName, m_nLineNo);
OutputDebugString(buffer);
free(buffer);
}
}
// output the current function name
inline void OutputFunction() const
{
if (m_pszFuncName && _tcslen(m_pszFuncName) > 0)
{
INT len = _sctprintf(_T("%s: "), m_pszFuncName) + 1;
PTCHAR buffer = (PTCHAR) malloc(len * sizeof(TCHAR));
_stprintf(buffer, _T("%s: "), m_pszFuncName);
OutputDebugString(buffer);
free(buffer);
}
}
private:
PCTSTR const m_pszFuncName;
PCTSTR const m_pszFileName;
const int m_nLineNo;
};
#endif // _RTRACE
#endif // NDEBUG
Для АТЛ В проектах у меня есть класс drop-in, который переопределяет макросы ATLTRACE и карты в Outp utDebugString` (включая принятие гибкого числа параметров): http://alax.info/blog/tag/outputdebugstring – 2012-11-26 21:53:07