syghの新フラグメント置き場

プログラミングTipsやコード断片の保管場所です。お絵描きもときどき載せます。

WindowsのOutputDebugString()関数とUnicode

WindowsOutputDebugStringW()関数とOutputDebugStringA()関数は、デバッグコンソールに文字列を出力します。

Visual Studioデバッグ実行すると、「出力ウィンドウ」に文字列が表示されます。
ただしAndroidのLogcatや、MacXcodeNSLogと違って、末尾に改行は自動付与されません。

ここで、

OutputDebugStringW converts the specified string based on the current system locale information and passes it to OutputDebugStringA to be displayed. As a result, some Unicode characters may not be displayed correctly.

と説明されているんですが、Visual Studio 2013までは確かに以下のようなコードは文字化け*1して日本語cR???となってしまうものの、Visual Studio 2015以降は正しく表示できています。

#include <Windows.h>

int main() {
    ::OutputDebugStringW(L"日本語©®™♡♥\n");
}

以下の説明から推察するに、VS2015ではWindows 10で追加されたAPIWaitForDebugEventEx()」をコールすることで、Unicode出力を実現しているようです。確かWindows 7/8.x上では、VS2015であってもOutputDebugStringW()Unicode固有文字を出力することはできていなかったように思います。

Important
In the past, the operating system did not output Unicode strings via OutputDebugStringW and instead only output ASCII strings. To force OutputDebugStringW to correctly output Unicode strings, debuggers are required to call WaitForDebugEventEx to opt into the new behavior. On calling WaitForDebugEventEx, the operating system will know that the debugger supports Unicode and is specifically opting into receiving Unicode strings.

ATLTRACE

ATL/MFCアプリやWinRTアプリでは、デバッグビルド時のみ有効になるATLTRACE()マクロ (atltrace.h) を使ってOutputDebugString()を間接的に利用することが多いですね。このマクロは第1引数に書式文字列を受け取るので便利です。MFCTRACE()マクロ (afx.h) は、ATLTRACE()と同じです*2

ただしVS2013 (ATL 12.0) 以降のATLTRACE()では、

hoge.cpp(123) : atlTraceGeneral - 出力メッセージ

というような感じで、ファイルパスと行番号と診断レベルが出力メッセージ先頭に付加されるようになりました。
Visual Studio IDEの出力ウィンドウでは、「FilePath(LineNumber):」の形で表示されたメッセージをダブルクリックすると、該当するソース行にジャンプできる機能が昔からあり、そのため __FILE____LINE__ を使って書式化されたメッセージを出力することがよくあったんですが、特にユーザーコードで工夫するまでもなく自動的にこの機能が利用できる形になりました。
ただ、常時出力されてしまうため、情報量が増えることでノイズも増え、メッセージ本体が埋もれてしまってうっとうしいと感じることもあります。

System.Diagnostics.Debug

.NETのDebug.WriteLine()メソッドやDebug.Print()メソッドは、VS2012/VS2013でもUnicode固有文字を出力できました。

System.Diagnostics.Debug.WriteLine("日本語©®™♡♥");

System.Diagnostics.Debugも内部的にOutputDebugStringW()を使っていると思っていたんですが、以下の解説によると、マネージコードに関しては別のデバッグエンジンが使われるため、OutputDebugStringW()の問題を回避できるようです。

Note
Visual Studio includes its own debugging environment and debugging engine, which together are called the Visual Studio debugger. For information on debugging in Visual Studio, see Debugging in Visual Studio. For debugging managed code, such as C#, using the Visual Studio debugger is often the easiest way to get started.

記憶が定かではないのですが、.NETのほうは確かWindows 10だけでなく、Windows 7/8.xでもUnicode固有文字を出力できていたような気がします。

*1:厳密に言うと「文字化け」というよりは、Unicode文字からCP932 (Shift_JIS) 文字へのマッピングが不可能であるために、代替文字に自動変換されています。

*2:昔はATLとMFCは別々に実装・メンテナンスされていたのですが、VC7で統合・整理されました。以後、MFCアプリからはATLの機能がすべて使えるようになっています。さらにVC2013以降はDLL版のATLが廃止され、スタティックリンク版のみになりました。Microsoft C/C++ 2003 - 2015 の変更履歴 | Microsoft Docs