vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#

https://www.vbarchiv.net
Rubrik: OOP / Tools   |   VB-Versionen: VB5, VB601.07.02
CDPlayer - Marke Eigenbau

Wir wollen einen CDPlayer proggen - klar. Aber: Wir möchten keine externen Controls und Komponenten einsetzen - auch klar. Und: Alle wichtigen Funktionen, wie Abspielen, Pause, Stoppen, nächster Titel usw. sollen vorhanden sein - Logisch! Wie? Staun :-) Alles mit nur einer einzigen Windows-API Funktion!

Autor:  Dieter OtterBewertung:  Views:  16.986 

Wir wollen einen CDPlayer proggen - klar. Aber: Wir möchten keine externen Controls und Komponenten einsetzen - auch klar. Und: Alle wichtigen Funktionen, wie Abspielen, Pause, Stoppen, nächster Titel usw. sollen vorhanden sein - Logisch! Wie? Staun

Alles mit nur einer einzigen Windows-API Funktion!

Ja, Sie haben richtig gelesen. Mit dem Einsatz einer einzigen Windows-API Funktion lässt sich ein vollständiger CDPlayer programmieren, mit allen wichtigen Bedienfunktionen.

Apropos Bedienfunktionen: Folgende Anforderungen stellen wir an den CDPlayer:

  • Anzeige der Gesamtlänge einer Audio-CD
  • Anzeige der Anzahl vorhandener Tracks (Lieder)
  • Ermitteln der Spieldauer der einzelnen Tracks
  • Wiedergabe starten
  • Wiedergabe mit bestimmten Lied starten
  • Pause
  • Wiedergabe stoppen
  • Wechseln zum vorigen / nächsten Lied
  • Schnelles Vor- und Zurückspulen
  • CD auswerfen

Wie würden Sie jetzt vorgehen?
Wahrscheinlich würden Sie erst einmal in der "Komponenten-Kiste" der im Installationsumfang von Visual Basic enthaltenen Controls "wühlen" und nach einer Multimedia-Komponente suchen. Wahrscheinlich würden Sie hier sogar fündig werden Gemeint ist das Microsoft Multimedia Control (MCI32.OCX).

Aber es geht auch ohne Control!
Wie bereits eingangs erwähnt möchten wir doch eigentlich auf externe Controls verzichten. Und das ist in diesem Fall (CDPlayer) auch überhaupt kein Problem, denn wie so oft finden wir die entsprechenden Befehle und Funktionen in der Windows-API Referenz. Genauer gesagt handelt es sich in diesem speziellen Fall um nur eine einzige Funktion, mit der sich alle oben aufgeführten Anforderungen realisieren lassen.

Machen wir es nicht länger spannend Alle Funktionen unseres CDPlayers realisieren wir mit Hilfe der universellen mciSendString-Funktion:

' benötigte API-Deklaration, auf der der gesamte
' CD-Player aufbaut
Private Declare Function mciSendString Lib "winmm.dll" _
  Alias "mciSendStringA" ( _
  ByVal lpstrCommand As String, _
  ByVal lpstrReturnString As String, _
  ByVal uReturnLength As Long, _
  ByVal hwndCallback As Long) As Long

Gestaltung der Oberfläche unseres CDPlayers

Bevor wir uns an das Coden machen, überlegen wir uns erst einmal, wie wir unseren CDPlayer designen möchten - sprich Oberflächengestaltung ist angesagt.

Starten wir also die Visual Basic Entwicklungsumgebung und erstellen ein neues Projekt. Der Form geben wir den Namen frmPlayer. Weitere Eigenschaften der Form:

AutoRedrawTrue
BorderStyle0 - Kein
CaptionCD-Wiedergabe
Height2835
Icon Audio-CD.ico (1 KB)
ShowInTaskbarTrue
Width4935

