【问题标题】:DeviceIoControl can't eject a non-empty CDROM drive?DeviceIoControl 无法弹出非空 CDROM 驱动器?
【发布时间】:2012-09-18 08:03:49
【问题描述】:

我尝试使用DeviceIoControl函数(Win32 API函数)弹出我的CDROM驱动器,当我的CDROM驱动器没有磁盘时它可以正常工作,但是插入磁盘后,Marshal.GetLastWin32Error()返回32(ERROR_SHARING_VIOLATION : 进程无法访问该文件,因为它正在被另一个进程使用),DeviceIoControl 中传递的 driveHandle 是由CreateFile() 函数创建的。

你能帮帮我吗?我喜欢这种操作光驱相关内容的方式,我可以使用 winmm.dll 来弹出我的光驱,但我认为这种方式值得一试。

好的,代码如下:

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); 
            }
        }
    }
}

【问题讨论】:

  • 正如它所说,有些东西正在使用它。尝试关闭它打开的任何东西(防病毒和资源管理器是不错的候选者),然后重试。
  • 如果是这样,为什么其他喷射器应用程序(使用winmm.dll)可以正常工作?实际上,错误发生在调用 CreateFile 之后。我从这个论坛 StackOverFlow 的帖子中引用了弹出 CD ROM 驱动器的代码。谢谢
  • 请提供用于弹出光驱的代码,没有它很难分析。
  • 该代码似乎没有检查DeviceIoControl(返回值)是否失败。
  • @Deanna:为什么你认为代码应该检查 DeviceIoControl 的失败?那只是弹出CDROM驱动器的代码,当然要检查错误,我必须在我怀疑发生错误的行之后插入像MessageBox.Show(Marshal.GetLastWin32Error().ToString()) 这样的命令。 (上面的代码只显示了错误代码,我必须在一些微软的网站上查找该错误代码)。谢谢!

标签: c# winapi


【解决方案1】:

如错误所述,设备正被其他设备使用,但在调用 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); }
    }
}

【讨论】:

  • 谢谢你,Deanna,它就像一个魅力。你这么好心帮我,我想知道其他人在哪里?再次感谢!
  • 对不起,我刚点了勾,它变成了绿色,但我不能投票给你,它需要 15 声望,我是新来的。非常感谢您,希望您能继续帮助我和其他人。
  • 啊,等我声望够了,我就给你投一票!谢谢!
猜你喜欢
  • 2021-04-19
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
  • 2014-09-26
相关资源
最近更新 更多