Finding Audio cd in ALL CD-Rom drives

Hi,

Does anyone know how to look for an audio cd in ALL Available Cd-Rom drives, just not looking for the first drive. And it also has to work for SCSI Cd-Rom drives.

Another small question, what is the least resource and CPU hungry: A Timer, or a continues loop in a function?

Lot's of points so detailed explanation please,

Thanks
Take Care
Marc
hellfire052497Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

intheCommented:
Listening
0
simonetCommented:
Hello, hellfire.

Here's a function that will retur, in a TStringList, the root letter of all CD drives that contain an Audio CD:

function GetAudioCDs(DriveList : TStringList) : boolean;
var
      pDrives : pchar;
  NumDrives : cardinal;
  i : integer;
  root : string;
  //Volume Information Variables
  nVNameSer                             : PDWORD;
  drv                                   : String;
  pVolName                              : PChar;
  FSSysFlags,   maxCmpLen   : DWord;
  pFSBuf                                 : PChar;

begin
      DriveList.clear;
      GetMem(pDrives, 1024);
  GetMem(pVolName, MAX_PATH);
  GetMem(pFSBuf, MAX_PATH);
  GetMem(nVNameSer, MAX_PATH);
  try
     NumDrives := 1023;
     NumDrives := GetLogicalDriveStrings(NumDrives, pDrives);
     NumDrives := NumDrives  div 4;
     for i := 0 to NumDrives do
     begin
        Root := string(pchar(pDrives+i*4));
        if GetDriveType(pchar(Root))=DRIVE_CDROM then
        begin
                         GetVolumeInformation(PChar(drv), pVolName, MAX_PATH, nVNameSer, maxCmpLen, FSSysFlags, pFSBuf, MAX_PATH);
              if boolean(CompareText(String(pVolName), 'AudioCD')) then
                 DriveList.add(Root)
        end;
     end;
  finally
     FreeMem(pDrives);
     FreeMem(pVolName);
     FreeMem(pFSBuf);
     FreeMem(nVNameSer);
  end;
  Result := (DriveList.count>0);
end;

This is an example of how to use the function above:

procedure TFrmMain.Button22Click(Sender: TObject);
var
  ls : TStringList;
begin
  ls := TStringList.create;
  if GetAudioCDs(ls) then
     memo1.lines.assign(ls);
  ls.Free;
end;

Now, regarding the question about timers vs. loop:

Timers will consume much less CPU than a loop, but it will take up slightly more resources (exactly 1 window handle) than a loop. This is because timers don't work on a loop, they are based on messages (WM_TIMER) from Windows. So, how it works is something that is already part of the OS. Windows has its own (and believe me, efficient!) way to control these messages.

The WM_TIMER messages really take very little CPU time. What can cause a dramatic impact is using very short intervals with a lot of code (or slow code) in the OnTimer event. SO watch out for that.

Now, concerning the loop, I myself don't like them for counting time, except for very rare occasions where a timer cannot be used and a multimedia timer is out of question. What happens is:

When your application is waiting for a WM_TIMER message, the process is idle. This means that it is waiting for user input, and meanwhile the OS (Windows) can safely perform other tasks. In a loop, your application is not idle, it is performing a task inside the loop, which, if not handled carefully, can prevent user from inputing information and even prevent Windows from safely performing other tasks related to your application, and, possibly, to other apps too. If the loop is not correctly written your application will not even repaint its window, because it will be busy in the loop and not receiving windows messages (WM_xxx) from Windows. That's why it's often good practice to call Application.ProcessMessages inside certain types of loops.

Let me know if you need more info.

Yours,

Alex
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
rwilson032697Commented:
Listening
0
CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

hellfire052497Author Commented:
Hi Alex,

Thanks for the code, but some questions. You state that it returns all cd-rom drives which contain an audio cd, while using this code it does return all found cd-roms correctly. BUT it returns just the drives regardless if they contain an audiocd or are empty. If I insert an audio cd in one of the drives, and run the code it does not indicate which drive has the audio cd in it. if I remove it, the code still returns the drives, and they are empty. So is there a way to simply return a string value to the first drive that actually contains an audio cd. Something that can be used in a timer to check when a cd is inserted in a cd-rom drive?

On the Timer VS Loop question, thanks for the useful info, clarified many things for me.
0
simonetCommented:
hellfire, I'll be reviewing the code I gave you and will get back to you shortly. Meanwhile, if you're looking for CD notification messages, I suggest you download this file:

http://www.delphi-jedi.org/Jedi:API_CDEVENTS:180576690

The link above contains a link to cdevents.zip, which is a library written by Tom Deprez (a.k.a. ZifNab). It contains all sorts of information about notification messages/events for CDs (insertion, removal, etc).

