Visual Basic 6.0 中級講座
VB6対応

 

Visual Basic 中学校 > VB6 中級講座 >

第3回 フロッピーディスクを探せ

 

以前私はフロッピーディスクドライブは必ずAドライブであると思っていましたが、実際はそうではありません。また、最近のパソコンにはフロッピーディスクドライブを搭載していない物まであります。では、あなたが作ったプログラムでフロッピーディスクに書き込みたい場合はどうしたらよいでしょうか。

今回は、フロッピーディスクドライブの有無、ドライブ文字(Aドライブとか、Bドライブとかの区別)を取得する方法を通して、ドライブに関する情報の取得方法を説明します。

この回の要約

・ファイルシステム関連の情報を取得するには FileSystemObjectやAPIを使う。

・ドライブの一覧をAPIで取得するにはGetLogicalDriveStrings関数を使う。

・ドライブのタイプをAPIで判定するにはGetDriveType関数を使う。

・FileSystemObjectを使えば、上記と同じことをスマートに行うことができる。


この回の使えるサンプル

・フロッピーディスクドライブを取得するサンプル。→サンプルA

・ドライブが有効かどうか判断するサンプル。→サンプルB

最初に方針を書いておくと、まず、FileSystemObject(ファイルシステムオブジェクト)を使ってドライブの情報を取得する方法を説明し、次に、FileSystemObject(ファイルシステムオブジェクト)を使わないで同様の操作を行う方法を説明します。自分のつもりでは後半がメインです。

 

1.FileSystemObject(ファイルシステムオブジェクト)

 

VBは日々強化されています。FileSystemObject(ファイルシステムオブジェクト)もその一環でVBを強力にバックアップしてくれています。FileSystemObject(ファイルシステムオブジェクト)はその名の通り、ファイル・フォルダ・ドライブに関する操作を担当するオブジェクトです。これを使うとVBから簡単にファイル・フォルダ・ドライブを制御することができます。

FileSystemObject(ファイルシステムオブジェクト)はVBに標準で付属しています。ただし、VB5以前では、付属はしていません(その代わり、IE5に付属していたと思います。この辺ちょっと知識不足ですいません)。また、試用版にも付属していたと思います(これも知識不足です。すいません)。

FileSystemObject(ファイルシステムオブジェクト)を使うには、VBの[プロジェクト]メニューから「参照設定」を選び、一覧の中から Microsoft Scripting Runtime を選びます。この一覧の中にMicrosoft Scripting Runtimeが表示されていない場合はFileSystemObject(ファイルシステムオブジェクト)がインストールされていないと言うことです。

次にフォームの宣言部に Dim oFs As FileSystemObject と記述して、フォームのロードイベントに Set oFs = New FileSystemObject と記入すると良いでしょう。このようにすると以後そのフォームでは oFs の名前でFileSystemObject(ファイルシステムオブジェクト)を参照できます。参照できると言うことはコマンドボタンやぴぅちゃーぼっくすと同じように扱うことができると言うことです。目に見えないコントロールがあると思えばよいでしょう。

FileSystemObject(ファイルシステムオブジェクト)の基本的な使い方は今回は説明しませんが、まぁこれを読んでいるみなさんならすぐ分かるでしょう。

さて、このFileSystemObject(ファイルシステムオブジェクト)を使ってAドライブがフロッピーディスクドライブかどうか調べるには次のようにします。

If oFs.Drives("A").DriveType = 1 Then

    MsgBox "Aドライブは多分フロッピーディスクドライブです。"

End If

簡単に説明するとDrivesプロパティは使用可能なすべてのドライブのコレクションです。今はAドライブを調べたいのでKeyには"A"を指定します。ドライブの種類はDriveTypeプロパティで調べられます。フロッピーディスクドライブならDriveTypeプロパティは 1 をしめします。DriveType定数の一覧は次の表の通りです。この表はMSDNからコピーした物です。

定数 説明
Unknown 0 ドライブの種類を判断できません。
Removable 1 リムーバブル メディア。フロッピー ディスク ドライブ・USBメモリそのほか多くの記憶装置が含まれます。
Fixed 2 固定メディア (取り外せないメディア)。ハード ディスクが含まれます (リムーバブル ハード ディスクも含まれます)。
Remote 3 ネットワーク ドライブ。これには、ネットワーク上のあらゆる場所の共有ドライブが含まれます。
CDROM 4 CD-ROM ドライブ。読み取り専用と書き込み可能な CD-ROM ドライブの区別は行われません。
RAMDisk 5 RAM (ランダム アクセス メモリ) ブロックによるドライブ。ローカル コンピュータ上では、ディスク ドライブのように機能します。

