by Clinton R. Johnson - xepol@poboxes.com
Borland tends to hide the best functionality. Don't ask me why. The TMediaPlayer, as a result, is probably the most under appreciated component in the entire VCL. I've noticed that many people in the Borland newsgroups have asked how to use multiple CDroms. Well, with this example, I'll show you not just how to use multiple CDroms, but also how to find which drives are CDroms (source is listed at the bottom).
I started by writing a function called CDList. It asks the system for a list of available drives in the system(GETLOGICALDRIVES). This returns a map showing which drive letters are used. Next, I use a bitmask to determine which drives are CDroms. By calling GETDRIVETYPE with the drive letter (formatted as the root directory ie : D:\), I can determine which drives are CDroms.
Next, I use the result of my CDList function to fill a ComboBox. I ensure that each drive letter added to the ComboBox has a colon appended to it. This makes it easier to use with the TMediaPlayer component.
Finally, I add an OnChange event handler to the ComboBox. First, if the TMediaPlayer is open, I stop it and close it. Stopping the CDrom is an important step. First, its a good habit to make sure that anything you deal with is in a known state, and secondly, if the system has multiple physical CDroms, the CDrom will keep playing even if the MediaPlayer is closed. I assign the FILENAME property of the MediaPlayer to the selected line in the ComboBox, and open the MediaPlayer again. The Filename property must be the drive letter appended by a colon, an undocumented feature, although Borland has recently added this information to their FAQ.
One of the reasons most people have problems with the Win32 API is its lack of consistency. You may have noticed that I had to pass the drive as a full path to the GETDRIVETYPE system call, but I only assign the drive letter and a colon to the MediaPlayer (and thus directly to the MCI layers). It's always important to remember little details like this - it makes the difference between functional code, and non functional code (and occasionally functional code, leading to premature hair loss).
On a final note, I set the Shareable property on the TMediaPlayer to true. I consider this a good habit. It lets you share the drive with other programs. I also re-open the drive, so that I can send it text commands. I've found that the text based commands are better documented than the binary MCI calls, and at times, more functional. I would not be able to do this if I did not set the Sharable property to true.
Here is the DFM file and source code for the demo unit.
object Form1: TForm1
Left = 200
Top = 110
Width = 441
Height = 81
Caption = 'Form1'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object ComboBox1: TComboBox
Left = 272
Top = 16
Width = 145
Height = 21
Style = csDropDownList
ItemHeight = 13
TabOrder = 0
OnChange = ComboBox1Change
end
object MediaPlayer1: TMediaPlayer
Left = 12
Top = 8
Width = 253
Height = 30
DeviceType = dtCDAudio
Shareable = True
TabOrder = 1
end
end
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs,
StdCtrls, MPlayer;
type
TForm1 = class(TForm)
ComboBox1: TComboBox;
MediaPlayer1: TMediaPlayer;
procedure FormCreate(Sender: TObject);
procedure ComboBox1Change(Sender:
TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//*****************************************************************************
// Returns a string, made of all CDROM drive letters
in the system.
//*****************************************************************************
Function CDList : String;
Var
Drives
: Integer;
Loop
: Integer;
Work
: String;
begin
//*****************************************************************************
// Get a map of the drives. Bit 0= A, Bit 25=Z.
If the bit is set, the drive
// is present on the system.
//*****************************************************************************
Drives := GetLogicalDrives;
Result := '';
For Loop := 0 To 25 Do
Begin
//*****************************************************************************
// For each drive in the system, check if it is a
CDROM, if so, all the letter
// to the result string.
//*****************************************************************************
If (((1 Shl Loop) And Drives)<>0)
Then
Begin
Work := Char(65+Loop)+':\';
If (GetDriveType(PChar(Work))=DRIVE_CDROM)
Then
Begin
Result
:= Result+Char(65+Loop);
End;
End;
End;
End;
procedure TForm1.FormCreate(Sender: TObject);
Var
CDs
: String;
Loop
: Integer;
begin
//*****************************************************************************
// Get a list of CD drives.
//*****************************************************************************
CDs := CDList;
ComboBox1.Clear;
//*****************************************************************************
// Fill a combo box with a list of drives.
I append : to the drive letter
// here, to make working with the TMediaPlayer later
that much easier.
//*****************************************************************************
For Loop := 1 To Length(CDs) Do
Begin
ComboBox1.Items.Add(Copy(CDs,Loop,1)+':');
End;
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
//*****************************************************************************
// DeviceID is 0 when the device is not OPEN.
If it is open, we need to
// stop and close it. This isn't required will all
CD players (ie multi tray
// players like the NEC 4x4), but if you have multiple
physical CDs, like I
// have, then it is required.
//*****************************************************************************
If (MediaPlayer1.DeviceId<>0) Then
Begin
MediaPlayer1.Stop;
MediaPlayer1.Close;
End;
//*****************************************************************************
// Here is the magic that makes the mediaplayer use
a different drive.
//*****************************************************************************
MediaPlayer1.FileName := ComboBox1.Text;
//*****************************************************************************
// Obviously no good without openning it!
//*****************************************************************************
MediaPlayer1.Open;
end;
end.