1.環境など
Visual Studio 2022/2019/2017(それ以前は未確認)
MFC
マルチバイト文字セット
2.現象
MFC の Direct2D ラッパークラス、CRenderTarget と CD2DTextLayout ですが、マルチバイト文字セットで正しく動きません
3.詳細
MFCの実装ファイル、afxrendertarget.cpp
場所は環境によりますが、わたしの環境では以下のあたり
【Visual Studio 2022】
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.32.31326\atlmfc\src\mfc
【Visual Studio 2019】
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\atlmfc\src\mfc
【Visual Studio 2017】
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\atlmfc\src\mfc
で確認したところ、CRenderTarget::DrawText では
m_pRenderTarget->DrawText(T2CW(strText), strText.GetLength(), textFormat->m_pTextFormat, &rect, *pForegroundBrush, options, measuringMode);
などとなっています。バッファだけUnicodeへ変換して、文字数は変換前のバイト数を渡しています。なので、全角文字を渡すとUnicode文字数より大きな文字数を渡してしまい、文字化けします。CD2DTextLayoutのコンストラクタも同様です。
4.対策
【CRenderTarget::DrawText】
CHwndRenderTarget の 派生クラスを用意し、同じ DrawText を宣言し、定義部分は afxrendertarget.cpp からコピーしてきて
m_pRenderTarget->DrawText(T2CW(strText), strText.GetLength(), textFormat->m_pTextFormat, &rect, *pForegroundBrush, options, measuringMode);
のところを
CStringW strTextW(strText);
m_pRenderTarget->DrawText(strTextW, strTextW.GetLength(), textFormat->m_pTextFormat, &rect, *pForegroundBrush, options, measuringMode);
と修正し、CHwndRenderTarget の代わりに使います。
【CD2DTextLayout::CD2DTextLayout】
このラッパークラスは使わず
IDWriteFactory* pDWFactory = AfxGetD2DState()->GetWriteFactory();
であれこれします。