Welche Anzeige- und Bedienelemente brauchen wir?
Das Display unserers CDPlayers
Jeder vernünftige CDPlayer hat ein Display, in welchem man Informationen zur Gesamtspielzeit, der Anzahl Titel oder auch den aktuellen Titel und die aktuelle Spielzeit des Titels ablesen kann. Für das Display verwenden wir ein ganz gewöhnliches Label-Control (Beschriftungsfeld), welches wir aus optischen Gründen jedoch in eine schwarze PictureBox legen. Plazieren Sie also zunächst ein PictureBox-Control auf die Form und erstellen darin ein Label-Control:

Eigenschaften lblDisplay:
BackStyle0 - Transparent
BorderStyle0 - Kein
FontMS Sans Serif, 18 fett
ForeColor&H00008080&
Left / Top0 / 90
Width / Height2430 / 540
Eigenschaften picDisplay:
BackColor&H00000000&
Left / Top210
Width / Height2535 / 750

Die Bedienknöpfe...
Als nächstes setzen wir alle notwendigen Bedienknöpfe auf die Form. Benötigt werden Schaltflächen für "Play", "Pause", "Stop", "voriges Lied", "Zurückspulen", "Vorwärtsspulen", "nächstes Lied" und "Eject". Für die einzelnen Funktionen verwenden wir die ganz normalen Standard-Schaltflächen (CommandButtons) ohne Caption (Beschriftung), dafür aber mit einer kleinen Grafik (Style = 1 - Grafisch). Die in unserem Beispielprojekt verwendeten Grafiken können Sie sich hier downloaden:  Buttons.zip (2 KB)

Platzieren Sie die Schaltflächen wie folgt auf der Form und geben diesen die in der Abbildung genannten Namen (cmdPlay, cmdPause, cmdStop usw.)

Bedienelemente unseres CDPlayers
Abb. Bedienelemente unseres CDPlayers

Hiermit wäre das Design schon fast abgeschlossen. Neben den Schaltflächen zur Titelwahl könnte man nun zusätzlich noch eine Combo-Listbox auf die Form setzen, über der man dann zur Laufzeit ein bestimmtes Lied auswählen kann. Die Liste enthält demnach immer die Anzahl Lieder auf der CD. Zusätzlich zeigen wir in der Liste dann noch die Spieldauer der einzelnen Tracks an.

Platzieren wir also direkt unterhalb des Display und der Schaltflächen eine ComboBox mit folgenden Eigenschaften:

Bedienteil mit ComboBoxEigenschaften:
NamecmbTracks
Style2 - Dropdown-Liste

Wir wollen aber kein eckiges Standard-Window
Eckige Standard-Fenster im grau/weißen Design sind out - unser CDPlayer soll deshalb runde Ecken mit einem Farbverlauf als Hintergrund bekommen. Deshalb haben wir anfangs auch die Eigenschaft BorderStyle auf den Wert 0 - Kein festgelegt. Die runden Ecken, sowie den Farbverlauf machen wir dann später zur Laufzeit. Hierzu bedienen wir uns folgender Tipps aus unserem Tipps & Tricks Archiv:

 Formen verformen
 Farbverlauf in Fenstern und Objekten

Wie aber soll das Fenster später vom Anwender verschoben werden können, wenn es keine Titelleiste enthält? Die Antwort liefert uns folgender Tipp:

 Verschieben eines Fensters ohne Titelleiste

Und damit Sie sich jetzt Tipparbeit sparen, haben wir die gesamten hier benötigten Tipps in ein BAS-Modul zusammengefasst, welches Sie sich jetzt downloaden und Ihrem Projekt hinzufügen sollten.

 basGUI.zip (2 KB)

Hiermit wäre das Designen der Oberfläche abgeschlossen. Zur Laufzeit bekommt unser CDPlayer dann nachfolgendes "Gesicht".

Unser CDPlayer zur Laufzeit
Sieht gar nicht schlecht aus - oder?

Halt! Wir brauchen ja noch einen Button, um das Fenster schließen zu können. Platzieren Sie also noch schnell einen CommandButton auf die Form, nennen diesen cmdExit und tragen als Caption ebenfalls Exit ein.

Code-Grundgerüst der Form

