【问题标题】:Windows CDROM EjectWindows CDROM 弹出
【发布时间】:2023-04-04 20:57:01
【问题描述】:

有人知道在 Windows 2000 或更高版本上以编程方式关闭 CD 托盘的方法吗? 存在打开的 CD 托盘,但我似乎无法将其关闭,尤其是在 W2k 下。

如果可能的话,我特别在寻找一种从批处理文件中执行此操作的方法,但 API 调用就可以了。

【问题讨论】:

    标签: windows winapi


    【解决方案1】:

    我有点喜欢使用 DeviceIOControl,因为它可以让我弹出任何类型的可移动驱动器(例如 USB 和闪存盘以及 CD 托盘)。使用 DeviceIOControl 正确弹出磁盘的代码是(只需添加正确的错误处理):

    bool ejectDisk(TCHAR driveLetter)
    {
      TCHAR tmp[10];
      _stprintf(tmp, _T("\\\\.\\%c:"), driveLetter);
      HANDLE handle = CreateFile(tmp, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
      DWORD bytes = 0;
      DeviceIoControl(handle, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &bytes, 0);
      DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &bytes, 0);
      DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &bytes, 0);
      CloseHandle(handle);
      return true;
    }
    

    【讨论】:

    • 这很好用,但请注意正确的拼写 DeviceIoControl(没有大写 O)。
    • 它是 C++。您需要添加一些错误处理,因为对CreateFileDeviceIoControl 的调用都可能失败。然后你需要从你的程序中调用这个函数。
    • 但是对于CreateFile() 的范围解析,这也将编译为 C 代码。不知道为什么需要范围解析,我知道这是一个旧答案,但也许有人可能会发表评论。另请注意IOCTL_STORAGE_LOAD_MEDIA 可用于关闭抽屉。
    • @Clifford:我想我是从一些认为必要的代码库中复制粘贴过来的。当我格式化代码时(惊奇!这不是原始代码,ASFAIR 它跨越了一个类中的多个函数并进行了错误处理)我一定错过了它。有趣的是,有人花了八年才注意到:)。顺便说一句,现在修复它。关于IOCTL_STORAGE_LOAD_MEDIA 的好提示!
    【解决方案2】:

    这是使用 Win32 API 的简单方法:

    
    [DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)]
            protected static extern int mciSendString(string lpstrCommand,StringBuilder lpstrReturnString,int uReturnLength,IntPtr hwndCallback);
    
     public void OpenCloseCD(bool Open)
     {
        if (Open)
        {
            mciSendString("set cdaudio door open", null, 0, IntPtr.Zero);
        }
        else
        {
            mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero);
        }
    }
    
    

    【讨论】:

    • 这在具有多个驱动器的系统上如何工作?我没有看到任何指定驱动器的内容。
    • @unixman 推荐的替代方案是什么?那是 DeviceIoControl 吗?
    • @jalf DeviceIOControl 有效,或者您可以尝试使用 Windows 资源管理器外壳。例如模拟点击我的电脑中驱动器的弹出菜单。
    • FYI 下面的答案是一个支持驱动器号的 DeviceIoControl 方法stackoverflow.com/a/77291/3225
    【解决方案3】:

    我注意到 Andreas Magnusson 的回答与 Explorer 的“弹出”按钮的作用并不完全相同。具体来说,在使用 Andreas 的代码的 Explorer 中,驱动器并没有灰显,但如果您使用了 Eject 命令,驱动器就会灰显。所以我做了一些调查。

    我在从资源管理器(Windows 7 SP1 64 位)运行 Eject 命令时运行了 API Monitor。我还发现了一篇很好的(现已失效的)MSKB 文章 165721,标题为 How To Ejecting Removable Media in Windows NT/Windows 2000/Windows XP。文章最有趣的部分引述如下:

    1. 使用 GENERIC_READ|GENERIC_WRITE、FILE_SHARE_READ|FILE_SHARE_WRITE 和 OPEN_EXISTING 调用 CreateFile。 lpFileName 参数应该是 \\.\X: (其中 X 是真正的驱动器号)。所有其他参数都可以为零。
    2. 通过 DeviceIoControl 发出 FSCTL_LOCK_VOLUME IOCTL 来锁定卷。如果任何其他应用程序或系统正在使用该卷,则此 IOCTL 将失败。一旦这个函数成功返回,应用程序就可以保证该卷不被系统中的任何其他东西使用。
    3. 通过发出 FSCTL_DISMOUNT_VOLUME IOCTL 卸载卷。这会导致文件系统删除有关该卷的所有信息,并丢弃它保留的有关该卷的任何内部信息。
    4. 确保可以通过发出 IOCTL_STORAGE_MEDIA_REMOVAL IOCTL 来删除媒体。在调用此 IOCTL 之前,将 PREVENT_MEDIA_REMOVAL 结构的 PreventMediaRemoval 成员设置为 FALSE。这会阻止设备阻止媒体被移除。
    5. 使用 IOCTL_STORAGE_EJECT_MEDIA IOCTL 弹出媒体。如果设备不允许自动弹出,则可以跳过 IOCTL_STORAGE_EJECT_MEDIA,并指示用户移除媒体。
    6. 关闭第一步获得的卷句柄或发出FSCTL_UNLOCK_VOLUME IOCTL。这允许驱动器被其他人使用 进程。

    Andreas 的回答,MSKB 文章,以及我对 Explorer 的 API 嗅探可以总结如下:

    1. CreateFile 调用打开卷。 (所有方法)。
    2. DeviceIoControlFSCTL_LOCK_VOLUME 调用。 (所有方法)。
    3. DeviceIoControlFSCTL_DISMOUNT_VOLUME 调用。 (仅限 Andreas 和 MSKB 方法。Explorer 由于某种原因没有调用它。这个 IOCTL 似乎会影响驱动器在 Explorer 中是否变灰。我不确定 Explorer 为什么不调用它)。
    4. DeviceIoControl 调用时将 IOCTL_STORAGE_MEDIA_REMOVALPREVENT_MEDIA_REMOVAL 成员设置为 FALSE(MSKB 和 Explorer 方法。Andreas 的答案中缺少此步骤)。
    5. DeviceIoControlIOCTL_STORAGE_EJECT_MEDIA(Andreas 和 MSKB 文章)或 IOCTL_DISK_EJECT_MEDIA(Explorer;请注意此 IOCTL 已过时并替换为 STORAGE IOCTL。不确定为什么 Explorer 仍使用旧的)调用。

    最后,我决定遵循 MSKB 文章中概述的程序,因为它似乎是最彻底和最完整的程序,并附有 MSKB 文章的支持。

    【讨论】:

    • 原发帖人在问如何关闭CD-ROM托盘,而不是弹出它。
    • @RossRidge:这就是为什么标题为“Windows CDROM Eject”的原因? 讽刺>
    • 尽管有标题,但问题很明确。 “有人知道在 Windows 2000 或更高版本上以编程方式关闭 CD 托盘的方法吗?”(强调我的)
    【解决方案4】:

    Nircmd 是一个非常方便的免费命令行实用程序,具有多种选项,包括打开和关闭 CD 托盘。

    【讨论】:

    • 仅供参考:www.nirsoft.net 被我的公司屏蔽了,我发现了这个关于该程序的信息。 spywarefiles.prevx.com/RRIDCH001610050/NIRCMD.EXE.html
    • 阅读该描述并不让我担心 - 他们似乎担心 Nircmd,因为它是一个可以做事的实用程序。 Sophos、Avast 和 ESET 在我的任何系统上都没有阻止 nircmd,无论是在家里还是在工作中。另一方面,我从未听说过 Prevx。
    【解决方案5】:

    要关闭驱动器托盘,请按照here 的说明进行操作,但不是将 DeviceIoControl 与 IOCTL_STORAGE_EJECT_MEDIA 一起使用,您需要使用 IOCTL_STORAGE_LOAD_MEDIA 调用 DeviceIoControl。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 2021-04-19
      • 1970-01-01
      • 2013-08-02
      • 1970-01-01
      • 2020-09-18
      • 2010-10-21
      相关资源
      最近更新 更多