Buchempfehlung
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Umfassend, aber leicht verständlich führt dieses Buch in die Programmierung von ATMEL AVR Mikrocontrollern ein. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Code-Beispiel

Code-Beispiele » Multimedia

Winamp General Purpose Plugin

Lizenz:Erster Autor:Letzte Bearbeitung:
GPLMitgliedgrindstone 06.05.2015

General Purpose Plugin für Winamp

Und es geht doch!Ein Winamp-Plugin, in freeBasic geschrieben!
Dieses kleine Beispiel kann nichts (zumindest nichts sinnvolles), außer zu zeigen, daß es da ist und daß es funktioniert. Es wurde erstellt mit freeBasic 0.24.0 und FbEdit 1.0.7.6c und getestet mit den Winamp-Versionen 2.80 und 5.63 unter Windows XP. Es soll als Basis für eigene Entwicklungen dienen, darum habe ich es ausführlich kommentiert und mich dabei bemüht, deutlich zu machen, wie so ein Plugin funktioniert.
Das Plugin wird als als dll kompiliert und in den Plugin- Ordner vom Winamp kopiert. Der Name des Plugins muß mit gen_ beginnen, damit Winamp es erkennt.
Als Informationsquelle für eigene Entwicklungen sei hier auf das Winamp SDK verwiesen (zugegeben: schwere Kost, besonders für Einsteiger), zu finden unter
Externer Link!http://download.nullsoft.com/winamp/plugin-dev/WA5.55_SDK.exe
Hier ist insbesondere die Datei wa_ipc.h unverzichtbar, zu finden im Ordner Winamp SDK\Winamp, in der alle Winampfunktionen, die per "SendMessage" angesprochen werden können, ausführlich erklärt sind (wenn auch auf englisch).

The same (?) :-] in english:

General purpose plugin for Winamp

After all it works! A Winamp plugin, written in FreeBASIC!
This little example can do nothing (at least nothing useful) except demonstrating that it exists and that it works. It was created with freeBasic 0.24.0 and FbEdit 1.0.7.6c and tested with the Winamp versions 2.80 and 5.63 running under Windows XP. It shall be the base for own developments, and for that I have commented it detailed and was endeavoured to explain how such a plugin works.
The plugin has to be compiled as dll and copied into the plugin - directory of Winamp. The name of the plugin has to begin with gen_ to be recognized by Winamp.
As information source for own developments it shall be made reference to the Externer Link!Winamp SDK (I grant: hard bread, particularly for beginners).
Especially the file "Winamp SDK\Winamp\wa_ipc.h" is indispensable, where all Winamp functions which can be affected by "SendMessage", are described in detail.

(The english commented source code can be found further below)

#Include Once "windows.bi" 'ermöglicht Zugriff auf die Windows-API-Funktionen

Declare Function finit() As Integer
Declare Sub fconfig
Declare Sub fquit
Declare Function PluginProc(hwnd As HWND, message As UInteger, wparam As Integer, lparam As Integer) As LRESULT
Declare Sub PluginThread(parameter as Any Ptr)

'Über diese UDT kommuniziert Winamp mit dem Plugin. Der Name der UDT ist frei wählbar,
' ebenso die Namen der Variablen. Die Reihenfolge der Variablen innerhalb des UDT sowie
' deren Datentypen sind hingegen von Winamp vorgegeben und dürfen NICHT geändert werden.
Type winampGeneralPurposePlugin
  version As Integer        'enthält die Version der Plugin-Struktur
  description As Any Ptr    'enthält den Pointer auf den Namen des Plugins
  init As Any Ptr           'enthält den Pointer auf die Funktion "finit()"
  config As Any Ptr         'enthält den Pointer auf die Sub "fconfig"
  quit As Any Ptr           'enthält den Pointer auf die Sub "fquit"
  hwndParent As HWND        'enthält das Handle des Winamp-Hauptfensters. Wird von Winamp gesetzt
  hDllInstance As HINSTANCE 'enthält das Instanzhandle der Plugin-dll. Wird von Winamp gesetzt
End Type

Dim Shared As winampGeneralPurposePlugin plugin 'Über diese Variable kommuniziert Winamp mit
                                                ' dem Plugin. Der Name der Variable ist frei
                                                ' wählbar
Dim Shared As WNDPROC OldProc 'Pointer auf die ursprüngliche Winampprozedur
Dim Shared As Any Ptr th      'Pointer auf den Plugin-Thread