Bald geht es ans Eingemachte Zunächst fügen wir aber erst einmal den notwendigen Code und Funktionsaufrufe ein, so dass unser CDPlayer-Fenster entsprechend dargestellt und verschoben werden kann. Die Verformung unserer Form (wir wollten ja runde Ecken) findet im Form_Load Event statt. Ebenfalls rufen wir hier die Prozedur für den Farbverlauf auf. Die gewünschten Farben deklarieren wir als Konstanten im Allgemein-Teil der Form.

Option Explicit
Const ColorFrom = &HA56B39
Const ColorTo = &HF9DAB5
Private Sub Form_Load()
  ' Form verformen
  Dim rgn As Long
 
  ' Rechteckige Region mit runden Ecken
  rgn = CreateRoundRectRgn(0, 0, _
    Me.Width / Screen.TwipsPerPixelX, _
    Me.Height / Screen.TwipsPerPixelY, _
    20, 20)
 
  ' Region an ein Fenster verweisen.
  SetWindowRgn Me.hWnd, rgn, True
 
  ' Danach wird der Speicherbereich der Region
  ' freigegeben ...und fertig
  DeleteObject rgn
 
  ' Farbverlauf oben nach unten
  MakeGradient Me, ColorFrom, ColorTo, 1
End Sub

Damit der Farbverlauf auch immer schön angezeigt wird, ist es notwendig, MakeGradient ebenfalls im Form_Resize aufzurufen:

Private Sub Form_Resize()
  ' Farbverlauf neu zeichnen!
  MakeGradient Me, ColorFrom, ColorTo, 1
End Sub

Da unsere Form über keine Titelleiste verfügt, und somit auch nicht über diese verschoben werden kann, benötigen wir folgenden Code. Dieser ermöglicht es uns die Form zur Laufzeit zu verschieben, indem man auf einen freien Bereich des Fensters klickt und bei gedrückter Maustaste die Form an die gewünschte Position auf dem Desktop zieht.

' Form verschieben ermöglichen
Private Sub Form_MouseDown(Button As Integer, _
  Shift As Integer, x As Single, Y As Single)
 
  Dim lResult As Long
 
  If Button = 1 Then
    Call ReleaseCapture
    lResult = SendMessage(Me.hWnd, WM_NCLBUTTONDOWN, _
      HTCAPTION, 0&)
  End If
End Sub
Über den Exit-Button soll der CDPlayer geschlossen werden:
Private Sub cmdExit_Click()
  ' Schließen
  Unload Me
  End
End Sub

Starten Sie jetzt ruhig einmal das Projekt und testen, ob die Form wie gewünscht angezeigt wird, und ob sich die Form auch verschieben lässt.

CD-Informationen lesen und Display aktualisieren

Aber jetzt - jetzt geht es ans Eingemachte. Wir coden die CD-Funktionen

Auslesen der Audio-CD Informationen
Beim Starten unseres CDPlayers prüfen wir gleich einmal, ob sich eine Audio-CD im CDROM-Laufwerk befindet, und wenn ja, ermitteln wir alle relevanten CD-Informationen. Diese Infos speichern wir in Variablen, die wir im Allgemein-Teil der Form wie folgt deklarieren:

' benötigte API-Deklaration, auf der der gesamte
' CD-Player aufbaut
Private Declare Function mciSendString Lib "winmm.dll" _
  Alias "mciSendStringA" ( _
  ByVal lpstrCommand As String, _
  ByVal lpstrReturnString As String, _
  ByVal uReturnLength As Long, _
  ByVal hwndCallback As Long) As Long
 
' UDT für Track-Infos
Private Type TrackInfo
  nPosition As Long
  nLength As Long
End Type
 
Private UDT_Track() As TrackInfo
 
Private bCDPlay As Boolean
Private bPause As Boolean
Private iTracks As Integer
Private iTrack As Integer
Private lTotalLength As Long
 
Private Enum eShowMode
  iShowTotal = 0
  iShowTrack = 1
End Enum

Ergänzen Sie das Form_Load Event wie folgt:

Private Sub Form_Load()
  ...
 
  ' Jetzt aktuelle CD-Info auslesen
  CD_Init  
End Sub

Und hier natürlich der entsprechende Code zum Ermitteln der CD-Informationen:

' CD initialisieren
Private Sub CD_Init(Optional ByVal bClose As Boolean = True)
  Dim nResult As Long
  Dim I As Integer
 
  ' zunächst alles stoppen
  bCDPlay = False
  SendCommand "stop cdaudio"
  SendCommand "close cdaudio"
 
  ' CD-Audio öffnen und Zeitformat festlegen
  SendCommand "open cdaudio"
  SendCommand "set cdaudio time format milliseconds"
 
  ' Gesamtzeit ermitteln
  lTotalLength = SendCommand("status cdaudio length")
 
  ' Anzahl Tracks, sowie einzelne Track-Länge
  ' ermitteln (wir gehen mal von max. 100 Tracks aus)
  iTracks = 0
  cmbTracks.Clear
  cmbTracks.AddItem "(Lied auswählen)"
  cmbTracks.ListIndex = 0
 
  For I = 1 To 100
    nResult = SendCommand("status cdaudio position track " & _
      CStr(I))
 
    ' kein Track mehr verfügbar?
    If nResult = 0 Then Exit For
 
    ' Track-Info ermitteln
    iTracks = iTracks + 1
    ReDim Preserve UDT_Track(iTracks)
    With UDT_Track(I)
      .nPosition = nResult
      .nLength = SendCommand("status cdaudio length track " & _
        CStr(I))
 
      cmbTracks.AddItem "[" & Format$(I, "00") & "] " & _
        CD_FormatTime(.nLength)
    End With
  Next I
 
  ' CD-Audio schließen
  If bClose Then SendCommand "close cdaudio"
 
  ' Display aktualisieren
  Display_Show iShowTotal
End Sub

Als nächstes proggen wir den Code, um das CD-Display entsprechend zu aktualisieren. Hierbei gibt es drei unterschiedliche Anzeigen:

  1. [NO DISC], falls keine CD im Laufwerk
  2. Anzeige der Gesamttitel + Gesamtspielzeit (wenn CD nicht abgespielt wird)
  3. Anzeige des aktuellen Titels + aktuelle Abspielzeit (wenn gerade ein Track abgespielt wird)
' Display aktualisieren
Private Sub Display_Show(nMode As eShowMode)
  Dim nResult As Long
 
  With lblDisplay
    If iTracks > 0 Then
      If nMode = iShowTotal Then
        ' Gesamt-Info anzeigen
        .Caption = "[" & Format$(iTracks, "00") & "] " & _
          "<" & CD_FormatTime(lTotalLength) & ">"
      Else
        ' Track-Info anzeigen
        If bCDPlay Then
          ' bisher gespielte Zeit
          nResult = SendCommand("status cdaudio position") - _
            UDT_Track(iTrack).nPosition
          .Caption = "[" & Format$(iTrack, "00") & "] " & _
            "<" & CD_FormatTime(nResult) & ">"
        Else
          ' Track + Dauer
          .Caption = "[" & Format$(iTrack, "00") & "] " & _
            "<" & CD_FormatTime(UDT_Track(iTrack).nLength) & ">"
        End If
      End If
    Else
      ' keine CD oder keine Audio-CD
      .Caption = "[NO DISC]"
    End If
  End With
 
  ' ComboBox aktualisieren
  cmbTracks.Tag = "NoAction"
  If iTracks > 0 And bCDPlay Then
    cmbTracks.ListIndex = iTrack
  Else
    cmbTracks.ListIndex = 0
  End If
  cmbTracks.Tag = ""
 
  ' Schaltflächen aktualisieren
  cmdPlay.Enabled = ((iTracks > 0) And (Not bCDPlay Or bPause))
  cmdPause.Enabled = (iTracks > 0 And bCDPlay And Not bPause)
  cmdStop.Enabled = (iTracks > 0 And bCDPlay)
  cmdPrev.Enabled = (iTracks > 0 And iTrack > 1)
  cmdRew.Enabled = (iTracks > 0 And bCDPlay)
  cmdFwd.Enabled = (iTracks > 0 And bCDPlay)
  cmdNext.Enabled = (iTracks > 0 And iTrack < iTracks)
  cmdEject.Enabled = True