(私のCDROMドライブ兼DVDROMドライブは 4 になりました。)

 

さて、注意する点はいくつかあります。まず、フロッピーディスクドライブの他にもDriveTypeプロパティが1である。ドライブが存在する点です。USBメモリがそうですし、私の環境では確認できないのですがMOドライブなどもDriveTypeプロパティが1になると思います。

次に、Aドライブが存在しない可能性を考慮していない点は問題です。Aドライブが存在しない環境でこの例を実行するとエラーが発生します。

このことからもう一つの問題点が浮かび上がります。つまり、いくつのドライブがあって、それらのドライブ文字は何かという情報はどうやって取得するのか?ということです。そこでこの点を説明しましょう。

FileSystemObject(ファイルシステムオブジェクト)には便利なことに指定したドライブが存在するか確認するDriveExistsメソッド  があります。このプロパティを使ってAドライブが存在するかどうかは次のようにして確認できます。

If oFs.DriveExists("A") = True Then

MsgBox "Aドライブは存在します。"

End If

従って未知のドライブにアクセスする前に確認することができるわけです。このメソッドをAからZまで26回ためせば利用可能なすべてのドライブ文字を取得することができます。その例を示します。

Dim K As Integer

Dim S As String

S = "利用可能などライブ文字の一覧" & vbCrlf

For K = 1 To 26

If oFs.DriveExists(Chr(64+k)) = True Then

    S = S & Chr(64+k) & " "

End If

Next K

MsgBox S

なんだか面倒な方法です。なお、AからZまでをループで順番に回すには文字コードが連続していることを利用してChr関数を使うと良いでしょう。

まぁともかくこれでフロッピーディスクドライブを探すことはできるわけです。MOドライブとの区別が付かないと言う問題点が残っていますがこれはしょうがないみたいです。

念のためにフロッピーディスクドライブのドライブ文字を表示するサンプルを載せておきます。

Dim K As Integer

Dim S As String

Dim FloppyCount As Integer

For K = 1 To 26

    If oFs.DriveExists(Chr(64+K)) = True Then

        If oFs.Drives(Chr(64+K)).DriveType = 1 Then

            FloppyCount = FloppyCount + 1 

            S = S & Chr(64+K) & " "

        End If

    End IF

Next K

If FloppyCount = 0 Then

    S = "使用可能なフロッピーディスクドライブはありません。"

Else

    S = FloppyCount & " 個のフロッピーディスクドライブがあります。" & vbCrlf & S

End If

MsgBox S

 

2.FileSystemObject(ファイルシステムオブジェクト)を使うべきか?

 

以上FileSystemObject(ファイルシステムオブジェクト)を使ってドライブの種類を判定する方法を説明しましたが、どうでしょうか。これだけのためにFileSystemObject(ファイルシステムオブジェクト)を使うのは大げさだと思いませんか?

FileSystemObject(ファイルシステムオブジェクト)は簡単でVBの中で安心して使えるという利点の一方、プログラムを配布するときのサイズが大きくなる。ライセンス上の問題がある。など大きな不利点を抱えています。

それでもFileSystemObject(ファイルシステムオブジェクト)は便利ですし、ライセンス上の問題も避ける方法はあるので、もし、プログラムの中でFileSystemObject(ファイルシステムオブジェクト)の出番が多いのならば使っても良いでしょう。

けれど、今回のテーマのようにフロッピーディスクドライブのドライブ文字を知りたいためだけに使うというのは・・・?

最終的には個人の判断でしょう。その判断の材料となるようにFileSystemObject(ファイルシステムオブジェクト)を使わないでドライブの種類を判別する方法をこれから説明しましょう。

 

3.Windowsは知っている

 

Windowsのマイコンピュータのアイコンをダブルクリックすると利用可能なドライブの一覧が表示されます。しかもドライブの種類に応じてアイコンも区別されます。ということはWindowsはすべてのドライブの種類を把握しているのです。従って、Windowsに直接聞くことができればFileSystemObject(ファイルシステムオブジェクト)を使わなくてもドライブの種類が分かるというわけです。