'Die Kommunikationsvariable wird initialisiert
With plugin
  .version = &h10 'dieser Wert darf nicht verändert werden
  .description = StrPtr("Mein erstes Plugin") 'Name, wie er in der Pluginliste angezeigt wird
  .init = ProcPtr(finit)     'Pointer auf die Funktion "finit()"
  .config = ProcPtr(fconfig) 'Pointer auf die Sub "fconfig"
  .quit = ProcPtr(fquit)     'Pointer auf die Sub "fquit"
  .hwndParent = 0            'Handle des Winamp-Hauptfensters. Wird von Winamp gesetzt
  .hDllInstance = 0          'Instanzhandle der Plugin-dll. Wird von Winamp gesetzt
End With

'Nach dem Laden des Plugins ruft Winamp diese Funktion auf, die den Pointer auf die
' Kommunikationsvariable zurückgibt. Der Name der Funktion darf nicht geändert werden.
Extern "C"

Function winampGetGeneralPurposePlugin() As winampGeneralPurposePlugin Ptr Export
    Return @plugin
End Function

End Extern

Function finit() As Integer Export

    'Diese Funktion wird von Winamp nach dem Laden des Plugins aufgerufen. Der Name der
    ' Funktion ist frei wählbar, der Pointer auf diese Funktion wird in der Kommunikations-
    ' variablen übergeben. Hier kann das Plugin alles erledigen, was für seinen Betrieb nötig
    ' ist. Als Beispiel meldet es sich mit der Nachricht, daß es erfolgreich gestartet wurde.
    MessageBox(plugin.hwndParent, "Die 'Init'-Funktion wurde aufgerufen. Das Plugin wurde erfolgreich geladen!", "", MB_OK)

  '****************************************************************************************
  'Von Winamp aus wird die Init - Funktion nur einmal beim Start aufgerufen. Soll das Plugin
  ' periodisch irgendwelche Aktionen ausführen, gibt es dafür zwei Möglichkeiten.

  ' Möglchkeit 1:
  ' Die Fensterprozedur des Hauptfensters von Winamp wird auf eine Prozedur des Plugins
  ' umgeleitet, hier auf die Funktion "PluginProc" (Name frei wählbar). Der Pointer auf die
  ' ursprüngliche Fensterprozedur wird in der Variable "OldProc" gespeichert und das
  ' Programm nach Beendigung von "PluginProc" dort fortgesetzt. Die Zeit zwischen zwei
  ' Durchläufen hängt davon ab, womit Winamp sonst noch beschäftigt ist und schwankt sehr
  ' stark von unter 100µs bis über 300ms, was zu Problemen führen kann, denn Winamp wartet
  ' mit dem erneuten Aufruf von "PluginProc" nicht, bis deren vorheriger Durchlauf beendet
  ' ist (siehe Beispiel).
    OldProc = SetWindowLong(plugin.hwndParent, GWL_WNDPROC, @PluginProc)
    Sleep 10, 1 'der API Zeit geben, die Aktion auszuführen

    ' Möglichkeit 2:
    ' Die Prozedur des Plugins wird in einem eigenen Thread gestartet, d.h. sie läuft parallel
    ' zum Hauptprogramm in einer Endlosschleife. Es können auch mehrere Threads gleichzeitig
    ' gestartet werden. Aber Achtung: ein schlecht programmierter Thread ist ein echter
    ' Ressourcenfresser!
    th = ThreadCreate(@PluginThread)
  '****************************************************************************************

  Return 0
End Function

Sub fconfig

  'Diese Sub wird aufgerufen, wenn im Einstellungsmenü von Winamp unter 'Plugins/Allgemein'
  ' 'Mein erstes Plugin' ausgewählt und auf 'konfigurieren' geklickt wird

  MessageBox(plugin.hwndParent, "Hier wird das Plugin konfiguriert", "", MB_OK)

End Sub

Sub fquit

  'Diese Sub wird beim Beenden von Winamp aufgerufen. Wer ganz sauber programmieren will,
  ' kann hier einen eventuell gestarteten Thread ordnungsgemäß beenden. Normalerweise
  ' übernimmt jedoch Winamp diese Aufgabe.

  MessageBox(0, ">Mein erstes Plugin< sagt 'Auf Wiedersehen'", "", MB_OK)

End Sub

