※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

大抵の場合は、Win32 APIを使用しなくても済んでしまうのですが、たまに必要なときがあります。

ファイルIO


.NET FrameworkのSystem.IOクラスでは、「\\.\physicaldrive0」などの物理ドライブに対するアクセスが出来ないので、CreateFile APIを使用する事になります。
参考資料は、Windows の ReadFile 関数を使用するで、ポイントは、
  • DllImportでDLLとAPIを指定する
  • プロジェクトのビルドプロパティで、「アンセーフコードの許可」をチェック
となります。
ただし、MSのサンプルでは、CreateFileメソッドの返却値が0以外のときは成功としているのですが、無効なドライブを指定した時は、0xffffffffが返され、正常終了扱いとなってしまいます。

なお、「\\.\c:」の様な、論理ドライブに対する処理は、System.IO.DriveInfoクラスを使用すれば可能です。
System.IO.DriveInfo = new System.IO.DriveInfo("c");
Console.WriteLine(string.Format("{0} {1} {2}Byte(s)",
     info.ToString(), info.DriveFormat, info.TotalSize));

全てのドライブを取得するには、staticメソッドのGetDrivesを使用します。
foreach (System.IO.DriveInfo info in System.IO.DriveInfo.GetDrives())
{
    Console.WriteLine(string.Format("{0} {1} {2}Byte(s)",
         info.ToString(), info.DriveFormat, info.TotalSize));
}


MSのWindows の ReadFile 関数を使用するの、CreateFileのエラー判定処理を修正すると共に、ドライブの容量を取得するDeviceIoControl処理を追加した、C#のコンソールアプリケーションベースのコードをメモとして載せておきます。
なお、DeviceIoControl処理の詳細は、Microsoft Platform SDKのWinIoCtl.hを見るのが一番かもしれません。

class FileReader
{
    const uint GENERIC_READ = 0x80000000;
    const uint FILE_SHARE_WRITE = 0x00000002;
    // 物理ディスクを指定する場合、OPEN_EXISTINGを指定しなければいけないらしい 
    const uint OPEN_EXISTING = 3;

    System.IntPtr handle;

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
    static extern unsafe System.IntPtr CreateFile
    (
        string FileName,          // file name
        uint DesiredAccess,       // access mode
        uint ShareMode,           // share mode
        uint SecurityAttributes,  // Security Attributes
        uint CreationDisposition, // how to create
        uint FlagsAndAttributes,  // file attributes
        int hTemplateFile         // handle to template file
    );

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
    static extern unsafe bool ReadFile
    (
        System.IntPtr hFile,      // handle to file
        void* pBuffer,            // data buffer
        int NumberOfBytesToRead,  // number of bytes to read
        int* pNumberOfBytesRead,  // number of bytes read
        int Overlapped            // overlapped buffer
    );

    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
    static extern unsafe bool CloseHandle
    (
        System.IntPtr hObject // handle to object
    );


    // ドライブの容量を取得するためにDeviceIoControlを使用する
    const uint IOCTL_DISK_GET_LENGTH_INFO = 0x7405c;
    [System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
    static extern unsafe bool DeviceIoControl(
        System.IntPtr hFile,      // handle to file
        uint dwIoControlCode,     // 実行する動作の制御コード
        void* lpInBuffer,         // 入力データを供給するバッファへのポインタ
        uint nInBufferSize,       // 入力バッファのバイト単位のサイズ
        void* lpOutBuffer,        // 出力データを受け取るバッファへのポインタ
        uint nOutBufferSize,      // 出力バッファのバイト単位のサイズ
        uint* lpBytesReturned,    // バイト数を受け取る変数へのポインタ
        int Overlapped            // overlapped buffer
    );


    public bool Open(string FileName)
    {
        // open the existing file for reading       
        handle = CreateFile
        (
            FileName,
            GENERIC_READ,
            FILE_SHARE_WRITE,
            0,
            OPEN_EXISTING,
            0,
            0
        );

        // 物理ドライブ処理のエラーは、0xffffffffとなる
         if (handle != System.IntPtr.Zero
             && (uint)handle.ToInt32() != (uint)0xffffffff)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public unsafe int Read(byte[] buffer, int index, int count)
    {
        int n = 0;
        fixed (byte* p = buffer)
        {
            if (!ReadFile(handle, p + index, count, &n, 0))
            {
                return 0;
            }
        }
        return n;
    }

    public bool Close()
    {
        return CloseHandle(handle);
    }

    // ディスクの容量を取得する
    public unsafe long GetDiskSize()
    {
       long lDiskSize = 0;
        uint nBytes = sizeof(long);
        bool bResult = DeviceIoControl(handle,
            IOCTL_DISK_GET_LENGTH_INFO, null, 0,
            &lDiskSize, nBytes, &nBytes, 0);
        return lDiskSize;
    }

}

class Program
{
    static void Main(string[] args)
    {
        FileReader fr = new FileReader();
        for (int i = 0; i <= 9; i++)
        {
            string sDrivePath = string.Format(@"\\.\physicaldrive{0}", i);
            if (fr.Open(sDrivePath))
            {
                long lDiskSize = fr.GetDiskSize();
                fr.Close();
                double dSize = lDiskSize / 1000000;
                if (dSize > 1000)
                {
                    dSize /= 1000;
                    System.Console.WriteLine(
                        string.Format("Drive{0} {1,7:F1}GB", i, dSize));
                }
                else
                    System.Console.WriteLine(
                        string.Format("Drive{0} {1,7:F1}MB", i, dSize));
            }
        }
        return;
    }
}


レジストリ


.NET Frameworkでは、Microsoft.Win32.Registryからルートレジストリをアクセスできます。

たとえば、ADO.NET 2.0では、Microsoft Data Access Components(MDAC)2.8以降のバージョンが必要とされています。
MDACのバージョンは、レジストリのHKEY_LOCAL_MACHINE\Software\Microsoft\DataAccess\FullInstallVerを取得する事で確認できます。
そこで、MDACのバージョンを確認するメソッドは、
private bool ChkMDAC()
{
    string sFullVer = (string)Microsoft.Win32.Registry.GetValue
              (@"HKEY_LOCAL_MACHINE\Software\Microsoft\DataAccess", "FullInstallVer", "");
    bool bResult = false;
    if (!string.IsNullOrEmpty(sFullVer))
    {
        string[] sVer = sFullVer.Split('.');

        int iVer1 = Convert.ToInt16(sVer[0]);
        int iVer2 = Convert.ToInt16(sVer[1]);
        if (iVer1 < 2 || (iVer1 == 2 && iVer2 < 80))
            bResult = false;
        else
            bResult = true;
    }

    return bResult;
}
の様になります。

※ マイクロソフトのサポート情報では、レジストリ上のバージョン情報はあてにならない場合があるので、Component Checkerというツールを使って確認する事を推奨していますが、不特定多数のユーザ向けのソフトウェアの場合、Component Checkerツールのインストールも要求するような事は非現実的だと思います。
また、レジストリのバージョン情報を参照するときも、FullInstallVer値と、Version値の両方の値を確認するように推奨していますが、手元のマシンの場合、
FullInstallVer: "2.81.1117.0"
Version: "2.0.0"
となっています