「C#言語でWin32 API」の編集履歴(バックアップ)一覧はこちら
「C#言語でWin32 API」(2008/01/04 (金) 01:38:52) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
大抵の場合は、Win32 APIを使用しなくても済んでしまうのですが、たまに必要なときがあります。
**ファイルIO
.NET FrameworkのSystem.IOクラスでは、「\\.\physicaldrive0」などの物理ドライブに対するアクセスが出来ないので、CreateFile APIを使用する事になります。
参考資料は、[[Windows の ReadFile 関数を使用する>http://msdn2.microsoft.com/ja-jp/library/2d9wy99d(vs.80).aspx]]で、ポイントは、
-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 関数を使用する>http://msdn2.microsoft.com/ja-jp/library/2d9wy99d(vs.80).aspx]]の、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"
となっています