Windowsに情報を問い合わせるにはやはりAPIを使います。MSDNで DriveType と検索するとすぐにいくつかの情報が手に入ります。中にはこれから私が説明しようとしているドライブの種類を判定するサンプルまでありました(私はこのサンプルとは少し違う方法で説明します)。

ドライブの種類を取得するAPIが存在して、その名前が GetDriveTypeだと言うこともすぐに分かるでしょう。APIの名前さえ分かってしまえばこっちのものです。この関数の宣言は次のようになります。

Private Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long

引数も1つだけなのでわかりやすいですね。このAPI関数を使ってAドライブがフロッピーディスクドライブかどうか調べるには次のようにします。

If GetDriveType("A:\") = 2 Then MsgBox "多分フロッピードライブです。"

ただし、この場合でもAドライブはフロッピーディスクなのか、USBメモリなのかの区別はできません。

FileSystemObject(ファイルシステムオブジェクト)の例と似ていますが、引数が "A" ではなく "A:\" であること、フロッピーディスクドライブを表す定数が 1 ではなく 2 であることなどの違いがあります。

このGetDriveTypeの戻り値は次の表のようになります。

定数 意味
DRIVE_UNKNOWN 0 ドライブの種類が判別できません。
DRIVE_NO_ROOT_DIR 1 指定のルートディレクトリが存在しません。
DRIVE_REMOVABLE 2 ドライブからディスクを抜くことができます。
DRIVE_FIXED 3 ドライブからディスクを抜くことができません。
DRIVE_REMOTE 4 リモート (ネットワーク) ドライブです。
DRIVE_CDROM 5 CD-ROM ドライブです。
DRIVE_RAMDISK 6 RAM ディスクです。

(この表の定数の欄はC++のヘッダーファイルに記載されている物です。その他の情報はMSDNからコピーした物です。)

さて、ここでもFileSystemObject(ファイルシステムオブジェクト)の時と同じ問題が発生します。つまり、Aドライブが存在しない場合はエラーになるということです。このためGetDriveType関数を使用する前にどのドライブ文字が有効なのか調べておく必要があります。

 

4.NULLはずし

 

有効なドライブを取得するAPI関数は何でしょうか?MSDNでGetDriveTypeの説明を表示させて「同期」ボタンを押すと関連した分野のAPI関数がずらっと表示されます。名前からそれらしい関数を探すと、GetLogicalDrives,GetLogicalDriveStringsという関数が目に入ります。

このどちらでも有効なドライブの一覧を取得することができますが、今回は簡単な方のGetLogicalDriveStringsを使用します。この関数は例によってバッファへのポインタを引数に取ります。バッファへのポインタについては前回やりましたね。しかし、前回の内容を読んでいなくても大丈夫ですから安心してください。

まず、GetLogicalDriveStrings関数の宣言は次のようになります。

Private Declare Function GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long

この関数は2つの引数を取ります。2番目の引数から説明します。2番目の引数は固定長文字列型で、この引数にドライブの一覧が格納されます。第1引数には第2引数の文字数を指定します。

この関数を使用して有効なドライブの一覧を取得するのに、次のようにしてはどうでしょうか?

'これはまちがった例です

Dim Buffer As String

Dim Ret As Long

Buffer = Space(100)

Ret = GetLogicalDriveStrings(Len(Buffer), Buffer)

MsgBox Buffer

この例では目的は達成できません。有効なドライブの内最初の一つだけが表示されます。なぜでしょう。それはこの関数の仕様にあります。この関数は第2引数に有効なドライブの一覧を格納してくれるのですが、ドライブとドライブの間をNULLで区切って格納します。そして、VBの文字列型ではNULLは無効ですから、最初のドライブ名と次のドライブ名の間にあるNULLにひっかかって1つしか表示されないと言うわけです。

この問題を回避するためにはドライブ名とドライブ名の間にあるNULLを取り去るしかないでしょう。そのため有効なドライブの一覧を取得する完全なコードは次のようになります。

Dim Buffer As String

Dim Ret As Long

Dim Stock As String

Dim K As Integer

Buffer = Space(100)

Ret = GetLogicalDriveStrings(Len(Buffer), Buffer)

For K = 1 To 100

    If Mid(Buffer , K , 1) <> vbNullChar Then

        Stock = Stock & Mid(Buffer , K , 1)

    End If

Next K

MsgBox Stock

この例ではループを回して1文字ずつNULLかどうか確認しています。(NULLは文字コードが0である文字のことなのでChr(0)でひっかかります)。VB6以上ならばReplace関数を使って一撃で

Stock = Replace(Buffer , vbNullChar)

のように置き換えることもできます。これは便利ですね。

 

5.フロッピーディスクドライブ

 

これでようやく必要な情報がそろいました。最後にフロッピーディスクドライブのドライブ文字を取得するFloppy関数サンプルを示しておきます。 ただし、既に指摘したようにフロッピーディスクドライブとUSBメモリの区別はできません。

Private Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Private Declare Function
GetLogicalDriveStrings Lib "kernel32" Alias "GetLogicalDriveStringsA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long

'■Floppy
'■機能:フロッピーディスクドライブが何ドライブか調べる
'■戻り値:フロッピーディスクドライブ名。たとえば"A:\"。
'■ フロッピーディスクドライブが見つからないときは空文字を返す。

Public Function Floppy() As String

    Dim Buffer As String * 106
    Dim DriveList As String
    Dim K As Integer

    '有効なドライブの一覧を取得する。
    Call GetLogicalDriveStrings(Len(Buffer), Buffer)

    'NULLをはずす。
    For K = 1 To Len(Buffer)
        If Mid(Buffer, K, 1) <> Chr(0) Then
            DriveList = DriveList & Mid(Buffer, K, 1)
        End If
    Next K

    'それぞれのドライブのタイプをチェックする。
    For K = 1 To Len(DriveList) \ 3
        If GetDriveType(Mid(DriveList, (K - 1) * 3 + 1, 3)) = 2 Then
            Floppy = Mid(DriveList, (K - 1) * 3 + 1, 3)
            Exit Function
        End If
    Next
K

    Floppy = ""

End Function

■サンプルA

この関数を使ってフロッピーディスクドライブのドライブ文字を表示させるには次のようにするだけです。

MsgBox Floppy

つまり、この関数を記述しておけばコード内でFloppyと記述するとフロッピーディスクのドライブ文字を表すことになります。ただ、1つ注意しておきますと、この関数はフロッピーディスクドライブが2つ以上ある場合には最初の1つだけを返します。2つ以上返すようにする方法はみなさんで考えてみてください。

 

6.おまけ

 

フロッピーディスクドライブを取得する目的は達成しましたが、現実にはフロッピーディスクドライブにアクセスする前にフロッピーディスクが挿入されているかなどチェックしたいでしょう。これはFileSystemObject(ファイルシステムオブジェクト)を使うとIsReadyプロパティで簡単に調べられます。FileSystemObject(ファイルシステムオブジェクト)を使わないでこれを行う方法は現在研究中です。知っている人は教えてください。一応現在までの研究成果を発表しておきます。

次の自作関数DriveEnabledで、指定したドライブがアクセス可能か調べることができます。

Public Function DriveEnabled(DriveLetter As String) As Boolean

Dim Target As String
Dim Ret As String

Target = Left(DriveLetter, 1)
Target = Target & ":\"

On Error GoTo ErrorHandle
Ret = Dir(Target)
On Error GoTo 0

DriveEnabled = True
Exit Function

ErrorHandle:
DriveEnabled = False

End Function

■サンプルB

 

この関数を使ってAドライブがアクセス可能か調べるには次のようにします。

If DriveEnabled("A:\") = True Then

    MsgBox "アクセス可能です。"

End If

この関数の気に入らない点は、エラー処理を逆手に取っているところです。エラーに頼るプログラムは良いプログラムではありません。今は作動しても将来作動しなくなる可能性があります。

 

7.最後に

 

どうでしたか。FileSystemObject(ファイルシステムオブジェクト)とAPI、2つのアプローチ。API関数を駆使すれば、FileSystemObject(ファイルシステムオブジェクト)のすべての機能をとりこむこともきっとできるのでしょう。でもそれを実現したコードはきっとものすごい複雑な物になっていることでしょう。

私は、この手のプログラムをするときにはたいていFileSystemObject(ファイルシステムオブジェクト)を使っています。でも、本当にフロッピーディスクドライブだけ取得すればいい場合とか、ファイルをコピーだけできればいい場合とかはAPIで軽く済ませます。

考えてみれば、FileSystemObject(ファイルシステムオブジェクト)以外でも同じことはありますね。なにしろフォームや、コマンドボタンだってAPIで描画できるのですから・・・。(もっともそれをやるくらいならC++を使うべきだと思う。)

それでは、また次回。