TRACE マクロを使用すると、コードがデバッグモードでコンパイルされているときに診断メッセージをデバッガに出力できます。リリースモードで同じメッセージが必要です。これを達成する方法はありますか?
(リリース モードで TRACE を使用すべきではない理由について議論するのに時間を無駄にしないでください :-)
実際、TRACEマクロはOutputDebugStringよりもはるかに柔軟性があります。printf()スタイルのフォーマット文字列とパラメータリストを取りますが、OutputDebugStringは単一の文字列を取ります。リリースモードで完全なTRACE機能を実装するには、次のようなことを行う必要があります。
void trace(const char* format, ...)
{
char buffer[1000];
va_list argptr;
va_start(argptr, format);
wvsprintf(buffer, format, argptr);
va_end(argptr);
OutputDebugString(buffer);
}
数年前、同様の機能が必要だったので、次のコードをまとめました。rtrace.h などのファイルに保存し、stdafx.h の最後に含め、プリプロセッサが定義するリリース モードに _RTRACE を追加します。
多分誰かがそれの用途を見つけるでしょう:-)
ジョン
#pragma once
//------------------------------------------------ ------------------------------------------------
///
// 作者: ジョン・カレン
// 日付: 2006/04/12
// ベース: 可変引数リストの MSDN の例と TRACE の ATL 実装。
///
// 説明: RELEASE ビルドで TRACE ステートメントを使用できるようにします。
// TRACE マクロの定義と RTRACE クラスの観点からの再定義とオーバーロード
// 演算子 ()。トレース出力は、OutputDebugString() を直接呼び出すことによって生成されます。
///
///
// 使用法: stdafx.h の末尾に追加し、_RTRACE をプリプロセッサの定義に追加します (通常は
// RELEASE ビルドの場合。DEBUG ビルドの場合、フラグは無視されます。
///
//------------------------------------------------ ------------------------------------------------
#ifdef _DEBUG
// NL は FTRACE(_T("\n")); を書くためのショートカットとして定義されています。たとえば、代わりに FTRACE(NL); と書きます。
#define NL _T("\n")
#define LTRACE TRACE(_T("%s(%d): "), __FILE__, __LINE__); 痕跡
#define FTRACE TRACE(_T("%s(%d): %s: "), __FILE__, __LINE__, __FUNCTION__); 痕跡
#else // _DEBUG
#ifdef _RTRACE
#undef TRACE
#define TRACE RTRACE()
#define LTRACE RTRACE(__FILE__, __LINE__)
#define FTRACE RTRACE(__FILE__, __LINE__, __FUNCTION__)
#define NL _T("\n")
クラス RTRACE
{
公衆:
// デフォルトのコンストラクタ、パラメータなし
RTRACE(void) : m_pszFileName( NULL ), m_nLineNo( 0 ), m_pszFuncName( NULL ) {};
// オーバーロードされたコンストラクタ、ファイル名、および lineno
RTRACE(PCTSTR const pszFileName, int nLineNo) :
m_pszFileName(pszFileName), m_nLineNo(nLineNo), m_pszFuncName(NULL) {};
// オーバーロードされたコンストラクター、ファイル名、lineno、および関数名
RTRACE(PCTSTR const pszFileName, int nLineNo, PCTSTR const pszFuncName) :
m_pszFileName(pszFileName), m_nLineNo(nLineNo), m_pszFuncName(pszFuncName) {};
仮想 ~RTRACE(void) {};
// RTRACE()() など、引数は渡されません
void operator()() const
{
// 引数は渡されません。要求があれば、ファイル、行、および関数をダンプするだけです
OutputFileAndLine();
OutputFunction();
}
// フォーマット文字列とパラメータが渡されます。例: RTRACE()(_T("%s\n"), someStringVar)
void operator()(const PTCHAR pszFmt, ...) const
{
// 要求があればファイル、行、関数をダンプし、TRACE 引数を続けます
OutputFileAndLine();
OutputFunction();
// 標準の TRACE 出力処理を実行します
va_list ptr; va_start(ptr, pszFmt);
INT len = _vsctprintf( pszFmt, ptr ) + 1;
TCHAR* buffer = (PTCHAR) malloc( len * sizeof(TCHAR) );
_vstprintf( バッファ, pszFmt, ptr );
OutputDebugString(バッファ);
free( バッファ );
}
プライベート:
// 現在のファイルと行を出力
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( バッファ );
free( バッファ );
}
}
// 現在の関数名を出力
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( バッファ, _T("%s: "), m_pszFuncName );
OutputDebugString( バッファ );
free( バッファ );
}
}
プライベート:
PCTSTR const m_pszFuncName;
PCTSTR const m_pszFileName;
const int m_nLineNo;
};
#endif // _RTRACE
#endif // NDEBUG
TRACE は、 OutputDebugStringの単なるマクロです。そのため、 OutputDebugStringを呼び出す独自の TRACE マクロを簡単に作成 (または別の名前で呼び出す) ことができます。
MFC では、TRACE は ATLTRACE として定義されます。そして、次のように定義されているリリース モードでは:
#define ATLTRACE __noop
そのため、MFC の標準の TRACE を使用しても、実際には TRACE テキストを読み取ることはできません。書き出すことさえできないからです。代わりに独自の TRACE 関数を記述してから、TRACE マクロを再定義することができます。次のようなことができます。
void MyTrace(const CString& text)
{
::OutputDebugString(text); // Outputs to console, same as regular TRACE
// TODO: Do whatever output you need here. Write to event log / write to text file / write to pipe etc.
}