質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Unicode

Unicodeはエンコーディングの標準規格です。1つの文字コード体系で多国語の表現を可能にすることを目指して作られています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

3583閲覧

C++におけるDrawTextExの引数の文字コード

Weapon

総合スコア106

Unicode

Unicodeはエンコーディングの標準規格です。1つの文字コード体系で多国語の表現を可能にすることを目指して作られています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/02/26 18:25

前提・実現したいこと

WindowsAPIの基本的なDrawTextExのレンダリングについて型が合わないとエラーが出ます。

発生している問題・エラーメッセージ

'int DrawTextExA(HDC,LPSTR,int,LPRECT,UINT,LPDRAWTEXTPARAMS)': 引数 2 を 'LPCTSTR' から 'LPSTR' へ変換できません。

該当のソースコード

LPCTSTR Lender3 = TEXT("Hello World\nWindows API Programming");
DrawTextEx( hdc, Lender3, -1, &rc, DT_WORDBREAK|DT_EXPANDTABS|DT_TABSTOP, &dtp );

試したこと

DrawTextExは調べてもLPTSTRと定義されているのにエラーメッセージではLPSTRと出てきます。LPSTRをLPTSTRにするとTEXTマクロが使えなかったり文字コードの仕組みがよくわかりません。
どうすれば以上の関数を使用できるでしょうか。ほかの関数で代用できることはわかりますがこの関数の使い方を知りたいです。
そして文字コードは基本的にUNICODEで統一していったほうがいいんでしょうか。

補足情報(FW/ツールのバージョンなど)

VisualStudio2017 Community
Windows10 Pro

C++

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ドキュメントによると、食わせる文字列は変更される(最大4文字長くなる)可能性があるとのこと。
長メのTCHAR配列を用意し、文字列をコピーしてDrawTextEx()に食わすことになろうかと。

C

1TCHAR Lender3[256] = TEXT("Hello World\nWindows API Programming"); 2DrawTextEx( 3 hdc, 4 Lender3, 5 -1, 6 &rc, 7 DT_WORDBREAK|DT_EXPANDTABS|DT_TABSTOP, 8 &dtp 9 );

※ 変更される恐れがないならconst_cast<LPSTR>(Lender3) でもよさげ。
[追記] ↑違うポ。 gazette2さんのフォロー回答を参照されたし。

投稿2018/02/26 20:14

編集2018/02/27 02:12
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

一般的な文字列コードに関するエラーを避ける方法は次のようになります。

  1. Tのあるマクロを使用する。

LPCWSTR, LPCSTR → LPCTSTR
LPWSTR, LPSTR → LPTSTR
WCHAR, CHAR → TCHAR

  1. 文字列は_T()で囲む

LPCSTR x = "...";
LPCWSTR x = L"...";
LPCWSTR x = TEXT("...");
→ LPCTSTR x = _T("...");

  1. strlenなどの標準C関数使用時に注意

strlen : Ansi用
wcslen : Unicode用
tcslen : strlenの T version.
0. なるべくUnicode設定を使用する


そして、epistemeさんの答えに捕捉です。
追加説明したい部分は

変更される恐れがないならconst_cast<LPSTR>(Lender3) でもよさげ

ですが、これは正しい情報ではありません。

一応
TSTR WCHAR LPTSTR LPCSTR LPCTSTRなどいろいろありまして複雑に思われますが要すると次のようになります。

  1. Cは const(コードの説明ではあまり重要ではありません)
  2. Wは Unicode
  3. WもTもないものは Ansi(Multi-byteコードもansiの一種)
  4. Tはマジック文字(ワイルドカード)

例えば
LPWSTR, WCHAR, LPCWSTRなどはすべてUnicodeです。
LPSTR, CHAR, LPCSTRなどはAnsiコードです。

そして、4番のTは設定によって変わります。
設定がUnicodeになっている場合Tの部分がWに変わり、そうでない場合Tの部分が無くなります。

例えばLPTSTRは
Unicode設定下 ⇒ LPWSTR
Ansi設定下 ⇒ LPSTR

なので、変更される恐れがなくてもconst_cast<LPSTR>を使用すると設定によって次のコードは

LPCTSTR Lender3 = _T("....."); DrawTextEx(..., const_cast<LPSTR>(Lender3), ...);

Unicode設定の場合

LPCWSTR Lender3 = TEXT("....."); DrawTextEx(..., const_cast<LPSTR>(Lender3), ...); // ERROR! :DrawTextExの2番目の因数はLPWSTRに翻訳される。LPWSTRが必要な部分にLPSTRを入れるのはエラー。

なので単にconst_cast<LPSTR>(Lender3)を使用するとUnicode設定下には使えないコードになってしまいます。そしてAnsiコードよりUnicodeを使用するのをお勧めします。


追加

C言語の基礎に戻って考えてみますと""で囲まれた文字列ってすべてConstですね。

const char *p1 = "..."; // OK char *p2 = "..." // Error(昔の本やコンパイラーの場合許可される場合もあるがこれはエラーです) p1[0] = 'd'; // Error. 文字列はconst.

ここまでは分かっていると思います。