End Sub

Wie Sie sehen nutzen wir hier auch gleich die Möglichkeit, die Bedienschaltflächen entsprechend der gerade laufenden Aktion zu aktualisieren. So lässt sich z.B. der "Play"-Knopf nur dann anwählen, wenn eine CD im Laufwerk liegt und kein Abspielvorgang gestartet ist.

Die mciSendString-Funktion liefert uns alle Zeitangaben in Millisekunden. Im Display möchten wir aber nicht Millisekunden stehen haben, sondern Minuten:Sekunden (mm:ss). Also müssen wir die Millisekunden-Angaben entsprechend umrechnen und formatieren:

' Millisekunden nach mm:ss umrechnen
Private Function CD_FormatTime(ByVal lMSec As Long) As String
  Dim iMin As Integer
  Dim iSec As Integer
 
  iSec = Int(lMSec / 1000)
  iMin = Int(iSec / 60)
  iSec = iSec - (iMin * 60)
 
  CD_FormatTime = Format$(iMin, "00") & ":" & Format$(iSec, "00")
End Function

Die Funktion SendCommand ist nur eine Hilfsfunktion, über der wir ein Kommando an die mciSendString API-Funktion schicken und das Ergebnis im Funktionsrückgabewert zurückbekommen:

' MCI-Kommando senden
Private Function SendCommand(ByVal sCommand As String) _
  As Long
 
  Dim nResult As Long
  Dim sReturn As String
 
  sReturn = Space$(256)
  nResult = mciSendString(sCommand, sReturn, _
    Len(sReturn), 0&)
 
  SendCommand = Val(sReturn)
End Function

Legen Sie eine Audio-CD in das CDROM-Laufwerk und starten anschließend das Projekt. Das Display sollte nun die Anzahl Tracks, sowie die Gesamtspielzeit der CD anzeigen. Weiterhin ist die Combo-Listbox (cmbTracks) mit den Zeit-Informationen der einzelnen Tracks gefüllt.

Fehlen jetzt nur noch die Abspiel-Funktionen. Mehr dazu gleich.

Implementierung der CD-Funktionen

Bevor wir uns den einzelnen Abspiel-Funktionen widmen, überlegen wir noch kurz: Das Display soll ja ständig den aktuellen Status anzeigen. Also entweder [No Disc] oder eben die entsprechenden CD-Informationen. Wird ein Track gerade abgespielt, soll im Display die aktuelle Spieldauer angezeigt werden. Demnach brauchen wir noch einen Timer, mit dem wir in kurzen Zeitabständen die Aktivitäten des CDROM-Laufwerks prüfen.

Platzieren Sie also noch ein Timer-Control auf die Form und setzen die Eigenschaft Interval auf den Wert 500 (Millisekunden). Immer wenn das Timer_Event ausgelöst wird, fragen wir den aktuellen CD-Status ab:

Private Sub Timer1_Timer()
  ' aktuellen Track ermitteln
  iTrack = SendCommand("status cdaudio current track")
 
  ' keine CD eingelegt
  If iTracks = 0 Or SendCommand("status cdaudio length") = 0 Then
    CD_Init
  Else
    ' aktuellen Track ermitteln
    If bCDPlay Then
      Display_Show iShowTrack
    Else
      Display_Show iShowTotal
    End If
  End If
End Sub

Abspielen, Pause und Stoppen

Wie bereits eingangs unseres Workshops erwähnt, lassen sich alle CD-Funktionen mit nur einer einzigen API-Funktion realisieren. Hier der entsprechende Code:
Private Sub cmdPlay_Click()
  ' Wiedergabe starten
  picDisplay.SetFocus
  If iTrack < 1 Then iTrack = 1
  SendCommand "open cdaudio"
  SendCommand "set cdaudio time format milliseconds"
  SendCommand "play cdaudio"
  bCDPlay = True
  bPause = False
  Timer1_Timer
End Sub
Private Sub cmdPause_Click()
  ' Pause
  picDisplay.SetFocus
  SendCommand "stop cdaudio"
  bPause = True
  Timer1_Timer