Using event's, you reescan the drives (with the code I'll be repost inghere) and get the new scenario.

yours,

Alex
0
simonetCommented:
Marc,

Here's the function again. Indeed there were 2 mistakes in it, but I am reposting the whole function again. It now works as desired:

function GetAudioCDs(DriveList : TStringList) : boolean;
var
  pDrives : pchar;
  NumDrives : cardinal;
  i : integer;
  root : string;
  //Volume Information Variables
  nVNameSer  : PDWORD;
  drv      : String;
  pVolName : pChar;
  FSSysFlags,   maxCmpLen   : DWord;
  pFSBuf   : PChar;
begin
  DriveList.clear;
  GetMem(pDrives, 1024);
  GetMem(pVolName, MAX_PATH);
  GetMem(pFSBuf, MAX_PATH);
  GetMem(nVNameSer, MAX_PATH);
  try
     NumDrives := 1023;
     NumDrives := GetLogicalDriveStrings(NumDrives, pDrives);
     NumDrives := NumDrives  div 4;
     for i := 0 to NumDrives do
     begin
        Root := string(pchar(pDrives+i*4));
        if GetDriveType(pchar(Root))=DRIVE_CDROM then
        begin
           GetVolumeInformation(PChar(Root), pVolName, MAX_PATH, nVNameSer, maxCmpLen, FSSysFlags, pFSBuf, MAX_PATH);
           if (CompareText(String(pVolName), 'Audio CD')=0) then
              DriveList.add(Root)
        end;
     end;
  finally
     FreeMem(pDrives);
     FreeMem(pVolName);
     FreeMem(pFSBuf);
     FreeMem(nVNameSer);
  end;
  Result := (DriveList.count>0);
end;


Try this new function and let me know. BTW, Sorry for the mistake.

yours,

Alex
0
simonetCommented:
So, Marc, did it work?

Let me know how it went.

Alex
0
hellfire052497Author Commented:
Hi,

yes and no. When the drives are empty, the memo remains empty, but when I load an audio cd in 1 drive, both drive numbers appear. also when removing the audio cd, and rerunning the code, both drives appear again. So I guess something is still wrong???

Take Care
Marc
0
IndefreiCommented:
for i := 0 to NumDrives do
       begin
       Root := string(pchar(pDrives+i*4));
       if GetDriveType(pchar(Root))=DRIVE_CDROM then
        begin
           GetVolumeInformation(PChar(Root), pVolName, MAX_PATH,
             nVNameSer, maxCmpLen, FSSysFlags, pFSBuf, MAX_PATH);
            if (CompareText(String(pVolName), 'Audio CD')=0) then
                                   DriveList.add(Root)
         end;
        end;

perhaps it's a question of re-initialization (clearing) of e.g. pVolName within the if... end
(just a try)
Indi
0
IndefreiCommented:
Yep,
i've been curious and tested it
it works
..
if (CompareText(String(pVolName), 'Audio CD')=0) then
begin
      DriveList.add(Root +  ' Audio CD') ;
      FreeMem(pVolName);
      GetMem(pVolName, MAX_PATH);
end;
..
regards
Indi
0
hellfire052497Author Commented:
Hi,

Great it works, I have one question left. I've been looking at the cdevents you suggested, and been playing with it. However one thing I just cannot get is this.

Transforming a shortstring to Char.

I have this

Var
 Drv : String[1];
Begin
 Drv :=  Memo1.Lines.Strings[0]; // instead of G:\ it gives G
 Audiocdevents1.isaudiocd(Drv);

But the Drv needs to be Char, I have been looking through the help file, but it doesn't make clear what a char is, What I figured out is that it is only one character long, But how to format a string to it????

If you can help me here too, i'll be very grateful
Thanks
Marc
0
simonetCommented:
Here it goes:

Var
 Drv : String[3];  // This will allocate space for all 3 characters: G : \
Begin
 Drv :=  Memo1.Lines.Strings[0];

yours,

Alex
0
hellfire052497Author Commented:
Hi,

No Drv has to become Char... So String[1] is correct, just needs to become Char. How?

Thanks
Marc
0
rwilson032697Commented:
Try this:

Var
 Drv : Char;
Begin
 Drv :=  Memo1.Lines.Strings[0][1];

Cheers,

Raymond.
0
IndefreiCommented:
Well, i guess char out of strings may be not possible directly

so try this reflecting Alex's solution once more
perhaps it helps
 
var
drvChar : char;
...
>>Root := string(pchar(pDrives+i*4));
    drvchar:= char(pchar(pDrives+i*4))

and you get the formated string, i think
good luck
Indi
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.