マクロの中のCは文字コードとは関係ありませんがそれなりに重要な意味があります。
マクロの中のCの観点からみるとWinAPIやMFC関数の中で文字列を因数にするものは大体二つの種類があります。

  1. LPCTSTR, LPCWSTR, LPCSTRなど、Cがついたものを因数に取る関数(例:CreateWindowEx)
  2. そうでないもの(LPTSTR, LPWSTR, LPSTRなど)(例:DrawTextEx)

がそれです。

1の場合は因数の中身が変更されない
2の場合は因数の中身が変更される可能性がある。
っていうことです。

詳しく説明すると関数の因数でCがついたものたち(1類)は

p1[0] = 'd';

みたいな行動を関数の中で絶対しないっていういわゆる保障的なものです。
しかし、2類関数たちはそんな保証をしません。
なので因数の中身が変更される可能性がいつでもあります。

最初に戻ってDrawTextExを見ますと

int DrawTextEx( _In_ HDC hdc, _Inout_ LPTSTR lpchText, _In_ int cchText, _Inout_ LPRECT lprc, _In_ UINT dwDTFormat, _In_ LPDRAWTEXTPARAMS lpDTParams );

2番目の因数がLPTSTRですね。
なのでこの関数の中でlpchTextが指している内容が変更される(もしくは可能性がある)っていうことで、

LPCTSTR p1 = _T("..."); LPTSTR p2 = new TCHAR[1024]; TCHAR arr[1024] = _T("..."); DrawTextEx(..., p1, ...); // Error: p1[0] = 'd';と全く同じコードになります。 DrawTextEx(..., p2, ...); // OK: newで作られたメモリーは書き込むことができます。 DrawTextEx(..., arr, ...); // OK: 配列は書き込むことができます。

なんか長くなりましたが要すると
1類関数には p1, p2, arrどちらでもいい。
2類関数には p1はできない。p2, arrはオッケー。
LPTSTR変数 -> LPCTSTR因数 : OK
LPCTSTR変数 -> LPTSTR因数 : Error
って言うことです。

投稿2018/02/27 02:00

編集2018/02/27 10:29
gazette2

総合スコア179

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2018/02/27 02:09

そっか、ふぉろーありがとです。 ただしくは const_cast<LPTSTR>(...) か。
gazette2

2018/02/27 02:42

勝手に口を挟んじゃってすみません。^^ 核心的な説明はepistemeさんの答えにありますので僕は一般論だけ書きました。const_cast<LPTSTR>(...)で無理ないと思います。
Weapon

2018/02/27 07:48

LPTSTRではTEXTや_Tが使えないのですがConstしか格納できないものですか?epistemeさんが最初に出した配列[]を使って文字数を定めてやる必要があるのでしょうか。文字列をConstにする意味への理解が達してないのですいません。 またDrawTextExの引数のLPTSTRはLPCTSTRではないのにConstを入れることが前提なのですか?
episteme

2018/02/27 07:57

const_cast<LPTSTR>(TEXT("ほげほげ")) を DrawTextEx() に食わすことができんかったですか? 食わせた文字列が変更されない(DT_MODIFYSTRINGを指定しない)ならこれでOKのはずなんだが。
gazette2

2018/02/27 08:24

こんにちは。マクロの中のCに関してはepistemeさんの説明で十分だと思ってここでは省略しました。足りなかったと思われましたらすぐ追加します。
Weapon

2018/02/27 08:51

おかげさまでコンパイル自体は成功してうまくいきました。 C付きの型か指定した文字数固定の文字列を使うことでTEXTや_Tを代入することができ、DrawTextEx関数に入れるときにcastしてconstを外して代入するということですよね?
gazette2

2018/02/27 09:21 編集

epistemeさんがおっしゃっている通りこの場合はコンパイルだけ出来れば特に問題ないと思います。(実際に関数の中で文字列が変更されたりしないので)
gazette2

2018/02/27 10:26

誤字、バッグなど修正しました。
guest

0

'int DrawTextExA(HDC,LPSTR,int,LPRECT,UINT,LPDRAWTEXTPARAMS)': 引数 2 を 'LPCTSTR' から 'LPSTR' へ変換できません。

このエラーは非constポインタの引数にconstポインタを渡そうとしたことを示しています。解決策としてはepistemeさんの回答を参考にしてください。

そして文字コードは基本的にUNICODEで統一していったほうがいいんでしょうか。

Windowsのネイティブ文字コードはUnicode(UTF-16)なのでWindows APIとの親和性においてはUnicodeを使うべきです(プロジェクトの設定も既定でUnicode文字セットになっているはずです)。プロジェクトの設定を「Unicode文字セットを使用する」として、文字コードはwchar_t(あるいはWCHAR)を使うのが一番トラブルが少ないです。

ちなみに、TEXTマクロやTCHAR,LPTSTRといった、コンパイルオプションによってcharとwchar_tを切り替える仕組みはWindows 9x系との互換性のために存在しています。今さら(よほど特殊な事情がない限り)9x向けにコンパイルすることはないでしょうから、今となっては利用価値はないでしょう。

投稿2018/02/27 00:56

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問