Tips1 有効なドライブの情報取得

次のTips


 Windows 95 ではMS−DOSのしがらみで"A"〜"Z"でドライブを表します。 これは便利な場合もありますが、かえって使いづらい場合もありますし、 プログラムも余計に記述する必要があります。ファイルから検索 (grep)ダイアログ等では、コンボボックス等で有効なドライブの一覧を表示し、 そのうちのひとつを選択出来るようにしたいものです。そのためには、その時点 で有効なドライブ、そのドライブタイプ、ドライブのボリューム名を取得する 必要があります。
 上記の目的には GetLogicalDriveStrings, GetDriveType, GetVolumeInformation のAPIを使用します(これらの詳細はオンラインヘルプを見て下さい)。
 すべて簡単に使用できますが、困ったことに、すべての有効なドライブに対し、 GetVolumeInformation でボリューム名を取得すると2〜3秒ほどを要してしまいます。 単純な実装では、ダイアログを開いてから、ユーザがすぐにダイアログを操作 可能になりません。これでは使い勝手がいいアプリとは言えません。
 筆者はこれを回避するために、マルチスレッドを使ってバックグラウンドでボリューム 名を取得するコードも書いてもみましたが、処理時間が長いことには変わり無いので、 プログラム起動直後にダイアログをオープンされたりすると、結局ユーザは待たされる ことになります。この場合、マルチスレッドのオーバヘッドがあり、単純な実装方法 よりもかえって良くないとも言えます。

 

■ GetVolumeInformation

 そこで、『すべての有効なドライブに対し、GetVolumeInformation をコールしない』という方法で上記の問題を解決することにしました。
 GetDriveType の帰り値が DRIVE_REMOVABLE, DRIVE_CDROM の時は ボリューム名の取得を行なわないようにします。これは、FD、CD−ROMと いったドライブはボリューム名の取得にかなりの時間を要する からです。

 コードは以下の様になります。

    char drives[INFOBUF_SIZE];
    char volumeName[INFOBUF_SIZE], fileSystem[INFOBUF_SIZE];
    GetLogicalDriveStrings(INFOBUF_SIZE, drives);   //  有効なドライブの一覧を取得
    const char *ptr = drives;
    while( *ptr != '\0' ) {                         //  有効なドライブが残っている間
        uint driveType = GetDriveType(ptr);
        if( driveType != DRIVE_REMOVABLE &&         //  リムーバブルでなく、
            driveType != DRIVE_CDROM )              //  CD−ROMでもなければ
        {
            GetVolumeInformation(ptr, volumeName, INFOBUF_SIZE, 0, 0, 0, 
                                fileSystem, INFOBUF_SIZE);  //  ボリューム名を取得
            printf("drive = %s, ", ptr);
            printf("volumneName = %s, ", volumeName);
            printf("fileSystem = %s\n", fileSystem);
        }
        ptr = strchr(ptr, '\0');                    //  次のドライブ
        ASSERT(ptr);
        ptr += 1;
    }
    

 

■ SHGetFileInfo

 高津戸敦氏から、ボリュームの名前を取得するのは GetVolumeInformation ではなく SHGetFileInfo であるとのご指摘をいただきました。ヘルプをよく見てみると、関数名からは想像しづらいことに、 この関数はボリューム名を取得することができます。さらにFDやCD−ROMに対してもそんなに時間がかかりません。(^o^)
 VC++や秀丸はFDやCD−ROMの場合にボリューム名が表示されないので、以前のコードで満足していましたが、 やはりドキュメントは関係なさそうでも、一通りよーく読まなきゃだめだということですね。
 で、コードは以下のようになりました。

    char drives[INFOBUF_SIZE];
    GetLogicalDriveStrings(INFOBUF_SIZE, drives);   //  有効なドライブの一覧を取得
    const char *ptr = drives;
    while( *ptr != '\0' ) {                         //  有効なドライブが残っている間
        uint driveType = GetDriveType(ptr);
        SHFILEINFO shFileInfo;
        SHGetFileInfo(ptr, 0, &shFileInfo, sizeof(SHFILEINFO), SHGFI_DISPLAYNAME);
        printf("drive = %s, ", ptr);
        printf("volumneName = %s, ", shFileInfo.szDisplayName);
        ptr = strchr(ptr, '\0');                    //  次のドライブ
        ASSERT(ptr);
        ptr += 1;
    }

■ まとめ


次のTips 津田伸秀 のホームページに戻る。

Last Updated on 25-Oct-1996, Copyright (C) 1996 by Nobuhide Tsuda, All Right Reserved.
このホームページに関するご質問、ご要望、バグレポート等は  Nobuhide_Tsuda@jsn.justnet.or.jp  までメールをいただければ幸いです。