Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi: How to programmatically eject a CD using the drive letter

Tags:

windows

delphi

I have tried this code:

uses MMSystem;

mciSendString('Set cdaudio door open wait', nil, 0, handle);

mciSendString('Set cdaudio door closed wait', nil, 0, handle);

but there was no effect. I have heard that this does not work on all systems.

I'm trying to get a drive to eject on Windows XP, and would like to specify the drive via the drive letter (necessary for systems with multiple drives).

like image 470
Arthur Avatar asked Feb 12 '26 03:02

Arthur


1 Answers

This is code using the DeviceIOControl() API function, works for me on Windows XP (compiled and tested using Delphi 5):

function DeviceIOControlHelper(ADeviceHandle: THandle;
  ADeviceIOControlCode: DWORD): boolean;
var
  BytesReturned: Cardinal;
begin
  Result := DeviceIOControl(ADeviceHandle, ADeviceIOControlCode,
    nil, 0, nil, 0, BytesReturned, nil);
end;

function SetDriveDoorOpen(ADriveLetter: char; AValue: boolean): boolean;
const
  FILE_DEVICE_FILE_SYSTEM = 9;
  FILE_ANY_ACCESS = 0;
  FILE_READ_ACCESS = 1;
  METHOD_BUFFERED = 0;
  IOCTL_STORAGE_BASE = $2D;

(*
#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
*)

//  FSCTL_LOCK_VOLUME = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6,
//                               METHOD_BUFFERED, FILE_ANY_ACCESS);
  FSCTL_LOCK_VOLUME = (FILE_DEVICE_FILE_SYSTEM shl 16)
                      or (FILE_ANY_ACCESS shl 14)
                      or (6 shl 2) or METHOD_BUFFERED;
//  FSCTL_DISMOUNT_VOLUME = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8,
//                                   METHOD_BUFFERED, FILE_ANY_ACCESS);
  FSCTL_DISMOUNT_VOLUME = (FILE_DEVICE_FILE_SYSTEM shl 16)
                          or (FILE_ANY_ACCESS shl 14)
                          or (8 shl 2) or METHOD_BUFFERED;
//  IOCTL_STORAGE_EJECT_MEDIA = CTL_CODE(IOCTL_STORAGE_BASE, 0x0202,
//                                       METHOD_BUFFERED, FILE_READ_ACCESS);
  IOCTL_STORAGE_EJECT_MEDIA = (IOCTL_STORAGE_BASE shl 16)
                              or (FILE_READ_ACCESS shl 14)
                              or ($0202 shl 2) or METHOD_BUFFERED;
//  IOCTL_STORAGE_LOAD_MEDIA = CTL_CODE(IOCTL_STORAGE_BASE, 0x0203,
//                                      METHOD_BUFFERED, FILE_READ_ACCESS);
  IOCTL_STORAGE_LOAD_MEDIA = (IOCTL_STORAGE_BASE shl 16)
                              or (FILE_READ_ACCESS shl 14)
                              or ($0203 shl 2) or METHOD_BUFFERED;
var
  DriveCmdStr: string;
  DriveHandle: THandle;
begin
  Result := FALSE;
  DriveCmdStr := Format('\\.\%s:', [ADriveLetter]);
  DriveHandle := CreateFile(PChar(DriveCmdStr), GENERIC_READ, FILE_SHARE_WRITE,
    nil, OPEN_EXISTING, 0, 0);
  if DriveHandle <> INVALID_HANDLE_VALUE then begin
    if AValue then begin
      Result := DeviceIOControlHelper(DriveHandle, FSCTL_LOCK_VOLUME)
        and DeviceIOControlHelper(DriveHandle, FSCTL_DISMOUNT_VOLUME)
        and DeviceIOControlHelper(DriveHandle, IOCTL_STORAGE_EJECT_MEDIA);
    end else
      Result := DeviceIOControlHelper(DriveHandle, IOCTL_STORAGE_LOAD_MEDIA);
    CloseHandle(DriveHandle);
  end;
end;

Error handling omitted.

like image 72
mghie Avatar answered Feb 14 '26 19:02

mghie



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!