C# 设备控制can';是否弹出非空的CDROM驱动器?

C# 设备控制can';是否弹出非空的CDROM驱动器?,c#,winapi,C#,Winapi,我尝试使用DeviceIoControl函数(Win32 API函数)弹出我的CDROM驱动器,当我的CDROM驱动器没有磁盘时,它可以正常工作,但插入磁盘后,Marshal.GetLastWin32Error()返回32(错误\u共享\u冲突:进程无法访问该文件,因为另一个进程正在使用该文件),DeviceIoControl中传递的驱动句柄是由CreateFile()函数创建的 你能帮我一下吗?我喜欢这种处理CD-ROM相关内容的方式,我可以使用winmm.dll弹出我的CD-ROM,但我认为

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

你能帮我一下吗?我喜欢这种处理CD-ROM相关内容的方式,我可以使用winmm.dll弹出我的CD-ROM,但我认为这种方式值得一试

好的,代码如下:

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); 
            }
        }
    }
}
使用系统;
使用系统组件模型;
使用系统文本;
使用System.Windows.Forms;
使用System.IO;
使用System.Runtime.InteropServices;
名称空间DVD_弹出器
{
公共部分类Form1:Form
{
常量int OPENEXISTING=3;
const int IOCTL_STORAGE_EJECT_MEDIA=2967560;
const uint GENERICREAD=0x8000000;
常量int无效_句柄=-1;
公共表格1()
{
初始化组件();
DriveInfo[]drs=DriveInfo.GetDrives();
列表光盘=新列表();
foreach(drs中的DriveInfo-dInfo)
{                
if(dInfo.DriveType==DriveType.CDRom)
{
添加光盘(dInfo);
}                                
}
comboBox1.DataSource=CDROM;
comboBox1.DisplayMember=“Name”;
如果(comboBox1.Items.Count>0)comboBox1.SelectedIndex=0;
按钮1.单击+=(发件人,e)=>
{
弹出(@“\\.\”+((DriveInfo)comboBox1.SelectedItem)。名称[0]+“:”;
};
}
[DllImport(“内核32”,SetLastError=true)]
静态外部IntPtr CreateFile(字符串文件名、uint desiredAccess、uint共享模式、IntPtr属性、uint creationDisposition、uint标志和属性、IntPtr文件模板);
[DllImport(“内核32”)]
静态外部int CloseHandle(IntPtr fileHandle);
[DllImport(“内核32”)]
静态外部布尔设备控制(IntPtr driveHandle、int ctrlCode、IntPtr inBuffer、int inBufferSize、IntPtr EXBUFFER、int EXBUFFERSIZE、ref int BYTES返回、IntPtr重叠);
返回int字节;
专用无效弹出(字符串驱动器)
{
IntPtr driveHandle=CreateFile(cdDrive,GENERICREAD,0,IntPtr.Zero,OPENEXISTING,0,IntPtr.Zero);
尝试
{
if((int)driveHandle!=无效的\u句柄)
设备控制(driveHandle、IOCTL_存储_弹出_介质、IntPtr.Zero、0、IntPtr.Zero、0、ref字节返回、IntPtr.Zero);
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
}
最后
{
闭合手柄(驱动手柄);
}
}
}
}

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

正如它所说的,有东西在使用它。尝试关闭任何打开它的东西(反病毒和资源管理器是很好的选择),然后再试一次。如果是这样,为什么要使用另一个喷射器应用程序(使用winmm.dll)可以正常工作吗?事实上,错误发生在调用CreateFile之后。我在本论坛的帖子中引用的弹出CD-ROM驱动器的代码堆栈溢出。感谢提供用于弹出CD-ROM驱动器的代码,没有它很难分析。该代码似乎没有检查
设备控制的故障(返回值)。@Deanna:为什么你认为代码应该检查DeviceIoControl的故障?这只是弹出CDROM驱动器的代码,当然为了检查错误,我必须在我怀疑错误发生的行之后插入一个命令,如MessageBox.Show(Marshal.GetLastWin32Error().ToString())。(上面的代码只显示错误代码,我必须在某些Microsoft网站上查找该错误代码).谢谢!谢谢你,迪娜,它很有魅力。你真是太好了,我想知道其他人在哪里?再次感谢!对不起,我刚刚点击了勾号,它变成了绿色,但我不能投票给你,它需要15个声誉,我是新来的。非常感谢你,希望你能继续帮助我和其他人。啊,一旦我的声誉这就够了,我会投你一票的!谢谢!