Windows CDROM 弹出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/58670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:10:51  来源:igfitidea点击:

Windows CDROM Eject

windowswinapi

提问by kenny

Does anyone know a method to programmatically close the CD tray on Windows 2000 or higher? Open CD tray exists, but I can't seem to make it close especially under W2k.

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

I am especially looking for a method to do this from a batch file, if possible, but API calls would be OK.

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

采纳答案by DaveK

Here is an easy way using the Win32 API:

这是使用 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);
    }
}

回答by Andreas Magnusson

I kind of like to use DeviceIOControl as it gives me the possibility to eject any kind of removable drive (such as USB and flash-disks as well as CD trays). Da codez to properly eject a disk using DeviceIOControl is (just add proper error-handling):

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

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

回答by James Johnston

I noticed that Andreas Magnusson's answer didn't quite work exactly the same as Explorer's Eject button did. Specifically, the drive wasn't grayed out in Explorer using Andreas' code, but was if you used the Eject command. So I did some investigating.

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

I ran API Monitor while running the Eject command from Explorer (Windows 7 SP1 64-bit). I also found a good MSKB article 165721 titled How To Ejecting Removable Media in Windows NT/Windows 2000/Windows XP. The most interesting part of the MSKB article is quoted below:

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

  1. Call CreateFile with GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, and OPEN_EXISTING. The lpFileName parameter should be \.\X: (where X is the real drive letter). All other parameters can be zero.
  2. Lock the volume by issuing the FSCTL_LOCK_VOLUME IOCTL via DeviceIoControl. If any other application or the system is using the volume, this IOCTL fails. Once this function returns successfully, the application is guaranteed that the volume is not used by anything else in the system.
  3. Dismount the volume by issuing the FSCTL_DISMOUNT_VOLUME IOCTL. This causes the file system to remove all knowledge of the volume and to discard any internal information that it keeps regarding the volume.
  4. Make sure the media can be removed by issuing the IOCTL_STORAGE_MEDIA_REMOVAL IOCTL. Set the PreventMediaRemoval member of the PREVENT_MEDIA_REMOVAL structure to FALSE before calling this IOCTL. This stops the device from preventing the removal of the media.
  5. Eject the media with the IOCTL_STORAGE_EJECT_MEDIA IOCTL. If the device doesn't allow automatic ejection, then IOCTL_STORAGE_EJECT_MEDIA can be skipped and the user can be instructed to remove the media.
  6. Close the volume handle obtained in the first step or issue the FSCTL_UNLOCK_VOLUME IOCTL. This allows the drive to be used by other processes.
  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's answer, the MSKB article, and my API sniffing of Explorer can be summarized as follows:

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

  1. CreateFilecalled to open the volume. (All methods).
  2. DeviceIoControlcalled with FSCTL_LOCK_VOLUME. (All methods).
  3. DeviceIoControlcalled with FSCTL_DISMOUNT_VOLUME. (Andreas's and MSKB methods only. Explorer does not call this for some reason. This IOCTL seems to be what affects whether the drive is grayed out in Explorer or not. I am not sure why Explorer doesn't call this).
  4. DeviceIoControlcalled with IOCTL_STORAGE_MEDIA_REMOVALand PREVENT_MEDIA_REMOVALmember set to FALSE(MSKB and Explorer methods. This step is missing from Andreas's answer).
  5. DeviceIoControlcalled with IOCTL_STORAGE_EJECT_MEDIA(Andreas and MSKB article) or IOCTL_DISK_EJECT_MEDIA(Explorer; note this IOCTL was obsoleted and replaced with the STORAGE IOCTL. Not sure why Explorer still uses the old one).
  1. CreateFile调用打开卷。(所有方法)。
  2. DeviceIoControl用 调用FSCTL_LOCK_VOLUME。(所有方法)。
  3. DeviceIoControl用 调用FSCTL_DISMOUNT_VOLUME。(仅限 Andreas 和 MSKB 方法。资源管理器出于某种原因不会调用它。这个 IOCTL 似乎是影响驱动器在资源管理器中是否变灰的原因。我不确定为什么资源管理器不调用它)。
  4. DeviceIoControl调用IOCTL_STORAGE_MEDIA_REMOVAL并且PREVENT_MEDIA_REMOVAL成员设置为FALSE(MSKB 和 Explorer 方法。Andreas 的答案中缺少此步骤)。
  5. DeviceIoControl调用IOCTL_STORAGE_EJECT_MEDIA(Andreas 和 MSKB 文章)或IOCTL_DISK_EJECT_MEDIA(资源管理器;注意这个 IOCTL 已过时并替换为 STORAGE IOCTL。不知道为什么资源管理器仍然使用旧的)。

To conclude, I decided to follow the procedure outlined in the MSKB article, as it seemed to be the most thorough and complete procedure, backed up with an MSKB article.

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

回答by Slion

To close the drive tray do as described herebut instead of using DeviceIoControl with IOCTL_STORAGE_EJECT_MEDIA you need to call DeviceIoControl with IOCTL_STORAGE_LOAD_MEDIA.

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

回答by Dave Webb

Nircmdis a very handy freeware command line utility with various options, including opening and closing the CD tray.

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