.NETのDriveInfoクラスにはCD-ROMドライブの開閉やリムーバブルメディアの取り外しを行うためのメソッドが無いので、APIを使用して実現する。 具体的にはDeviceIoControlを使用してデバイスに直接制御信号を送る。 送信する命令を変えることでドライブのトレイ開閉や、メディアがセットされているかどうかを調べることもできる。
実装
以下のコードでは、次の四つのメソッドを用意して、DriveInfoクラスの拡張メソッドとして呼び出せるようにしている。
- Eject
- メディアの取り外す、またはドライブのトレイを開く
- Load
- メディアをセットする、またはドライブのトレイを閉じる
- IsTrayOpened
- ドライブのトレイが開いているかどうかを返す
- HasMedia
- ドライブにメディアがセットされているかどうかを返す (DriveInfo.IsReadyと同等)
なお、このコードはNT系のWindowsのみを対象としていて、9x系では動作しない。
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
class Sample {
static void Main()
{
foreach (var d in DriveInfo.GetDrives()) {
Console.WriteLine("{0,-10} {1}", d.Name, d.DriveType);
}
Console.Write("テストするドライブを指定してください: ");
var drive = new DriveInfo(Console.ReadLine().TrimEnd());
if (drive.IsTrayOpened()) {
Console.WriteLine("トレイを閉じます");
drive.Load();
Console.WriteLine("トレイを閉じました");
}
else {
Console.WriteLine("トレイは閉じています");
}
Console.WriteLine("メディアをチェックします");
if (drive.HasMedia()) {
Console.WriteLine("メディアがセットされています");
}
else {
Console.WriteLine("メディアはセットされていません");
}
Console.WriteLine("トレイを開きます");
drive.Eject();
Console.WriteLine("トレイを開きました");
}
}
/// <summary>DriveInfoクラスにトレイの開閉を行う拡張メソッドを追加するクラス</summary>
static class DriveInfoEjectLoadExtensions {
/// <summary>ドライブにメディアがセットされているかどうかを返す</summary>
public static bool HasMedia(this DriveInfo drive)
{
using (var volume = Open(drive, false)) {
return IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_CHECK_VERIFY);
}
}
/// <summary>ドライブのトレイが開いているかどうかを返す</summary>
public unsafe static bool IsTrayOpened(this DriveInfo drive)
{
using (var volume = Open(drive, true)) {
/*
* http://www.eggheadcafe.com/conversation.aspx?messageid=33820121&threadid=33794406
* http://forum.sources.ru/index.php?showtopic=225102
*/
const int dataLength = 8;
byte* data = stackalloc byte[dataLength];
SCSI_PASS_THROUGH_DIRECT* sptd = stackalloc SCSI_PASS_THROUGH_DIRECT[1];
var size = Marshal.SizeOf(typeof(SCSI_PASS_THROUGH_DIRECT));
sptd[0].Length = (ushort)size;
sptd[0].PathId = 0;
sptd[0].TargetId = 0;
sptd[0].CdbLength = 12;
sptd[0].DataIn = IOControl.SCSI_IOCTL_DATA_IN;
sptd[0].DataTransferLength = dataLength;
sptd[0].TimeOutValue = 5;
sptd[0].DataBuffer = (void*)data;
sptd[0].Cdb[0] = 0xbd; // mechanism status
sptd[0].Cdb[9] = 8; // timeout value
uint bytesReturned;
if (!IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_SCSI_PASS_THROUGH_DIRECT, (void*)sptd, (uint)size, (void*)sptd, (uint)size, out bytesReturned, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
return ((data[1] & 0x10) == 0x10);
}
}
/// <summary>メディアをセットする、またはドライブのトレイを閉じる</summary>
public static void Load(this DriveInfo drive)
{
using (var volume = Open(drive, false)) {
if (!IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_LOAD_MEDIA))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>メディアの取り外す、またはドライブのトレイを開く</summary>
public static void Eject(this DriveInfo drive)
{
using (var volume = Open(drive, false)) {
/*
* http://support.microsoft.com/kb/165721/
*/
const int maxRetry = 20; // デバイスロックの最大試行回数
var locked = false;
for (var t = 0; t < maxRetry; t++) {
if (IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_LOCK_VOLUME)) {
locked = true;
break;
}
else {
System.Threading.Thread.Sleep(1000); // ロックできなければ1秒後に再試行
}
}
if (!locked)
throw new IOException("デバイスがビジー状態です");
if (!IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_DISMOUNT_VOLUME))
throw new Win32Exception(Marshal.GetLastWin32Error());
unsafe {
uint bytesReturned;
PREVENT_MEDIA_REMOVAL* inBuffer = stackalloc PREVENT_MEDIA_REMOVAL[1];
inBuffer[0].PreventMediaRemoval = 0; // FALSE
if (!IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_MEDIA_REMOVAL, (void*)inBuffer, (uint)Marshal.SizeOf(typeof(PREVENT_MEDIA_REMOVAL)), (void*)IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_EJECT_MEDIA))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
/// <summary>ドライブを開いてSafeFileHandleを取得する</summary>
private static SafeFileHandle Open(DriveInfo drive, bool accessWrite)
{
uint accessFlags;
if (drive.DriveType == DriveType.CDRom)
accessFlags = GENERIC_READ;
else if (drive.DriveType == DriveType.Removable)
accessFlags = GENERIC_READ | GENERIC_WRITE;
else
throw new NotSupportedException("リムーバブルドライブではありません");
if (accessWrite)
accessFlags |= GENERIC_WRITE;
var handle = CreateFile(string.Format(@"\\.\{0}:", drive.Name[0]),
accessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
0,
IntPtr.Zero);
if (handle == INVALID_HANDLE_VALUE)
throw new Win32Exception(Marshal.GetLastWin32Error());
return new SafeFileHandle(handle, true);
}
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(string lpFIleName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_SHARE_READ = 0x00000001;
private const uint FILE_SHARE_WRITE = 0x00000002;
private const uint OPEN_EXISTING = 3;
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
// DeviceIoControl呼び出し関連のクラス
private static class IOControl {
[DllImport("kernel32", SetLastError = true)]
public static unsafe extern bool DeviceIoControl(IntPtr hDevice,
uint dwIoControlCode,
void* lpInBuffer,
uint nInBufferSize,
void* lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
public const uint FILE_ANY_ACCESS = 0x00000000;
public const uint FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
public const uint FILE_READ_ACCESS = 0x00000001;
public const uint FILE_WRITE_ACCESS = 0x00000002;
public const byte SCSI_IOCTL_DATA_OUT = 0;
public const byte SCSI_IOCTL_DATA_IN = 1;
public const byte SCSI_IOCTL_DATA_UNSPECIFIED = 2;
public const uint METHOD_BUFFERED = 0;
public const uint METHOD_IN_DIRECT = 1;
public const uint METHOD_OUT_DIRECT = 2;
public const uint METHOD_NEITHER = 3;
public const uint FILE_DEVICE_CONTROLLER = 4;
public const uint FILE_DEVICE_FILE_SYSTEM = 9;
public const uint FILE_DEVICE_MASS_STORAGE = 45;
public static readonly uint IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER;
public static readonly uint IOCTL_SCSI_PASS_THROUGH_DIRECT = CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS);
public static readonly uint FSCTL_BASE = FILE_DEVICE_FILE_SYSTEM;
public static readonly uint FSCTL_LOCK_VOLUME = CTL_CODE(FSCTL_BASE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS);
public static readonly uint FSCTL_DISMOUNT_VOLUME = CTL_CODE(FSCTL_BASE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS);
public static readonly uint IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
public static readonly uint IOCTL_STORAGE_CHECK_VERIFY = CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS);
public static readonly uint IOCTL_STORAGE_MEDIA_REMOVAL = CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS);
public static readonly uint IOCTL_STORAGE_EJECT_MEDIA = CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS);
public static readonly uint IOCTL_STORAGE_LOAD_MEDIA = CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS);
private static uint CTL_CODE(uint t, uint f, uint m, uint a)
{
return (uint)((t << 16) | (a << 14) | (f << 2) | m);
}
public unsafe static bool IOCtl(IntPtr hDevice, uint dwIoControlCode)
{
uint bytesReturned;
return DeviceIoControl(hDevice, dwIoControlCode, (void*)IntPtr.Zero, 0, (void*)IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
}
}
[StructLayout(LayoutKind.Sequential)]
private unsafe struct SCSI_PASS_THROUGH_DIRECT {
public ushort Length;
public byte ScsiStatus;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte CdbLength;
public byte SenseInfoLength;
public byte DataIn;
public uint DataTransferLength;
public uint TimeOutValue;
public void* DataBuffer;
public uint SenseInfoOffset;
public fixed byte Cdb[16];
}
[StructLayout(LayoutKind.Sequential)]
private struct PREVENT_MEDIA_REMOVAL {
public byte PreventMediaRemoval;
}
}
Imports System
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports Microsoft.Win32.SafeHandles
Class Sample
Shared Sub Main()
For Each d As DriveInfo In DriveInfo.GetDrives()
Console.WriteLine("{0,-10} {1}", d.Name, d.DriveType)
Next
Console.Write("テストするドライブを指定してください: ")
Dim drive As New DriveInfo(Console.ReadLine().TrimEnd())
If drive.IsTrayOpened() Then
Console.WriteLine("トレイを閉じます")
drive.Load()
Console.WriteLine("トレイを閉じました")
Else
Console.WriteLine("トレイは閉じています")
End If
Console.WriteLine("メディアをチェックします")
If drive.HasMedia() Then
Console.WriteLine("メディアがセットされています")
Else
Console.WriteLine("メディアはセットされていません")
End If
Console.WriteLine("トレイを開きます")
drive.Eject()
Console.WriteLine("トレイを開きました")
End Sub
End Class
''' <summary>DriveInfoクラスにトレイの開閉を行う拡張メソッドを追加するクラス</summary>
Module DriveInfoEjectLoadExtensions
''' <summary>ドライブにメディアがセットされているかどうかを返す</summary>
<Extension()> _
Public Function HasMedia(ByVal drive As DriveInfo) As Boolean
Using volume As SafeFileHandle = Open(drive, False)
Return IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_CHECK_VERIFY)
End Using
End Function
''' <summary>ドライブのトレイが開いているかどうかを返す</summary>
<Extension()> _
Public Function IsTrayOpened(ByVal drive As DriveInfo) As Boolean
Using volume As SafeFileHandle = Open(drive, True)
'
' http://www.eggheadcafe.com/conversation.aspx?messageid=33820121&threadid=33794406
' http://forum.sources.ru/index.php?showtopic=225102
'
Const dataLength As Integer = 8
Dim sptd As New SCSI_PASS_THROUGH_DIRECT()
Dim size As Integer = Marshal.SizeOf(GetType(SCSI_PASS_THROUGH_DIRECT))
Dim bytesReturned As UInteger
Try
sptd.Length = CUShort(size)
sptd.PathId = 0
sptd.TargetId = 0
sptd.CdbLength = 12
sptd.DataIn = IOControl.SCSI_IOCTL_DATA_IN
sptd.DataTransferLength = dataLength
sptd.TimeOutValue = 5
sptd.DataBuffer = Marshal.AllocCoTaskMem(dataLength)
sptd.Cdb = New Byte(15) {}
sptd.Cdb(0) = &hBD ' mechanism status
sptd.Cdb(9) = 8 ' timeout value
If Not IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_SCSI_PASS_THROUGH_DIRECT, sptd, CUInt(size), sptd, CUInt(size), bytesReturned, IntPtr.Zero) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Return (Marshal.ReadByte(sptd.DataBuffer, 1) And &h10) = &h10
Finally
If sptd.DataBuffer <> IntPtr.Zero Then Marshal.FreeCoTaskMem(sptd.DataBuffer)
End Try
End Using
End Function
''' <summary>メディアをセットする、またはドライブのトレイを閉じる</summary>
<Extension()> _
Public Sub Load(ByVal drive As DriveInfo)
Using volume As SafeFileHandle = Open(drive, True)
If Not IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_LOAD_MEDIA) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
End Using
End Sub
''' <summary>メディアの取り外す、またはドライブのトレイを開く</summary>
<Extension()> _
Public Sub Eject(ByVal drive As DriveInfo)
Using volume As SafeFileHandle = Open(drive, True)
'
' http://support.microsoft.com/kb/165721/
'
Const maxRetry As Integer = 20 ' デバイスロックの最大試行回数
Dim locked As Boolean = False
For t As Integer = 0 To maxRetry - 1
If IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_LOCK_VOLUME) Then
locked = True
Exit For
Else
System.Threading.Thread.Sleep(1000) ' ロックできなければ1秒後に再試行
End If
Next
If Not locked Then Throw New IOException("デバイスがビジー状態です")
If Not IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_DISMOUNT_VOLUME) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Dim bytesReturned As UInteger
Dim pmr As PREVENT_MEDIA_REMOVAL
pmr.PreventMediaRemoval = 0 ' FALSE
If Not IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_MEDIA_REMOVAL, pmr, CUInt(Marshal.SizeOf(GetType(PREVENT_MEDIA_REMOVAL))), IntPtr.Zero, CUInt(0), bytesReturned, IntPtr.Zero) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
If Not IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_EJECT_MEDIA) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
End Using
End Sub
''' <summary>ドライブを開いてSafeFileHandleを取得する</summary>
Private Function Open(ByVal drive As DriveInfo, ByVal accessWrite As Boolean) As SafeFileHandle
Dim accessFlags As UInteger
If drive.DriveType = DriveType.CDRom Then
accessFlags = GENERIC_READ
Else If drive.DriveType = DriveType.Removable Then
accessFlags = GENERIC_READ Or GENERIC_WRITE
Else
Throw New NotSupportedException("リムーバブルドライブではありません")
End If
If accessWrite Then accessFlags = accessFlags Or GENERIC_WRITE
Dim handle As IntPtr = CreateFile(String.Format("\\.\{0}:", drive.Name(0)), _
accessFlags, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, _
IntPtr.Zero, _
OPEN_EXISTING, _
0, _
IntPtr.Zero)
If handle = INVALID_HANDLE_VALUE Then Throw New Win32Exception(Marshal.GetLastWin32Error())
Return New SafeFileHandle(handle, True)
End Function
<DllImport("kernel32", SetLastError := True, CharSet := CharSet.Auto)> _
Private Function CreateFile(ByVal lpFIleName As String, _
ByVal dwDesiredAccess As UInteger, _
ByVal dwShareMode As UInteger, _
ByVal lpSecurityAttributes As IntPtr, _
ByVal dwCreationDisposition As UInteger, _
ByVal dwFlagsAndAttributes As UInteger, _
ByVal hTemplateFile As IntPtr) As IntPtr
End Function
Private Const GENERIC_READ As UInteger = &h80000000UI
Private Const GENERIC_WRITE As UInteger = &h40000000UI
Private Const FILE_SHARE_READ As UInteger = &h00000001UI
Private Const FILE_SHARE_WRITE As UInteger = &h00000002UI
Private Const OPEN_EXISTING As UInteger = 3
Private ReadOnly INVALID_HANDLE_VALUE As IntPtr = New IntPtr(-1)
' DeviceIoControl呼び出し関連のクラス
Private Class IOControl
<DllImport("kernel32", SetLastError := True)> _
Public Shared Overloads Function DeviceIoControl(ByVal hDevice As IntPtr, _
ByVal dwIoControlCode As UInteger, _
ByVal lpInBuffer As IntPtr, _
ByVal nInBufferSize As UInteger, _
ByVal lpOutBuffer As IntPtr, _
ByVal nOutBufferSize As UInteger, _
<Out> ByRef lpBytesReturned As UInteger, _
ByVal lpOverlapped As IntPtr) As Boolean
End Function
<DllImport("kernel32", SetLastError := True)> _
Public Shared Overloads Function DeviceIoControl(ByVal hDevice As IntPtr, _
ByVal dwIoControlCode As UInteger, _
ByRef lpInBuffer As SCSI_PASS_THROUGH_DIRECT, _
ByVal nInBufferSize As UInteger, _
ByRef lpOutBuffer As SCSI_PASS_THROUGH_DIRECT, _
ByVal nOutBufferSize As UInteger, _
<Out> ByRef lpBytesReturned As UInteger, _
ByVal lpOverlapped As IntPtr) As Boolean
End Function
<DllImport("kernel32", SetLastError := True)> _
Public Shared Overloads Function DeviceIoControl(ByVal hDevice As IntPtr, _
ByVal dwIoControlCode As UInteger, _
ByRef lpInBuffer As PREVENT_MEDIA_REMOVAL, _
ByVal nInBufferSize As UInteger, _
ByVal lpOutBuffer As IntPtr, _
ByVal nOutBufferSize As UInteger, _
<Out> ByRef lpBytesReturned As UInteger, _
ByVal lpOverlapped As IntPtr) As Boolean
End Function
Public Const FILE_ANY_ACCESS As UInteger= &h00000000
Public Const FILE_SPECIAL_ACCESS As UInteger= FILE_ANY_ACCESS
Public Const FILE_READ_ACCESS As UInteger = &h00000001
Public Const FILE_WRITE_ACCESS As UInteger = &h00000002
Public Const SCSI_IOCTL_DATA_OUT As Byte = 0
Public Const SCSI_IOCTL_DATA_IN As Byte = 1
Public Const SCSI_IOCTL_DATA_UNSPECIFIED As Byte = 2
Public Const METHOD_BUFFERED As UInteger = 0
Public Const METHOD_IN_DIRECT As UInteger = 1
Public Const METHOD_OUT_DIRECT As UInteger = 2
Public Const METHOD_NEITHER As UInteger = 3
Public Const FILE_DEVICE_CONTROLLER As UInteger= 4
Public Const FILE_DEVICE_FILE_SYSTEM As UInteger= 9
Public Const FILE_DEVICE_MASS_STORAGE As UInteger= 45
Public Shared ReadOnly IOCTL_SCSI_BASE As UInteger = FILE_DEVICE_CONTROLLER
Public Shared ReadOnly IOCTL_SCSI_PASS_THROUGH_DIRECT As UInteger = CTL_CODE(IOCTL_SCSI_BASE, &h0405, METHOD_BUFFERED, FILE_READ_ACCESS Or FILE_WRITE_ACCESS)
Public Shared ReadOnly FSCTL_BASE As UInteger = FILE_DEVICE_FILE_SYSTEM
Public Shared ReadOnly FSCTL_LOCK_VOLUME As UInteger = CTL_CODE(FSCTL_BASE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
Public Shared ReadOnly FSCTL_DISMOUNT_VOLUME As UInteger = CTL_CODE(FSCTL_BASE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
Public Shared ReadOnly IOCTL_STORAGE_BASE As UInteger = FILE_DEVICE_MASS_STORAGE
Public Shared ReadOnly IOCTL_STORAGE_CHECK_VERIFY As UInteger = CTL_CODE(IOCTL_STORAGE_BASE, &h0200, METHOD_BUFFERED, FILE_READ_ACCESS)
Public Shared ReadOnly IOCTL_STORAGE_MEDIA_REMOVAL As UInteger = CTL_CODE(IOCTL_STORAGE_BASE, &h0201, METHOD_BUFFERED, FILE_READ_ACCESS)
Public Shared ReadOnly IOCTL_STORAGE_EJECT_MEDIA As UInteger = CTL_CODE(IOCTL_STORAGE_BASE, &h0202, METHOD_BUFFERED, FILE_READ_ACCESS)
Public Shared ReadOnly IOCTL_STORAGE_LOAD_MEDIA As UInteger = CTL_CODE(IOCTL_STORAGE_BASE, &h0203, METHOD_BUFFERED, FILE_READ_ACCESS)
Private Shared Function CTL_CODE(ByVal t As UInteger, ByVal f As UInteger, ByVal m As UInteger, ByVal a As UInteger) As UInteger
Return CUInt(t << 16 Or a << 14 Or f << 2 Or m)
End Function
Public Shared Function IOCtl(ByVal hDevice As IntPtr, ByVal dwIoControlCode As UInteger) As Boolean
Dim bytesReturned As UInteger
Return DeviceIoControl(hDevice, dwIoControlCode, IntPtr.Zero, CUInt(0), IntPtr.Zero, CUInt(0), bytesReturned, IntPtr.Zero)
End Function
End Class
<StructLayout(LayoutKind.Sequential)> _
Private Structure SCSI_PASS_THROUGH_DIRECT
Public Length As UShort
Public ScsiStatus As Byte
Public PathId As Byte
Public TargetId As Byte
Public Lun As Byte
Public CdbLength As Byte
Public SenseInfoLength As Byte
Public DataIn As Byte
Public DataTransferLength As UInteger
Public TimeOutValue As UInteger
'Public DataBuffer As Byte()
Public DataBuffer As IntPtr
Public SenseInfoOffset As UInteger
<MarshalAs(UnmanagedType.ByValArray, SizeConst := 16)> Public Cdb As Byte()
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure PREVENT_MEDIA_REMOVAL
Public PreventMediaRemoval As Byte
End Structure
End Module
動作例
Q:\に接続されている光学ディスクドライブでの例。 テストに使ったのはIODATA製ブルーレイドライブ、BRD-SH10B。
実行結果例
E:\temp>eject.exe A:\ Removable C:\ Fixed D:\ Removable E:\ Fixed F:\ Fixed Q:\ CDRom R:\ CDRom テストするドライブを指定してください: q:\ トレイを閉じます トレイを閉じました メディアをチェックします メディアがセットされています トレイを開きます トレイを開きました
D:\に接続されているUSBメモリでの例。 テストに使ったのはSandisk製のもの。 Ejectメソッドを実行すると、「ハードウェアの安全な取り外し」を行った場合と同等の動作となる。
実行結果例
E:\temp>eject.exe A:\ Removable C:\ Fixed D:\ Removable E:\ Fixed F:\ Fixed Q:\ CDRom R:\ CDRom テストするドライブを指定してください: d:\ トレイは閉じています メディアをチェックします メディアがセットされています トレイを開きます トレイを開きました