/* 使用可能なディスクの一覧を表示するプログラム GetVolumeInformationよりSHGetFileInfoを使用したほうが、 光学メディアへのアクセスが速いがボリュームシリアル番号は取れない。 フラグの値はwinbase.hで定義されている。 #define FS_CASE_IS_PRESERVED ファイル名大文字小文字を区別して保存 #define FS_CASE_SENSITIVE ファイル名大文字小文字を区別して参照 #define FS_UNICODE_STORED_ON_DISK ファイル名はUNICODEをサポート #define FS_PERSISTENT_ACLS ファイルシステムはACLを保持している #define FS_VOL_IS_COMPRESSED ファイルシステムは圧縮されている #define FS_FILE_COMPRESSION ファイルシステムは圧縮可能である #define FS_FILE_ENCRYPTION ファイルシステムは暗号化をサポート ボリュームシリアル番号はフォーマットの度に変化する。 フォーマット時の日付と時刻が関係しているらしい。 ネットワークドライブは共有している全てで同じになる。 Windows95/98ではネットワークドライブのシリアル番号は取れない。 GetDriveTypeの戻り値もwinbase.hにある。 #define DRIVE_UNKNOWN 0 タイプを取得できないエラー #define DRIVE_NO_ROOT_DIR 1 おそらくパラメーターエラー #define DRIVE_REMOVABLE 2 #define DRIVE_FIXED 3 #define DRIVE_REMOTE 4 #define DRIVE_CDROM 5 #define DRIVE_RAMDISK 6 なおDVD-R/RWはCDROMタイプ、DVD-RAMはREMOVABLE、USB-HDDはFIXED 光学ドライブやFDDはメディアが刺さっていなければ フラグとボリューム名を取れず、環境によってはシステムアラートが出る。 したがってSetErrorModeでアラートを抑止してから、 GetDiskFreeSpaceEx(95OSR2以上)を実行して ERROR_NOT_READY(21)が返ってくればメディアが無いことをチェックできる。 ボリュームラベルの制限(MDNより) ボリューム ラベルは、NTFSの場合は半角32文字以内、 FAT場合は半角11文字以内で指定できます。 ボリュームラベルにスペースは使えますが、タブ文字は使えません。 FAT ボリューム ラベルには、次の文字を使わないでください。 * ? / \ | . , ; : + = [ ] < > " この制限は NTFS ボリュームには適用されません。 FATの場合、小文字で指定しても大文字で格納されます。 NTFSは変換されず、大文字と小文字がそのまま表示されます。 ドライブ容量を表現するULARGE_INTEGERは整数ではなく構造体で、 直接比較や代入は出来ない。構造体はwtypes.hで定義されている。 const ULARGE_INTEGER ulargezero = { (ULONGLONG)0 }; ※ドライブタイプやフラグなどの定義はOSの機能拡張により 変動し、SDKのバージョンアップで追加される可能性がある。 ボリュームラベルやファイルシステム名の長さの規定も同様。 ディスクサイズはバイト単位だと64ビットでの計算が必要だが それを文字列で表現すると以下の計算により最大20桁 ruby -e "p (Math.log10(0xffffffffffffffff) + 1.0).floor" */ #include #include #include #include #include #include std::string strsyserr(int n, const char *desc = ""); std::string getvolumeinfo(char drive); const char *getdrivetype(char drive); std::string sizestr(ULARGE_INTEGER v); int main(int argc, char *argv[]) { try { const max = (sizeof DWORD) * 8; DWORD map = GetLogicalDrives(); if (map == (DWORD)0) { throw std::runtime_error(strsyserr(GetLastError())); } for (int i = 0; i < max; i++) { if (map & (DWORD)(1 << i)) { char drive = (char)('A' + i); std::cout << getvolumeinfo(drive) << std::endl; } } } catch (std::exception &e) { std::cerr << e.what() << std::endl; exit(-1); } exit(0); return 0; } std::string getvolumeinfo(char drive) { class errmode { public: UINT keep; errmode(UINT mode) { keep = SetErrorMode(mode); } ~errmode() { SetErrorMode(keep); } } keep(SEM_FAILCRITICALERRORS); char dname[3]; char rname[4]; char lname[MAX_PATH]; char fname[MAX_PATH]; sprintf(dname, "%c:", drive); const char *dtype = getdrivetype(drive); const ULARGE_INTEGER ulargezero = { (ULONGLONG)0 }; DWORD serial, comlen, fflags; sprintf(rname, "%c:\\", drive); ULARGE_INTEGER avail, total, tfree; if (GetDiskFreeSpaceEx(rname, &avail, &total, &tfree) == 0) { DWORD e = GetLastError(); if (e != ERROR_NOT_READY) { throw std::runtime_error(strsyserr(e, dname)); } else { /* メディアの入っていないリムーバブルとみなす */ serial = comlen = fflags = (DWORD)0; avail = total = tfree = ulargezero; // 定数からキャストできない lname[0] = fname[0] = '\0'; } } else { if (GetVolumeInformation((LPCTSTR)rname, (LPTSTR)lname, MAX_PATH, &serial, &comlen, &fflags, (LPTSTR)fname, MAX_PATH) != TRUE) { throw std::runtime_error(strsyserr(GetLastError(), dname)); } } /* NTFSの場合ラベルの文字の制約はタブだけなので 意図的に一番最後にボリュームラベルを配置している */ return (boost::format("%c:%08X:%s:%s:%s/%s@%s") % drive % serial % dtype % fname % sizestr(avail) % sizestr(total) % lname).str(); } const char *getdrivetype(char drive) { char rname[4]; sprintf(rname, "%c:\\", drive); switch (UINT dtype = GetDriveType(rname)) { case DRIVE_UNKNOWN: // タイプを取得できないエラー return "UNKNOWN"; case DRIVE_NO_ROOT_DIR: // おそらくパラメーターエラー return "NOROOT"; case DRIVE_REMOVABLE: return "REMOVABLE"; case DRIVE_FIXED: return "FIXED"; case DRIVE_REMOTE: return "REMOTE"; case DRIVE_CDROM: return "CDROM"; case DRIVE_RAMDISK: return "RAMDISK"; default: return "UNDEFINE"; } } std::string sizestr(ULARGE_INTEGER v) { char buff[20 + 1]; // floor(log10(0xffffffffffffffff))が20 sprintf(buff, "%I64d", v.QuadPart); return std::string(buff); } std::string strsyserr(int n, const char *desc) { std::string mss; LPVOID buf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, n, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL); mss = (LPCTSTR)buf; LocalFree(buf); return *desc ? std::string(desc) + ":" + mss : mss; }