トップ回答者
メタファイルとユニコード

質問
回答
-
しかし、日本語以外の場合、文字化けがおこります。中国語(簡体)では、文字化けしました。
ディスプレイ側では、正しく表示されています。
メタファイルは詳しくありませんが、「内部がマルチバイト文字で扱うからこそ、このような変な引数(マルチバイト文字表現でのバイト数が必要)になる」と仮定すると、異なる文字セット(日本語環境で中国語(簡体))は扱えないということでしょう。
正確には「Unicode 非対応のプログラムの言語」で選択されている言語に依存すると予想されます。
(The Windows Metafile image format unfortunately does not provide any unicode support と書いているページもありますね)上記の情報が正しいと仮定して、出力先がクリップボードと考えると、クリップボードの貼り付け先が、「Unicode 非対応のプログラムの言語」で選択されている言語でメタファイル内の文字列を認識することになりますので、自分のプログラムでどんな工夫をしたとしても、、「Unicode 非対応のプログラムの言語」で日本語を選んでいる状態では、簡体字の文字は扱えません。
クリップボードを介してメタファイル形式で、異なる文字セットの文字を扱うという仕様がそもそも実現不可能な仕様と言うことになりますので、仕様を見直してください。なお、画面に表示できるのは、どちらの文字も表現可能な Unicode で描画しているだけでしょうから、画面の描画と比較することには意味がないと思います。
- 編集済み AzuleanMVP, Moderator 2017年7月19日 16:13
- 回答としてマーク Brillia 2017年7月25日 6:15
すべての返信
-
以下のページの症状と似ていると思うのですが、
このケースではTextOut()の文字数の指定に誤りがある疑いが指摘されています。確認してみてはどうでしょう。
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年7月24日 8:18
-
>○:pDC->TextOut( x, y, Strings , lstrlen(Strings) * sizeof(TCHAR) );
引数の「Strings」が、CString又はCStringWクラスのインスタンスであれば
CDC::TextOut( int x, int y, const CString &str)
の方のオーバーロード関数を使用すれば良いだけなのですが、
別の型の場合は、そのクラスにおいてのUnicodeでの
「文字数」を算定するメンバ関数の結果をnCountに使用したほうが良いでしょう。現在のマニュアルは正しい説明がされています(下記参照)。
https://msdn.microsoft.com/ja-jp/library/yzabsdzx(v=vs.120).aspx
- 編集済み 仲澤@失業者 2017年7月19日 7:53
-
-
CDC::TextOut()のーバーロードがうまくいかないとのこと、申し訳ありません。
COleServerItemのクリップボードの場合でしたね。この場合、リンクしたページの質問者さんの発言にある通り
TextOut()でUnicode文字列を出力する場合に、引数のnCountには、
「Unicode文字列の文字数ではなく、その文字列をMBCSにしたときのバイト数を渡す」
と正しく表示されるようです。また、同ページには
「半角と全角が混在した文字列の場合は、lstrlen(Strings)*sizeof(TCHAR)では正しく表示されません。」
との記述もあり、CT2A()でMBCSに変換後、strlen(・・変換後の文字列・・)の結果をnCountに与えるとうまくいったのことでした。又は、
CStringA MBCS_String( ・・Unicode文字列・・); のようにMBCS文字列に変換して、
nCount = MBCS_String.GetLength();
としてもうまくいくであろうと予測できます。 -
しかし、日本語以外の場合、文字化けがおこります。中国語(簡体)では、文字化けしました。
ディスプレイ側では、正しく表示されています。
メタファイルは詳しくありませんが、「内部がマルチバイト文字で扱うからこそ、このような変な引数(マルチバイト文字表現でのバイト数が必要)になる」と仮定すると、異なる文字セット(日本語環境で中国語(簡体))は扱えないということでしょう。
正確には「Unicode 非対応のプログラムの言語」で選択されている言語に依存すると予想されます。
(The Windows Metafile image format unfortunately does not provide any unicode support と書いているページもありますね)上記の情報が正しいと仮定して、出力先がクリップボードと考えると、クリップボードの貼り付け先が、「Unicode 非対応のプログラムの言語」で選択されている言語でメタファイル内の文字列を認識することになりますので、自分のプログラムでどんな工夫をしたとしても、、「Unicode 非対応のプログラムの言語」で日本語を選んでいる状態では、簡体字の文字は扱えません。
クリップボードを介してメタファイル形式で、異なる文字セットの文字を扱うという仕様がそもそも実現不可能な仕様と言うことになりますので、仕様を見直してください。なお、画面に表示できるのは、どちらの文字も表現可能な Unicode で描画しているだけでしょうから、画面の描画と比較することには意味がないと思います。
- 編集済み AzuleanMVP, Moderator 2017年7月19日 16:13
- 回答としてマーク Brillia 2017年7月25日 6:15
-
COleServerItem::CopyToClipboard関数でクリップボードに貼り付けられるときのみ、TextOutで出力される文字列が化けるという現象です。
CopyToClipboard関数は、WMFを作成するデバイスコンテキストを生成して、OnDraw関数を実行していました。
※CMetaFileDC::Create()
WMFが、Unicode未対応ならばと、EMFを作成するデバイスコンテキストを生成+CDC::TextOut( int x, int y, const CString &str)関数
で、ユニコード文字列の文字化けが無くなりました。
※CMetaFileDC::CreateEnhanced()現在わかった内容は、次の2点です。
・UNICODE版のアプリで、WMFを作成するときのTextOut関数はバイト数が必要。だけど、WMF自体がUNICODE文字列は未対応。
(ここで疑問なのですが、TextOut関数に渡している文字列は、Unicode文字列で、日本語なら正しく表示される。中国語は文字化けする。中国語OSでは、日本語文字列、中国語文字列両方文字化けする。不思議です。)
・EMFを作成する場合では、UNICODE文字列が対応しており、CDC::TextOut( int x, int y, const CString &str)関数も使用できる
ということが分かってきました。
とりあえず、UNICODE文字列を使用するには、EMFを使用すると理解します。
- 編集済み Brillia 2017年7月21日 3:33
-
回答ではありません。参考としての発言になってしまいますが、
1.WMF(Windows Metafile)は1990~1992年(頃)に発行されたフォーマットで、
16bitのGDI用に設計されたものです。
アプリ内で作成し、アプリ内で正確に再生することは可能ですが、
DCへの初期化コマンドなどが含まれないため、
物理ファイルが作られた時の基本的な初期化条件が不明となってしまい、
単体では正確に再生することが困難な仕様でした。
公式文書は発見できませんでしたが、WMFはマイクロソフトが非推奨としたはず。
という記憶があります。2.EMF(Enhanced Metafile)は1993年に発行されたフォーマットで、32bit用にWMFを拡張したものです。
こちらは初期化に必要な要素も(ほぼ)含まれているため単体で正確に再生することができます。そういった経過から、WMFよりEMFの方がややサポートが良いかもしれません。
ただし、残念ながら両者とも、PostScriptやそれから派生したPDF等にとってかわられてしまい、
サポートしているアプリケーションが少ないのが現状です。