C言語で、unicodeを扱うには?

解決


ゴートラ  2006-09-11 10:20:43  No: 62975  IP: 192.*.*.*

初めまして。ゴートラと申します。

私は、下記の環境で開発をやっております。

  統合開発環境:Microsoft Visual Studio .NET 2003
  言語:C++(但し、ソースファイルは.cppでなく.c)
  種類:Win32 プロジェクトのコンソール アプリケーション

現在、FindFirstFileを使用し、
指定したフォルダ以下のファイル一覧を作成しようとしているのですが、
Unicodeでしか文字コードが割り当てわれていない文字がフォルダ名に存在すると、
Unicode文字の部分が「?」に変換され、
「ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。」
というエラーが返ってきてしまいます。

出力結果が?になっていてもかまいませんが、
該当フォルダ以下のファイル名が一つも取得できなくて困っています。


どうぞ、よろしくお願いします。

編集 削除
Blue  2006-09-11 10:33:21  No: 62976  IP: 192.*.*.*

あちらで回答しましたが?
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200609/06090030.txt

編集 削除
Blue  2006-09-11 10:49:39  No: 62977  IP: 192.*.*.*

ちなみに FindFirstFileW を使う場合、ほかの対応する構造体や関数もすべて 〜〜W(もしくは w〜) にする必要があります。

列挙してからどうしているのかよくわかりませんけど、Unicodeで取得した文字列は
Unicodeで表示するような関数を使わないと、結局表示できませんので。
(printfでは表示できない。wprintfを使う。(setlocaleが必要になる))

編集 削除
επιστημη  2006-09-11 12:04:02  No: 62978  IP: 192.*.*.*

/* おためし */

#include <stdio.h>
#include <locale.h>
#include <windows.h>

int main() {
  WIN32_FIND_DATAW fdw;
  HANDLE handle;

  setlocale(LC_ALL,"japanese");
  handle = FindFirstFileW(L"*.*", &fdw);
  if ( handle != INVALID_HANDLE_VALUE ) {
    do {
      wprintf(L"[%s] ", fdw.cFileName);
    } while ( FindNextFileW(handle, &fdw) );
    FindClose(handle);
  }
}

編集 削除
Blue  2006-09-11 13:25:09  No: 62979  IP: 192.*.*.*

よく考えたら
>(printfでは表示できない。wprintfを使う。(setlocaleが必要になる))
でも、(wprintfだと)Shift_JISに変換できないUnicodeは表示できないですね。

参考:
http://forums.belution.com/ja/vc/000/374/67s.shtml
の てつさんのところ。

編集 削除
Blue  2006-09-11 13:46:55  No: 62980  IP: 192.*.*.*

επιστημη さんのお試しコードをちょっとお借りして WriteConsoleW で表示させる例です。
(setlocaleの必要はなかったです。)

#include <windows.h>
#include <stdio.h>

int main( void )
{
    WIN32_FIND_DATAW fdw;
    HANDLE handle;
    HANDLE hStdout;
    DWORD ret;
    wchar_t filePath[ 256 ];

    hStdout = GetStdHandle( STD_OUTPUT_HANDLE );

    handle = FindFirstFileW( L"*.*", &fdw );
    if ( handle != INVALID_HANDLE_VALUE )
    {
        do
        {
            swprintf( filePath, L"[%s]\n", fdw.cFileName );
            WriteConsoleW( hStdout, filePath, wcslen( filePath ), &ret, NULL );
        }
        while ( FindNextFileW( handle, &fdw ) );
        FindClose( handle );
    }
    return 0;
}

編集 削除
επιστημη  2006-09-11 14:37:21  No: 62981  IP: 192.*.*.*

× swprintf( filePath, L"[%s]\n", fdw.cFileName );
○ swprintf( filePath, 256, L"[%s]\n", fdw.cFileName );

編集 削除
Blue  2006-09-11 14:49:18  No: 62982  IP: 192.*.*.*

>× swprintf( filePath, L"[%s]\n", fdw.cFileName );
>○ swprintf( filePath, 256, L"[%s]\n", fdw.cFileName );
あら?
Microsoft Visual Studio .NET 2003だと、サイズを指定しないとダメなんですかね。

VC6用(?)
sprintf、swprintf
http://www.microsoft.com/JAPAN/developer/library/vccore/_crt_sprintf.2c_.swprintf.htm

MSDN2
sprintf、_sprintf_l、swprintf、_swprintf_l、__swprintf_l 
http://msdn2.microsoft.com/ja-JP/library/ybk95axf.aspx

とおもったら、
<MSDN2>
Visual C++ 2005 では、swprintf 関数は ISO C 規格に準拠しています。
この規格では、2 番目のパラメータ count を size_t 型で指定する必要があります。
</MSDN2>
とありますね。
2005より前のコンパイラでは ISO C 規格に準拠していないんですね。

といって、VC6や2003では count を指定出来ないような・・・

編集 削除
Blue  2006-09-11 14:59:03  No: 62983  IP: 192.*.*.*

http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/vclib/html/_crt_sprintf.2c_.swprintf.asp
のほうが詳しく書かれていました。

編集 削除
επιστημη  2006-09-11 15:13:31  No: 62984  IP: 192.*.*.*

へー。じゃ、どっちが×とか○とかじゃないのか。
僕はもっぱら2005で、表示結果がヘンテコになったんでヘルプみたらばcountが付いてたぞ、と。

編集 削除
ゴートラ  2006-09-12 22:29:51  No: 62985  IP: 192.*.*.*

Blueさん、επιστημη さん

回答ありがとうございます。

おかげ様で、該当フォルダ以下のファイル名の取得に成功致しました。
まだまだ、改良の余地がある状態ですが、
一つのプログラムとして、
意味があるかないかの境目の部分は越えたと思っています。

ありがとうございました。

編集 削除