複雑になってしまいますが、私用領域とそれ以外に分けて DrawText で描画すればできるかもしれません。
例です。
※ (修正)描画部分を関数にしてみました
修正したはずが、反映されませんでした。
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// 外字フォントファイルをロード
const TCHAR* fontPath = L"C:\\Windows\\FONTS\\EUDC.TTE";
if (AddFontResourceEx(fontPath, FR_PRIVATE, NULL) == 0) {
MessageBox(hWnd, L"フォントのロードに失敗しました", L"エラー", MB_OK | MB_ICONERROR);
return -1;
}
// EUDCフォントを作成
HFONT hFont_EUDC = CreateFont(
24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"EUDC");
// MS 明朝フォントを作成
HFONT hFont_MSMincho = CreateFont(
24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH, L"MS 明朝");
// フォントを選択
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont_EUDC);
// 以降を関数に変更しました。
//// 描画領域
//RECT rectMax = { 50, 200, 400, 250 };
//RECT rect = rectMax;
//// 描画するテキスト
//const wchar_t text[] = L"あいう\uE849かきく";
//// 1回で描画するテキストの格納用
//wchar_t wtext[1000];
//memset(wtext, 0, sizeof(wtext));
//const wchar_t* p = text;
//const wchar_t* start_p = text;
//int len_regular = 0;
//int len_eudc = 0;
//bool isEUDC = false;
//while (true) {
// isEUDC = false;
// if (*p >= 0xE000 && *p <= 0xF8FF) {
// isEUDC = true;
// }
// if (*p == '\0' || (isEUDC && len_regular > 0) || (!isEUDC && len_eudc > 0)) {
// memset(wtext, 0, sizeof(wtext));
// if (len_regular > 0) {
// wcsncpy(wtext, start_p, len_regular);
// SelectObject(hdc, hFont_MSMincho);
// DrawText(hdc, wtext, -1, &rect, DT_LEFT | DT_CALCRECT);
// DrawText(hdc, wtext, -1, &rect, DT_LEFT);
// rect.left = rect.right;
// }
// if (len_eudc > 0) {
// wcsncpy(wtext, start_p, 1);
// SelectObject(hdc, hFont_EUDC);
// DrawText(hdc, wtext, -1, &rect, DT_LEFT | DT_CALCRECT);
// DrawText(hdc, wtext, -1, &rect, DT_LEFT);
// rect.left = rect.right;
// }
// start_p = p;
// len_eudc = 0;
// len_regular = 0;
// }
// if (*p == '\0') {
// break;
// }
// if (isEUDC) {
// len_eudc++;
// }
// else {
// len_regular++;
// }
// p++;
//}
// *** MyDrawText関数呼び出し
RECT rect;
rect = MyDrawText(hdc, hFont_EUDC, hFont_MSMincho,
50, 100,
L"あいう\uE849\uE849かきく\uE849");
rect = MyDrawText(hdc, hFont_EUDC, hFont_MSMincho,
rect.left, rect.bottom + 10,
L"あいうえおかきくけこ");
// フォントを元に戻す
SelectObject(hdc, hOldFont);
DeleteObject(hFont_EUDC);
DeleteObject(hFont_MSMincho);
ReleaseDC(hWnd, hdc);
// 外字フォントファイルをメモリから削除
RemoveFontResourceEx(fontPath, FR_PRIVATE, NULL);
EndPaint(hWnd, &ps);
} break;
作成したMyDrawText 関数です。
※ DrawText で文字数指定できたので、mallocを使わないように変更しました。
RECT MyDrawText(HDC p_hdc, HFONT p_hFont_EUDC, HFONT p_hFont,
int p_left, int p_top, const wchar_t* p_text) {
// 全体の描画範囲(返り値)を格納
RECT ret = { p_left, p_top, p_left, p_top };
// DrawText DT_CALCRECTで計算された描画範囲を格納
RECT rect = { p_left, p_top, p_left, p_top };
// 私用領域とそれ以外を区別するための変数
// 文字へのポインター
const wchar_t* p = p_text;
// 連続する領域の先頭のポインター
const wchar_t* start_p = p_text;
// start_p の文字列が私用領域の範囲か?
bool isEUDC = false;
// 描画する文字数
int len = 0;
// 文字が私用領域の範囲か?
bool iswEUDC = false;
while (true) {
// 文字が私用領域の範囲かチェックする
iswEUDC = false;
if (*p >= 0xE000 && *p <= 0xF8FF) {
// 私用領域の文字
iswEUDC = true;
}
if (*p == '\0' || iswEUDC != isEUDC) {
// フォントを選択する
if (len > 0) {
if (isEUDC) {
SelectObject(p_hdc, p_hFont_EUDC);
}
else {
SelectObject(p_hdc, p_hFont);
}
// 描画範囲(ボックス)を計算する
DrawText(p_hdc, start_p, len, &rect, DT_LEFT | DT_CALCRECT);
// 描画する。
DrawText(p_hdc, start_p, len, &rect, DT_LEFT);
// 全体の描画範囲(ret)を計算する。(left, top は同じ)
ret.right = rect.right;
if (ret.bottom < rect.bottom) {
ret.bottom = rect.bottom;
}
// 次に描画する位置(rect.left)を計算する。
rect.left = rect.right;
// 次の領域の文字列用に初期化する
start_p = p;
isEUDC = iswEUDC;
len = 0;
}
}
if (*p == '\0') {
break;
}
len++;
p++;
}
return ret;
}
実行結果を添付します。
みずらいですが、ご参考までに