End Sub
Private Sub cmdStop_Click()
  ' Wiedergabe stoppen
  picDisplay.SetFocus
  SendCommand "stop cdaudio"
  SendCommand "close cdaudio"
  bCDPlay = False
  bPause = False
  iTrack = 1
  Timer1_Timer
End Sub

Titelwechsel und schnelles Vor-/Zurückspulen

Private Sub cmdNext_Click()
  ' nächstes Lied
  picDisplay.SetFocus
  iTrack = iTrack + 1
  SendCommand "play cdaudio from " & UDT_Track(iTrack).nPosition
  bCDPlay = True: bPause = False
  Timer1_Timer
End Sub
Private Sub cmdPrev_Click()
  ' voriges Lied
  picDisplay.SetFocus
  iTrack = iTrack - 1
  SendCommand "play cdaudio from " & UDT_Track(iTrack).nPosition
  bCDPlay = True: bPause = False
  Timer1_Timer
End Sub
Private Sub cmdRew_Click()
  ' Zurückspulen
  Dim nPos As Long
 
  ' 3 Sekunden zurück
  picDisplay.SetFocus
  nPos = SendCommand("status cdaudio position") - 3000
  If nPos < 0 Then nPos = 0
  SendCommand "play cdaudio from " & nPos
  Timer1_Timer
End Sub
Private Sub cmdFwd_Click()
  ' Vorspulen
  Dim nPos As Long
 
  ' 3 Sekunden vor
  picDisplay.SetFocus
  nPos = SendCommand("status cdaudio position") + 3000
  SendCommand "play cdaudio from " & nPos
  Timer1_Timer
End Sub

CD auswerfen (CDROM-Laufwerk öffnen)

Private Sub cmdEject_Click()
  ' CD auswerfen
  cmdStop.Value = True
  SendCommand "set cdaudio door open"
End Sub

Titel-Direktwahl

Fehlt jetzt nur noch die Direktwahl eines Titels aus der ComboBox-Liste:

Private Sub cmbTracks_Click()
  ' Track manuell auswählen und starten
  With cmbTracks
    If .Tag <> "NoAction" And .ListIndex > 0 Then
      iTrack = .ListIndex
 
      If Not bCDPlay Then
        SendCommand "open cdaudio"
        SendCommand "set cdaudio time format milliseconds"
      End If
 
      SendCommand "play cdaudio from " & _
        UDT_Track(iTrack).nPosition
      bCDPlay = True: bPause = False
      Timer1_Timer
    End If
  End With
End Sub

CDPlayer-Fenster schließen

Wird unser CDPlayer beendet, d.h. das Fenster geschlossen, stoppen wir eine evtl. laufende CD-Wiedergabe und schließen den MCI-Device:

Private Sub Form_Unload(Cancel As Integer)
  ' alles stoppen
  bCDPlay = False
  SendCommand "stop cdaudio"
  SendCommand "close cdaudio"
End Sub

Zusammenfassung

Mit Hilfe unseres Workshops "CDPlayer - Marke Eigenbau" haben Sie jetzt nicht nur erfahren, wie sich mit Hilfe der API-Funktion mciSendString die Abspielfunktionen eines CDPlayers realisieren lassen, sondern auch, wie man eine Oberfläche designt und in welchen Schritten man bei der Programmierung eines solchen Projekts vorgeht.

Hier noch mal eine kurze Zusammenfassung der mciSendString-Kommandos:

AktionCommand
Device öffnenopen cdaudio
Zeitformat festlegenset cdaudio time format milliseconds
Gesamtspielzeitstatus cdaudio length
Dauer eines einzelnen Tracksstatus cdaudio length track #no
aktueller Trackstatus cdaudio current track
aktuelle Positionstatus cdaudio position
Wiedergabe startenplay cdaudio
Abspielen ab bestimmter Positionplay cdaudio from #pos
Wiedergabe stoppenstop cdaudio
Device schließenclose cdaudio

Und nun viel Spaß mit Ihrem neuen CDPlayer



Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
 
Copyright ©2000-2024 vb@rchiv Dieter OtterAlle Rechte vorbehalten.


Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.