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

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

詳細はこちら
C++

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

Q&A

解決済

2回答

4607閲覧

C++:WritePrivateProfileStringの挙動に関して

退会済みユーザー

退会済みユーザー

総合スコア0

C++

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

0グッド

0クリップ

投稿2019/09/24 07:40

編集2019/09/24 08:18

■概要
C++をVisual Studio2017を使用して開発を行っております。
この度、WritePrivateProfileString関数を使用した際に、対象のファイルの保存形式がS-JISとUTF-16LE(BOM付き)の場合で異なる挙動を示した原因が分からずこの場をお借りして、ご質問させて頂いております。

■iniファイルがSJIS(CRLF)の場合
00 01 02 03 04 05 06 07・・・
5B 00・・・

5b 00 は" [ "を意味しています。UTF16なので、5Bの直後に00が入っています。

■iniファイルがUTF16-LE(BOM付き,CRLF)の場合
00 01 02 03 04 05 06 07・・・
FF FE 0D 00 0A 00 5B 00・・・

最初のFF FEに関してはBOMになります。SJISの方についていないのは当然です。しかし、その直後に0D 0A(おそらく改行コードのCRLF)が入っています。

■デバッグして分かっていること
WritePrivateProfileStringを実施する直前にiniファイルをバイナリで確認したところ、FF FEのBOMを意味する文字コードしか入っていないことを確認済みです。また、WritePrivateProfileString実施直後にiniファイルをバイナリで確認した時に、0D 00 0A 00(改行CRLFを意味する)が入っています。

■まとめ
上記のような差が出る原因がわかりません。私の想いとしては、「iniファイルがUTF16-LE(BOM付き)の場合」であっても、改行コードが入らない状態にすることです。

■iniファイルにCRLFが入るのが嫌な理由
iniファイル作成後、ツールを再起動した際、iniファイルの1行目から読み込み処理を行っていきます。そちらの処理では、1行目に" [ "が存在することが前提として起動する処理であるため、今回の修正で、iniファイルの1行目にFF FE 0D 00 0A 00、つまり" [ "が存在しないのは都合が悪いです。
■コード

①呼び出し側(Dlg.cpp)
ma.CreateIni(b.m_DevName, b.m_SvName, b.m_RcvFolder, b.m_CopyPath, b.m_Port);

②上記①に呼ばれる側(A.cpp)
int A::CreateIni(CString DevName, CString SvName, CString RcvName, CString IniPath, CString Port)
{
if(::WritePrivateProfileString((LPCTSTR)strName, SERVERNAME, (LPCTSTR)SvName, IniPath) == 0)
return -1;
}

③バイナリの書き込み
if (file.Open(strIniPath, CFile::modeWrite | CFile::modeCreate | CFile::shareExclusive)) {
BYTE bom[2] = {0xff, 0xfe};
file.Write(bom, 2);
file.Close();
}

※注
maは「Aクラスのインスタンス」です。
b.xxxは「Bクラスのメンバ変数」で、ダイアログでユーザが入力した値がCString型で格納されています。

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

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

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

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

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

y_waiwai

2019/09/24 07:43

コードを提示しましょう
KoichiSugiyama

2019/09/24 08:07

BOMの後にCRLFが入ると何か他の処理に不都合があるのでしょうか?その辺りも記述していただいた方が良いかと思います。ないのであればWritePrivateProfile系APIの仕様と捉えても良いのでは。
退会済みユーザー

退会済みユーザー

2019/09/24 08:13

y_waiwai様 ご指摘ありがとうございます。コードを追加させて頂きました。
退会済みユーザー

退会済みユーザー

2019/09/24 08:18

KoichiSugiyama様 ご指摘ありがとうございます。反映させました。以下の箇所をご確認ください。 ■iniファイルにCRLFが入るのが嫌な理由
takabosoft

2019/09/24 08:46

そのツールとやらはShiftJISにもUTF16にも対応しているのに、先頭の空行を読み飛ばすことすらできないんでしょうか・・・(ソースが無いとかですかね?)
guest

回答2

0

WindowsのPrivateProfileString系の関数はファイルのエンコードを指定できないので、通常なら使用しているWindowsの言語設定に合わされてしまうはず。例えば中国語(GB2312)の文字列がセットされているファイルから読み出すと文字化けしてしまいます。また、ファイルのシェア設定もできないので複数のアプリから同時にアクセスしてしまうと壊れてしまうこともあります。
なので、私はINIファイルアクセスのクラスを独自に構築してアクセスしています。

PrivateProfileString系の関数って昔のコードの互換性のためにあるようなものなので、新規で使うのは私はあまりおすすめしません。

投稿2019/09/24 09:09

PineMatsu

総合スコア3579

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

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

退会済みユーザー

退会済みユーザー

2019/09/25 06:34

コメントありがとうございます。私もPrivateProfileString系は使いたくなかった(iniファイルではなくxmlなどを使いたかった)ですが、既存の修正をなるべく加えないようにとの依頼であったため、このような形を取りました(汗)
guest

0

ベストアンサー

手元のコードでも再現取れました。

cpp

1 CString strIniPath = _T("C:\...\TestIni.ini"); 2 3 CFile file; 4 if (file.Open(strIniPath, CFile::modeWrite | CFile::modeCreate | CFile::shareExclusive)) { 5 BYTE bom[2] = {0xff, 0xfe}; 6 file.Write(bom, 2); 7 file.Close(); 8 } 9 10 if(::WritePrivateProfileString(_T("TEST"), _T("KEY"), _T("VALUE"), strIniPath) == 0) { 11 ASSERT(0); 12 }

WritePrivateProfileStringWの挙動だと思いますので、仕方ないのかなと思います。
ツール側を改良するか、ツールを呼び出す前にiniの先頭の空行を削除するか
どちらかお好きな方を採用してください。

投稿2019/09/24 08:59

takabosoft

総合スコア8356

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

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

退会済みユーザー

退会済みユーザー

2019/09/24 23:37

ご返答ありがとうございます。 >WritePrivateProfileStringWの挙動だと思いますので、仕方ないのかなと思います。 上記、安心しました。仕様とのことなので、再検討し修正するか判断します。 返答遅くなり申し訳ありません。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問