3

関数 (Win32 API 関数) を使用DeviceIoControlして CDROM ドライブを取り出してみました。CDROM ドライブにディスクがない場合は完全に機能しますが、ディスクを挿入した後、Marshal.GetLastWin32Error()返された 32 ( ERROR_SHARING_VIOLATION: プロセスはファイルが使用されているため、ファイルにアクセスできません別のプロセスによって)、渡された driveHandle は関数DeviceIoControlによって作成されCreateFile()ます。

助けていただけませんか?CD ROM 関連のものを操作するこの方法が気に入っています。winmm.dll を使用して CDROM を取り出すことができますが、この方法は試してみる価値があると思います。

OK、コードは次のとおりです。

using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.IO;

using System.Runtime.InteropServices;

namespace DVD_ejector
{

    public partial class Form1 : Form
    {
        const int OPENEXISTING = 3;
        const int IOCTL_STORAGE_EJECT_MEDIA = 2967560;
        const uint GENERICREAD = 0x80000000;
        const int INVALID_HANDLE = -1;
        public Form1()
        {
            InitializeComponent();
            DriveInfo[] drs = DriveInfo.GetDrives();
            List<DriveInfo> cdRoms = new List<DriveInfo>();
            foreach (DriveInfo dInfo in drs)
            {                
                if (dInfo.DriveType == DriveType.CDRom)
                {
                    cdRoms.Add(dInfo);                    
                }                                
            }
            comboBox1.DataSource = cdRoms;               
            comboBox1.DisplayMember = "Name";

            if (comboBox1.Items.Count > 0) comboBox1.SelectedIndex = 0;
            button1.Click += (sender, e) =>
            {
                Eject(@"\\.\" + ((DriveInfo)comboBox1.SelectedItem).Name[0]+":");
            };
        }
        [DllImport("kernel32", SetLastError=true)]
        static extern IntPtr CreateFile(string fileName, uint desiredAccess, uint shareMode, IntPtr attributes,uint creationDisposition, uint flagsAndAttribute, IntPtr fileTemplate);
        [DllImport("kernel32")]
        static extern int CloseHandle(IntPtr fileHandle);
        [DllImport("kernel32")]
        static extern bool DeviceIoControl(IntPtr driveHandle, int ctrlCode, IntPtr inBuffer, int inBufferSize, IntPtr outBuffer, int outBufferSize, ref int bytesReturned, IntPtr overlapped);
        int bytesReturned;
        private void Eject(string cdDrive)
        {
            IntPtr driveHandle = CreateFile(cdDrive, GENERICREAD, 0, IntPtr.Zero, OPENEXISTING, 0, IntPtr.Zero);
            try
            {
                if((int)driveHandle != INVALID_HANDLE) 
                   DeviceIoControl(driveHandle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                CloseHandle(driveHandle); 
            }
        }
    }
}
4

1 に答える 1

3

エラーが示すように、デバイスは別のものによって使用されていますが、CreateFileではなく呼び出しで失敗してDeviceIoControlおり、コードは失敗を正しくチェックしていません。

共有違反が発生する理由は、デバイスを排他的に開こうとしているからです。これは、ウイルス対策、エクスプローラー、検索インデクサーなど、デバイスまたはその上のファイルを開こうとした場合に失敗します。

この更新されたEject関数は、共有モードとエラー処理を修正し、正しい場所でエラーを報告するようになりました。

private void Eject(string cdDrive) {
    IntPtr driveHandle = new IntPtr(INVALID_HANDLE);
    try {
        // Open the device
        driveHandle = CreateFile(cdDrive, GENERICREAD, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, IntPtr.Zero, OPENEXISTING, 0, IntPtr.Zero);
        if ((int)driveHandle == INVALID_HANDLE) { throw new Win32Exception(); }

        // Try and eject
        bool ejected = DeviceIoControl(driveHandle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero);
        if (!ejected) { throw new Win32Exception(); }

    } catch (Exception ex) {
        MessageBox.Show(ex.Message);

    } finally {
        if ((int)driveHandle != INVALID_HANDLE) { CloseHandle(driveHandle); }
    }
}
于 2012-09-21T08:41:09.460 に答える