关于winapi:Windows CDROM弹出

关于winapi:Windows CDROM弹出

Windows CDROM Eject

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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
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;
}


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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);
    }
}

我注意到Andreas Magnusson的答案与Explorer的"弹出"按钮完全不同。具体来说,该驱动器并未使用Andreas的代码在资源管理器中显示为灰色,但如果您使用的是弹出命令,则该驱动器为灰色。所以我做了一些调查。

我从资源管理器(Windows 7 SP1 64位)运行"弹出"命令时运行了API Monitor。我还发现了一篇不错的(现已失效)的MSKB文章165721,标题为"如何在Windows NT / Windows 2000 / Windows XP中弹出可移动媒体"。本文最有趣的部分引述如下:

  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • Andreas的答案,MSKB文章以及我对Explorer的API嗅探可总结如下:

  • 调用CreateFile打开卷。 (所有方法)。
  • FSCTL_LOCK_VOLUME调用的DeviceIoControl。 (所有方法)。
  • FSCTL_DISMOUNT_VOLUME调用的DeviceIoControl。 (仅适用于Andreas和MSKB方法。Explorer出于某种原因未调用此方法。此IOCTL似乎是影响驱动器在Explorer中是否变灰的原因。我不确定为什么Explorer不调用此方法。)
  • DeviceIoControlPREVENT_MEDIA_REMOVAL成员设置为FALSEDeviceIoControl调用(MSKB和Explorer方法。Andreas的答案中缺少此步骤)。
  • DeviceIoControlIOCTL_STORAGE_EJECT_MEDIA(Andreas和MSKB文章)或IOCTL_DISK_EJECT_MEDIA(Explorer;请注意,此IOCTL已过时并被STORAGE IOCTL代替。不确定为什么Explorer仍使用旧的IOCTL)来调用。
  • 最后,我决定遵循MSKB文章中概述的过程,因为它似乎是最彻底,最完整的过程,并附有MSKB文章。


    要关闭驱动器托盘,请执行此处所述的操作,而不是将DeviceIoControl与IOCTL_STORAGE_EJECT_MEDIA结合使用,而需要通过IOCTL_STORAGE_LOAD_MEDIA调用DeviceIoControl。


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


    推荐阅读