Function PluginProc(hwnd As HWND, message As UInteger, wparam As Integer, lparam As Integer) As LRESULT

    'Beispiel für eine periodisch wiederkehrende Aktion. Die Funktion öffnet und schließt
    ' in einem Rhythmus von 1 Sekunde das Equalizerfenster

    Static As Integer busy = 0
    Static As String zeit

    'Wenn 'busy' gesetzt ( <> 0 )ist, gibt die Funktion die Kontrolle sofort wieder an das
    ' Hauptprogramm zurück. Das ist, wie weiter oben beschrieben, notwendig, wenn wie hier
    ' die Ausführungszeit der Funktion länger ist als die Zeit zwischen zwei Aufrufen. Ohne
    ' diese Schutzmaßnahme würde Winamp sofort nach dem Start des Plugins abstürzen (Solche
    ' Fehler können einen Programmierer in den Wahnsinn treiben).
    If busy = 0 Then

        busy = 1 'Funktionsaufruf sperren

        If zeit <> Time Then 'prüfen, ob 1 Sekunde vergangen ist
            SendMessage(plugin.hwndParent,WM_COMMAND,40036,0) 'Equalizerfenster öffnen/schließen
            zeit = Time 'aktuelle Zeit merken
        EndIf

        busy = 0 'Funktionsauruf wieder freigeben

    EndIf

    Return CallWindowProc(OldProc,hwnd,message,wParam,lParam) 'Rückkehr zum ursprünglichen
                                                              ' Programm

End Function

Sub PluginThread(parameter as Any Ptr)
    'Beispiel für eine Plugin-Prozedur, die in einem eigenen Thread läuft. Die Prozedur öffnet
    ' und schließt das Playlist-Fenster in einem Rhythmus von 2 Sekunden

    Dim As String zeit

    Do
        If zeit <> Time Then 'prüfen, ob 1 Sekunde vergangen ist
            zeit = Time 'aktuelle Zeit merken
            If InStr("02468",Right(zeit,1)) Then 'prüfen, ob der Sekundeneiner eine gerade Zahl ist
                SendMessage(plugin.hwndParent,WM_COMMAND,40040,0) 'Playlistfenster öffnen/schließen
            EndIf
        EndIf
        Sleep 100,1 'Pause zur Ressourcenschonung. Ohne diesen Sleep-Befehl würde der Thread die
                    ' gesamte verfügbare Prozessorzeit an sich ziehen
    Loop 'Endlosschleife

End Sub

#Include Once "windows.bi" 'Enables access to the Windows-API-functions

Declare Function finit() As Integer
Declare Sub fconfig
Declare Sub fquit
Declare Function PluginProc(hwnd As HWND, message As UInteger, wparam As Integer, lparam As Integer) As LRESULT
Declare Sub PluginThread(parameter As Any Ptr)

'Winamp uses this UDT to communicate with the plugin. The name of the UDT is arbitrary
Type winampGeneralPurposePlugin
  version As Integer        'Contains the version of the plugin structure
  description As Any Ptr    'Contains the pointer to the name of the plugin
  init As Any Ptr           'Contains the pointer to the function "finit()"
  config As Any Ptr         'Contains the pointer to the sub "fconfig"
  quit As Any Ptr           'Contains the pointer to the sub "fquit"
  hwndParent As HWND        'Contains the handle to the Winamp main window. Will be set by Winamp
  hDllInstance As HINSTANCE 'Contains the instance handle of the plugin - dll. Will be set by Winamp
End Type

Dim Shared As winampGeneralPurposePlugin plugin 'Winamp uses this variable to communicate with
                                                ' the plugin. The name of the variable is
                                                ' arbitrary
Dim Shared As WNDPROC OldProc 'Pointer to the previous Winamp procedure
Dim Shared As Any Ptr th      'Pointer to the plugin thread

'Initializing the communication variable
With plugin
    .version = &h10 'This value mustn't be changed
  .description = StrPtr("My first plugin") 'the name, as it is displayed in the plugin - list
  .init = ProcPtr(finit)     'Pointer to the function "finit()"
  .config = ProcPtr(fconfig) 'Pointer to the sub "fconfig"
  .quit = ProcPtr(fquit)     'Pointer to the sub "fquit"
  .hwndParent = 0            'Handle to the Winamp main window. Will be set by Winamp
  .hDllInstance = 0          'Instance handle of the plugin - dll. Will be set by Winamp
End With

'After loading the plugin Winamp calls this function, which returns the pointer to the
' communication variable. The name of this function MUST NOT be changed.
Extern "C"

Function winampGetGeneralPurposePlugin() As winampGeneralPurposePlugin Ptr Export
    Return @plugin
End Function

End Extern

