none
ロシア語(文字コード:iso-8859-5)の文字列表示 RRS feed

  • 質問

  • お世話になります。Hippopotamusと申します。

     

    現在、VS2003 / C++ / MFC使用のアプリにて、ロシア語(文字コード:iso-8859-5)の文字列について

    下記2つを行いたいと思っています。

     

    ・DrawText()を使ってクライアント領域への描画

    ・CTreeCtrlの1アイテムの文字列として表示

     

    Code Snippet
     clFont.CreateFont(0, 0, 0, 0, FW_DONTCARE, 0, 0, 0,
          RUSSIAN_CHARSET,   // 文字セット
          OUT_DEFAULT_PRECIS,   // 物理フォント検索方法
          CLIP_DEFAULT_PRECIS,   // クリップ方法
          PROOF_QUALITY,    // 論理フォント⇔論理フォント一致程度
          VARIABLE_PITCH | FF_ROMAN, // フォントのピッチとファミリ
          "Arial");

     

     

     

    上記のようにフォントを作る際にnCharSet引数にRUSSIAN_CHARSETを指定することで

    キリル文字が表示できることは確認できたのですが、

    RUSSIAN_CHARSET時は文字コード:Windows-1251を使用しているらしく、

    iso-8859-5が定めている通りの文字を表示できません。

     

    コードページ番号まで指定してフォントを作成する方法があるのでしょうか?

    どなたか、文字コード:iso-8859-5の文字列を表示する方法をご教示ください。

    宜しくお願いします。

    2008年8月18日 5:30

回答

  •  

    きちんと表示されないのは、変ですね。手元のコードでは 0xA2-0xAF でも 0xF2-0xFC, 0xFE, 0xFF もきちんと表示されていますね…。(WindowsXP SP3 + Visual Studio 2005 ではありますが)

     

    上記のコードはオリジナルのコードを手直しせずにそのまま貼り付けたものでしょうか?

    # できれば、文字化けするコードそのままを見たいのですが…

     

    上記のコードは OnDraw の一部でしょうから、OnDraw の中身を以下に差し替えてみるとどうなりますでしょう?

     

    Code Snippet

     // TODO: この場所にネイティブ データ用の描画コードを追加します。
     static unsigned char iso8859text [] = {
         0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
      0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
      0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
      0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
      0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
      0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
     } ;
     WCHAR bufText [256] ;
     CFont clFont ; 
     CFont* pFontBak ;
     int  nTextLen ;
     RECT rc ;

     GetClientRect (&rc) ;
     clFont.CreateFont (0, 0, 0, 0, FW_DONTCARE, 0, 0, 0, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS,  CLIP_DEFAULT_PRECIS,  PROOF_QUALITY,   VARIABLE_PITCH | FF_ROMAN,  TEXT("Arial Unicode MS")) ;
     nTextLen = MultiByteToWideChar (28595, MB_ERR_INVALID_CHARS, (char*)iso8859text, sizeof(iso8859text), bufText, ARRAYSIZE (bufText)) ;
     pFontBak = pDC->SelectObject (&clFont) ;
     // クライアント領域に描画
     pDC->DrawText (bufText, nTextLen, &rc, DT_TOP | DT_LEFT | DT_WORDBREAK) ;
     (void) pDC->SelectObject (pFontBak) ;
     return ;

     

     

    # MFC プロジェクトを作成した直後の ChildView の OnDraw に上記のコードを追加して動作しています。


     

     

    2008年8月20日 11:37

