none
シリアライズ化処理のマルチバイト化について RRS feed

  • 質問

  • 古い環境になるのですが、VisualStudio2003でMFCアプリ(SDIタイプ)を作成しています。
    標準で挿入されているDocumentクラスのSerialize関数で以下のように現在なっています。

    if (ar.IsStoring())
    {
        for(i=0;i<PARA_MAX;i++)ar<<para_edit_name[i];
    } else {
        for(i=0;i<PARA_MAX;i++)ar>>para_edit_name[i];
    }

    para_edit_name[i]はCString型です。
    ファイルに保存を選んだ時にpara_edit_name[]の文字列を全てファイルに
    保存するという物です。

    問題はVS2003は文字コードがデフォルトでマルチバイトなのですが、上記の
    アプリがWindows7でことごとく日本語表示の部分が文字化けします。
    文字コードがUnicodeになっていないからだと思うので、Unicode化対応を
    しているのですが、上記のコードのままだと保存されたテキストファイルは
    Unicode文字列で保存されてしまいますので、不都合なのです。
    数多くの保存されたテキストファイルは通常のマルチバイトで保存されている
    のでこのシリアライズ処理の保存&読込みをマルチバイトにしたいのですが、
    どうやればいいのかわかりません。

    SDI/MDIタイプのアプリは作成した事がないので無知識で困ってます。
    どなたか、教えてもらえないでしょうか。

    2010年3月29日 2:25

回答

  • CStringAが使えるのであれば、一回CStringAの変数に入れてからCStringのコンストラクタを介してpara_edit_name[i]に入れてみてはどうでしょうか?

     

    つまり

     

    for (i = 0; i < PARA_MAX; ++i)

    {

    if (ar.IsLoading()) {

    CStringA temp;

    arr >> temp;

    para_edit_name[i] = CString(temp);

    }

    else if (ar.IsStoring()) {

    arr << CStringA(para_edit_name[i]);

    }

    }


    わんくま同盟[http://blogs.wankuma.com/blue/]
    • 回答としてマーク shimpo 2010年3月29日 5:04
    2010年3月29日 4:54

すべての返信

  • プロジェクト全体で文字セットをUnicode文字セットにするのだが、シリアライズのときはマルチバイト文字セットに

    したいということでしょうか?

     

    VS2005以降であれば

    シリアライズ時のみ、CStringAクラスを使えばらくそうですが、VS2003はどうなんでしょうかね。


    わんくま同盟[http://blogs.wankuma.com/blue/]
    2010年3月29日 3:03
  • そういう事です。
    プロジェクト全体はUnicode文字セットにしています。
    表示関係は全て処理して文字化けは直ったのですが、ファイルI/Oは
    マルチバイトでないと都合悪いんです。

    wcstombs()で変換して下記のようにやってみたんですが、警告が出ますし
    警告無視して実行しても保存されたファイル内容もおかしいんです。

      char buf[PARA_MAX];
      for(i=0;i<PARA_MAX;i++) {
       memset( buf, 0, PARA_MAX );
       wcstombs( buf, para_edit_name[i], PARA_MAX );
       ar<<buf; ←ここで警告が出る。
      }
    ar<<CSting型はOKなのにar<<char型はダメなんですね。
    シリアライズの知識が無いので、ar<<・・・の使い方もどうもよくわかりません。

    CStinrgAってVS2003のMSDNで検索しても出てきませんけどどういう型なんでしょう?

    • 編集済み shimpo 2010年3月29日 4:12
    2010年3月29日 3:54
  • マルチバイト文字セットのときのCStringのシリアライズを自前で記述すると

     

    1.バイト数をバイナリで出力(たぶんint型)

    2.バイト数分出力

     

    ということになります。

    よって

    >ar<<buf; ←ここで警告が出る。

    は1バイトずつループで出力しないといけません。

    # bufはchar*型なのでchar型ではない。

     

     

    ひょっとするとCByteArrayのSerializeで行けるかも。

    以下検証なしで、適当。

    if (ar.IsStoring()) {

    CByteArray ba;

    int lenght = wsctombs(NULL, para_edit_name[i], 0);

    ba.SetSize(lenght + 1);

    wsctombs(ba.GetData(), para_edit_name[i], lenght + 1);

    ba.SetSize(lenght);

    ba.Serialize(ar);

    }

    else if (ar.IsLoading()) {

    CByteArray ba;

    ba.Serialize(ar);

    ba.SetAtGrow(ba.GetSize(), NULL);

    para_edit_name[i] = CString(ba.GetData());

    }

     


    わんくま同盟[http://blogs.wankuma.com/blue/]
    2010年3月29日 4:12
  • 挙げて頂いたコードを試しましたが、文字列が全部連結したようになってしまいました。

    更に調べたらCStringAの説明を見つけたので、単純の以下のようにしてみたら保存
    はマルチバイトで出来ました。

        for(i=0;i<PARA_MAX;i++)ar<<(CStringA)para_edit_name[i];

    ところが今度は読込みがうまく行きません。そのままだとマルチバイトでpara_edit_name[i]
    に入ってしまいます。(当然でしょうけど)
    読込み時にCStringにするにはどうすればよいのでしょう?(安直にキャストしただけ
    ではダメでした)

    2010年3月29日 4:43
  • CStringAが使えるのであれば、一回CStringAの変数に入れてからCStringのコンストラクタを介してpara_edit_name[i]に入れてみてはどうでしょうか?

     

    つまり

     

    for (i = 0; i < PARA_MAX; ++i)

    {

    if (ar.IsLoading()) {

    CStringA temp;

    arr >> temp;

    para_edit_name[i] = CString(temp);

    }

    else if (ar.IsStoring()) {

    arr << CStringA(para_edit_name[i]);

    }

    }


    わんくま同盟[http://blogs.wankuma.com/blue/]
    • 回答としてマーク shimpo 2010年3月29日 5:04
    2010年3月29日 4:54
  • 出来ました!
    ありがとうございました。m(_ _)m
    2010年3月29日 5:04