🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Unicode

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

Win32 API

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

文字コード

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

C++

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

Q&A

解決済

1回答

1446閲覧

Unicode文字の型変換エラー解消

Maitz.

総合スコア12

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Unicode

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

Win32 API

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

文字コード

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

C++

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

0グッド

0クリップ

投稿2021/03/19 06:25

前提・実現したいこと

WinAPIでチャット機能を作っています。
・エディットコントロールから文字列を取得
・取得した文字列を2次元配列に格納
・配列の文字列を改行記号を含む1行の文字列に整形
・整形した文字列を表示用のエディットコントロールに送信
という機能を目指しています。

全角文字をテストしたところ、よくわからん動作をしました。
コードや設定の間違っている点、一般的なやり方との違いなどあれば教えていただきたいです。

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

半角英数の文字列は成功しました。
しかし、全角日本語の文字列を入力すると空白になってしまいます。

該当のソースコード

c++

1LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 2{ 3// 中略 4 switch (message) 5 { 6 case WM_CREATE: 7// 中略 8 hEdit = CreateWindowEx(0, TEXT("Edit"), 9 TEXT("rog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog\r\nrog"), 10 WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | ES_MULTILINE | ES_READONLY, 11 500, 10, 400, 300, hStatic, (HMENU)ID_EDIT, hInst, NULL); 12// 中略 13 hEditchat = CreateWindowEx(0, TEXT("Edit"), 14 TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER , 15 100, 320, 680, 30, hStatic, (HMENU)ID_EDITchat, hInst, NULL); 16 hButtonchat = CreateWindowEx(0, TEXT("BUTTON"), 17 TEXT("チャット送信"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 18 800, 340, 120, 30, hWnd, (HMENU)ID_BUTTONchat, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); 19// 中略 20 break; 21// 中略 22 case WM_COMMAND: 23 wmId = LOWORD(wParam); 24 wmEvent = HIWORD(wParam); 25 // 選択されたメニューの解析: 26 switch (wmId) 27 { 28// 中略 29 case ID_BUTTONchat: 30 wchar_t getline[256]; 31 char sendline[256]; 32 int i; size_t num; 33 34 GetWindowText(hEditchat, getline, 256); 35 i = wcstombs_s(&num, sendline, sizeof(sendline) / sizeof(char),getline,_TRUNCATE); 36 linestr::addline(sendline); 37 38 wchar_t* displayline ; 39 displayline = linestr::wcemitline(); 40 SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)displayline); 41 break; 42// 中略 43 default: 44 return DefWindowProc(hWnd, message, wParam, lParam); 45 } 46 return 0; 47} 48 49class linestr { 50public: 51 enum { 52 logmax = 50,//ログの最大行数を示す。 53 }; 54 static void defline() { 55 nowline = 0; 56 for (int i = 0; i < logmax; i++) { 57 oneline[i][0] = ' '; 58 oneline[i][1] = ' '; 59 oneline[i][2] = '\0'; 60 } 61 strncpy_s(oneline[0],_countof(oneline[0]), "start up\0", 9); 62 } 63 static int addline(char* newline) { 64 nowline += 1; 65 while (nowline >= logmax) nowline -= logmax; 66 strncpy_s(oneline[nowline],_countof(oneline[nowline]), newline, 76); 67 return 0; 68 } 69 static char* mtemitline() { 70 int line = nowline; 71 mtwordline[0] = { '\0' }; 72 73 for (int i = 0; i < logmax; i++) { 74 strncat_s(mtwordline,_countof(mtwordline), oneline[line], 76); 75 strncat_s(mtwordline,_countof(mtwordline), "\r\n", 2); 76 77 line -= 1; 78 while (line < 0) line += 50; 79 } 80 return mtwordline; 81 } 82 static wchar_t* wcemitline() { 83 wchar_t wcline[8000] = { '\0' }; 84 char* mtline = mtemitline(); 85 int i; 86 size_t num; 87 i = mbstowcs_s(&num, wcline, sizeof(wcline) / sizeof(wchar_t), mtline, _TRUNCATE); 88 89 return wcline; 90 } 91 92private: 93 static char oneline[50][76]; 94 static int nowline; 95 static char mtwordline[4000]; 96 static char wcwordline[4000]; 97 98}; 99char linestr::oneline[50][76]; 100int linestr::nowline; 101char linestr::mtwordline[4000] = { '\0' }; 102char linestr::wcwordline[4000] = { '\0' }; 103

試したこと

ネットで調べたところ、マルチバイト文字は古いなどの情報が出てきましたが、具体的な解決法は見つかりませんでした。

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

VS Community 2019
Unicode 文字セットを使用する

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

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

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

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

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

guest

回答1

0

ベストアンサー

本題に入る前に。

linestr::wcemitlineがぶっ壊れているのに気がつくでしょうか?変数wclineの寿命は関数を抜けるときに尽きるにも関わらずその領域へのポインタを返却して呼び出し元で参照しています。もっとも典型的なバグです。

次にlinestrクラスのメンバー変数/関数がすべてstaticなのはなぜでしょうか。ただのグローバル変数じゃないですか。やめましょう。まあlinestrクラス型の変数をstaticにしとくのがいいんじゃないですかね、今回は。

文字コード変換をやめるためにlinestrクラス内での文字列を全部wchar_tで扱いましょう。つまりUTF-16で扱うことにするわけです。

次にstrncat_sとかが見えてますが、Cで文字列操作するのはバグとバグしか産まないので素直にstd::wstringを使いましょう。+=で文字列連結が安全に出来ます。

投稿2021/03/19 11:36

yumetodo

総合スコア5852

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

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

Maitz.

2021/03/21 10:39

回答ありがとうございます。 `wcemitline`は、wcwordline変数をwchar_t型として返り値格納にする予定でしたが、見落としていました。 linestrに含まれる要素にstaticをつけまくっている点ですが、元々これらはグローバル変数で作成していました。作成中にネットで「グローバル変数は良くない、クラス内変数で同様に表現できる」という情報をみて、関係する変数と関数を一つのクラスにまとめました。 また、c++では`std::basic_string`がおすすめというのは参考にさせていただきます。元々、c言語のみの知識で書いていたので、string.hの関数・仕様を基準に書いていました。 また修正前のプログラムについて、明らかに間違っているのになぜか半角文字では正常に機能しているという疑問が浮上しました。 また余裕があれば、コメントいただけると助かります。
yumetodo

2021/03/21 11:40

>作成中にネットで「グローバル変数は良くない、クラス内変数で同様に表現できる」という情報をみて、関係する変数と関数を一つのクラスにまとめました。 現状では実質的にただのグローバル変数ですね。それは非staticなメンバー変数を作ってそのクラスを管理しようってことですね。 とにかくCで文字列をいじろうと考えないことです。そういうことをするのにただの一ミリも向いていないので。std::basic_stringと必要に応じてstd::baisc_string_viewを用いることで安全にかつ読みやすく実現できます。 >また修正前のプログラムについて、明らかに間違っているのになぜか半角文字では正常に機能しているという疑問が浮上しました。 たまたま当該メモリーが上書きされることなく、コンパイラもこの未定義動作を最適化に活用しなかったため動作していただけでは。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問