すべての返信

  •  

    一度 Unicode に変換してから、DrawText を利用するというのは如何でしょうか? ISO8959-5 から Unicode への変換には、コードページ変換テーブル 28595 が使えますので (コードページ変換テーブル 28595 がインストールされている前提です)、

     

    Code Snippet

        static char iso8859_5_text [] = {
         (char)0xB1, (char)0xB2, (char)0xB3, (char)0xB4, (char)0xB5, (char)0xB6, (char)0xB7, (char)0xB8, (char)0xB9,
        } ;
        WCHAR buf [128] ;
        int  n ;

        n = MultiByteToWideChar (28595, 0, iso8859_5_text, sizeof (iso8859_5_text), buf, ARRAYSIZE (buf)) ;
        TextOutW (hdc, 0, 0, buf, n) ;

     

     

    のような形で (hdc には RUSSIAN_CHARSET で確保した font を割り当てています) 表示できると思います。

    # この例では TextOutW になっていますが、そこが DrawTextW になると思います。

     

    2008年8月20日 6:21
  • ご返信、ありがとうございます。

    実は、Unicodeに変換する方法は以前、以下のようなコードで試してみました。


     

    Code Snippet

     // UTF-16用フォント作成
     clFont.CreateFont(0, 0, 0, 0, FW_DONTCARE, 0, 0, 0,
          DEFAULT_CHARSET,   // 文字セット
          OUT_DEFAULT_PRECIS,   // 物理フォント検索方法
          CLIP_DEFAULT_PRECIS,   // クリップ方法
          PROOF_QUALITY,    // 論理フォント⇔論理フォント一致程度
          VARIABLE_PITCH | FF_ROMAN, // フォントのピッチとファミリ
          _T("Arial Unicode MS"));


     // ドキュメントクラスからデータ(ISO-8859-5)取得
     pszData = new CHAR[pDoc->GetDataSize() + 1];
     if (pszData == NULL) {
      return;
     }
     memset(pszData, 0x00, sizeof(TCHAR) * (pDoc->GetDataSize() + 1));
     memcpy(pszData, pDoc->GetData(), pDoc->GetDataSize());


     // ISO-8859-5 ⇒ UTF-16変換
     int nUTF16Size = MultiByteToWideChar(28595, MB_ERR_INVALID_CHARS, pszData, pDoc->GetDataSize(), NULL, 0);
     pszWideStr = new WCHAR[nUTF16Size + 1];
     if (pszWideStr == NULL) {
      return;
     }
     memset(pszWideStr, 0x00, sizeof(WCHAR) * (nUTF16Size + 1));
     nUTF16Size = MultiByteToWideChar(28595, MB_ERR_INVALID_CHARS, pszData, pDoc->GetDataSize(), pszWideStr, nUTF16Size);


     // クライアント領域に描画
     CString csDrawText;
     csDrawText = pszWideStr;
     pDC->DrawText(csDrawText, &rc, 0);

     

     

    しかし、上記の方法ではiso-8859-5の文字コードで0xA2~0xAF, 0xF2~0xFC, 0xFE, 0xFFに
    当たる部分が文字化けして「?」で表示されてしまいました。

    (コードページ変換テーブル 28595とArial Unicode MSフォントがインストール済みであることは確認済みです。)


     

    やはり、日本語OSではiso-8859-5の文字コード全てを表示するのは難しいのでしょうか…?

     

    2008年8月20日 10:48
  •  

    きちんと表示されないのは、変ですね。手元のコードでは 0xA2-0xAF でも 0xF2-0xFC, 0xFE, 0xFF もきちんと表示されていますね…。(WindowsXP SP3 + Visual Studio 2005 ではありますが)

     

    上記のコードはオリジナルのコードを手直しせずにそのまま貼り付けたものでしょうか?

    # できれば、文字化けするコードそのままを見たいのですが…

     

    上記のコードは OnDraw の一部でしょうから、OnDraw の中身を以下に差し替えてみるとどうなりますでしょう?

     

    Code Snippet

     // TODO: この場所にネイティブ データ用の描画コードを追加します。
     static unsigned char iso8859text [] = {
         0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
      0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
      0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
      0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
      0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
      0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
     } ;
     WCHAR bufText [256] ;
     CFont clFont ; 
     CFont* pFontBak ;
     int  nTextLen ;
     RECT rc ;

     GetClientRect (&rc) ;
     clFont.CreateFont (0, 0, 0, 0, FW_DONTCARE, 0, 0, 0, RUSSIAN_CHARSET, OUT_DEFAULT_PRECIS,  CLIP_DEFAULT_PRECIS,  PROOF_QUALITY,   VARIABLE_PITCH | FF_ROMAN,  TEXT("Arial Unicode MS")) ;
     nTextLen = MultiByteToWideChar (28595, MB_ERR_INVALID_CHARS, (char*)iso8859text, sizeof(iso8859text), bufText, ARRAYSIZE (bufText)) ;
     pFontBak = pDC->SelectObject (&clFont) ;
     // クライアント領域に描画
     pDC->DrawText (bufText, nTextLen, &rc, DT_TOP | DT_LEFT | DT_WORDBREAK) ;
     (void) pDC->SelectObject (pFontBak) ;
     return ;

     

     

    # MFC プロジェクトを作成した直後の ChildView の OnDraw に上記のコードを追加して動作しています。


     

     

    2008年8月20日 11:37
  • 返信が遅くなってしまい、申し訳ありません。

     

    以前、貼りつけたコードは文字化けするコードそのままです。

    OnDrawのコードをご教授いただいたコードと差し替えてビルドしてみたところ、

    『CDC:: DrawTextA(LPCTSTR,int,LPRECT,UINT)' : 1 番目の引数を 'WCHAR [256]' から 'LPCTSTR' に変換できません。』
    とエラーが出たのでDrawTextの部分のみ、下記のように変更してみました。

     

    Code Snippet

    // クライアント領域に描画

    // pDC->DrawText (bufText, nTextLen, &rc, DT_TOP | DT_LEFT | DT_WORDBREAK) ;

     ::DrawTextW(::GetDC(this->m_hWnd), bufText, nTextLen, &rc, DT_TOP | DT_LEFT | DT_WORDBREAK) ;

     

     

    これで、全文字が表示できることを確認できました。

    また、前回、私が貼りつけたコードのDrawText部分も同様にDrawTextW()を使用したところ、

    全文字が表示できました。

     

    当開発環境はマルチバイト文字セットプロジェクトだった為、

    Unicodeに変換した後は、明示的にDrawTextW()を使用しなければいけなかったのですね。

    プロジェクトの文字セットによる影響範囲をきちんと理解出来ていませんでした。

     

    下記についてもUnicodeに変換後、SetWindowTextW()を使用することで表示できそうです。

    ・CTreeCtrlの1アイテムの文字列として表示

     

    丁寧に教えてくださって、本当にありがとうございました。

    大変、助かりました。

     

     

    2008年8月25日 6:29