Function finit() As Integer Export

    'This function is called by Winamp after loading the plugin. The name of the function is
    ' arbitrary, the pointer to the function is forwarded by the communication variable.
    ' Here the plugin can do everything that is necassary for its operation. As an example it
    ' reports the message that it has been started successfully.
    MessageBox(plugin.hwndParent, "The 'init'-function has been called. The plugin was started successfully!", "", MB_OK)

  '****************************************************************************************
  'The init - function is only called once at the start of the plugin. If the plugin shall
  ' do anything periodically, there are two options:
  '
  ' Option 1:
  ' The window procedure of the Winamp main window is redirected to a procedure of the
  ' plugin, in this example to the function "PluginProc" (name arbitrary). The pointer to the
  ' original procedure will be stored in the variable "OldProc", and the program will be
  ' continued there after "PluginProc" has ended. The time between two cycles depends on what
  ' Winamp is doing else and varys very strong from less than 100µs to more than 300ms, what
  ' can cause problems, because Winamp doesn't wait for the end of the plugin procedure before
  ' calling it again (see example).
  OldProc = Cast(WNDPROC,SetWindowLong(plugin.hwndParent, GWL_WNDPROC, Cast(Integer,@PluginProc)))
    Sleep 10, 1 'give enough time to the API to accomplish the operation

    'Option 2:
    ' The procedure of the plugin is started as a thread, that means, it runs parallel to the
    ' main program in an infinite loop. There can be even run multiple threads. But watch
    ' out: A bad programmed thread is a real ressource killer!
    th = ThreadCreate(@PluginThread)
  '****************************************************************************************

  Return 0
End Function

Sub fconfig

  'This sub will be called when
  [i]Options > Preferences > General Purpose > My first plugin > Configure[/i] is clicked.

  MessageBox(plugin.hwndParent, "Here the plugin will be configured", "", MB_OK)

End Sub

Sub fquit

  'This sub is called when Winamp shuts down.

  MessageBox(0, ">My first plugin< says: 'Goodbye'", "", MB_OK)

End Sub

Function PluginProc(hwnd As HWND, message As UInteger, wparam As Integer, lparam As Integer) As LRESULT

    'Example for a periodically performed operation. The function opens and closes the
    ' equalizer window at a rhithm of 1 second.

    Static As Integer busy = 0
    Static As String memTime

    'If 'busy' is set ( <> 0 ), the control is returned to the main program immediately.
    ' As mentioned above this is necessary when -like in this case- the operation time of the
    ' function is longer than the gap between two calls. Without this protective measure
    ' Winamp would crash immediate after starting the plugin (That kind of bug can drive
    ' a programmer insane).
    If busy = 0 Then

        busy = 1 'Block the function

        If memTime <> Time Then 'Check if 1 second has passed
            SendMessage(plugin.hwndParent,WM_COMMAND,40036,0) 'Toggle equalizer window
            memTime = Time 'Memorise time
        EndIf

        busy = 0 'Unblock the function

    EndIf

    Return CallWindowProc(OldProc,hwnd,message,wParam,lParam) 'Return to the calling program

End Function

Sub PluginThread(parameter As Any Ptr)
    'Example for a plugin procedure running as a thread. The procedure opens and closes the
    ' playlist window at a rhithm of 2 seconds.

    Dim As String memTime

    Do
        If memTime <> Time Then 'Check if 1 second has passed
            memTime = Time 'Memorise time
            If InStr("02468",Right(memTime,1)) Then 'Check if the unit position in an even number
                SendMessage(plugin.hwndParent,WM_COMMAND,40040,0) 'Toggle playlist window
            EndIf
        EndIf
        Sleep 100,1 'Pause for saving ressources. Without this Sleep - statement the thread
                    ' would claim the whole available processing time
    Loop 'Infinite loop

End Sub

Quellen:
Externer Link!http://phimuemue.com/blog.php?article=%20162
Externer Link!http://www.delphi-zone.com/2010/02/how-to-load-winamp-general-plugins-in-delphi/
Externer Link!http://wiki.winamp.com/wiki/Beginner%27s_Basic_Plugin_Guide
Externer Link!http://wiki.winamp.com/wiki/Basic_Plugin_Guide_-_Tutorial#2


Zusätzliche Informationen und Funktionen
  • Das Code-Beispiel wurde am 04.03.2013 von Mitgliedgrindstone angelegt.
  • Die aktuellste Version wurde am 06.05.2015 von Mitgliedgrindstone gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen