<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.shoutcast.com/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.shoutcast.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=SMonty</id>
		<title>Winamp Developer Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.shoutcast.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=SMonty"/>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Special:Contributions/SMonty"/>
		<updated>2026-05-02T10:30:52Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.22.3</generator>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Tips_for_Writing_an_Awesome_Online_Service</id>
		<title>Tips for Writing an Awesome Online Service</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Tips_for_Writing_an_Awesome_Online_Service"/>
				<updated>2010-03-05T16:54:35Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Tour Tracker */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;A Winamp Online Service is simply a web page&amp;quot;&lt;br /&gt;
        quote from an unidentified if not too creative web page developer, circa 2009.&lt;br /&gt;
&lt;br /&gt;
When I first heard the above statement I was somewhat surprised.  Winamp Online Services are not just web pages.  True, you could create a web page and use it as an Online Service but that would be like, .... well like using your smart phone to just make phone calls.  There's so much more creative things that can be done.  In this document I'd like to point out some cool things that have already been done with Online Services hopefully generating ideas for even more fantastic mashups.&lt;br /&gt;
&lt;br /&gt;
To start with, if you are unfamiliar with what an Online Service is, you can find an excellent description of creating, submitting and managing a service at the [[Online_Service_Developer]] page.&lt;br /&gt;
&lt;br /&gt;
Most importantly, a full description of the JavaScript APIs that can be called from an Online Service can be found at the [[Complete_JavaScript_API_technology_framework]] page.  These are the api methods that can make Online Services special, far beyond a 'normal' web page.  Not to mention that I also wrote the wiki doc above, so if you like this one, the API reference above would also be good.&lt;br /&gt;
&lt;br /&gt;
If you happened to actually read the two links listed above, rather than coming back to them after reading this, you may have realized what I will be driving at in this document:&lt;br /&gt;
&lt;br /&gt;
'''In order to make an absolutely astounding Online Service, the web page must use the underlying APIs to integrate with the Winamp music player.'''&lt;br /&gt;
&lt;br /&gt;
To restate this, there are facilities to control and retrieve information from the Winamp player.  These apis turn a web page into a cool Winamp Online Service.  Can you think of some cool things to do with this?....I thought you could.  Let's see some Online Services that have already been done.&lt;br /&gt;
&lt;br /&gt;
==Tour Tracker==&lt;br /&gt;
In case you don't know (check out the Winamp Online Services), the Tour Tracker Online Service provides a way for users to see upcoming concert information for the bands they are currently listening to on the Winamp player.  There are links on this service to purchase tickets to the concerts.  Way easier than the old days. &lt;br /&gt;
&lt;br /&gt;
Here is some JavaScript code from the Tour Tracker Online Service.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function getartist() {&lt;br /&gt;
   if (!artist) {&lt;br /&gt;
     if (window.external &amp;amp;&amp;amp; window.external.Transport) {&lt;br /&gt;
       artist = window.external.Transport.GetMetadata(&amp;quot;artist&amp;quot;);&lt;br /&gt;
       songtitle = window.external.Transport.GetMetadata(&amp;quot;title&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       document.location.href=&amp;quot;index.php?artist=&amp;quot; + artist;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code retrieves the artist name and the title from the currently playing track.  So what could you do with that?  Well, how about....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function loadscript() {&lt;br /&gt;
   // just load ONCE on page-load&lt;br /&gt;
   if (window.external &amp;amp;&amp;amp; window.external.Transport) {&lt;br /&gt;
     var refreshval = ReadCookie(&amp;quot;refresh&amp;quot;);&lt;br /&gt;
     if (refreshval == 1) {&lt;br /&gt;
       document.getElementById(&amp;quot;refreshcheckbox&amp;quot;).checked = true;&lt;br /&gt;
       rc = window.external.Transport.RegisterForEvents(onEvents);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 function unloadscript() {&lt;br /&gt;
   if (window.external &amp;amp;&amp;amp; window.external.Transport) {&lt;br /&gt;
     rc = window.external.Transport.UnregisterFromEvents(onEvents);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the JavaScript code is registering to receive 'events' from the Winamp player.  The loadscript() function is executed when the web page is first loaded and the unloadscript() is executed when the page is unloaded.  The function 'onEvents' is called when events occur in the player.  Note that the refresh flag is read from the cookie and is used to set the &amp;quot;refreshcheckbox&amp;quot; UI element on the page.  Don't forget to 'Transport.UnregisterFromEvents()' when the page unloads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function onEvents(event){&lt;br /&gt;
   if (event.event == &amp;quot;OnPlay&amp;quot; &amp;amp;&amp;amp; document.getElementById&lt;br /&gt;
             (&amp;quot;refreshcheckbox&amp;quot;).checked == true) {&lt;br /&gt;
     if (document.getElementById(&amp;quot;WindowBox&amp;quot;).style.display==&amp;quot;block&amp;quot;) {&lt;br /&gt;
       // empty then block&lt;br /&gt;
       // don't switch if user is in the process of purchasing tickets!&lt;br /&gt;
     } else {&lt;br /&gt;
       getartist();&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is the onEvents handler.  event.event == &amp;quot;OnPlay&amp;quot; is the event fired whenever a new music track is started on the Winamp player.  What this means is that the Tour Tracker Online Service can retrieve the author and title whenever a new track starts playing.  Tour Tracker then uses this information to open a new web page in the browser to a site that can show up-coming concerts for the artist and allow the user to purchase tickets.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function browsetab(urldata) {&lt;br /&gt;
   var urltouse = urldata.toLowerCase();&lt;br /&gt;
   urltouse = urltouse.replace(' ', '-');&lt;br /&gt;
   window.external.Application.LaunchURL(urltouse);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the following screenshot, you can see that the currently playing song is 'Stuck with You' by Huey Lewis and the News.  The Tour Tracker Online Service appears in the browser, showing scheduled concerts for the band.  There is an Auto-Refresh checkbox in the upper right corner of the screen (not visible in the screenshot), that will cause Tour Tracker to automatically bring up concert information (if any) for the artist for the next track (John Waite).&lt;br /&gt;
&lt;br /&gt;
[[File:TourTrackerWinampOnlineService.PNG]]&lt;br /&gt;
&lt;br /&gt;
Now is that 'just' a web page?  I think not.&lt;br /&gt;
&lt;br /&gt;
==AOL Radio==&lt;br /&gt;
The AOL Radio Online Service does something else interesting.  Here are two screenshots, one with the default Bento skin and another with a custom skin.&lt;br /&gt;
&lt;br /&gt;
Here's the first&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Radiowithbentoskin.PNG]]&lt;br /&gt;
&lt;br /&gt;
And here's the second&lt;br /&gt;
&lt;br /&gt;
[[File:Radiowithnewskin.PNG]]&lt;br /&gt;
&lt;br /&gt;
Do you see something different?  Okay, Okay, other than the color difference.  Did you notice that the AOL Radio Online Service web page changed color also?  This is a good example of making an online service blend in with the Winamp player.  Also notice the 'Sponsored Links'.  This is a good example of NOT making it blend in with the Winamp player.  But to be fair, the 'Sponsored Links' is somewhat different than the rest of the page so let's talk about the page itself.&lt;br /&gt;
&lt;br /&gt;
The AOL Radio Online Service web page uses code like the following to obtain the color and font information about the Winamp player.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function updateSkinColors()&lt;br /&gt;
 {&lt;br /&gt;
   // globals for anyone who wants 'em!&lt;br /&gt;
   sColorItemBg = window.external.Skin.GetClassicColor(0); &lt;br /&gt;
   sColorItemFg = window.external.Skin.GetClassicColor(1); &lt;br /&gt;
   sColorWndBg = window.external.Skin.GetClassicColor(2); &lt;br /&gt;
   sColorBtnFg = window.external.Skin.GetClassicColor(3); &lt;br /&gt;
   sColorWndFg = window.external.Skin.GetClassicColor(4); &lt;br /&gt;
   sColorHilite = window.external.Skin.GetClassicColor(5); &lt;br /&gt;
   sColorSel = window.external.Skin.GetClassicColor(6); &lt;br /&gt;
   sColorListHeadBg = window.external.Skin.GetClassicColor(7); &lt;br /&gt;
   sColorListHeadFont = window.external.Skin.GetClassicColor(8); &lt;br /&gt;
   sColorListHeadTop = window.external.Skin.GetClassicColor(9); &lt;br /&gt;
   sColorListHeadMid = window.external.Skin.GetClassicColor(10); &lt;br /&gt;
   sColorListHeadBot = window.external.Skin.GetClassicColor(11); &lt;br /&gt;
   sColorListHeadEmpty = window.external.Skin.GetClassicColor(12); &lt;br /&gt;
   sColorScrollFg = window.external.Skin.GetClassicColor(13); &lt;br /&gt;
   sColorScrollBg = window.external.Skin.GetClassicColor(14); &lt;br /&gt;
   sColorScrollInvFg = window.external.Skin.GetClassicColor(15); &lt;br /&gt;
   sColorScrollInvBg = window.external.Skin.GetClassicColor(16); &lt;br /&gt;
   sColorScrollEmpty = window.external.Skin.GetClassicColor(17); &lt;br /&gt;
   sColorSelbarFg = window.external.Skin.GetClassicColor(18); &lt;br /&gt;
   sColorSelbarBg = window.external.Skin.GetClassicColor(19); &lt;br /&gt;
   sColorInactSelbarFg = window.external.Skin.GetClassicColor(20); &lt;br /&gt;
   sColorInactSelbarBg = window.external.Skin.GetClassicColor(21); &lt;br /&gt;
    &lt;br /&gt;
   sColorPlFg = window.external.Skin.GetPlaylistColor(0); &lt;br /&gt;
   sColorPlCurrentFg = window.external.Skin.GetPlaylistColor(1); &lt;br /&gt;
   sColorPlBg = window.external.Skin.GetPlaylistColor(2); &lt;br /&gt;
   sColorPlSelbar = window.external.Skin.GetPlaylistColor(3); &lt;br /&gt;
   sColorPlGenericFg = window.external.Skin.GetPlaylistColor(4); &lt;br /&gt;
   sColorPlGenericBg = window.external.Skin.GetPlaylistColor(5); &lt;br /&gt;
   &lt;br /&gt;
   sFontName = window.external.Skin.font; &lt;br /&gt;
   sFontSize = window.external.Skin.fontsize; &lt;br /&gt;
  .&lt;br /&gt;
  .&lt;br /&gt;
  .&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The page then uses script such as this to change the page to use the same colors and fonts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function updateColors()&lt;br /&gt;
 {&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
   $(&amp;quot;#wa_body&amp;quot;).css(&amp;quot;backgroundColor&amp;quot;, sColorItemBg);&lt;br /&gt;
   $(&amp;quot;#nav&amp;quot;).css({ backgroundColor: sColorSelbarBg, color: sColorSelbarFg });&lt;br /&gt;
   $(&amp;quot;#upgrade_msg&amp;quot;).css(&amp;quot;borderColor&amp;quot;, sColorSelbarBg);&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the code above we're adjusting the css attributes for the elements identified with id= parameter set to the text after the &amp;quot;#&amp;quot;s.  And we set them to the values we retrieved from the Winamp player in the previous function.&lt;br /&gt;
&lt;br /&gt;
With these functions, you can make an Online Service look totally integrated inside the Winamp player.  When done right, it doesn't even look like a separate web page.&lt;br /&gt;
&lt;br /&gt;
==Song of the Day==&lt;br /&gt;
Here is another example of outstanding use of one of the apis, the Transport API.&lt;br /&gt;
&lt;br /&gt;
Below is a snapshot of the &amp;quot;Song of the Day&amp;quot; Online Service from Spinner.&lt;br /&gt;
&lt;br /&gt;
[[File:Songoftheday.PNG]]&lt;br /&gt;
&lt;br /&gt;
Notice the big, ol' round button in the center of the track information.  Notice how the first track has a &amp;quot;Pause&amp;quot; button and all the rest have &amp;quot;Play&amp;quot; buttons.  That's because I clicked on the play button for the first song and it started playing and now, I can pause it.  If you listen to this track, Winamp will eventually move on to the next track in the playlist and, magically, the buttons will change as Winamp begins to play the next track.  Also notice that when you click to play one of the items on the web page, a Playlist is created and the song you selected begins to play.  How can this be done?  Well, it isn't really magic.  You don't need to be Harry Potter to do this.&lt;br /&gt;
&lt;br /&gt;
This can be done using the Transport, Transport Events and Playqueue apis.&lt;br /&gt;
&lt;br /&gt;
====Transport====&lt;br /&gt;
The Transport API controls the Winamp player, like pushing buttons on the front of a CD player.  When the user presses on the buttons on this page, the page calls the following api methods depending on which button was previously being shown:&lt;br /&gt;
&lt;br /&gt;
 window.external.Transport.Play();&lt;br /&gt;
    or&lt;br /&gt;
 window.external.Transport.Pause();&lt;br /&gt;
&lt;br /&gt;
Simple, huh?&lt;br /&gt;
===Transport Events===&lt;br /&gt;
But how does the web page know to change from the pause image to the play image when the track ends?  Conversly, how does it know to switch from play to pause when it starts the next song?  The answer is to register for events from the Winamp player.  You've seen this already in the first example we talked about, the Tour Tracker Online Service.  Remember this api method?&lt;br /&gt;
&lt;br /&gt;
 window.external.Transport.RegisterForEvents(onEvents);&lt;br /&gt;
&lt;br /&gt;
Note: Don't forget to &amp;quot;UnregisterFromEvents&amp;quot; when you are done.&lt;br /&gt;
&lt;br /&gt;
The onEvents function is passed a parameter indicating what kind of event occurred. Let's say &amp;quot;OnPlay&amp;quot; or &amp;quot;OnEndOfFile&amp;quot; (actually the end of a track).  With these two events you can change the appropriate images.&lt;br /&gt;
&lt;br /&gt;
===PlayQueue API===&lt;br /&gt;
Now what about that queing things to be played thingy?  That can be done with the methods of the PlayQueue api.  The following api call will clear the list of tracks to be played.  You might want to use the Transport.Stop() api to stop the Winamp player as clearing the play queue will not stop the currently playing song.&lt;br /&gt;
&lt;br /&gt;
 window.external.PlayQueue.ClearQueue();&lt;br /&gt;
&lt;br /&gt;
To enqueue tracks to be played, you need to call....wait for it..... the Enqueue method.&lt;br /&gt;
&lt;br /&gt;
 window.external.PlayQueue.Enqueue(&amp;lt;URL&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;URL&amp;gt; is replaced with a string containing the URL of the track to be played.  Do this for each of the tracks that you want queued.&lt;br /&gt;
&lt;br /&gt;
Finally, how do we get the song that was clicked to begin playing?  Especially if it was not the first one in our newly constructed Playqueue?  You do this by changing the value of the PlayQueue cursor property.&lt;br /&gt;
&lt;br /&gt;
 window.external.PlayQueue.cursor = n;&lt;br /&gt;
&lt;br /&gt;
Where n is the offset into the play queue of the track to be played.  Be aware that this value is zero (0) based, meaning the first track in the play queue is at cursor=0.&lt;br /&gt;
&lt;br /&gt;
Now just use the Transport.Play() method to kick off the music.&lt;br /&gt;
&lt;br /&gt;
==Finale==&lt;br /&gt;
So.  We've looked at three different Winamp Online Services.  Each one uses apis to do things that 'normal' web pages cannot.  The services are more tightly integrated with the Winamp player to cause some very interesting behaviors.  Check out the documentation listed at the front of this article and spur on your imagination to create an Awesome Online Service.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Tips_for_Writing_an_Awesome_Online_Service</id>
		<title>Tips for Writing an Awesome Online Service</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Tips_for_Writing_an_Awesome_Online_Service"/>
				<updated>2010-03-05T16:50:36Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: New page: ==Overview==    &amp;quot;A Winamp Online Service is simply a web page&amp;quot;         quote from an unidentified if not too creative web page developer, circa 2009.  When I first heard the above statemen...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;A Winamp Online Service is simply a web page&amp;quot;&lt;br /&gt;
        quote from an unidentified if not too creative web page developer, circa 2009.&lt;br /&gt;
&lt;br /&gt;
When I first heard the above statement I was somewhat surprised.  Winamp Online Services are not just web pages.  True, you could create a web page and use it as an Online Service but that would be like, .... well like using your smart phone to just make phone calls.  There's so much more creative things that can be done.  In this document I'd like to point out some cool things that have already been done with Online Services hopefully generating ideas for even more fantastic mashups.&lt;br /&gt;
&lt;br /&gt;
To start with, if you are unfamiliar with what an Online Service is, you can find an excellent description of creating, submitting and managing a service at the [[Online_Service_Developer]] page.&lt;br /&gt;
&lt;br /&gt;
Most importantly, a full description of the JavaScript APIs that can be called from an Online Service can be found at the [[Complete_JavaScript_API_technology_framework]] page.  These are the api methods that can make Online Services special, far beyond a 'normal' web page.  Not to mention that I also wrote the wiki doc above, so if you like this one, the API reference above would also be good.&lt;br /&gt;
&lt;br /&gt;
If you happened to actually read the two links listed above, rather than coming back to them after reading this, you may have realized what I will be driving at in this document:&lt;br /&gt;
&lt;br /&gt;
'''In order to make an absolutely astounding Online Service, the web page must use the underlying APIs to integrate with the Winamp music player.'''&lt;br /&gt;
&lt;br /&gt;
To restate this, there are facilities to control and retrieve information from the Winamp player.  These apis turn a web page into a cool Winamp Online Service.  Can you think of some cool things to do with this?....I thought you could.  Let's see some Online Services that have already been done.&lt;br /&gt;
&lt;br /&gt;
==Tour Tracker==&lt;br /&gt;
In case you don't know (check out the Winamp Online Services), the Tour Tracker Online Service provides a way for users to see upcoming concert information for the bands they are currently listening to on the Winamp player.  There are links on this service to purchase tickets to the concerts.  Way easier than the old days. &lt;br /&gt;
&lt;br /&gt;
Here is some JavaScript code from the Tour Tracker Online Service.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function getartist() {&lt;br /&gt;
   if (!artist) {&lt;br /&gt;
     if (window.external &amp;amp;&amp;amp; window.external.Transport) {&lt;br /&gt;
       artist = window.external.Transport.GetMetadata(&amp;quot;artist&amp;quot;);&lt;br /&gt;
       songtitle = window.external.Transport.GetMetadata(&amp;quot;title&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
       document.location.href=&amp;quot;index.php?artist=&amp;quot; + artist;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code retrieves the artist name and the title from the currently playing track.  So what could you do with that?  Well, how about....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function loadscript() {&lt;br /&gt;
   // just load ONCE on page-load&lt;br /&gt;
   if (window.external &amp;amp;&amp;amp; window.external.Transport) {&lt;br /&gt;
     var refreshval = ReadCookie(&amp;quot;refresh&amp;quot;);&lt;br /&gt;
     if (refreshval == 1) {&lt;br /&gt;
       document.getElementById(&amp;quot;refreshcheckbox&amp;quot;).checked = true;&lt;br /&gt;
       rc = window.external.Transport.RegisterForEvents(onEvents);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 function unloadscript() {&lt;br /&gt;
   if (window.external &amp;amp;&amp;amp; window.external.Transport) {&lt;br /&gt;
     rc = window.external.Transport.UnregisterFromEvents(onEvents);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here the JavaScript code is registering to receive 'events' from the Winamp player.  The loadscript() function is executed when the web page is first loaded and the unloadscript() is executed when the page is unloaded.  The function 'onEvents' is called when events occur in the player.  Note that the refresh flag is read from the cookie and is used to set the &amp;quot;refreshcheckbox&amp;quot; UI element on the page.  Don't forget to 'Transport.UnregisterFromEvents()' when the page unloads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function onEvents(event){&lt;br /&gt;
   if (event.event == &amp;quot;OnPlay&amp;quot; &amp;amp;&amp;amp; document.getElementById&lt;br /&gt;
             (&amp;quot;refreshcheckbox&amp;quot;).checked == true) {&lt;br /&gt;
     if (document.getElementById(&amp;quot;WindowBox&amp;quot;).style.display==&amp;quot;block&amp;quot;) {&lt;br /&gt;
       // empty then block&lt;br /&gt;
       // don't switch if user is in the process of xxxing tickets!&lt;br /&gt;
     } else {&lt;br /&gt;
       getartist();&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is the onEvents handler.  event.event == &amp;quot;OnPlay&amp;quot; is the event fired whenever a new music track is started on the Winamp player.  What this means is that the Tour Tracker Online Service can retrieve the author and title whenever a new track starts playing.  Tour Tracker then uses this information to open a new web page in the browser to a site that can show up-coming concerts for the artist and allow the user to xxx tickets.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function browsetab(urldata) {&lt;br /&gt;
   var urltouse = urldata.toLowerCase();&lt;br /&gt;
   urltouse = urltouse.replace(' ', '-');&lt;br /&gt;
   window.external.Application.LaunchURL(urltouse);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the following screenshot, you can see that the currently playing song is 'Stuck with You' by Huey Lewis and the News.  The Tour Tracker Online Service appears in the browser, showing scheduled concerts for the band.  There is an Auto-Refresh checkbox in the upper right corner of the screen (not visible in the screenshot), that will cause Tour Tracker to automatically bring up concert information (if any) for the artist for the next track (John Waite).&lt;br /&gt;
&lt;br /&gt;
[[File:TourTrackerWinampOnlineService.PNG]]&lt;br /&gt;
&lt;br /&gt;
Now is that 'just' a web page?  I think not.&lt;br /&gt;
&lt;br /&gt;
==AOL Radio==&lt;br /&gt;
The AOL Radio Online Service does something else interesting.  Here are two screenshots, one with the default Bento skin and another with a custom skin.&lt;br /&gt;
&lt;br /&gt;
Here's the first&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Radiowithbentoskin.PNG]]&lt;br /&gt;
&lt;br /&gt;
And here's the second&lt;br /&gt;
&lt;br /&gt;
[[File:Radiowithnewskin.PNG]]&lt;br /&gt;
&lt;br /&gt;
Do you see something different?  Okay, Okay, other than the color difference.  Did you notice that the AOL Radio Online Service web page changed color also?  This is a good example of making an online service blend in with the Winamp player.  Also notice the 'Sponsored Links'.  This is a good example of NOT making it blend in with the Winamp player.  But to be fair, the 'Sponsored Links' is somewhat different than the rest of the page so let's talk about the page itself.&lt;br /&gt;
&lt;br /&gt;
The AOL Radio Online Service web page uses code like the following to obtain the color and font information about the Winamp player.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function updateSkinColors()&lt;br /&gt;
 {&lt;br /&gt;
   // globals for anyone who wants 'em!&lt;br /&gt;
   sColorItemBg = window.external.Skin.GetClassicColor(0); &lt;br /&gt;
   sColorItemFg = window.external.Skin.GetClassicColor(1); &lt;br /&gt;
   sColorWndBg = window.external.Skin.GetClassicColor(2); &lt;br /&gt;
   sColorBtnFg = window.external.Skin.GetClassicColor(3); &lt;br /&gt;
   sColorWndFg = window.external.Skin.GetClassicColor(4); &lt;br /&gt;
   sColorHilite = window.external.Skin.GetClassicColor(5); &lt;br /&gt;
   sColorSel = window.external.Skin.GetClassicColor(6); &lt;br /&gt;
   sColorListHeadBg = window.external.Skin.GetClassicColor(7); &lt;br /&gt;
   sColorListHeadFont = window.external.Skin.GetClassicColor(8); &lt;br /&gt;
   sColorListHeadTop = window.external.Skin.GetClassicColor(9); &lt;br /&gt;
   sColorListHeadMid = window.external.Skin.GetClassicColor(10); &lt;br /&gt;
   sColorListHeadBot = window.external.Skin.GetClassicColor(11); &lt;br /&gt;
   sColorListHeadEmpty = window.external.Skin.GetClassicColor(12); &lt;br /&gt;
   sColorScrollFg = window.external.Skin.GetClassicColor(13); &lt;br /&gt;
   sColorScrollBg = window.external.Skin.GetClassicColor(14); &lt;br /&gt;
   sColorScrollInvFg = window.external.Skin.GetClassicColor(15); &lt;br /&gt;
   sColorScrollInvBg = window.external.Skin.GetClassicColor(16); &lt;br /&gt;
   sColorScrollEmpty = window.external.Skin.GetClassicColor(17); &lt;br /&gt;
   sColorSelbarFg = window.external.Skin.GetClassicColor(18); &lt;br /&gt;
   sColorSelbarBg = window.external.Skin.GetClassicColor(19); &lt;br /&gt;
   sColorInactSelbarFg = window.external.Skin.GetClassicColor(20); &lt;br /&gt;
   sColorInactSelbarBg = window.external.Skin.GetClassicColor(21); &lt;br /&gt;
    &lt;br /&gt;
   sColorPlFg = window.external.Skin.GetPlaylistColor(0); &lt;br /&gt;
   sColorPlCurrentFg = window.external.Skin.GetPlaylistColor(1); &lt;br /&gt;
   sColorPlBg = window.external.Skin.GetPlaylistColor(2); &lt;br /&gt;
   sColorPlSelbar = window.external.Skin.GetPlaylistColor(3); &lt;br /&gt;
   sColorPlGenericFg = window.external.Skin.GetPlaylistColor(4); &lt;br /&gt;
   sColorPlGenericBg = window.external.Skin.GetPlaylistColor(5); &lt;br /&gt;
   &lt;br /&gt;
   sFontName = window.external.Skin.font; &lt;br /&gt;
   sFontSize = window.external.Skin.fontsize; &lt;br /&gt;
  .&lt;br /&gt;
  .&lt;br /&gt;
  .&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The page then uses script such as this to change the page to use the same colors and fonts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 function updateColors()&lt;br /&gt;
 {&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
   $(&amp;quot;#wa_body&amp;quot;).css(&amp;quot;backgroundColor&amp;quot;, sColorItemBg);&lt;br /&gt;
   $(&amp;quot;#nav&amp;quot;).css({ backgroundColor: sColorSelbarBg, color: sColorSelbarFg });&lt;br /&gt;
   $(&amp;quot;#upgrade_msg&amp;quot;).css(&amp;quot;borderColor&amp;quot;, sColorSelbarBg);&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
   .&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the code above we're adjusting the css attributes for the elements identified with id= parameter set to the text after the &amp;quot;#&amp;quot;s.  And we set them to the values we retrieved from the Winamp player in the previous function.&lt;br /&gt;
&lt;br /&gt;
With these functions, you can make an Online Service look totally integrated inside the Winamp player.  When done right, it doesn't even look like a separate web page.&lt;br /&gt;
&lt;br /&gt;
==Song of the Day==&lt;br /&gt;
Here is another example of outstanding use of one of the apis, the Transport API.&lt;br /&gt;
&lt;br /&gt;
Below is a snapshot of the &amp;quot;Song of the Day&amp;quot; Online Service from Spinner.&lt;br /&gt;
&lt;br /&gt;
[[File:Songoftheday.PNG]]&lt;br /&gt;
&lt;br /&gt;
Notice the big, ol' round button in the center of the track information.  Notice how the first track has a &amp;quot;Pause&amp;quot; button and all the rest have &amp;quot;Play&amp;quot; buttons.  That's because I clicked on the play button for the first song and it started playing and now, I can pause it.  If you listen to this track, Winamp will eventually move on to the next track in the playlist and, magically, the buttons will change as Winamp begins to play the next track.  Also notice that when you click to play one of the items on the web page, a Playlist is created and the song you selected begins to play.  How can this be done?  Well, it isn't really magic.  You don't need to be Harry Potter to do this.&lt;br /&gt;
&lt;br /&gt;
This can be done using the Transport, Transport Events and Playqueue apis.&lt;br /&gt;
&lt;br /&gt;
====Transport====&lt;br /&gt;
The Transport API controls the Winamp player, like pushing buttons on the front of a CD player.  When the user presses on the buttons on this page, the page calls the following api methods depending on which button was previously being shown:&lt;br /&gt;
&lt;br /&gt;
 window.external.Transport.Play();&lt;br /&gt;
    or&lt;br /&gt;
 window.external.Transport.Pause();&lt;br /&gt;
&lt;br /&gt;
Simple, huh?&lt;br /&gt;
===Transport Events===&lt;br /&gt;
But how does the web page know to change from the pause image to the play image when the track ends?  Conversly, how does it know to switch from play to pause when it starts the next song?  The answer is to register for events from the Winamp player.  You've seen this already in the first example we talked about, the Tour Tracker Online Service.  Remember this api method?&lt;br /&gt;
&lt;br /&gt;
 window.external.Transport.RegisterForEvents(onEvents);&lt;br /&gt;
&lt;br /&gt;
Note: Don't forget to &amp;quot;UnregisterFromEvents&amp;quot; when you are done.&lt;br /&gt;
&lt;br /&gt;
The onEvents function is passed a parameter indicating what kind of event occurred. Let's say &amp;quot;OnPlay&amp;quot; or &amp;quot;OnEndOfFile&amp;quot; (actually the end of a track).  With these two events you can change the appropriate images.&lt;br /&gt;
&lt;br /&gt;
===PlayQueue API===&lt;br /&gt;
Now what about that queing things to be played thingy?  That can be done with the methods of the PlayQueue api.  The following api call will clear the list of tracks to be played.  You might want to use the Transport.Stop() api to stop the Winamp player as clearing the play queue will not stop the currently playing song.&lt;br /&gt;
&lt;br /&gt;
 window.external.PlayQueue.ClearQueue();&lt;br /&gt;
&lt;br /&gt;
To enqueue tracks to be played, you need to call....wait for it..... the Enqueue method.&lt;br /&gt;
&lt;br /&gt;
 window.external.PlayQueue.Enqueue(&amp;lt;URL&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;URL&amp;gt; is replaced with a string containing the URL of the track to be played.  Do this for each of the tracks that you want queued.&lt;br /&gt;
&lt;br /&gt;
Finally, how do we get the song that was clicked to begin playing?  Especially if it was not the first one in our newly constructed Playqueue?  You do this by changing the value of the PlayQueue cursor property.&lt;br /&gt;
&lt;br /&gt;
 window.external.PlayQueue.cursor = n;&lt;br /&gt;
&lt;br /&gt;
Where n is the offset into the play queue of the track to be played.  Be aware that this value is zero (0) based, meaning the first track in the play queue is at cursor=0.&lt;br /&gt;
&lt;br /&gt;
Now just use the Transport.Play() method to kick off the music.&lt;br /&gt;
&lt;br /&gt;
==Finale==&lt;br /&gt;
So.  We've looked at three different Winamp Online Services.  Each one uses apis to do things that 'normal' web pages cannot.  The services are more tightly integrated with the Winamp player to cause some very interesting behaviors.  Check out the documentation listed at the front of this article and spur on your imagination to create an Awesome Online Service.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Main_Page</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Main_Page"/>
				<updated>2010-03-05T16:48:35Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Developer Resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Welcome ==&lt;br /&gt;
Welcome to Winamp's Developer Network wiki.  By consolidating Winamp documentation, code samples, reference materials, and sample articles, we've created a one-stop shop for all things related to Winamp development. The purpose of this site is to help facilitate the development of [[Skin_Developer|Winamp skins]], [[Plug-in_Developer|plug-ins]],  [[Visual_Developer|visualization presets]] and [[Online_Service_Developer|online services]].  In order to offer the most relevant material (''and since no one is more of an expert than you''), our goal is to present a wiki that is updated, maintained, and moderated by the Winamp developer community.&lt;br /&gt;
&lt;br /&gt;
Why develop for Winamp, you ask?  Besides being a kickass media player with a flexible programming platform, Winamp has a very loyal fan base with over 72 million worldwide users per month. So chances are your creative masterpiece will live well beyond the boundaries of your hard drive.  Now that we've got your creative juices flowing (or at a minimum, appealed to your desire for fame and adoration), you can use the '''Developer Network''' as a springboard for everything you need.  Most importantly, you can [http://www.winamp.com/user/submit upload] your creation and share it with the World. ''(Note: You'll need a winamp.com account to upload).''&lt;br /&gt;
&lt;br /&gt;
=== How to use the Wiki ===&lt;br /&gt;
There are several ways that you can use this wiki.  Use it as a reference guide.  Start sifting through the content to find the information you need to start developing.  If you find out that some key information is missing or you see that something on the site is completely inaccurate, we welcome your contributions.  We'd love for you to update the site with killer content and [[Articles]].  Before you start contributing though, make sure you check out the Developer Network [[Policies &amp;amp; Guidelines]] page and create an account.  By creating an account or logging into the Winamp Developer Network, you are agreeing to our [[Winamp Developer Network Wiki Terms and Conditions|Terms of Service]] and [http://www.winamp.com/legal/privacy Privacy Policy]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you've never edited a wiki before, you might want to check out [http://en.wikipedia.org/wiki/Wikipedia:How_to_edit_a_page Wikipedia: How to edit a page]for some pointers.&lt;br /&gt;
&lt;br /&gt;
== Who Should Use the Wiki ==&lt;br /&gt;
This wiki is for everyone.  Whether you're a seasoned vet, intermediate coder, loyal fan, or even newbie.  Primarily though, it's for Winamp developers and user-contributors who want to be actively engaged in the advancement of the Winamp media player.  Either by leveraging the content of this site to build better '''skins''', '''plug-ins''', '''visualizations''' and '''online services'''; or by sharing your knowledge and expertise with the community.&lt;br /&gt;
&lt;br /&gt;
===Skin Developer===&lt;br /&gt;
To put it as simply as possible, skins change the way your Winamp player looks. If you want to get fancy and say that it changes the GUI (graphical user interface) then you can, but really all you need to know is if you download or create a new skin, Winamp will put on a little mask and pretend to look different.  Check [[Skin Developer]] page for more details.&lt;br /&gt;
&lt;br /&gt;
====Classic Skins====&lt;br /&gt;
Based on the Winamp 2 model, [[Skin_Developer#Creating_Classic_Skins|Classic skins]] are easier to create than Modern skins, but they do not allow the developer to change the form or function of the player. [[Skin_Developer#Creating_Classic_Skins|Classic skins]] developers may only replace a standard set of images that alter the player's visual appearance.&lt;br /&gt;
&lt;br /&gt;
====Modern Skins====&lt;br /&gt;
[[Skin_Developer#Creating_Modern_Skins|Modern skins]] are skins that adhere to the Winamp 3+ skin model. Modern (or freeform) skins offer developers a tremendous amount of flexibility by allowing you to change the player's shape, size, layout, and function. Learn how to create a modern skin for Winamp!&lt;br /&gt;
&lt;br /&gt;
=== Visual Developer===&lt;br /&gt;
You know those funny dancing colors you see when you hear music – and no ''Autumn Moonpuppy'', I’m not talking about that time you &amp;quot;toured&amp;quot; with The Dead.  [[Visual_Developer|Visualizers]] are dynamic add-ons that produce images, colors, and textures that change based elements of the music being played.  Winamp offers two primary visualization platforms (AVS &amp;amp; MilkDrop) allowing you to create different presets.  If you’re feeling invincible, you can even attempt to create your own visualization environment.&lt;br /&gt;
&lt;br /&gt;
=== Plug-in Developer===&lt;br /&gt;
&lt;br /&gt;
[[Plug-in_Developer|Plug-ins]] can pretty much do anything! ...within reason, of course.  You can alter the sound of your music, turn your mobile phone into a Winamp remote control, or if ya’d like, translate Winamp into another language.  Basically, we’ve made the platform flexible enough so that you can craft your idyllic feature and plug it right into Winamp.&lt;br /&gt;
&lt;br /&gt;
'''Types of Plug-ins'''&lt;br /&gt;
&lt;br /&gt;
There are all kinds of categorizes of plug-ins:  Input, Output, Visualization, DSP/Effect, General Purpose, Media Library and Portables. That means, you can go nuts in discovering how a single plug-in can change your life. You can read up on the taxonomy of a plug-in here.&lt;br /&gt;
&lt;br /&gt;
'''Start Creating Your Plug-in'''&lt;br /&gt;
&lt;br /&gt;
If you feel like developing one yourself, you can – &lt;br /&gt;
# Check out the [[Plug-in_Developer#Tools|suggested tools]]&lt;br /&gt;
# Read-up on the [[Plug-in_Developer#SDK_Documentation|SDK documentation]]&lt;br /&gt;
# [http://download.nullsoft.com/winamp/plugin-dev/WA5.55_SDK.exe Download the SDK]&lt;br /&gt;
# Visit the [http://forums.winamp.com/ Winamp Forums]&lt;br /&gt;
# [http://www.winamp.com/user/login Submit your plug-in]. Ain’t it easy?&lt;br /&gt;
&lt;br /&gt;
=== Online Service Developer===&lt;br /&gt;
[[Online_Service_Developer|Online Services]] are web pages that are rendered by the embedded browser within Winamp.  The awesomeness of these pages is that they can interact with the Winamp Player.  In this way a web page can start and stop the player, examine and create playlists, enqueue songs for playback, the colors used in the skin of the player, etc.  We're excited to see what you come up with by merging html web pages and the Winamp player.&lt;br /&gt;
&lt;br /&gt;
== Developer Resources ==&lt;br /&gt;
*[[Articles]] - link consolidation of all articles written by all types of developers&lt;br /&gt;
*[[Plug-in_Developer#SDK_Documentation|SDK Documentation]]&lt;br /&gt;
* Download the SDK&lt;br /&gt;
*[[Developers_FAQ | Frequently Asked Questions]] &lt;br /&gt;
*[[Skin Developer]]&lt;br /&gt;
*[[Visual Developer]]&lt;br /&gt;
*[[Plug-in Developer]]&lt;br /&gt;
*[[Online Service Developer]]&lt;br /&gt;
*[[Tips for Writing an Awesome Online Service]]&lt;br /&gt;
*[[Glossary|Glossary of Terms]]&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
Check out the [[Developers FAQ]]. Not to mistaken for the standard frequently asked questions that live on the Winamp Forums (although there may be some overlap), this FAQ is specific to developers.&lt;br /&gt;
&lt;br /&gt;
==Contribute to the Wiki ==&lt;br /&gt;
Just like the success of Winamp itself, the success of the Developer Network relies on you. We encourage '''everyone''' to contribute - from the expert developer to the passionate user. Your updates, additions, and moderation efforts are critical and we definitely appreciate your efforts making this one of the premier developer sites.&lt;br /&gt;
&lt;br /&gt;
*[[Policies &amp;amp; Guidelines]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/MilkDrop_Unleashed_Guide</id>
		<title>MilkDrop Unleashed Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/MilkDrop_Unleashed_Guide"/>
				<updated>2009-12-22T14:56:06Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Usage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
===Installation===&lt;br /&gt;
MilkDrop 2 comes with Winamp.  To install it, just download and install the latest version of Winamp.  During the installation, make sure the &amp;quot;MilkDrop&amp;quot; visualizer option is checked, so that it gets installed, too.  &lt;br /&gt;
&lt;br /&gt;
Once Winamp is installed, launch it.  Load some music files into your playlist and start playing some music.  (Be sure to play some music before trying to launch the visualizer - otherwise you'll just see a black screen.)&lt;br /&gt;
&lt;br /&gt;
Once music is playing, hit CTRL+K and a list of visualization plug-ins will appear.  Select &amp;quot;MilkDrop 2&amp;quot; from the list.  Then click the &amp;quot;Start&amp;quot; button, and it will launch the visualizer.  &lt;br /&gt;
&lt;br /&gt;
    Quick Tips:    &lt;br /&gt;
      * If you want to go full-screen, double-click on the visualizer itself.&lt;br /&gt;
      * CTRL+SHIFT+K starts or stops the visualizer.&lt;br /&gt;
      * To configure MilkDrop's options, exit the visualizer and hit ALT+K.&lt;br /&gt;
    &lt;br /&gt;
    If you have trouble getting MilkDrop to run properly after installation, &lt;br /&gt;
    try installing various recent WHQL drivers for your video card, or installing &lt;br /&gt;
    DirectX; doing these two things (especially the first) will fix 99% of&lt;br /&gt;
    problems. See the Troubleshooting section of the documentation for more&lt;br /&gt;
    information.&lt;br /&gt;
&lt;br /&gt;
===Tweaking to achieve best image quality===&lt;br /&gt;
&lt;br /&gt;
a) Fullscreen Display Mode   [first tab of config screen]&lt;br /&gt;
&lt;br /&gt;
When you run MilkDrop fullscreen, it changes the display mode to whatever you select here.  Generally speaking, the speed (framerate) and smoothness of MilkDrop will drop as the resolution (number of pixels on the screen)increases.  So, if it's running to slow in fullscreen mode, try selecting a smaller fullscreen display mode. &lt;br /&gt;
        &lt;br /&gt;
b) Canvas Stretch  [second tab]&lt;br /&gt;
&lt;br /&gt;
This option lets you trade resolution [crispness] for speed.  If MilkDrop runs too slow, in any mode (windowed/fullscreen/desktop), try cranking up the canvas stretch to, say, 1.5X or 2X.  The image will not look as crisp, but MilkDrop will probably run much faster.  (Assuming that your graphics chip was the bottleneck.)&lt;br /&gt;
&lt;br /&gt;
c) Mesh Size  [second tab]&lt;br /&gt;
&lt;br /&gt;
This is the main option that affects how much processor (CPU) MilkDrop uses.  If you crank it up far beyond the default, expect to be CPU-bound (where your framerate drops because the CPU is the bottleneck).  To get MilkDrop to speed up, drop the Mesh Size back down.  The Mesh Size decides how many points on the screen the per-vertex equations will be executed for; the higher the mesh size, the more fidelity you will see in the motion.  &lt;br /&gt;
        &lt;br /&gt;
d) Tips for LCD and laptop users&lt;br /&gt;
&lt;br /&gt;
LCD screens: Note that most LCD screens (flatpanels) usually run at a fixed frequency only - usually 60 Hz - meaning that they update the screen 60 times per second.  However, sometimes the video driver reports that it supports other refresh rates, such as 72, 75, 85, etc. It is strongly recommended that [for fullscreen mode, and for Windows in general] you choose a display mode with a 60 Hz refresh rate, for the smoothest possible animation.  For this plugin, you will also want to choose Maximum Framerates that divide evenly into 60 - such as 60, 30, 20, 15, 12, 10, 6, 5, and so on - so that the # of times the LCD shows each frame of animation remains constant, resulting in the smoothest possible animation.&lt;br /&gt;
&lt;br /&gt;
e) color (bit) depth: 16 or 32?&lt;br /&gt;
&lt;br /&gt;
The answer, nowadays, is a resounding &amp;quot;32&amp;quot;.  Video memory is plentiful these days; use 32 bit color, for both your windows desktop (...so that MilkDrop's windowed mode can run at 32 bits) and for MilkDrop's Fullscreen Display Mode setting (where &amp;quot;8888&amp;quot; denotes 32 bits). Some ancient video cards don't have enough memory to run MilkDrop properly (or smoothly) in 32 bits, though; you might want to try 16-bit color if your card has less than 32 MB of video memory, if you are using a laptop, or if your video card is significantly old.  In the MilkDrop config panel, 16-bit modes show up as &amp;quot;555&amp;quot; or &amp;quot;565&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you find that your card runs best in 32-bit color, you should have no problems with brightness levels while running MilkDrop. However, if your card runs best in 16-bit color, you should then adjust the Brightness slider on the second tab of the config panel (which only affects 16-bit color video modes!).  The goal is to make the image as bright as possible, without oversaturating it (washing it out, often to bright pink or white).  This setting also varies for different cards, depending on how the card rounds color values, so we recommend seeing how bright you can set the slider closer to '0') without oversaturating the image.  Usually,a setting of '0' or '2' works the best.&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
&lt;br /&gt;
'''4.a. Keyboard Commands'''&lt;br /&gt;
    &lt;br /&gt;
The following keys can be used to control MilkDrop while it is running.&lt;br /&gt;
(Note: pressing F1 while MilkDrop is running will show you this list)&lt;br /&gt;
          &lt;br /&gt;
GENERAL&lt;br /&gt;
 escape: exit to winamp&lt;br /&gt;
&lt;br /&gt;
PRESET LOADING&lt;br /&gt;
 BACKSPACE: return to previous preset&lt;br /&gt;
 SPACE: transition to next preset&lt;br /&gt;
 H: instant Hard cut (to next preset)&lt;br /&gt;
 R: toggle random (vs. sequential) preset traversal&lt;br /&gt;
 L: load a specific preset (invokes the 'Load' menu)&lt;br /&gt;
 +/-: rate current preset (better/worse)&lt;br /&gt;
 scroll lock: lock/unlock current preset &lt;br /&gt;
   (keyboard light on means preset is locked)&lt;br /&gt;
   (prevents random switch to new preset)&lt;br /&gt;
 A: aggregate preset - loads a random preset,&lt;br /&gt;
    steals the warp shader from a different random preset,&lt;br /&gt;
    and steals the composite shader from a third random preset.&lt;br /&gt;
 D: cycle between various lock-states for the warp and&lt;br /&gt;
    composite shaders.  When one of these shaders is locked,&lt;br /&gt;
loading a new preset will load everything *except* the&lt;br /&gt;
locked shaders, creating a mix between the two presets.&lt;br /&gt;
&lt;br /&gt;
PRESET EDITING AND SAVING&lt;br /&gt;
 M: show/hide the preset-editing menu&lt;br /&gt;
 S: save new preset (asks you for the new filename)&lt;br /&gt;
 N: show per-frame variable moNitor&lt;br /&gt;
(see [[MilkDrop Preset Authoring]])&lt;br /&gt;
&lt;br /&gt;
MUSIC PLAYBACK&lt;br /&gt;
 z/x/c/v/b: navigate playlist (prev/play/pause/stop/next)&lt;br /&gt;
 U: toggle shuffle&lt;br /&gt;
 P: show playlist&lt;br /&gt;
 up/down arrows: volume up/down&lt;br /&gt;
 left/right arrows: rewind/ffwd 5 seconds&lt;br /&gt;
 SHIFT + left/right arrows: rewind/ffwd 30 seconds&lt;br /&gt;
&lt;br /&gt;
FUNCTION KEYS                                &lt;br /&gt;
 F1: show help screen&lt;br /&gt;
 F2: show song title&lt;br /&gt;
 F3: show song length&lt;br /&gt;
 F4: show preset name&lt;br /&gt;
 F5: show fps (frames per second)&lt;br /&gt;
 F6: show rating of current preset&lt;br /&gt;
 F7: re-read custom message file (milk_msg.ini) from disk&lt;br /&gt;
 F8: jump to new directory (for presets)&lt;br /&gt;
 F9: toggle stereo 3D on/off&lt;br /&gt;
&lt;br /&gt;
SPRITES AND CUSTOM MESSAGES (FOR VJ's)&lt;br /&gt;
 T: launch song title animation&lt;br /&gt;
 Y: enter custom message mode&lt;br /&gt;
 ##: load message ## (where ## is a 2-digit numeric code (00-99) &lt;br /&gt;
 of a message defined in milk_msg.ini)&lt;br /&gt;
 *: clear any digits entered.&lt;br /&gt;
DELETE: clear message (if visible)&lt;br /&gt;
 F7: re-read milk_msg.ini from disk&lt;br /&gt;
 K: enter sprite mode&lt;br /&gt;
 ##: load sprite ## (where ## is a 2-digit numeric code (00-99) &lt;br /&gt;
     of a sprite defined in milk_img.ini)&lt;br /&gt;
 *: clear any digits entered.&lt;br /&gt;
 DELETE: clear newest sprite &lt;br /&gt;
 SHIFT + DELETE: clear oldest sprite&lt;br /&gt;
 CTRL+SHIFT+DELETE: clear all sprites&lt;br /&gt;
 F7: no effect (milk_img.ini is never cached)&lt;br /&gt;
 SHIFT + K: enter sprite kill mode&lt;br /&gt;
 ##: clear all sprites with code ##&lt;br /&gt;
 *: clear any digits entered.&lt;br /&gt;
 CTRL + T/Y: kill song title and/or any custom messages&lt;br /&gt;
 CTRL + K: kill all sprites&lt;br /&gt;
             &lt;br /&gt;
Note that there are more keys available, but because many&lt;br /&gt;
are only relevant to people designing their own presets, &lt;br /&gt;
they are listed in the preset authoring guide instead.&lt;br /&gt;
    &lt;br /&gt;
'''4.b. config panel'''&lt;br /&gt;
 &lt;br /&gt;
The configuration panel lets you customize the way MilkDrop runs.&lt;br /&gt;
To learn how to get to the configuration panel, see the &amp;quot;Installation&amp;quot;&lt;br /&gt;
section above.&lt;br /&gt;
        &lt;br /&gt;
Once you're in the config panel, you'll see a number of tabs&lt;br /&gt;
at the top, some dropdown boxes, and some checkboxes.  Each&lt;br /&gt;
of the tabs at the top brings you to a different page of &lt;br /&gt;
configuration options.  To get help on a setting, simply click&lt;br /&gt;
on the '?' in the upper-right corner of the config panel, &lt;br /&gt;
and then click on the setting you want help with.&lt;br /&gt;
&lt;br /&gt;
'''4.c. preset authoring'''&lt;br /&gt;
    &lt;br /&gt;
Please check the [[MilkDrop Preset Authoring]] guide for instructions on how to create and save your own presets.&lt;br /&gt;
&lt;br /&gt;
'''4.d. rating system'''&lt;br /&gt;
&lt;br /&gt;
The built-in rating system allows you to rate each preset on a scale &lt;br /&gt;
from 0 to 5.  A rating of 5 is very good, while a rating of 0 is&lt;br /&gt;
the worst.  The ratings decide how often the presets will be randomly&lt;br /&gt;
loaded.  If a preset has a rating of 0, it will never be randomly&lt;br /&gt;
loaded (unless they're all zero; then they all have an equal chance).&lt;br /&gt;
        &lt;br /&gt;
To show the rating for a preset, press F6.  You can adjust the &lt;br /&gt;
rating for a preset with the +/- keys.  When you make adjustments,&lt;br /&gt;
they save automatically; there's no need to save the preset to make&lt;br /&gt;
the rating change permanent.&lt;br /&gt;
        &lt;br /&gt;
Here's a recommended interpretation of the numeric values:&lt;br /&gt;
            0 = I never want to see this preset again&lt;br /&gt;
            1 = very ugly&lt;br /&gt;
            2 = mediocre&lt;br /&gt;
            3 = fair&lt;br /&gt;
            4 = good&lt;br /&gt;
            5 = downright stimulating&lt;br /&gt;
            &lt;br /&gt;
If a preset seems &amp;quot;lost&amp;quot; because you set its rating to 0 and it&lt;br /&gt;
won't ever come back, you can always load it up by hitting 'L'&lt;br /&gt;
to conjure the 'Load Preset' menu, finding the preset you want,&lt;br /&gt;
loading it, then hitting +.&lt;br /&gt;
&lt;br /&gt;
'''4.e. custom messages'''&lt;br /&gt;
&lt;br /&gt;
ABOUT CUSTOM MESSAGES:&lt;br /&gt;
The &amp;quot;Custom Message&amp;quot; feature of MilkDrop allows you to display&lt;br /&gt;
short text messages on the screen while MilkDrop is running.&lt;br /&gt;
They are highly configurable; you can set all of the following&lt;br /&gt;
parameters: the font, the size, the positioning, color, bold &lt;br /&gt;
state, italic state, and so on; and you can even have it &lt;br /&gt;
randomize some of these properties.&lt;br /&gt;
&lt;br /&gt;
CREATING THE MESSAGES:&lt;br /&gt;
You can save up to 100 messages in the file MILK_MSG.INI in&lt;br /&gt;
your Winamp\Plugins\ folder.  To open this file, go to the &lt;br /&gt;
MilkDrop configuration screen (ALT+K from Winamp) and click the&lt;br /&gt;
&amp;quot;Edit Custom Messages&amp;quot; button.  Or, you can just edit it &lt;br /&gt;
manually if you know how; it's plain-text.&lt;br /&gt;
            &lt;br /&gt;
The first thing you see when you open the file is a bunch of&lt;br /&gt;
lines that start with two forward slashes (//).  These are&lt;br /&gt;
comment lines, and they explain the syntax for adding a font&lt;br /&gt;
or a message to the file.  This is your main reference for&lt;br /&gt;
finding out what all the parameters do for the fonts &amp;amp; messages;&lt;br /&gt;
it is recommended that you leave this information in the file,&lt;br /&gt;
although it can be removed or (modified) and the messages will&lt;br /&gt;
still work.&lt;br /&gt;
&lt;br /&gt;
After the comments come first the fonts, then the messages.&lt;br /&gt;
The fonts are simply a way to specify a typeface, bold state,&lt;br /&gt;
italics state, and red/green/blue color for the font.  You can &lt;br /&gt;
configure up to 16 fonts like this (numbered 00-15). These fonts&lt;br /&gt;
will serve as template fonts for the custom messages.&lt;br /&gt;
&lt;br /&gt;
The next section is the actual messages.  Each one has a&lt;br /&gt;
text message (the 'text' parameter) that will be shown to the&lt;br /&gt;
user, and each one references one of the 16 fonts that were&lt;br /&gt;
defined in the previous section.  You can also specify the&lt;br /&gt;
size (size), position (x,y), a growth factor (growth) that&lt;br /&gt;
will grow/shrink the message over its lifetime, the number&lt;br /&gt;
of seconds to show the message (time), and the fraction of that&lt;br /&gt;
time that is spent fading in (fade).  &lt;br /&gt;
&lt;br /&gt;
You can also randomize some of these values: 'randx' and 'randy'&lt;br /&gt;
will randomly perturb the (x,y) coordinates every time the message&lt;br /&gt;
is shown to the user, and 'randr'/'randg'/'randb' will randomly&lt;br /&gt;
perturb the (r,g,b) color in the same way.&lt;br /&gt;
&lt;br /&gt;
Finally, you can override any of the default properties for the&lt;br /&gt;
font that this message uses: (face, bold, ital, r, g, b).&lt;br /&gt;
&lt;br /&gt;
INVOCATION AND USAGE:&lt;br /&gt;
There are two ways to invoke custom messages: one automatic,&lt;br /&gt;
the other manual.  &lt;br /&gt;
&lt;br /&gt;
The automatic way is to go to the MilkDrop config panel (ALT+K),&lt;br /&gt;
click the 'More Options' button, and set the value in the&lt;br /&gt;
'Time between RANDOM custom messages' box to something greater&lt;br /&gt;
than zero.  This will cause MilkDrop to randomly display custom &lt;br /&gt;
messages while it is running, and the average time (in seconds) &lt;br /&gt;
between messages will be the value you entered here.  If you &lt;br /&gt;
wish to disable random custom messages, set this value to -1&lt;br /&gt;
(or any negative number).  Note that all messages in the file&lt;br /&gt;
have an equal change of being picked.&lt;br /&gt;
&lt;br /&gt;
The manual way is to type in the two-digit code (00-99) of the &lt;br /&gt;
message while MilkDrop is running.  However, you can't use the &lt;br /&gt;
numeric keypad for this - you have to use the numbers at the &lt;br /&gt;
TOP of your keyboard to do it.  If you mess up while entering&lt;br /&gt;
the first digit, just press the '*' key to start over.&lt;br /&gt;
            &lt;br /&gt;
Note that if you change the MILK_MSG.INI file while MilkDrop&lt;br /&gt;
is running, you will not be able to see the changes until&lt;br /&gt;
you hit F7, which tells MilkDrop to re-read the MILK_MSG.INI &lt;br /&gt;
file from disk.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.f. sprites'''&lt;br /&gt;
&lt;br /&gt;
ABOUT SPRITES:&lt;br /&gt;
The &amp;quot;Sprite&amp;quot; feature of MilkDrop allows you to display any image of your choice in the foreground (on top of MilkDrop) while it runs.  The sprites can fade in and out, move around, respond to the music, and so on.  You define them in a file - milk_img.ini in your winamp\plugins directory - much like you define custom messages, each having an identifying code number from 00 through 99 (used to invoke them).  However, the way the individual sprites are defined is different; you write code for them, instead of just setting parameter values.  This is a little bit tougher to do (it's very much like preset authoring), but adds a great deal of flexibility to what you can do with the sprites.&lt;br /&gt;
&lt;br /&gt;
CREATING THE SPRITES:&lt;br /&gt;
            &lt;br /&gt;
You can define up to 100 sprites in the file MILK_IMG.INI in your Winamp\Plugins\ folder.  To open this file, go to the MilkDrop configuration screen (ALT+K from Winamp) and click the &amp;quot;Edit Sprites&amp;quot; button.  Or, you can just edit it manually if you know how; it's plain-text.&lt;br /&gt;
            &lt;br /&gt;
The first thing you see when you open the file is a bunch of lines that start with two forward slashes (//).  These are comment lines, and they explain the syntax for creating a sprite. This is your main reference for finding out what all the parameters do for the fonts &amp;amp; messages; it is recommended that you leave this information in the file, although it can be removed (or modified) and the sprites will still work.&lt;br /&gt;
&lt;br /&gt;
After the comments come the sprite definitions.  Each sprite is made up of one parameter that indicates the image file to use (this is the 'img=...' line), and two types of code: initialization code, and regular code.  &lt;br /&gt;
            &lt;br /&gt;
The first - initialization code - is executed only once, when you launch the sprite.  Use it to do one-time initialization of variables (such as the opacity (a), rotation angle (rot), position (x,y), and so on) or to invent new variables that you will access later. This code is marked by the 'init_1=...', 'init_2=...', etc. lines. The second type of code - marked by 'code_1=...', 'code_2=...', etc. is executed every frame, just prior to plastering the sprite on             the screen.  Use it to animate the sprite, moving it around (changing x,y), scaling it up and down (sx,sy), fading it in and out (a), changing its color, and so on.&lt;br /&gt;
            &lt;br /&gt;
            Please see the comments included in the sample milk_img.ini file&lt;br /&gt;
            for full details and examples on how to author sprites.&lt;br /&gt;
&lt;br /&gt;
INVOCATION AND USAGE:&lt;br /&gt;
There is currently only one way to invoke sprites: manually. To do this, first press 'K' to enter 'sprite mode' (while running MilkDrop).  Now, whenever you type in a two-digit             code (00-99), MilkDrop will try to find &amp;amp; launch the sprite you've requested, from the milk_img.ini file.  If there is an error, it will display an error message in the upper-right corner.  Note that to enter the two-digit code, you can't use the numeric keypad; you have to use the numbers at the TOP of  your keyboard.  &lt;br /&gt;
&lt;br /&gt;
If you make an error entering the first digit of the code, just press '*' to start over.  If you want to clear the most recently-invoked sprite, press DELETE.  If you want to clear the oldest sprite, press SHIFT + DELETE.  If you want to clear all sprites, press SHIFT + CTRL + DELETE.&lt;br /&gt;
&lt;br /&gt;
If you want to clear sprites by their 2-digit code, press SHIFT + K (instead of just 'K') to enter 'sprite kill mode.' Now, when you enter a two-digit code, instead of invoking the sprite, MilkDrop clears all running sprites with that two-digit code.&lt;br /&gt;
&lt;br /&gt;
===Trouble Shooting===&lt;br /&gt;
&lt;br /&gt;
If MilkDrop has a critical problem (e.g. fails to load, freezes, etc.)or if the image is distorted, torn, corrupted, or all one solid color, try the following two suggestions to resolve the problem.  In 90% of these cases it can be fixed.  If you have a different problem, scroll down past this part and try to find the appropriate symptom and its solution.&lt;br /&gt;
&lt;br /&gt;
====1. UPDATE YOUR VIDEO DRIVER, OR TRY OTHER DRIVERS====&lt;br /&gt;
    &lt;br /&gt;
Almost all display problems are caused by buggy video drivers! A &amp;quot;driver&amp;quot; is a piece of software that translates graphics-related commands from programs, like MilkDrop, into the native language of your specific graphics hardware.&lt;br /&gt;
&lt;br /&gt;
For desktop machines, there are typically three sources for video drivers: &lt;br /&gt;
# those from the *chip* manufacturer's website (usually nvidia.com or ati.com) (best source) &lt;br /&gt;
# those from the card manufacturer's website (LeadTEK, PNY, etc.)&lt;br /&gt;
# those that shipped with Windows (yuck)&lt;br /&gt;
        &lt;br /&gt;
For laptops:&lt;br /&gt;
# the driver from the *laptop* manufacturer&lt;br /&gt;
# (maybe) the driver from the graphics chip manufacturer (ATI, Nvidia, etc) - however, it's fairly common to find that the laptop requires a custom driver written by the laptop manufacturer.&lt;br /&gt;
# the driver that shipped with Windows (yuck)&lt;br /&gt;
&lt;br /&gt;
Give them all a shot.  Track down every driver you can find for your card, and try it.  Try the WHQL ones first - these versions of the drivers have passed &amp;quot;Windows Hardware Quality Labs&amp;quot; certification and are usually the more stable and reliable ones. In general, it's a very good idea to use only Microsoft-certified WHQL drivers for your video card.  Often people want to get the newest, fastest beta drivers, but these drivers are almost ALWAYS riddled with new bugs.  You can also watch the version number of the drivers a company releases - if the version number just jumped to a new series such as from the 70's to the 80's), watch out, it probably has a lot of bugs that need worked out - give it 3-4 months before expecting the new driver series to work well.  With video drivers, the newest isn't always the best!&lt;br /&gt;
&lt;br /&gt;
Here is a list of some common card/chip manufacturers and where to get their drivers.  Don't forget to choose the WHQL driver!&lt;br /&gt;
&lt;br /&gt;
            [http://www.nvidia.com/page/drivers.html NVIDIA driver]&lt;br /&gt;
                Card manufacturers using NVIDIA (GeForce) graphics chips:&lt;br /&gt;
                (note - most of these just link you to the nvidia driver above)&lt;br /&gt;
                [http://www.xfxforce.com/web/support/showSearchDriversProductCode.jspa XFX]&lt;br /&gt;
                [http://www.evga.com/support/drivers EVGA]&lt;br /&gt;
                [http://www.bfgtech.com/driverdownload.aspx BFG]&lt;br /&gt;
                [http://www2.pny.com/support/support.aspx PNY]  &lt;br /&gt;
            [http://ati.amd.com/support/driver.html ATI driver] &lt;br /&gt;
                Card manufacturers using ATI (Radeon) graphics chips:&lt;br /&gt;
                [http://www.visiontek.com/teksupport/drivers/drivers.html VisionTek]              &lt;br /&gt;
                [http://www.dmmdownload.com/current.php Diamond]                &lt;br /&gt;
            [http://downloadcenter.intel.com Intel] - then click 'graphics' on the left&lt;br /&gt;
            [http://www.sis.com/download SiS] - agree, then select 'graphics drivers'&lt;br /&gt;
            [http://www.s3graphics.com S3] - then click 'drivers'&lt;br /&gt;
            [http://www.via.com.tw/en/products/graphics VIA]    &lt;br /&gt;
            [http://www.matrox.com/graphics/en/corpo/support/drivers/home.php Matrox]&lt;br /&gt;
            [http://www.creative.com/language.asp?sDestUrl=/support/downloads Creative Labs]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For others - or in general - if your graphics chip is made by Trident, for example, then try a [http://www.google.com/ google] search for:&lt;br /&gt;
        &lt;br /&gt;
                Trident graphics driver&lt;br /&gt;
                        &lt;br /&gt;
Then click on &amp;quot;support&amp;quot;, then &amp;quot;drivers&amp;quot; (or &amp;quot;downloads&amp;quot;), then &amp;quot;graphics driver&amp;quot;, and so on.&lt;br /&gt;
&lt;br /&gt;
====2. [RE]INSTALL DIRECTX====&lt;br /&gt;
    &lt;br /&gt;
Make sure you have a quasi-recent version of Microsoft DirectX installed.  In reality, though, almost every PC in the world has DirectX 9 on it at this point, so this shouldn't be a problem. If you go to download it, you'll only be able to find DirectX 10 - this is fine to install, though, as it includes DirectX 9 inside it.  As a last resort, though, if you are having problems, you could try re-installing DirectX to see if it helps.&lt;br /&gt;
&lt;br /&gt;
If you're having a non-critical problem, browse the following list of common problems and their causes and solutions.  Note that for each symptom- cause-solution block, there can be multiple symptoms with the same cause and solution, and the same symptom might be listed in multiple blocks.&lt;br /&gt;
&lt;br /&gt;
If the solutions below don't work for you, please visit the forums at http://forums.winamp.com/forumdisplay.php?forumid=84, where you can read the most recent troubleshooting issues and solutions.&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
    ENTRY 1&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        -any error message saying &amp;quot;Failed to create ...&amp;quot; &lt;br /&gt;
            or &amp;quot;not enough memory...&amp;quot;, or&lt;br /&gt;
        -only a portion of the screen displays correctly; the rest is &lt;br /&gt;
            either filled with garbage or badly flickering&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        1) Your video card might not have enough memory to run MilkDrop at &lt;br /&gt;
        the resolution (screen width and height) you've picked, &lt;br /&gt;
        2) your drivers might be out of date, &lt;br /&gt;
        3) you might need to reinstall DirectX (very very rare), or&lt;br /&gt;
        4) your graphics card might be to crappy to *actually* run&lt;br /&gt;
             pixel shaders well.&lt;br /&gt;
    SOLUTION:    &lt;br /&gt;
        1) To battle video memory problems:&lt;br /&gt;
            &lt;br /&gt;
            Go to the config panel and try smaller video modes (e.g.,&lt;br /&gt;
            320x240 is smaller than 640x480).  Even better is to try&lt;br /&gt;
            a lower color bit depth; if you'd selected a 32-bit (&amp;quot;8888&amp;quot;) &lt;br /&gt;
            video mode before, try a 16- (&amp;quot;565&amp;quot; or &amp;quot;555&amp;quot;) or 24-bit (&amp;quot;888&amp;quot;) &lt;br /&gt;
            one, for example.  Note that it might only work in one of them; &lt;br /&gt;
            so make sure you try them all.  Trying these things is especially &lt;br /&gt;
            important on laptops with limited video memory, or older video &lt;br /&gt;
            cards with a small amount of video memory.&lt;br /&gt;
        &lt;br /&gt;
            Finally, you can try locking the texture size (or &amp;quot;canvas size&amp;quot;) &lt;br /&gt;
            to 256x256 pixels, just to see if that fixes the problem.  &lt;br /&gt;
            If it does, try using a smaller fullscreen video mode to&lt;br /&gt;
            free up some memory, or if running windowed, close other&lt;br /&gt;
            graphics-hungry applications.&lt;br /&gt;
        &lt;br /&gt;
        2,3) for instructions on how to reinstall DirectX or update &lt;br /&gt;
            drivers, go here.&lt;br /&gt;
            &lt;br /&gt;
        4) Go to the MilkDrop config panel (hit ALT+K) and on the second tab, &lt;br /&gt;
            in the &amp;quot;Pixel Shaders&amp;quot; box, select &amp;quot;None.&amp;quot;  Now does MilkDrop run &lt;br /&gt;
            ok?  If so, your video card probably just can't reliably run&lt;br /&gt;
            pixel shaders, due to either inferior hardware, or it could&lt;br /&gt;
            be the driver.  You can always try setting &amp;quot;Pixel Shaders&amp;quot; &lt;br /&gt;
            back to &amp;quot;Auto&amp;quot; and then installing a newer (preferably WHQL) &lt;br /&gt;
            video driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    ENTRY 2&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        -When I go to the Load Preset menu ('L') in MilkDrop, some of the&lt;br /&gt;
            presets on disk are missing.&lt;br /&gt;
        -I downloaded some new presets and put them in my Plugins\MilkDrop2\Presets&lt;br /&gt;
            directory, but I can't access them from within MilkDrop.&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        You probably have an older video card that can't handle the pixel&lt;br /&gt;
        shaders needed to run some of the presets.  MilkDrop automatically&lt;br /&gt;
        hides any presets from you that you can't run.&lt;br /&gt;
    SOLUTION:&lt;br /&gt;
        * You could b uy a new graphics card - one that meets the minimum&lt;br /&gt;
        recommendation for MilkDrop 2.  These cost less than $40.&lt;br /&gt;
        * You could try forcing MilkDrop to try to run these presets.&lt;br /&gt;
        Sometimes MilkDrop just hides them from you because it predicts&lt;br /&gt;
        they will run horribly slow on your graphics card; in case it&lt;br /&gt;
        is wrong about that, try this.  Go into the MilkDrop config&lt;br /&gt;
        panel (ALT+K) and go to the More Settings tab.  Under the &lt;br /&gt;
        &amp;quot;Pixel Shaders&amp;quot; option, change it from &amp;quot;Auto&amp;quot; to &amp;quot;Shader Model 2&amp;quot;&lt;br /&gt;
        or &amp;quot;Shader Model 3&amp;quot;.  Then try to run MilkDrop and see if the&lt;br /&gt;
        presets appear.  If they do, you're in luck; if they don't, your&lt;br /&gt;
        GPU really doesn't support those shader models.&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    ENTRY 3&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        MilkDrop always looks the same - it's always showing the same&lt;br /&gt;
        preset, and it never changes to a new preset unless I tell it to.&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        Scroll Lock is on.&lt;br /&gt;
    SOLUTION:&lt;br /&gt;
        The Scroll Lock key is how you tell MilkDrop to lock the current&lt;br /&gt;
        preset - i.e. don't randomly transition to a new preset unless you &lt;br /&gt;
        do it.  The state of the Scroll Lock key is remembered when you&lt;br /&gt;
        start or stop MilkDrop, too, so be careful of that.  If you are&lt;br /&gt;
        experiencing this problem, you can fix it in any of the following&lt;br /&gt;
        three ways:&lt;br /&gt;
          1. hit Scroll Lock while MilkDrop is running (and the viz window is active);&lt;br /&gt;
          2. load up the MilkDrop config panel (ALT+K), go to the More Settings&lt;br /&gt;
              tab, and uncheck the &amp;quot;Start milkdrop with preset lock (scroll lock) &lt;br /&gt;
              key ON&amp;quot; box;&lt;br /&gt;
          3. if you're using a modern skin, there is a &amp;quot;random&amp;quot; button on&lt;br /&gt;
              the frame of the window, which is the inverse of the Scroll Lock&lt;br /&gt;
              state - i.e. you probably have Scroll Lock on and &amp;quot;random&amp;quot; off.&lt;br /&gt;
              Click the &amp;quot;Random&amp;quot; button to turn random transitions back on&lt;br /&gt;
              (and notice that scroll lock gets turned off as a result).&lt;br /&gt;
&lt;br /&gt;
    ENTRY 4&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        I was browsing for presets from within MilkDrop ('L') key and &lt;br /&gt;
        got lost.  How do I get back to my presets?&lt;br /&gt;
    SOLUTION:   &lt;br /&gt;
        Two ways to fix this.  The easiest is to just reset MilkDrop&lt;br /&gt;
        to its defaults - hit ALT+K to load the MilkDrop config panel,&lt;br /&gt;
        then click the 'Defaults' button.  The next time you launch&lt;br /&gt;
        MilkDrop, it will start you in the default preset directory.&lt;br /&gt;
        &lt;br /&gt;
        To fix it manually (and preserve all your settings), run&lt;br /&gt;
        MilkDrop, hit F8, and paste in this path:&lt;br /&gt;
          C:\Program Files\Winamp\Plugins\Milkdrop2\presets&lt;br /&gt;
        [or equivalent].&lt;br /&gt;
        &lt;br /&gt;
        Another way to fix it is to hit 'L', and browse all the way &lt;br /&gt;
        down to the root folder (repeatedly select &amp;quot;..&amp;quot;), then&lt;br /&gt;
        go into Program Files, Winamp, Plugins, MilkDrop2, and finally,&lt;br /&gt;
        presets.&lt;br /&gt;
&lt;br /&gt;
    ENTRY 5&lt;br /&gt;
    SYMPTOM:&lt;br /&gt;
        -things flicker through (such as my AIM window ticker, taskbar&lt;br /&gt;
        clock, web page animations, etc.) when I'm running MilkDrop&lt;br /&gt;
        in fullscreen mode.&lt;br /&gt;
    CAUSE:&lt;br /&gt;
        You're probably running MilkDrop fullscreen at the same&lt;br /&gt;
        resolution &amp;amp; color depth as your desktop, and Windows isn't &lt;br /&gt;
        properly handling MilkDrop's request for exclusive access to the&lt;br /&gt;
        screen, and is still letting other applications paint (draw)&lt;br /&gt;
        themselves.&lt;br /&gt;
    SOLUTION:&lt;br /&gt;
        Change either your Windows desktop resolution or color depth, or &lt;br /&gt;
        MilkDrop's fullscreen resolution or color depth, so that there&lt;br /&gt;
        is some difference between the two.   (To change your Windows &lt;br /&gt;
        display settings, go to the Start Menu -&amp;gt; Settings -&amp;gt; Control &lt;br /&gt;
        Panel -&amp;gt; Display -&amp;gt; Settings tab, and then change the &amp;quot;colors&amp;quot; &lt;br /&gt;
        or &amp;quot;screen area&amp;quot; settings from there.)  Also make sure you're&lt;br /&gt;
        not using &amp;quot;fake&amp;quot; fullscreen mode (...uncheck this box on the&lt;br /&gt;
        main screen of the config panel).&lt;br /&gt;
&lt;br /&gt;
===Known Issues / Misc. / Tips:===&lt;br /&gt;
&lt;br /&gt;
    a. Tip for video capture: if you'd like to save sequences of video &lt;br /&gt;
        from this plugin, there are several programs out there that will &lt;br /&gt;
        let you do this.  Warning: you will need a ton of free hard drive &lt;br /&gt;
        space, and a fast CPU helps.  A few of these programs are:&lt;br /&gt;
            &amp;quot;FRAPS&amp;quot;               http://www.fraps.com/&lt;br /&gt;
            &amp;quot;Hypercam&amp;quot;            http://www.hyperionics.com&lt;br /&gt;
    &lt;br /&gt;
    b. Close other apps:&lt;br /&gt;
        For the best graphics performance, try to close as many other &lt;br /&gt;
        applications as you can, before running the plugin, especially &lt;br /&gt;
        those that tend to work in the background, such as anti-virus &lt;br /&gt;
        or file-swapping software.  Also, if you must leave other &lt;br /&gt;
        applications open, try to minimize them (i.e. shrink the window &lt;br /&gt;
        down to the taskbar) so that they stay out of the painting loop.&lt;br /&gt;
    &lt;br /&gt;
    c. Windows Vista / Winamp with per-user settings&lt;br /&gt;
        Be aware that if you're running Vista as a non-admin user,&lt;br /&gt;
        you can't write to (or delete from) files in the Program Files&lt;br /&gt;
        directory, which is were MilkDrop 2 is installed.  So, anything&lt;br /&gt;
        you try to write or save (like milkdrop's settings file, milk2.ini; &lt;br /&gt;
        or presets) will probably end up deep in some user-specific, &lt;br /&gt;
        virtualized &amp;quot;Program Files&amp;quot; directory somewhere on your hard &lt;br /&gt;
        drive.  Yell at Microsoft for this one!&lt;br /&gt;
        &lt;br /&gt;
        Also, if you installed Winamp with per-user settings (instead of &lt;br /&gt;
        shared settings) - on any OS, not just Vista - be aware that your&lt;br /&gt;
        .INI files (milk2.ini, milk2_img.ini, milk2_cfg.ini) are all&lt;br /&gt;
        stored in a folder like this:&lt;br /&gt;
            &lt;br /&gt;
            C:\Documents and Settings\\Application Data\Winamp\Plugins         &lt;br /&gt;
            &lt;br /&gt;
        (Note that 'Application Data' is a hidden folder.)  However,&lt;br /&gt;
        presets, textures, and things like that are all shared between&lt;br /&gt;
        users, in the real [c:\Program Files]\winamp\plugins\milkdrop2 folder. &lt;br /&gt;
        If you want to keep your presets separate, you can still do that, &lt;br /&gt;
        though - just put them in a personal folder, and then seek to it&lt;br /&gt;
        from within MilkDrop.  If you're using per-user settings in Winamp,&lt;br /&gt;
        it will remember which folder you last used.&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using Line-In===&lt;br /&gt;
-----------------------&lt;br /&gt;
    If you want to use your sound card's Line-In or CD Audio inputs for&lt;br /&gt;
    sound data (instead of mp3 files), you can do this.  Do the following:&lt;br /&gt;
        1. CONNECT WIRES&lt;br /&gt;
            Connect your audio source (a stereo, a live feed, whatever) into&lt;br /&gt;
            the line-in (or microphone) 1/8&amp;quot; jack on your sound card.  You&lt;br /&gt;
            might want to test &amp;amp; verify that your cable is good before doing &lt;br /&gt;
            this.&lt;br /&gt;
        2. SELECT SOUND INPUT CHANNEL &amp;amp; ADJUST VOLUME&lt;br /&gt;
            In Windows, double-click the speaker icon in your systray (where&lt;br /&gt;
            the clock is).  Then, on the menu, go to Options -&amp;gt; Properties&lt;br /&gt;
            and select the &amp;quot;Recording&amp;quot; option.  Then make sure the Line In&lt;br /&gt;
            (or Microphone) input channel (whichever is appropriate for&lt;br /&gt;
            your case) is SELECTED (with a check mark) and that the volume &lt;br /&gt;
            is close to, or at, the maximum.  Hit OK.           &lt;br /&gt;
        3. TELL WINAMP TO USE LINE-IN&lt;br /&gt;
            Open Winamp, and hit CTRL+L (the &amp;quot;Open Location&amp;quot; hotkey).  Now&lt;br /&gt;
            type in &amp;quot;linein://&amp;quot; as the location you want to open.  (Leave out&lt;br /&gt;
            the quotes and make sure you use FORWARD slashes.)  Hit PLAY&lt;br /&gt;
            ('x' key for the lazy), and the little built-in oscilloscope (or &lt;br /&gt;
            spectrum analyzer) in Winamp should start showing your signal.&lt;br /&gt;
        4. RUN MILKDROP&lt;br /&gt;
            Run MilkDrop as usual.  If the waves are too small or large, &lt;br /&gt;
            either adjust the volume from Windows' Volume Control, or adjust&lt;br /&gt;
            the sound level at the source.       &lt;br /&gt;
   &lt;br /&gt;
    If you are doing shows using live audio, and if you have a multiple monitor&lt;br /&gt;
    setup, you might also want to use the &amp;quot;VJ mode&amp;quot; feature, which lets you &lt;br /&gt;
    control MilkDrop (even editing shaders on the fly, etc.) via a separate monitor.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide</id>
		<title>Talk:Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-09-21T16:33:41Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Basic gen_empty.dll File Crashes WinAMP On Start Of WinAMP. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Is this format okay?==&lt;br /&gt;
Hey everyone, this is my first work with any Winamp plugin code and my first edits to the wiki. Sorry if anything is in the wrong format or wrong place. Please feel free to move or work on it; I'm open to suggestions on how to improve. --[[User:Culix|Culix]] 02:29, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Questions and TODO ==&lt;br /&gt;
&lt;br /&gt;
I still have a few questions about writing plugins. These should probably be filled into the guide at some point. --[[User:Culix|Culix]] 02:34, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* How do the naming conventions work for plugins? It seems more complicated than simply naming your file 'gen_*' or 'ml_*'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The answer to this is complicated, as so much with Winamp.  The prefix is actually used by Winamp.exe to find plugins and identify what type they are.  There is another way to create plugins that does not require the prefix.  This second way is called Wasabi.  Wasabi is a way to 'share' code among components of a software system (i.e., Winamp).  Wasabi dlls do not need the prefix.  We'll get to Wasabi if we keep writing these kinds of tutorials.  Is there something specific about the prefixes that leads you to believe that there is a 'real' answer?  Maybe I can investigate further.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* For the &amp;quot;cannot convert parameter from 'const char [x]' to 'LPCTSTR'&amp;quot; error, which option from the [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb MSDN FAQ] should we actually use? Is it better to change the project settings to use a multi-byte character set?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I would not change the project settings and instead use the L&amp;quot;&amp;quot; or _TEXT constructs to indicate that the strings are wide strings.  Winamp programmers prefer to be even more specific and actually call the MessageBoxW() or MessageBoxA() methods to make it absolutely clear as to which function and what form the input is in (this would make the project switch meaningless).  Since Winamp is a very popular application around the world it is best to use UNICODE.&amp;lt;/p&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Having said that, Winamp is also ancient (in computer years) and so every once in a while you might run across places within Winamp that do not handle UNICODE and will require ASCII strings.  For example, notice the description field of the winampGeneralPurposePlugin structure.  It was never converted to use UNICODE since that would change the size of the structure requiring a new revision and all the attendant problems that go along with that.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Why do some people put their 'extern &amp;quot;C&amp;quot; __declspec' code in the header and others in the .cpp? Does it matter?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The point of the extern &amp;quot;C&amp;quot; is to tell the linker not to perform C++ name mangling on the function name.  This is necessary when some other application needs to invoke the method and therefore needs to use a name that is easier to use.  Technically it doesn't matter whether you put them in a header or cpp file and it boils down to the more common reasons why you choose to put things in header files rather than including them in the cpp file.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Basic gen_empty.dll File Crashes WinAMP On Start Of WinAMP.===&lt;br /&gt;
I have turned off pre-compiled headers in VS 2008 Pro.  &lt;br /&gt;
Right Click On Solution--&amp;gt;Properties--&amp;gt;Configuration Properties--&amp;gt;Linker--&amp;gt;Additional Dependencies has been blanked.  &lt;br /&gt;
Right Click On Solution--&amp;gt;Properties--&amp;gt;Configuration Properties--&amp;gt;C/C++ --&amp;gt;Precompiled Headers--&amp;gt;Create/Use Precompiled Header = &amp;quot;Not Using Precompiled Headers&amp;quot;&lt;br /&gt;
WinXP with service pack 3.&lt;br /&gt;
WinAMP 5.56 with Pacemaker and Playlist File Remover plugins installed.  &lt;br /&gt;
WinAMP was running just fine with Pacemaker, though Playlist File Remover doesn't send files to the recycle bin like it should (It worked in prior versions of WinAMP, but not 5.56, that's why I want to write a plugin)&lt;br /&gt;
&lt;br /&gt;
I get Visual Studio to compile a gen_empty.dll, but when I copy that to the &amp;quot;C:\Program Files\Winamp\Plugins&amp;quot; folder, WinAMP will crash on launch.  It begins to create visible WinAMP application window outlines on the screen, but then it fails to complete.  The outlined windows dissapear, and WinAMP.exe process vanishes from the task manager.&lt;br /&gt;
&lt;br /&gt;
Removing the empty blank gen_empty.dll from &amp;quot;C:\Program Files\Winamp\Plugins&amp;quot; fixes the problem, WinAMP starts normally, just as it did before.&lt;br /&gt;
&lt;br /&gt;
I even commented out the MessageBox-es so the functions would do NOTHING, and tried the resulting gen_empty.dll. &lt;br /&gt;
&lt;br /&gt;
'''What is wrong with this generic, blank plugin source code that causes WinAMP 5.56 to fail?'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#ifndef gen_empty_h&lt;br /&gt;
#define gen_empty_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define GPPHDR_NAME &amp;quot;gen_empty v1.0 (gen_empty.dll)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  char *description;             // name/title of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // (?)&lt;br /&gt;
  HINSTANCE hDllInstance;        // (?)&lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
extern winampGeneralPurposePlugin *gen_plugins[256];&lt;br /&gt;
typedef winampGeneralPurposePlugin * (*winampGeneralPurposePluginGetter)();&lt;br /&gt;
#endif&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
//-----------------------------------------------------------------&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  GPPHDR_NAME, // name/title of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
//MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_empty. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
//  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_empty.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
//  MessageBox(0, L&amp;quot;Quit event triggered for gen_empty.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this is an export function called by winamp which returns this plugin info&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
//-----------------------------------------------------------------&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Doesn't appear to be in the code===&lt;br /&gt;
Hi, I examined your code and could see nothing that would cause Winamp to crash.  I then copied the code you posted to my development machine, compiled it and moved it to the plugins directory and Winamp worked fine.  I tested this on 5.56 and 5.57.&lt;br /&gt;
&lt;br /&gt;
My thought would be to look at some of the project options you may have set as I believe the C++ code is not the problem.  My first thought might be the packing for structures.&lt;br /&gt;
&lt;br /&gt;
==Next Steps==&lt;br /&gt;
I think a good extension of this article would be to answer the user's question of &amp;quot;Okay, now what?&amp;quot;. If we could give them hints about where to go next, possibly depending on the type of plugin they want to write, that might be useful. This may just involve fleshing out the guide articles for each type of plugin and then linking to those... unless someone can think of something better? --[[User:Culix|Culix]] 14:54, 10 June 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:56:14Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Another API call */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....What to do?....I know.  How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  The first thing you should see is the message about 'init' being called. 'Configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method winampGetGeneralPurposePlugin(), it is called by Winamp to retrieve the plugin.  This method actually returns a reference to the plugin.  Cool huh?  Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string containing the version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for fields such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display an ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.  The UNICODE version would have a &amp;quot;W&amp;quot; on the end.  Versions with neither actually depend on whether the preprocessor directive UNICODE is defined (a setting in the project).&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the &amp;quot;%S&amp;quot; (upper case S) in wsprintf this time rather than &amp;quot;%s&amp;quot; (lower case s).  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly to create the string used in the MessageBox (since UNICODE is defined for this project MessageBox will invoke MessageBoxW).&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played. At that point Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case a pointer to a structure.  The enqueueFileWithMetaStruct structure is defined in WA_IPC.h.  The structure contains the path and filename, a title and the length of the song in seconds.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:49:08Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Adding another API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....What to do?....I know.  How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  The first thing you should see is the message about 'init' being called. 'Configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method winampGetGeneralPurposePlugin(), it is called by Winamp to retrieve the plugin.  This method actually returns a reference to the plugin.  Cool huh?  Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string containing the version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for fields such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display an ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.  The UNICODE version would have a &amp;quot;W&amp;quot; on the end.  Versions with neither actually depend on whether the preprocessor directive UNICODE is defined (a setting in the project).&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the &amp;quot;%S&amp;quot; (upper case S) in wsprintf this time rather than &amp;quot;%s&amp;quot; (lower case s).  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly to create the string used in the MessageBox (since UNICODE is defined for this project MessageBox will invoke MessageBoxW).&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:47:07Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Adding another API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....What to do?....I know.  How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  The first thing you should see is the message about 'init' being called. 'Configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method winampGetGeneralPurposePlugin(), it is called by Winamp to retrieve the plugin.  This method actually returns a reference to the plugin.  Cool huh?  Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string containing the version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for fields such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display an ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.  The UNICODE version would have a &amp;quot;W&amp;quot; on the end.  Versions with neither actually depend on whether the preprocessor directive UNICODE is defined (a setting in the project).&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly to create the string used in the MessageBox (since UNICODE is defined for this project).&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:41:36Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Examining the Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....What to do?....I know.  How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  The first thing you should see is the message about 'init' being called. 'Configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method winampGetGeneralPurposePlugin(), it is called by Winamp to retrieve the plugin.  This method actually returns a reference to the plugin.  Cool huh?  Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:37:21Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Calling an API Method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....What to do?....I know.  How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  The first thing you should see is the message about 'init' being called. 'Configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:35:07Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Calling an API Method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....What to do?....I know.  How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:34:09Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* wa_ipc.h */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  So, in Visual Studio, navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp subdirectory under the directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-08-07T15:30:32Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Accessing information from Winamp */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Maybe it needs to do something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp, beneath the existing includes:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  Navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp directory under the base directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUEUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-07-13T21:37:51Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* One Last API call (for now) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  Navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp directory under the base directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===Another API call===&lt;br /&gt;
Add the following after the previous MessageBox statement:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
enqueueFileWithMetaStruct eFWMS = {0};&lt;br /&gt;
eFWMS.filename=&amp;quot;c:\\test\\folder\\test.mp3&amp;quot;;&lt;br /&gt;
eFWMS.title = &amp;quot;Test It Good&amp;quot;;&lt;br /&gt;
eFWMS.length = 300;&lt;br /&gt;
SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&amp;amp;eFWMS,IPC_ENQUUEFILE);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
You can use a real filename if you have one.  The title and length fields are only used by Winamp in the Winamp playlist until the file is actually played, then Winamp will look inside the file for the real title and length. &lt;br /&gt;
&lt;br /&gt;
This example shows how to use that WPARAM thingy (thingy is a technical term).  In this method the WPARAM gives Winamp information to use along with the request, in this case the filename and path, a title and length.  This method will Enqueue the file to be played at the bottom of the Winamp playlist.&lt;br /&gt;
&lt;br /&gt;
Compile, copy, restart Winamp and configure your plugin. After four message boxes (less if you became fed up with them all and removed some), you will notice that the specified file has been added to the Winamp Playlist with the specified title and length.  Note, that if the file does not actually exist, Winamp will simply skip over it when you try and play it.&lt;br /&gt;
&lt;br /&gt;
===What's in a UI===&lt;br /&gt;
Now that I think I've gotten the point across let's get rid of those Message Boxes and create some real UI.  The first thing we need to....hmmm, footsteps....gotta go....talk about this next time.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-07-13T21:10:49Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Adding another API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  Navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp directory under the base directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is an ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===One Last API call (for now)===&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-07-13T21:10:18Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Examining the wa_ipc.h file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  Navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp directory under the base directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.  Searching for IPC_GETVERSION will take you right to the description of how the method works.&lt;br /&gt;
&lt;br /&gt;
Sometimes the method description will indicate that a method is only available at a certain level of Winamp, such as 'requires Winamp 5.0+', i.e. the reason we needed the IPC_GETVERSION.  &lt;br /&gt;
&lt;br /&gt;
You may also notice that some methods have both 'normal' and 'wide' versions.  'normal' versions take ANSI/ASCII parameters while 'wide' versions take UNICODE chars and strings.&lt;br /&gt;
&lt;br /&gt;
===Adding another API===&lt;br /&gt;
Let's try another API call.  Put the following after the previous MessageBox:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char *winampVersion;&lt;br /&gt;
&lt;br /&gt;
winampVersion = (char *)SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSIONSTRING);&lt;br /&gt;
MessageBoxA(NULL,winampVersion,&amp;quot;Winamp Version 2&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The SendMessage in this code is requesting a string version of the Winamp executable.  It will return a char * to a string such as '5.57 build 2514 Beta'.  This is useful for displaying the version and build number, such as in the Help-&amp;gt;About dialog.&lt;br /&gt;
&lt;br /&gt;
The next line invokes the Windows MessageBoxA API to display a ANSI string.  I meant to do that. No, no, I really did.  I wanted to point out that some Winamp 2 API methods return simple char pointers not wchar_t pointers.  This means that there may be some conversion required before using strings.  Just in case, the &amp;quot;A&amp;quot; on the end of the method is a specialized version of MessageBox that takes ANSI strings rather than UNICODE strings.&lt;br /&gt;
&lt;br /&gt;
Replace the line with the call to MessageBoxA with the following:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wsprintf(msg,L&amp;quot;String Version: %S\n&amp;quot;,winampVersion);&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version 3&amp;quot;, MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
See it works.  Notice the '%S' in wsprintf.  &amp;quot;%S&amp;quot; says the input value is ANSI string and wsprintf can handle it correctly.&lt;br /&gt;
&lt;br /&gt;
===One Last API call (for now)===&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-07-13T20:04:00Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Examining the Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  Navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp directory under the base directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter (known as a WPARAM in Windows) and is set to 0.  The fourth parameter (known as an LPARAM in Windows) is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;br /&gt;
===Examining the wa_ipc.h file===&lt;br /&gt;
How did I know what to use for WPARAM and LPARAM?  Well the wa_ipc.h file of course.  Go ahead and open it in Visual Studio.  The first thing you'll notice is blocks of comments.  Blocks of comments?  OH YEAH.  Let's just look at the comments for five minutes, I'll wait......&lt;br /&gt;
&lt;br /&gt;
Seriously, if you scroll down in this file you'll see the Winamp 2 API methods.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial</id>
		<title>Basic Plugin Guide - Tutorial</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Basic_Plugin_Guide_-_Tutorial"/>
				<updated>2009-07-13T19:46:02Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: New page: ==Accessing information from Winamp== Our first page Beginner's Basic Plugin Guide showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, confi...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Accessing information from Winamp==&lt;br /&gt;
Our first page [[Beginner's Basic Plugin Guide]] showed you how to create a general plugin dll that will be invoked by Winamp when it is loaded, configured and quit.  While this is really cool, it lacks something.  Let's fix that now.&lt;br /&gt;
&lt;br /&gt;
===Keeping it simple===&lt;br /&gt;
In order to keep these explanations simple, I'd rather not add a lot of code to create a Windows UI.  We will eventually create a UI, but first let's invoke some Winamp 2 API methods.  Just to see how they work.  &lt;br /&gt;
&lt;br /&gt;
When we last left our hero....err plugin, we had created three methods 'init', 'config' and 'quit'.  'init' is invoked by Winamp when the plugin is first loaded.  'quit' is invoked by Winamp when the plugin is unloaded, i.e., when Winamp is closing.  'config' is invoked when someone configures the plugin.  A user can configure a plugin by selecting Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;General Purpose, clicking on the plug-in in the right hand pane and then pressing the 'Configure selected plug-in' button.  Note that I will refer to this as 'configuring the plugin' from now on as that much typing is annoying.&lt;br /&gt;
&lt;br /&gt;
While we would normally add code to 'init' to set up our UI and event notification system, let's keep it even simpler than that (we'll cover the basics of that in a future tutorial).  Let's add the API calls to the 'config' method for now.  Just to see how they work.&lt;br /&gt;
&lt;br /&gt;
===wa_ipc.h===&lt;br /&gt;
The top secret, knows everything, key to the executive washroom file is called wa_ipc.h.  This file defines constants for all of the Winamp 2 API methods that are made available for external developers.  And they are fairly well documented (gasp).  Yes, I know this sounds impossible, when do developers actually write documentation?  Well trust me this file is very well documented so it does happen.&lt;br /&gt;
&lt;br /&gt;
This header can be found in the SDK under the Winamp SDK\Winamp directory.  Add these two lines to the top of gen_myplugin.cpp:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;wa_ipc.h&amp;quot;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But wait! This isn't enough.  There's always a catch.  The compiler has no idea where to find wa_ipc.h.  So we have to tell it.  Navigate to Project-&amp;gt;gen_myplugin Properties-&amp;gt;Configuration Properties-&amp;gt;C/C++-&amp;gt;General and enter the path to the Winamp directory under the base directory where you installed the Winamp SDK.  Now Visual studio should be able to find the header.&lt;br /&gt;
&lt;br /&gt;
===Calling an API Method===&lt;br /&gt;
Hmmm, what should we do....How about we get the version of Winamp that is currently running?  Sounds like a useful thing for a plug-in to do.  Place the following code into the 'config' method, immediately under the MessageBox about the config event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
wchar_t msg[1024];&lt;br /&gt;
&lt;br /&gt;
int version = SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETVERSION);&lt;br /&gt;
int majVersion = WINAMP_VERSION_MAJOR(version);&lt;br /&gt;
int minVersion = WINAMP_VERSION_MINOR(version);&lt;br /&gt;
&lt;br /&gt;
wsprintf(msg,L&amp;quot;The version of Winamp is: %x\n&amp;quot;&lt;br /&gt;
  L&amp;quot;Major version: %x\nMinor version: %x\n&amp;quot;,&lt;br /&gt;
  version,&lt;br /&gt;
  majVersion,&lt;br /&gt;
  minVersion&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
MessageBox(plugin.hwndParent,msg,L&amp;quot;Winamp Version&amp;quot;,MB_OK);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile the plugin and move the dll over into the Winamp plug-ins directory (make sure to exit Winamp before trying to copy the dll, Windows can be so possessive.)  Start Winamp.  After Winamp starts and you see the message about the 'init' being called, 'configure' the plugin and you should see the 'config' event message, press OK.  If you've done everything correctly you should now see the version message box appear.&lt;br /&gt;
&lt;br /&gt;
===Examining the Code===&lt;br /&gt;
The first line declares a buffer of 1024 wchar_t.  This buffer is used to format output that we want to add to the MessageBox.  &lt;br /&gt;
&lt;br /&gt;
The second line uses Windows SendMessage API to send a message, WM_WA_IPC (second parameter), in this case to plugin.hwndParent (first parameter).  WM_WA_IPC indicates a message that Winamp is supposed to handle rather than Windows itself.  The third parameter is usually used to pass a parameter and is set to 0.  The fourth parameter is a constant that identifies what we want Winamp to do for us, in this case 'get me the version of winamp'.&lt;br /&gt;
&lt;br /&gt;
But 'Hold on Thar Partner' you might be saying.  Where did that plugin.hwndParent come from?  We didn't set it in our plug-in.  Turns out that Winamp stored the handle to its main window into the plugin structure when it loaded it.  Notice the method used to retrieve the plugin (winampGetGeneralPurposePlugin) actually returns a reference to the plugin?  Cool huh, Winamp can then load the hwndParent and hDllInstance and it becomes available to the plug-in.  The point is that we are sending messages to the Winamp main window so that it can give us the info we're looking for.&lt;br /&gt;
&lt;br /&gt;
The next two lines use macros defined in WA_IPC.h to break apart the version into major and minor numbers.  Another useful feature when you need to know the version of Winamp to determine whether a feature is supported.&lt;br /&gt;
&lt;br /&gt;
The rest of the new lines format a wide string (wsprintf) so we can use it in MessageBox to print it to the screen.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-13T18:18:24Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* What's next? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,           // handle to Winamp main window, loaded by winamp when this dll is loaded&lt;br /&gt;
  0            // hinstance to this dll, loaded by winamp when this dll is loaded&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== winampGeneralPurposePlugin===&lt;br /&gt;
You might be wondering why the last two fields in the winampGeneralPurposePlugin structure are left empty.  You might have noticed the reference that is returned as part of the winampGetGeneralPurposePlugin() method.  This is the method that the Winamp.exe calls when loading these gen_*.dll files.  As part of loading the plugin, the Winamp.exe will store the handle to its main window and the hinstance for the plugin dll into these two fields.  Since these are references, these values become available for use by the plugin.&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project.&lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
Taking this page as a start of a tutorial on plugins, let's move on to actually calling the Winamp 2 API methods from within our newly created plugin. [[Basic Plugin Guide - Tutorial #2]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\gen_myplugin.cpp(25) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\gen_myplugin.cpp(42) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&amp;lt;pre&amp;gt;     The answer here is to leave the Visual Studio option alone (set to use UNICODE) &lt;br /&gt;
     and use the 'L' on the front of the strings.  While you will find some parts of &lt;br /&gt;
     Winamp still use ANSI strings, it is still meant to be an International application &lt;br /&gt;
     and that means UNICODE.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&amp;lt;pre&amp;gt;    There are two commonly used methods to create plugins.  The first is what is known as &lt;br /&gt;
    Winamp 2, which we will get into shortly.  Winamp 2 requires that plugins be prepended &lt;br /&gt;
    with an identifier to their purpose, i.e., in_, out_, gen_, ml_, etc.&lt;br /&gt;
&lt;br /&gt;
    The second method is known as Wasabi, which is actually a framework used to share &lt;br /&gt;
    information between application components.  Wasabi files do not need a prefix.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-13T18:13:57Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Troubleshooting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,           // handle to Winamp main window, loaded by winamp when this dll is loaded&lt;br /&gt;
  0            // hinstance to this dll, loaded by winamp when this dll is loaded&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== winampGeneralPurposePlugin===&lt;br /&gt;
You might be wondering why the last two fields in the winampGeneralPurposePlugin structure are left empty.  You might have noticed the reference that is returned as part of the winampGetGeneralPurposePlugin() method.  This is the method that the Winamp.exe calls when loading these gen_*.dll files.  As part of loading the plugin, the Winamp.exe will store the handle to its main window and the hinstance for the plugin dll into these two fields.  Since these are references, these values become available for use by the plugin.&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project.&lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\gen_myplugin.cpp(25) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\gen_myplugin.cpp(42) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&amp;lt;pre&amp;gt;     The answer here is to leave the Visual Studio option alone (set to use UNICODE) &lt;br /&gt;
     and use the 'L' on the front of the strings.  While you will find some parts of &lt;br /&gt;
     Winamp still use ANSI strings, it is still meant to be an International application &lt;br /&gt;
     and that means UNICODE.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&amp;lt;pre&amp;gt;    There are two commonly used methods to create plugins.  The first is what is known as &lt;br /&gt;
    Winamp 2, which we will get into shortly.  Winamp 2 requires that plugins be prepended &lt;br /&gt;
    with an identifier to their purpose, i.e., in_, out_, gen_, ml_, etc.&lt;br /&gt;
&lt;br /&gt;
    The second method is known as Wasabi, which is actually a framework used to share &lt;br /&gt;
    information between application components.  Wasabi files do not need a prefix.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide</id>
		<title>Talk:Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-02T18:10:41Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Questions and TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Is this format okay?==&lt;br /&gt;
Hey everyone, this is my first work with any Winamp plugin code and my first edits to the wiki. Sorry if anything is in the wrong format or wrong place. Please feel free to move or work on it; I'm open to suggestions on how to improve. --[[User:Culix|Culix]] 02:29, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Questions and TODO ==&lt;br /&gt;
&lt;br /&gt;
I still have a few questions about writing plugins. These should probably be filled into the guide at some point. --[[User:Culix|Culix]] 02:34, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* How do the naming conventions work for plugins? It seems more complicated than simply naming your file 'gen_*' or 'ml_*'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The answer to this is complicated, as so much with Winamp.  The prefix is actually used by Winamp.exe to find plugins and identify what type they are.  There is another way to create plugins that does not require the prefix.  This second way is called Wasabi.  Wasabi is a way to 'share' code among components of a software system (i.e., Winamp).  Wasabi dlls do not need the prefix.  We'll get to Wasabi if we keep writing these kinds of tutorials.  Is there something specific about the prefixes that leads you to believe that there is a 'real' answer?  Maybe I can investigate further.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* For the &amp;quot;cannot convert parameter from 'const char [x]' to 'LPCTSTR'&amp;quot; error, which option from the [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb MSDN FAQ] should we actually use? Is it better to change the project settings to use a multi-byte character set?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I would not change the project settings and instead use the L&amp;quot;&amp;quot; or _TEXT constructs to indicate that the strings are wide strings.  Winamp programmers prefer to be even more specific and actually call the MessageBoxW() or MessageBoxA() methods to make it absolutely clear as to which function and what form the input is in (this would make the project switch meaningless).  Since Winamp is a very popular application around the world it is best to use UNICODE.&amp;lt;/p&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Having said that, Winamp is also ancient (in computer years) and so every once in a while you might run across places within Winamp that do not handle UNICODE and will require ASCII strings.  For example, notice the description field of the winampGeneralPurposePlugin structure.  It was never converted to use UNICODE since that would change the size of the structure requiring a new revision and all the attendant problems that go along with that.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Why do some people put their 'extern &amp;quot;C&amp;quot; __declspec' code in the header and others in the .cpp? Does it matter?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The point of the extern &amp;quot;C&amp;quot; is to tell the linker not to perform C++ name mangling on the function name.  This is necessary when some other application needs to invoke the method and therefore needs to use a name that is easier to use.  Technically it doesn't matter whether you put them in a header or cpp file and it boils down to the more common reasons why you choose to put things in header files rather than including them in the cpp file.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Next Steps==&lt;br /&gt;
I think a good extension of this article would be to answer the user's question of &amp;quot;Okay, now what?&amp;quot;. If we could give them hints about where to go next, possibly depending on the type of plugin they want to write, that might be useful. This may just involve fleshing out the guide articles for each type of plugin and then linking to those... unless someone can think of something better? --[[User:Culix|Culix]] 14:54, 10 June 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide</id>
		<title>Talk:Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-02T17:51:54Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Questions and TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Is this format okay?==&lt;br /&gt;
Hey everyone, this is my first work with any Winamp plugin code and my first edits to the wiki. Sorry if anything is in the wrong format or wrong place. Please feel free to move or work on it; I'm open to suggestions on how to improve. --[[User:Culix|Culix]] 02:29, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Questions and TODO ==&lt;br /&gt;
&lt;br /&gt;
I still have a few questions about writing plugins. These should probably be filled into the guide at some point. --[[User:Culix|Culix]] 02:34, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* How do the naming conventions work for plugins? It seems more complicated than simply naming your file 'gen_*' or 'ml_*'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The answer to this is complicated, as so much with Winamp.  The prefix is actually used by Winamp.exe to find plugins and identify what type they are.  There is another way to create plugins that does not require the prefix.  This second way is called Wasabi.  Wasabi is a way to 'share' code among components of a software system (i.e., Winamp).  Wasabi dlls do not need the prefix.  We'll get to Wasabi if we keep writing these kinds of tutorials.  Is there something specific about the prefixes that leads you to believe that there is a 'real' answer?  Maybe I can investigate further.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* For the &amp;quot;cannot convert parameter from 'const char [x]' to 'LPCTSTR'&amp;quot; error, which option from the [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb MSDN FAQ] should we actually use? Is it better to change the project settings to use a multi-byte character set?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I would not change the project settings and instead use the L&amp;quot;&amp;quot; or _TEXT constructs to indicate that the strings are wide strings.  Winamp programmers prefer to be even more specific and actually call the MessageBoxW() or MessageBoxA() methods to make it absolutely clear as to which function and what form the input is in (this would make the project switch meaningless).  Since Winamp is a very popular application around the world it is best to use UNICODE.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Having said that, Winamp is also ancient (in computer years) and so every once in a while you might run across Winamp functions that do not handle UNICODE and will require ASCII strings.&lt;br /&gt;
&lt;br /&gt;
* Why do some people put their 'extern &amp;quot;C&amp;quot; __declspec' code in the header and others in the .cpp? Does it matter?&lt;br /&gt;
&lt;br /&gt;
==Next Steps==&lt;br /&gt;
I think a good extension of this article would be to answer the user's question of &amp;quot;Okay, now what?&amp;quot;. If we could give them hints about where to go next, possibly depending on the type of plugin they want to write, that might be useful. This may just involve fleshing out the guide articles for each type of plugin and then linking to those... unless someone can think of something better? --[[User:Culix|Culix]] 14:54, 10 June 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide</id>
		<title>Talk:Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-02T17:51:08Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Questions and TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Is this format okay?==&lt;br /&gt;
Hey everyone, this is my first work with any Winamp plugin code and my first edits to the wiki. Sorry if anything is in the wrong format or wrong place. Please feel free to move or work on it; I'm open to suggestions on how to improve. --[[User:Culix|Culix]] 02:29, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Questions and TODO ==&lt;br /&gt;
&lt;br /&gt;
I still have a few questions about writing plugins. These should probably be filled into the guide at some point. --[[User:Culix|Culix]] 02:34, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* How do the naming conventions work for plugins? It seems more complicated than simply naming your file 'gen_*' or 'ml_*'.&lt;br /&gt;
&lt;br /&gt;
 The answer to this is complicated, as so much with Winamp.  The prefix is actually used by Winamp.exe to find plugins and identify what type they are.  There is another way to create plugins that does not require the prefix.  This second way is called Wasabi.  Wasabi is a way to 'share' code among components of a software system (i.e., Winamp).  Wasabi dlls do not need the prefix.  We'll get to Wasabi if we keep writing these kinds of tutorials.  Is there something specific about the prefixes that leads you to believe that there is a 'real' answer?  Maybe I can investigate further.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* For the &amp;quot;cannot convert parameter from 'const char [x]' to 'LPCTSTR'&amp;quot; error, which option from the [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb MSDN FAQ] should we actually use? Is it better to change the project settings to use a multi-byte character set?&lt;br /&gt;
&lt;br /&gt;
I would not change the project settings and instead use the L&amp;quot;&amp;quot; or _TEXT constructs to indicate that the strings are wide strings.  Winamp programmers prefer to be even more specific and actually call the MessageBoxW() or MessageBoxA() methods to make it absolutely clear as to which function and what form the input is in (this would make the project switch meaningless).  Since Winamp is a very popular application around the world it is best to use UNICODE.  &lt;br /&gt;
&lt;br /&gt;
Having said that, Winamp is also ancient (in computer years) and so every once in a while you might run across Winamp functions that do not handle UNICODE and will require ASCII strings.&lt;br /&gt;
&lt;br /&gt;
* Why do some people put their 'extern &amp;quot;C&amp;quot; __declspec' code in the header and others in the .cpp? Does it matter?&lt;br /&gt;
&lt;br /&gt;
==Next Steps==&lt;br /&gt;
I think a good extension of this article would be to answer the user's question of &amp;quot;Okay, now what?&amp;quot;. If we could give them hints about where to go next, possibly depending on the type of plugin they want to write, that might be useful. This may just involve fleshing out the guide articles for each type of plugin and then linking to those... unless someone can think of something better? --[[User:Culix|Culix]] 14:54, 10 June 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide</id>
		<title>Talk:Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Talk:Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-02T17:35:06Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Questions and TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Is this format okay?==&lt;br /&gt;
Hey everyone, this is my first work with any Winamp plugin code and my first edits to the wiki. Sorry if anything is in the wrong format or wrong place. Please feel free to move or work on it; I'm open to suggestions on how to improve. --[[User:Culix|Culix]] 02:29, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Questions and TODO ==&lt;br /&gt;
&lt;br /&gt;
I still have a few questions about writing plugins. These should probably be filled into the guide at some point. --[[User:Culix|Culix]] 02:34, 10 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
* How do the naming conventions work for plugins? It seems more complicated than simply naming your file 'gen_*' or 'ml_*'.&lt;br /&gt;
&lt;br /&gt;
 The answer to this is complicated, as so much with Winamp.  The prefix is actually used by Winamp.exe to find plugins and identify what type they are.  There is another way to create plugins that does not require the prefix.  This second way is called Wasabi.  Wasabi is a way to 'share' code among components of a software system (i.e., Winamp).  Wasabi dlls do not need the prefix.  We'll get to Wasabi if we keep writing these kinds of tutorials.  Is there something specific about the prefixes that leads you to believe that there is a 'real' answer?  Maybe I can investigate further.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* For the &amp;quot;cannot convert parameter from 'const char [x]' to 'LPCTSTR'&amp;quot; error, which option from the [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb MSDN FAQ] should we actually use? Is it better to change the project settings to use a multi-byte character set?&lt;br /&gt;
* Why do some people put their 'extern &amp;quot;C&amp;quot; __declspec' code in the header and others in the .cpp? Does it matter?&lt;br /&gt;
&lt;br /&gt;
==Next Steps==&lt;br /&gt;
I think a good extension of this article would be to answer the user's question of &amp;quot;Okay, now what?&amp;quot;. If we could give them hints about where to go next, possibly depending on the type of plugin they want to write, that might be useful. This may just involve fleshing out the guide articles for each type of plugin and then linking to those... unless someone can think of something better? --[[User:Culix|Culix]] 14:54, 10 June 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-02T16:58:09Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Troubleshooting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,           // handle to Winamp main window, loaded by winamp when this dll is loaded&lt;br /&gt;
  0            // hinstance to this dll, loaded by winamp when this dll is loaded&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== winampGeneralPurposePlugin===&lt;br /&gt;
You might be wondering why the last two fields in the winampGeneralPurposePlugin structure are left empty.  You might have noticed the reference that is returned as part of the winampGetGeneralPurposePlugin() method.  This is the method that the Winamp.exe calls when loading these gen_*.dll files.  As part of loading the plugin, the Winamp.exe will store the handle to its main window and the hinstance for the plugin dll into these two fields.  Since these are references, these values become available for use by the plugin.&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project.&lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\gen_myplugin.cpp(25) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\gen_myplugin.cpp(42) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-01T21:33:09Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Troubleshooting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,           // handle to Winamp main window, loaded by winamp when this dll is loaded&lt;br /&gt;
  0            // hinstance to this dll, loaded by winamp when this dll is loaded&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== winampGeneralPurposePlugin===&lt;br /&gt;
You might be wondering why the last two fields in the winampGeneralPurposePlugin structure are left empty.  You might have noticed the reference that is returned as part of the winampGetGeneralPurposePlugin() method.  This is the method that the Winamp.exe calls when loading these gen_*.dll files.  As part of loading the plugin, the Winamp.exe will store the handle to its main window and the hinstance for the plugin dll into these two fields.  Since these are references, these values become available for use by the plugin.&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project.&lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;gen_myplugin.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\gen_myplugin.cpp(25) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\gen_myplugin.cpp(42) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
The answer to this is complicated, as so much with Winamp.  The prefix is actually used by Winamp.exe to find plugins and identify what type they are.  There is another way to create plugins that does not require the prefix.  This second way is called Wasabi.  Wasabi is a way to 'share' code among components of a software system (i.e., Winamp).  Wasabi dlls do not need the prefix.  We'll get to Wasabi if we keep writing these kinds of tutorials.  Is there something specific about the prefixes that leads you to believe that there is a 'real' answer?  Maybe I can investigate further.&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-01T21:14:29Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Edit dependencies */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,           // handle to Winamp main window, loaded by winamp when this dll is loaded&lt;br /&gt;
  0            // hinstance to this dll, loaded by winamp when this dll is loaded&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== winampGeneralPurposePlugin===&lt;br /&gt;
You might be wondering why the last two fields in the winampGeneralPurposePlugin structure are left empty.  You might have noticed the reference that is returned as part of the winampGetGeneralPurposePlugin() method.  This is the method that the Winamp.exe calls when loading these gen_*.dll files.  As part of loading the plugin, the Winamp.exe will store the handle to its main window and the hinstance for the plugin dll into these two fields.  Since these are references, these values become available for use by the plugin.&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project.&lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\winamp_imms.cpp(29) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\winamp_imms.cpp(41) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-01T21:08:23Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Basic plugin code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,           // handle to Winamp main window, loaded by winamp when this dll is loaded&lt;br /&gt;
  0            // hinstance to this dll, loaded by winamp when this dll is loaded&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project. &lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\winamp_imms.cpp(29) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\winamp_imms.cpp(41) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-07-01T21:05:42Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Basic plugin code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (details: the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define PLUGIN_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin structure&lt;br /&gt;
  char *description;             // name/title of the plugin &lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // hwnd of the Winamp client main window (stored by Winamp when dll is loaded)&lt;br /&gt;
  HINSTANCE hDllInstance;        // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
// GPPHDR_VER is the version of the winampGeneralPurposePlugin (GPP) structure&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  PLUGIN_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
  0,&lt;br /&gt;
  0&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project. &lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\winamp_imms.cpp(29) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\winamp_imms.cpp(41) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/User_talk:Culix</id>
		<title>User talk:Culix</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/User_talk:Culix"/>
				<updated>2009-07-01T20:48:08Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Going to do some more updating */ new section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See my comments at [[Template_talk:Deleteme]].  I don't visit this Wiki very often, so if you leave a reply on my talk page, it may be a while before I see it. &amp;amp;mdash;[[User:Hydrargyrum|Hydrargyrum]]&amp;lt;sup&amp;gt;[[User_talk:Hydrargyrum|T]] [[Special:Emailuser/Hydrargyrum|@]]&amp;lt;/sup&amp;gt; 18:43, 18 June 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Going to do some more updating ==&lt;br /&gt;
&lt;br /&gt;
Hi Culix,&lt;br /&gt;
&lt;br /&gt;
I plan to make some more changes to your basic plugins wiki page.  This is an outstanding start which I wanted to do for a while.  You have encouraged me to actually do some of this.  There is some interesting things about parts of the code that you have that I'd like to explain.&lt;br /&gt;
&lt;br /&gt;
I'd like to turn these pages into a series of tutorials on plugins.  The trick is that the gen_ plugins and ml_plugins are probably the most commonly used.  We can go back and do some of the other types at some point but they tend to be more specialized.&lt;br /&gt;
&lt;br /&gt;
I think the next step will be to expand your basic plugin to retrieve information from the Winamp core.  I'll let you know and you can look at it.  After that we'll talk about creating a dialog that can invoke methods in the plugin.&lt;br /&gt;
&lt;br /&gt;
Thanks for starting the page.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/User:SMonty</id>
		<title>User:SMonty</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/User:SMonty"/>
				<updated>2009-07-01T20:41:05Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mystery developer.  Has access to places only cats normally go.  Working on software since stone tablets with holes punched in them were used for input.  Sneaks into Winamp and AOL, past searchlights, guards and dogs, to learn how Winamp works.  Can be contacted by projecting the silhouette of a Llama projected onto the clouds at night.  If case of a clear night, you're on your own, I'm having a beer.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/User:SMonty</id>
		<title>User:SMonty</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/User:SMonty"/>
				<updated>2009-07-01T20:34:41Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mystery developer.  Has access to places only cats normally go.  Working on software since stone tablets with holes punched in them were used for input.  Sneaks into Winamp and AOL, past searchlights, guards and dogs, to learn how Winamp works.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/User:SMonty</id>
		<title>User:SMonty</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/User:SMonty"/>
				<updated>2009-07-01T20:33:38Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: New page: Mystery developer.  Has access to places only cats normally go.  Working on software since stone tablets with holes punched in them were used for input.  Sneaks into Winamp and AOL to lear...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mystery developer.  Has access to places only cats normally go.  Working on software since stone tablets with holes punched in them were used for input.  Sneaks into Winamp and AOL to learn how Winamp works.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework</id>
		<title>Complete JavaScript API technology framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework"/>
				<updated>2009-07-01T16:14:38Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Add() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
[[Category:Winamp]]&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
The purpose of the Winamp Online Service API is to allow Winamp Online Services to interact with the Winamp client in order to provide service developers with a way to create custom experiences for their users based on the power of Winamp.  The overall idea is to include exceptional web sites within Winamp Online Services.&lt;br /&gt;
&lt;br /&gt;
The Winamp Online Service API is made up of methods that can be called from scripts within web pages rendered by the Winamp client.  The API can be invoked using any scripting language supported by the Microsoft Internet Explorer web browser (5.5 and above).  For simplicity, examples in this document will use JavaScript.&lt;br /&gt;
&lt;br /&gt;
==Setup==&lt;br /&gt;
The Winamp Online Services API is designed to allow web pages, hosted (displayed) within the embedded browser of the Winamp client, to access the functionality of the client.  There are several steps necessary to allow this to take place.&lt;br /&gt;
&lt;br /&gt;
#Make sure you have the latest version of the Winamp client that supports online services.&lt;br /&gt;
#Make sure you have the latest version of the ml_webdev plugin (ml_webdev.dll).  The presence of this plugin will create a &amp;quot;Web Dev Test Platform&amp;quot; within the Medial Library pane.&lt;br /&gt;
#In order to change the starting web page for the online service, start the Winamp client and configure the plugin.  &lt;br /&gt;
##Select Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;Media Library.  &lt;br /&gt;
##Select &amp;quot;API 2 Test Platform&amp;quot; and press &amp;quot;Configure selected plugin&amp;quot;.  &lt;br /&gt;
##On the Web Dev Preferences dialog, set the URL field to the URL of the initial web page for the online service.  For example, &amp;lt;nowiki&amp;gt;file://c:\myonlineservice\webdev.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
#Click on &amp;quot;Web Dev Test Platform&amp;quot; in the Media Library.  You may have to right click and choose refresh to see the new web page.&lt;br /&gt;
&lt;br /&gt;
You should now see the initial page of your online service in the Winamp embedded browser.&lt;br /&gt;
&lt;br /&gt;
==window.external==&lt;br /&gt;
The Winamp JavaScript API can be accessed through the window.external object in the Document Object Model (DOM) exposed by the IE browser control embedded within the Winamp client.  The API methods can only be accessed thru the Winamp client and are not available if the web page is displayed outside of the client.&lt;br /&gt;
&lt;br /&gt;
The invocation of all methods follow this form&lt;br /&gt;
 window.external.'''''API'''''.'''''Method'''''&lt;br /&gt;
&lt;br /&gt;
Properties can also be accessed using a similar form:&lt;br /&gt;
 window.external.'''''API'''''.'''''Property'''''&lt;br /&gt;
&lt;br /&gt;
Where ''API'' is a singleton class that defines a group of related methods (i.e., functionality).  For example, Transport (Stop, Play, Next, etc) which controls the &amp;quot;buttons&amp;quot; of the Winamp player. &lt;br /&gt;
&lt;br /&gt;
''Method'' is a function you can call as part of a particular API.  For example the following call will stop the Winamp client:&lt;br /&gt;
 window.external.Transport.Stop();&lt;br /&gt;
&lt;br /&gt;
''Property'' is an internal variable for the particular API that can be queried and in some cases set.  For example the following will provide access to the Winamp client shuffle &amp;quot;button&amp;quot;:&lt;br /&gt;
 var shuffle = window.external.Transport.shuffle;  // gets the current state&lt;br /&gt;
     OR&lt;br /&gt;
 window.external.Transport.shuffle = true;         // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
See the documentation on each API below for a complete list of methods and properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == Security Warnings ==&lt;br /&gt;
Using the Winamp JavaScript API, an online service web page has access to much more information (read: power) than a normal web page.  For example, playlists can be enumerated, and metadata for songs can be retrieved.  In order to control these capabilities a security system was implemented so that users are informed whenever an online service first attempts to use an API method or access a property.  For example, when an online service attempts to stop playback for the very first time, the user will be notified and asked whether the service should be allowed to do this.&lt;br /&gt;
&lt;br /&gt;
Note that this security model maintains user choices based on service ID so that the user will be prompted each time a service tries to invoke methods or access properties.  In addition, online services updated through the Winamp Online Service submission process, receive new service IDs, causing the users to be prompted again.&lt;br /&gt;
&lt;br /&gt;
A dialog is presented to the user that describes the action about to be performed and forces the user to choose whether the action should be Allowed or Denied.  A third button let's a user to indicate &amp;quot;Always Allow&amp;quot;.  If the user selects this button, the API will no longer prompt the user for this action (for this particular online service).  &lt;br /&gt;
&lt;br /&gt;
Be aware that choices for certain APIs will affect the entire API and all of its methods and properties.  For example, choosing &amp;quot;Always Allow&amp;quot; for Transport.Stop() will also always allow access to the other Tranport methods/properties.  Certain other APIs, such as the Application API affect only the action being attempted.  Some API methods and properties are considered inconsequential and not governed by this security model at all.  The scope of the user's choice will be described within the dialog.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transport API ==&lt;br /&gt;
The Transport API is used to control the Winamp client.  &amp;quot;Transport controls&amp;quot; was the name given to the buttons on the front panel that controlled hardware devices.  This name is used in Winamp for the same purpose.  It is also used to access information about the currently playing song.&lt;br /&gt;
&lt;br /&gt;
The Transport API can also be used to register for events involved with asset playback.  See the section [[#Transport Events API|Transport Events API]].&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Prev()====&lt;br /&gt;
Transport.Prev() can be used to press the &amp;quot;Previous Track&amp;quot; button on the Winamp player.  Invoking Prev() while an asset is already playing will cause the previous asset to begin playback immediately.  Invoking Prev() while the player is stopped will cause the previous asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Prev();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Prev();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Play()====&lt;br /&gt;
Transport.Play() can be used to press the &amp;quot;Play&amp;quot; button on the Winamp player.  Invoking Play() on an asset already playing will cause the asset to restart playback.  Pressing Play() on a paused asset will cause it to begin playing from its current position.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Play();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Pause()====&lt;br /&gt;
Transport.Pause() can be used to press the &amp;quot;Pause&amp;quot; button on the Winamp player.  Issuing Pause() again, or Play() will cause the asset to continue to play from the location where it was paused.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Pause();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Pause();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Stop()====&lt;br /&gt;
Transport.Stop() can be used to press the &amp;quot;Stop&amp;quot; button on the Winamp player.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Stop();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Stop();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
====Next()====&lt;br /&gt;
Transport.Next() can be used to press the &amp;quot;Next Track&amp;quot; button on the Winamp player.  Invoking Next() while the player is stopped will cause the next asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Next();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Next();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
Transport.GetMetadata() can be used to fetch metadata for the currently playing asset.  The &amp;quot;tag&amp;quot; parameter is specific to different asset encoding formats so a knowledge of the metadata field names is necessary to request specific data about an asset.  Some field names are common but others are specific to the encoding format of the asset.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(tag);&lt;br /&gt;
 where:&lt;br /&gt;
      '''tag''' = (string) identifier for the metadata to be returned.&lt;br /&gt;
Example:&lt;br /&gt;
 var metaStr = window.external.Transport.GetMetadata(&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A string value containing the requested metadata.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====bool shuffle====&lt;br /&gt;
Transport.shuffle provides access to the Winamp client shuffle &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isShuffling = window.external.Transport.shuffle; // get shuffle state&lt;br /&gt;
  window.external.Transport.shuffle = true;            // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
====bool repeat====&lt;br /&gt;
Transport.repeat provides access to the Winamp client repeat &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isRepeating = window.external.Transport.repeat; // get repeat state&lt;br /&gt;
  window.external.Transport.repeat = false;           // turns off repeat&lt;br /&gt;
&lt;br /&gt;
====int position====&lt;br /&gt;
Transport.position provides access to the position being played within the current asset.  Setting this value can change the location where playback occurs. position is in milliseconds.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var position = window.external.Transport.position; // get position in current track&lt;br /&gt;
  window.external.Transport.position = 221559;       // move playback of the current track &lt;br /&gt;
                                                     // to the specified position.&lt;br /&gt;
&lt;br /&gt;
====bool playing (read only) ====&lt;br /&gt;
Transport.playing indicates whether the Winamp Player is currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPlaying = window.external.Transport.playing; // is player playing?&lt;br /&gt;
&lt;br /&gt;
====bool paused (read only) ====&lt;br /&gt;
Transport.paused indicates whether the Winamp Player has been paused.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPaused = window.external.Transport.paused; // is player paused?&lt;br /&gt;
&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
Transport.length provides access to the length in seconds of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var length = window.external.Transport.length; // get length of current track in secs&lt;br /&gt;
&lt;br /&gt;
====string url (read only)====&lt;br /&gt;
Transport.url provides access to the URL (or filename) of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var url = window.external.Transport.url; // get url of current track&lt;br /&gt;
&lt;br /&gt;
====string title (read only)====&lt;br /&gt;
Transport.title provides access to the title of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var title = window.external.Transport.title; // get title of current track&lt;br /&gt;
&lt;br /&gt;
==Transport Events API==&lt;br /&gt;
The Event mechanism of the Transport API allows javascript programmers to specify a callback method that will be invoked whenever certain Transport events take place.  An Event object is passed back to the method from which properties can be accessed that provide more information about the event.&lt;br /&gt;
&lt;br /&gt;
===RegisterForEvents()===&lt;br /&gt;
The RegisterForEvents() method can be used to specify a JavaScript function that is to be called when any Transport Events occur.  An event object is passed that indicates the type of event.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean RegisterForEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.RegisterForEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===UnregisterFromEvents()===&lt;br /&gt;
The UnregisterFromEvents() method is used to stop receiving notifications about Transport events.&lt;br /&gt;
&lt;br /&gt;
Note:  The original handler used in RegisterForEvents() must be passed back into UnregisterFromEvents().&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean UnregisterFromEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.UnregisterFromEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Events===&lt;br /&gt;
The Transport API Event mechanism requires a JavaScript callback method that accepts a single parameter, a reference to a function.  This function will be invoked with an &amp;quot;event&amp;quot; object that will indicate the type of event that occurred as well as contain properties containing more information about the event.&lt;br /&gt;
&lt;br /&gt;
====OnStop====&lt;br /&gt;
The OnStop event is triggered when the Winamp client is stopped.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
integer event.position = contains the position within the file where the &amp;quot;Stop&amp;quot; was issued.  position is the number of milliseconds from the start of the asset.&lt;br /&gt;
&lt;br /&gt;
====OnPlay====&lt;br /&gt;
The OnPlay event is triggered when the Winamp client begins playback.  If the client is paused and then restarted by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
string event.filename = contains the filename/URL of the asset starting playback.&lt;br /&gt;
&lt;br /&gt;
====OnPause====&lt;br /&gt;
The OnPause event is triggered when the Winamp client is paused or unpaused.  If the client is started after being paused, by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
boolean event.paused = true (the player was paused), false (the player was unpaused)&lt;br /&gt;
&lt;br /&gt;
====OnEndOfFile====&lt;br /&gt;
The OnEndOfFile event is triggered when the player reaches the end of a track.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
===Callback function===&lt;br /&gt;
The callback function is invoked whenever a Transport event is detected.  The callback function is specified in both the RegisterForEvents() and UnregisterFromEvents() methods.  The method takes a single parameter, which is loaded with an object identifying the event that occurred.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 function EventHandler(event){&lt;br /&gt;
 {&lt;br /&gt;
     if (event.event == &amp;quot;OnStop&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnStop: position=&amp;quot; + event.position);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnEndOfFile&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnEndOfFile&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPause&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPause: paused=&amp;quot; + event.paused);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPlay&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPlay: filename=&amp;quot; + event.filename);&lt;br /&gt;
     }&lt;br /&gt;
     else {&lt;br /&gt;
       alert(&amp;quot;Unrecognized Event received&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== PlayQueue API ==&lt;br /&gt;
Provides access to the play queue (&amp;quot;Winamp Playlist&amp;quot;).  If you need access to the currently playing song, use the Transport API instead.&lt;br /&gt;
&lt;br /&gt;
Note that the Play Queue is the list of assets that are scheduled to be played by the Winamp client.  This is not necessarily the same as a user playlist.  Once placed in the play queue, assets can be rearrainged or deleted from the play queue without affecting a user playlist.  Individual assets can be placed in the play queue without being contained within a user playlist.  Additionally, after adding a playlist to the play queue, changes to the playlist will not affect the assets in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Play()====&lt;br /&gt;
The PlayQueue.Play() method stops playback, clears the play queue, enqueues the asset specified by the URL and starts playback.  If the URL cannot be found, playback will stop, the play queue will be cleared, the URL (or title and length) will appear in the queue but playback will not be started. &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play(URL);&lt;br /&gt;
 bool Play(URL, title);&lt;br /&gt;
 bool Play(URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Play(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Enqueue()====&lt;br /&gt;
PlayQueue.Enqueue() is used to add an asset to the play queue.  The selected asset is added to the bottom of the queue and current playback is not interrupted.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Enqueue(URL);&lt;br /&gt;
 bool Enqueue(URL, title);&lt;br /&gt;
 bool Enqueue(URL, title, length);&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Enqueue(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Insert()====&lt;br /&gt;
The PlayQueue.Insert() method can add an asset to the play queue at a specific index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Insert(position, URL);&lt;br /&gt;
 bool Insert(position, URL, title);&lt;br /&gt;
 bool Insert(position, URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
      '''position''' = (integer) a zero based number indicating the location within&lt;br /&gt;
           the play queue to insert the new asset.&lt;br /&gt;
           Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
                 queue is at position 0.&lt;br /&gt;
      '''url''' = (string) the URL of the asset to be added&lt;br /&gt;
      '''title''' = (string) the title to be displayed in the Play Queue.&lt;br /&gt;
      '''length''' = (integer) the length of the asset to be displayed in &lt;br /&gt;
           the play queue.&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Insert(1, &amp;quot;c:\\mySongs\\mySong.mp3&amp;quot;,300);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====ClearQueue()====&lt;br /&gt;
The PlayQueue.ClearQueue() method removes all assets from the play queue.  This does not stop the current playback.  ClearQueue is commonly used to prepare the Play Queue for the addition of new assets.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool ClearQueue()&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.ClearQueue();&lt;br /&gt;
&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
PlayQueue.GetMetadata() can be used to obtain asset metadata about an asset in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetMetadata(position, metadatatag);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position 0.&lt;br /&gt;
   '''metadatatag''' - (string) is a tag describing which metadata is requested.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var mdata = window.external.PlayQueue.GetMetadata(2,&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A String that contains the metadata requested for the asset located at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetTitle()====&lt;br /&gt;
PlayQueue.GetTitle() retrieves the title of the asset at the specified position within the play queue.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var title = window.external.PlayQueue.GetTitle(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the Title of the asset at the requested position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetURL()====&lt;br /&gt;
PlayQueue.GetURL() is used to obtain the URL from the asset at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetURL(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var url = window.external.PlayQueue.GetURL(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the URL of the asset at the rquested position in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
PlayQueue.length contains the length of the current play queue&lt;br /&gt;
&lt;br /&gt;
====int cursor====&lt;br /&gt;
PlayQueue.cursor provides access to the position of the currently playing asset within the play queue.  This cursor is 0 based, meaning that the first asset in the Play Queue has a cursor value of 0.  Valid values range from 0 to the length of the play queue minus one.&lt;br /&gt;
&lt;br /&gt;
If this value is changed before playback is started, the next asset to play will be the one assigned to this property.  However, if a song is already playing and this property is changed, the current asset will continue to play even though this property has been updated.  At the point that the current asset playback completes, the player will increment the cursor position and play the next asset in the queue rather than the one to which cursor was set.  So, for example, to specify the next asset to play while an asset is currently playing, set the cursor property to the position of the asset to play minus one.&lt;br /&gt;
&lt;br /&gt;
== Playlists API == &lt;br /&gt;
The Playlists API is used to process user playlists.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetPlaylists()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Array GetPlaylists();&lt;br /&gt;
Example:&lt;br /&gt;
 var playlists = window.external.Playlists.GetPlaylists();&lt;br /&gt;
Return Value:&lt;br /&gt;
A array-like object that can be used to examine all user playlists.&lt;br /&gt;
&lt;br /&gt;
Each element of the array represents a user playlist and contains the following properties&lt;br /&gt;
*filename - filename of the playlist&lt;br /&gt;
*title - name of the playlist&lt;br /&gt;
*playlistId - a unique identifier for the playlist, so you can retrieve it later.  Also used with OpenPlaylist/SavePlaylist&lt;br /&gt;
*length - total length (time) in seconds.  Cached data - not guaranteed to be accurate&lt;br /&gt;
*numitems - number of items in the playlist.  Cached data - not guaranteed to be accurate&lt;br /&gt;
&lt;br /&gt;
====OpenPlaylist()====&lt;br /&gt;
Playlists.OpenPlaylist() returns a Playlist object for the specified playlist ID.  You must use &lt;br /&gt;
Playlists.GetPlaylists() before issuing this request.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Playlist OpenPlaylist(playlistId);&lt;br /&gt;
 where:&lt;br /&gt;
   '''playlistId''' - (string) the Id of the playlist to be opened.&lt;br /&gt;
Example:&lt;br /&gt;
 var playlist1 = window.external.Playlists.OpenPlaylist(playlistId);&lt;br /&gt;
Return Value:&lt;br /&gt;
The Playlist object with the specified playistId.&lt;br /&gt;
&lt;br /&gt;
====SavePlaylist()====&lt;br /&gt;
Playlists.SavePlaylist() saves the specified playlist object with the specified ID.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool SavePlaylist(playlistId, playlist_to_save);&lt;br /&gt;
 where:&lt;br /&gt;
    '''playlistId''' (string) is the id of the playlist to be saved.&lt;br /&gt;
    '''playlist_to_save''' (Playlist) is the Playlist object to be saved.&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Playlists.SavePlaylist(playlistId, pl);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Playlist Object ===&lt;br /&gt;
Playlist objects can be created/returned by the OpenPlaylist() method as well as various other APIs.&lt;br /&gt;
&lt;br /&gt;
====Methods====&lt;br /&gt;
=====GetItemFilename()=====&lt;br /&gt;
The GetItemFilename() method retrieves the filename/URL of the item at the specified index into the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemFilename(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the filename&lt;br /&gt;
                   should be returned.  &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var filename = playlst.GetItemFilename(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the filename/URL of a particular item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemTitle()=====&lt;br /&gt;
The GetItemTitle() method returns the title of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the title&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var title = playlst.GetItemTitle(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The song title of the given item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemLength()=====&lt;br /&gt;
The GetItemLength() method retrieves the play length of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
 Number GetItemLength(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the length&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var itemLength = playlst.GetItemLength(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A number specifying the play length of the asset, in milliseconds.&lt;br /&gt;
&lt;br /&gt;
=====Reverse()=====&lt;br /&gt;
The Reverse() method reverses the order of the assets within a playlist, i.e., the first becomes last and the second becomes second to last, etc.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Reverse();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Reverse();&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=====Swap()=====&lt;br /&gt;
The Swap() method exchanges the assets at the two specified positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Swap(Number position1, Number position2)&lt;br /&gt;
 where: &lt;br /&gt;
   '''position1''' = (number) the index of the first item to be swapped.&lt;br /&gt;
   '''position2''' = (number) the index of the second item to be swapped.&lt;br /&gt;
   Note: position1 and position2 are &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Swap(0,1);&lt;br /&gt;
&lt;br /&gt;
=====Randomize()=====&lt;br /&gt;
The Randomize() method re-arranges the order of the playlist, placing the assets in random positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Randomize();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Randomize();&lt;br /&gt;
&lt;br /&gt;
=====Remove()=====&lt;br /&gt;
The Remove() method removes an asset from the playlist.  Subsequent assets are moved to lower number positions in the array.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Remove(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) the position of the asset to be removed.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Remove(0);&lt;br /&gt;
&lt;br /&gt;
=====SortByTitle()=====&lt;br /&gt;
The SortByTitle() method re-arrainges the order of the playlist so that it is alphabetical order by title.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByTitle();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByTitle();&lt;br /&gt;
&lt;br /&gt;
=====SortByFilename()=====&lt;br /&gt;
The SortByFilename() method re-arrainges the order of the playlist so that it is alphabetical order by filename.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByFilename();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByFilename();&lt;br /&gt;
&lt;br /&gt;
=====SetItemFilename()=====&lt;br /&gt;
Sets the filename of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 playlistObj.SetItemFilename(position, filename);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''filename''' = (string) the new filename &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetFilename(0, &amp;quot;c:\\\\myfavorites\\myfavsong.mp3&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemTitle()=====&lt;br /&gt;
Sets the title of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SetItemTitle(position, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''title''' = (string) the new title &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemTitle(0, &amp;quot;My Favorite Title&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemLength()=====&lt;br /&gt;
Sets the length of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 SetItemLength(position, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''length''' = (number) the new length &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemLength(0, 1000);&lt;br /&gt;
&lt;br /&gt;
=====InsertURL()=====&lt;br /&gt;
Inserts the specified asset in front of the asset at the specified position.  That and subsequent items are &amp;quot;pushed&amp;quot; to a higher position in the array.&lt;br /&gt;
&lt;br /&gt;
 InsertURL(position, url);&lt;br /&gt;
 InsertURL(position, url, title);&lt;br /&gt;
 InsertURL(position, url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position within the playlist before which to insert the asset&lt;br /&gt;
   '''url''' = (string) the URL of the asset to be inserted&lt;br /&gt;
   '''title''' = (string) title of the asset to be inserted&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be inserted&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====AppendURL()=====&lt;br /&gt;
The Playlist.AppendURL() method appends an asset URL to the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.AppendURL(url);&lt;br /&gt;
 Playlist.AppendURL(url, title);&lt;br /&gt;
 Playlist.AppendURL(url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) the URL to the asset to be appended&lt;br /&gt;
   '''title''' = (string) title of the asset to be appended&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be appended&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====Clear()=====&lt;br /&gt;
The Playlist.Clear() method will remove all assets from the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.Clear();&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful&lt;br /&gt;
&lt;br /&gt;
====Properties====&lt;br /&gt;
=====int numitems (read only)=====&lt;br /&gt;
The Playlist.numitems property contains the number of assets within the playlist.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Playlist Manager API ==&lt;br /&gt;
The Playlist Manager API provides methods to read and write playlists from permanent storage.&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bookmarks API ==&lt;br /&gt;
The Bookmarks API provides methods to manage bookmarks.&lt;br /&gt;
===Methods===&lt;br /&gt;
====Add()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean Add(url, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) The url of the asset to be bookmarked.&lt;br /&gt;
   '''title''' = (string) A suitable title to be used within the bookmark.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Bookmarks.Add(&amp;quot;c:\myfavs\songstocodeby.mp3&amp;quot;, &lt;br /&gt;
     &amp;quot;Songs To Code By&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Podcasts API ==&lt;br /&gt;
The Podcasts API provides methods to manage Podcasts.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Subscribe()====&lt;br /&gt;
The Podcasts.Subscribe() method is used to add a channel to the list of podcast subscriptions, automatically subscribe to the podcast and begin downloading of the available episodes.  Once downloaded the episodes can be selected for playback.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Subscribe(url);&lt;br /&gt;
 where:&lt;br /&gt;
     '''url''' = (string) the Podcast URL to subscribe to.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PodCasts.Subscribe(&amp;lt;nowiki&amp;gt;&amp;quot;http://services.winamp.com/rss/news&amp;quot;&amp;lt;/nowiki&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Config API ==&lt;br /&gt;
The Config API provides a means by which properties can be saved.  Properties added using the Config API are persistent across Winamp launches.&lt;br /&gt;
&lt;br /&gt;
===Adding and Retrieving Properties===&lt;br /&gt;
Adding a property is accomplished by identifying a property and assigning it a value.  Once assigned, the value can be retrieved like any other objects properties.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 window.external.Config.myProperty = &amp;quot;Test&amp;quot;;&lt;br /&gt;
 var myProp = window.external.Config.myProperty;  // myProp is set to &amp;quot;Test&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===Storing and Retrieving advanced data types===&lt;br /&gt;
Internally, all properties are stored as strings.  If you need to store datatypes more advanced than String, Number, or Boolean, it is recommended that you create a JSON string out of your data type.&lt;br /&gt;
&lt;br /&gt;
== Security API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
The Security.GetActionAuthorization() method can be used to determine whether a user has previously allowed or denied the functioning of a particular API's methods.  Group strings match API names.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 number Security.GetActionAuthorization(group);&lt;br /&gt;
 where:&lt;br /&gt;
    group = (string) Name of API to check for permission.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Security.GetActionAuthorization(&amp;quot;Transport&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return Data:&lt;br /&gt;
*-1 = Either the user has not specified whether to allow/deny use of this API or the action usage is unrestricted. &lt;br /&gt;
*0  = The user has previously specified to deny use of this API/method.&lt;br /&gt;
*1  = The user has previously specified to allow use of this API/method.&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Transport – Access to the currently playing track, and play controls (play, stop, seek, etc)&lt;br /&gt;
&lt;br /&gt;
PlayQueue – Access to the play queue (Winamp Playlist)&lt;br /&gt;
&lt;br /&gt;
Application – general Winamp information – version #, language pack&lt;br /&gt;
&lt;br /&gt;
Playlists – access to the media library playlists&lt;br /&gt;
&lt;br /&gt;
Bookmarks – access to the user’s bookmarks (place to bookmark radio streams, etc)&lt;br /&gt;
&lt;br /&gt;
Skin – access to information about the user’s skin – colors, fonts, etc.&lt;br /&gt;
&lt;br /&gt;
MediaCore – access to media playback information, such as supported extensions&lt;br /&gt;
&lt;br /&gt;
Podcasts – access to the user’s media library podcasts&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== MediaCore API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
==== IsRegisteredExtension() ====&lt;br /&gt;
MediaCore.IsRegisteredExtension() method can be used to determine if the Winamp client is able to playback a specific format.  The file extension of the asset usually indicates the format.  This method is important since Winamp support for different formats is contained within plugins which may or may not exist for use.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean IsRegisteredExtension(ext);&lt;br /&gt;
 where:&lt;br /&gt;
   '''ext''' = (string) identifies the format to be queried for support in the form of a &lt;br /&gt;
       character string of the extension (a starting period is optional).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var canPlay = window.external.MediaCore.IsRegisteredExtension(&amp;quot;mp3&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
Boolean value indicating whether the format is supported.&lt;br /&gt;
&lt;br /&gt;
==== GetMetadata() ====&lt;br /&gt;
MediaCore.GetMetadata() method can be used to obtain metadata about an asset.  This method differs from Transport.GetMetadata() in that the asset does not have to be currently playing.  It differs from PlayQueue.GetMetadata() in that it doesn't have to be present in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(url, tag);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be retrieved.&lt;br /&gt;
    '''tag''' = (string) the specific piece of metadata to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var art = window.external.MediaCore.GetMetadata(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the metadata requested.&lt;br /&gt;
&lt;br /&gt;
==== AddMetadataHook() ====&lt;br /&gt;
MediaCore.AddMetadataHook() method can be used to add or override metadata for an asset.  For example, some assets such as those that are streamed may not contain metadata.  This method allows the online service to add metadata for the specified asset.  Subsequent GetMetadata() methods will return this information.  Online services can override the metadata present within an asset using this method.  This method can be used by services that define or can obtain their own metadata for the assets they provide rather than rely on what might or might not be present in the asset itself.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string AddMetadataHook(url, tag, value);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be added.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be added.&lt;br /&gt;
    '''value''' - (string) the value of the metadata key being added.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.AddMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;,&amp;quot;myself&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
==== RemoveMetadataHook() ====&lt;br /&gt;
MediaCore.RemoveMetadataHook() method can be used to remove metadata added through the AddMetadataHook() method.  Subsequent GetMetadata() requests will return whatever metadata was available previously, if any.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string RemoveMetadataHook(url, tag);&lt;br /&gt;
 string RemoveMetadataHook(url);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be removed.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be removed.&lt;br /&gt;
&lt;br /&gt;
If only the url parameter is provided, all metadata added with AddMetadataHook() for the specified url will be removed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.RemoveMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== History API ==&lt;br /&gt;
The History branch of the Media Library pane is actually a database containing information about previously played assets.  The History API allows a service to search and retrieve information from this database.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
==== Query() ====&lt;br /&gt;
Prototype:&lt;br /&gt;
 results = History.Query(queryString);&lt;br /&gt;
 where:&lt;br /&gt;
   '''queryString''' = a properly formed string to match data to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var results = window.external.History.Query(&amp;quot;LASTPLAYED&amp;lt;[now]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
An &amp;quot;array-like&amp;quot; object that contains the results of the query.&lt;br /&gt;
&lt;br /&gt;
Each entry of the array contains the following properties:&lt;br /&gt;
* String filename&lt;br /&gt;
* String title&lt;br /&gt;
* Number length&lt;br /&gt;
* Number playcount&lt;br /&gt;
* Date lastplay&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fields:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date and time when this asset was last played.&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of times the asset has been played. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Local Media API  (test)==&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The LocalMedia API allows a service to search the assets within the Local Media branch of the Media Library.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
Prototype:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
returns an array of objects that match the specified criteria of the query string.&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| TYPE&lt;br /&gt;
| 0 for audio files, 1 for video files&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| ARTIST&lt;br /&gt;
| Artist&lt;br /&gt;
|-&lt;br /&gt;
| ALBUM&lt;br /&gt;
| Album&lt;br /&gt;
|-&lt;br /&gt;
| ALBUMARTIST&lt;br /&gt;
| Album Artist&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| TRACKNO&lt;br /&gt;
| Track number of file&lt;br /&gt;
|-&lt;br /&gt;
| GENRE&lt;br /&gt;
| Genre&lt;br /&gt;
|-&lt;br /&gt;
| YEAR&lt;br /&gt;
| Year&lt;br /&gt;
|-&lt;br /&gt;
| COMMENT&lt;br /&gt;
| Comment&lt;br /&gt;
|-&lt;br /&gt;
| COMPOSER&lt;br /&gt;
| Composer&lt;br /&gt;
|-&lt;br /&gt;
| DISC&lt;br /&gt;
| Disc number of a CD set&lt;br /&gt;
|-&lt;br /&gt;
| FILESIZE&lt;br /&gt;
| File size, in kilobytes&lt;br /&gt;
|-&lt;br /&gt;
| FILETIME&lt;br /&gt;
| Last known file date/time on disk&lt;br /&gt;
|-&lt;br /&gt;
| FOLDER&lt;br /&gt;
| Containing folder&lt;br /&gt;
|-&lt;br /&gt;
| LASTUPD&lt;br /&gt;
| Date/time of file imported to library or modified in library&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date/time of last play&lt;br /&gt;
|-&lt;br /&gt;
| RATING&lt;br /&gt;
| Rating value (1-5, or 0 or empty for unrated)&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of plays&lt;br /&gt;
|-&lt;br /&gt;
| PUBLISHER&lt;br /&gt;
| Publisher or record label&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_ALBUM_GAIN&lt;br /&gt;
| ReplayGain Album Gain&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_TRACK_GAIN&lt;br /&gt;
| ReplayGain Track Gain&lt;br /&gt;
|-&lt;br /&gt;
| BITRATE&lt;br /&gt;
| Bitrate (in KBPS)&lt;br /&gt;
|-&lt;br /&gt;
| TRACKS&lt;br /&gt;
| Total number of tracks on the disc&lt;br /&gt;
|-&lt;br /&gt;
| DISCS&lt;br /&gt;
| Total number of discs in the set&lt;br /&gt;
|-&lt;br /&gt;
| ISPODCAST&lt;br /&gt;
| 1 for a podcast episode, 0 otherwise&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTCHANNEL&lt;br /&gt;
| The name of the channel for a podcast&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTPUBDATE&lt;br /&gt;
| Date/time when the podcast was published&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Field Names:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Comparison Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Application API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
====LaunchURL()====&lt;br /&gt;
The Application.LaunchURL() method launches a URL in the bento browser&lt;br /&gt;
or default browser.  The default browser is launched if force_external = true or in skins that don't define a browser.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean LaunchURL(url, force_external);&lt;br /&gt;
 where:&lt;br /&gt;
      '''url''' = (string) The url to open in the browser&lt;br /&gt;
      '''force_external''' = (boolean) will force the url to be displayed in a browser&lt;br /&gt;
           outside of the Winamp client.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &lt;br /&gt;
 var rc = LaunchURL(&amp;lt;nowiki&amp;gt;&amp;quot;http://www.winamp.com&amp;quot;&amp;lt;/nowiki&amp;gt;, true); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int version (read only)====   &lt;br /&gt;
The version property returns the version number of the browser control within the Winamp client as an integer, e.g. 555 for 5.55,  560 for 5.6&lt;br /&gt;
====string versionstring (read only)====&lt;br /&gt;
The versionstring property returns the version number of the browser control within the Winamp client as a string, e.g. &amp;quot;5.55&amp;quot; for 5.55&lt;br /&gt;
====string language (read only) ====&lt;br /&gt;
Language identifier from the currently installed language pack.  Follows ISO 639-1 two letter language codes&lt;br /&gt;
&lt;br /&gt;
====string languagepack (read only) ====&lt;br /&gt;
Language pack identifier from the currently installed language pack.  follows the form&lt;br /&gt;
lc-CC&lt;br /&gt;
where lc is the two letter ISO 639-1 language code&lt;br /&gt;
and CC is the two letter ISO 3166 country code.&lt;br /&gt;
&lt;br /&gt;
Note: do not count on the country code being the same as the user's current location.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Security API ==&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
  GetActionAuthorization(group, action);&lt;br /&gt;
  where:&lt;br /&gt;
      '''group''' = (string) a group of related methods, i.e. the API name.&lt;br /&gt;
      '''action''' = (string) a specific method within a group.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var auth = window.external.Security.GetActionAuthorization(&amp;quot;application&amp;quot;, &lt;br /&gt;
           &amp;quot;launchurl&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value: an integer representing the following results&lt;br /&gt;
&lt;br /&gt;
*ACTION_UNDEFINED = -1,&lt;br /&gt;
*ACTION_DISALLOWED = 0,&lt;br /&gt;
*ACTION_PROMPT = 1,&lt;br /&gt;
*ACTION_ALLOWED = 2,&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Skin API ==&lt;br /&gt;
&lt;br /&gt;
The skin color API is a bit of a challenge.  This API reflects some the idiosyncrasies of the underlying skinning system.  &amp;quot;Classic&amp;quot; skins define a palette of 24 colors for the skin and an additional 6 colors for the playlist editor.  &amp;quot;Modern&amp;quot; skins define these as well as any number of other colors retrievable by name (e.g. wasabi.tree.text for the text color on tree views).  A website relying on any of these extra &amp;quot;named&amp;quot; colors should be careful to implement a fallback color based on the classic palette, as no named colors exist in classic skins!&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetClassicColor()====&lt;br /&gt;
The Skin.GetClassicColor() method is used to retrieve color information regarding different Skin UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetClassicColor(classiccolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''classiccolornumber''' = (integer) A number in the range 0-23 identifying the Skin's UI element &lt;br /&gt;
         for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var wndBgColor = window.external.Skin.GetClassicColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Skin UI element.&lt;br /&gt;
&lt;br /&gt;
====Classic Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|  0 &lt;br /&gt;
| Item Background&lt;br /&gt;
|-&lt;br /&gt;
|  1 &lt;br /&gt;
| Item Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  2 &lt;br /&gt;
| Window Background&lt;br /&gt;
|-&lt;br /&gt;
|  3 &lt;br /&gt;
| Button Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  4 &lt;br /&gt;
| Window Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  5 &lt;br /&gt;
| Hilite&lt;br /&gt;
|-&lt;br /&gt;
|  6 &lt;br /&gt;
| Selection&lt;br /&gt;
|-&lt;br /&gt;
|  7 &lt;br /&gt;
| List Header Background&lt;br /&gt;
|-&lt;br /&gt;
|  8 &lt;br /&gt;
| List Header Text&lt;br /&gt;
|-&lt;br /&gt;
|  9 &lt;br /&gt;
| List Header Frame Top&lt;br /&gt;
|-&lt;br /&gt;
| 10 &lt;br /&gt;
| List Header Frame Middle&lt;br /&gt;
|-&lt;br /&gt;
| 11 &lt;br /&gt;
| List Header Frame Bottom&lt;br /&gt;
|-&lt;br /&gt;
| 12 &lt;br /&gt;
| List Header Empty Background&lt;br /&gt;
|-&lt;br /&gt;
| 13 &lt;br /&gt;
| Scrollbar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 14 &lt;br /&gt;
| Scrollbar Background&lt;br /&gt;
|-&lt;br /&gt;
| 15 &lt;br /&gt;
| Scrollbar Inverse Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 16 &lt;br /&gt;
| Scrollbar Inverse Background&lt;br /&gt;
|-&lt;br /&gt;
| 17 &lt;br /&gt;
| Scrollbar Dead Area&lt;br /&gt;
|-&lt;br /&gt;
| 18 &lt;br /&gt;
| Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 19 &lt;br /&gt;
| Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 20 &lt;br /&gt;
| Inactive Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 21 &lt;br /&gt;
| Inactive Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 22 &lt;br /&gt;
| Alternating Item Background&lt;br /&gt;
|-&lt;br /&gt;
| 23 &lt;br /&gt;
| Alternating Item Foreground&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetPlaylistColor()====&lt;br /&gt;
The Skin.GetPlaylistColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetPlaylistColor(playlistcolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''playlistcolornumber''' = (integer) a number in the range 0-5 identifying the Playlist's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var normalBgColor = window.external.Skin.GetPlaylistColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Playlist Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 &lt;br /&gt;
| Normal&lt;br /&gt;
|-&lt;br /&gt;
| 1 &lt;br /&gt;
| Current&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Normal Background&lt;br /&gt;
|-&lt;br /&gt;
| 3 &lt;br /&gt;
| Selected Background&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Video Window Status Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 5 &lt;br /&gt;
| Video Window Status Bar Background&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetSkinColor()====&lt;br /&gt;
The Skin.GetSkinColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetSkinColor(skincolorname);&lt;br /&gt;
  where:&lt;br /&gt;
    '''skincolorname''' = (string) identifying the Skin's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var buttonTextColor = window.external.Skin.GetSkinColor(&amp;quot;wasabi.button.text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Skin Color Names====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.item.selected.fg&amp;quot;&lt;br /&gt;
|Selected item text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.column.separator&amp;quot; &lt;br /&gt;
|Color of line between columns&lt;br /&gt;
|-&lt;br /&gt;
|'''Item Lists, Lists with playable items'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.current&amp;quot;  &lt;br /&gt;
|Currently playing outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.focus&amp;quot;  &lt;br /&gt;
|Focused item dashed outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.selborder&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|'''Message box'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.msgBox.background&amp;quot;   &lt;br /&gt;
|Messagebox background color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.text&amp;quot;  &lt;br /&gt;
|Text object &amp;amp; message box text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.background&amp;quot;   &lt;br /&gt;
|Text object &amp;amp; message box text background color&lt;br /&gt;
|-&lt;br /&gt;
|'''Buttons'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.text&amp;quot;  &lt;br /&gt;
|Buttons text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.hiliteText&amp;quot; &lt;br /&gt;
|Buttons hilite text color, used by tab windows&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.dimmedText&amp;quot;  &lt;br /&gt;
|Buttons dimmed text color, when disabled&lt;br /&gt;
|-&lt;br /&gt;
|'''Popup menus'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.text&amp;quot;  &lt;br /&gt;
|Menu items text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.hiliteText&amp;quot;  &lt;br /&gt;
|Hilited item text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.dimmedText&amp;quot;  &lt;br /&gt;
|Disabled item text color&lt;br /&gt;
|-&lt;br /&gt;
|'''Components'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.foreground&amp;quot;  &lt;br /&gt;
|Old title bar text color when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.border&amp;quot;  &lt;br /&gt;
|Old title bar text outline when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|'''Labeled Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.foreground&amp;quot;  &lt;br /&gt;
|Text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.background&amp;quot; &lt;br /&gt;
|Text drop shadow color&lt;br /&gt;
|-&lt;br /&gt;
|'''Edit Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.selection&amp;quot;  &lt;br /&gt;
|Selected text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.text&amp;quot; &lt;br /&gt;
|Text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.background&amp;quot;  &lt;br /&gt;
|Text background&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color.inverse&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====string name (test)====&lt;br /&gt;
The Skin.name property gives access to the name of skin currently in use.  Changing this value will change the skin displayed for the player.&lt;br /&gt;
&lt;br /&gt;
====string font (read only)====&lt;br /&gt;
The Skin.font property provides the font name currently used in the player.&lt;br /&gt;
&lt;br /&gt;
====string fontsize (read only)====&lt;br /&gt;
The Skin.fontsize property provides the size of the font currently used in the player.&lt;br /&gt;
&lt;br /&gt;
== Metadata tag names ==&lt;br /&gt;
&lt;br /&gt;
When retrieving metadata through Winamp, a freeform string is passed.  The popular file formats (MP3, WMA, FLAC, M4A) will respond uniformly to a common base of strings.  However, each file format is idiosyncratic in how metadata is stored.  Some file types will respond to additional strings which are not documented here.&lt;br /&gt;
&lt;br /&gt;
Remember that the metadata is only as good as the tagging in the file itself.  A poorly tagged track will return poor metadata.&lt;br /&gt;
&lt;br /&gt;
Common metadata tags&lt;br /&gt;
 bitrate&lt;br /&gt;
 length&lt;br /&gt;
 type&lt;br /&gt;
 title&lt;br /&gt;
 artist&lt;br /&gt;
 albumartist&lt;br /&gt;
 album&lt;br /&gt;
 genre&lt;br /&gt;
 year&lt;br /&gt;
 disc&lt;br /&gt;
 publisher&lt;br /&gt;
 comment&lt;br /&gt;
 track&lt;br /&gt;
 composer&lt;br /&gt;
 conductor&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework</id>
		<title>Complete JavaScript API technology framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework"/>
				<updated>2009-07-01T16:10:53Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Enqueue() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
[[Category:Winamp]]&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
The purpose of the Winamp Online Service API is to allow Winamp Online Services to interact with the Winamp client in order to provide service developers with a way to create custom experiences for their users based on the power of Winamp.  The overall idea is to include exceptional web sites within Winamp Online Services.&lt;br /&gt;
&lt;br /&gt;
The Winamp Online Service API is made up of methods that can be called from scripts within web pages rendered by the Winamp client.  The API can be invoked using any scripting language supported by the Microsoft Internet Explorer web browser (5.5 and above).  For simplicity, examples in this document will use JavaScript.&lt;br /&gt;
&lt;br /&gt;
==Setup==&lt;br /&gt;
The Winamp Online Services API is designed to allow web pages, hosted (displayed) within the embedded browser of the Winamp client, to access the functionality of the client.  There are several steps necessary to allow this to take place.&lt;br /&gt;
&lt;br /&gt;
#Make sure you have the latest version of the Winamp client that supports online services.&lt;br /&gt;
#Make sure you have the latest version of the ml_webdev plugin (ml_webdev.dll).  The presence of this plugin will create a &amp;quot;Web Dev Test Platform&amp;quot; within the Medial Library pane.&lt;br /&gt;
#In order to change the starting web page for the online service, start the Winamp client and configure the plugin.  &lt;br /&gt;
##Select Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;Media Library.  &lt;br /&gt;
##Select &amp;quot;API 2 Test Platform&amp;quot; and press &amp;quot;Configure selected plugin&amp;quot;.  &lt;br /&gt;
##On the Web Dev Preferences dialog, set the URL field to the URL of the initial web page for the online service.  For example, &amp;lt;nowiki&amp;gt;file://c:\myonlineservice\webdev.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
#Click on &amp;quot;Web Dev Test Platform&amp;quot; in the Media Library.  You may have to right click and choose refresh to see the new web page.&lt;br /&gt;
&lt;br /&gt;
You should now see the initial page of your online service in the Winamp embedded browser.&lt;br /&gt;
&lt;br /&gt;
==window.external==&lt;br /&gt;
The Winamp JavaScript API can be accessed through the window.external object in the Document Object Model (DOM) exposed by the IE browser control embedded within the Winamp client.  The API methods can only be accessed thru the Winamp client and are not available if the web page is displayed outside of the client.&lt;br /&gt;
&lt;br /&gt;
The invocation of all methods follow this form&lt;br /&gt;
 window.external.'''''API'''''.'''''Method'''''&lt;br /&gt;
&lt;br /&gt;
Properties can also be accessed using a similar form:&lt;br /&gt;
 window.external.'''''API'''''.'''''Property'''''&lt;br /&gt;
&lt;br /&gt;
Where ''API'' is a singleton class that defines a group of related methods (i.e., functionality).  For example, Transport (Stop, Play, Next, etc) which controls the &amp;quot;buttons&amp;quot; of the Winamp player. &lt;br /&gt;
&lt;br /&gt;
''Method'' is a function you can call as part of a particular API.  For example the following call will stop the Winamp client:&lt;br /&gt;
 window.external.Transport.Stop();&lt;br /&gt;
&lt;br /&gt;
''Property'' is an internal variable for the particular API that can be queried and in some cases set.  For example the following will provide access to the Winamp client shuffle &amp;quot;button&amp;quot;:&lt;br /&gt;
 var shuffle = window.external.Transport.shuffle;  // gets the current state&lt;br /&gt;
     OR&lt;br /&gt;
 window.external.Transport.shuffle = true;         // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
See the documentation on each API below for a complete list of methods and properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == Security Warnings ==&lt;br /&gt;
Using the Winamp JavaScript API, an online service web page has access to much more information (read: power) than a normal web page.  For example, playlists can be enumerated, and metadata for songs can be retrieved.  In order to control these capabilities a security system was implemented so that users are informed whenever an online service first attempts to use an API method or access a property.  For example, when an online service attempts to stop playback for the very first time, the user will be notified and asked whether the service should be allowed to do this.&lt;br /&gt;
&lt;br /&gt;
Note that this security model maintains user choices based on service ID so that the user will be prompted each time a service tries to invoke methods or access properties.  In addition, online services updated through the Winamp Online Service submission process, receive new service IDs, causing the users to be prompted again.&lt;br /&gt;
&lt;br /&gt;
A dialog is presented to the user that describes the action about to be performed and forces the user to choose whether the action should be Allowed or Denied.  A third button let's a user to indicate &amp;quot;Always Allow&amp;quot;.  If the user selects this button, the API will no longer prompt the user for this action (for this particular online service).  &lt;br /&gt;
&lt;br /&gt;
Be aware that choices for certain APIs will affect the entire API and all of its methods and properties.  For example, choosing &amp;quot;Always Allow&amp;quot; for Transport.Stop() will also always allow access to the other Tranport methods/properties.  Certain other APIs, such as the Application API affect only the action being attempted.  Some API methods and properties are considered inconsequential and not governed by this security model at all.  The scope of the user's choice will be described within the dialog.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transport API ==&lt;br /&gt;
The Transport API is used to control the Winamp client.  &amp;quot;Transport controls&amp;quot; was the name given to the buttons on the front panel that controlled hardware devices.  This name is used in Winamp for the same purpose.  It is also used to access information about the currently playing song.&lt;br /&gt;
&lt;br /&gt;
The Transport API can also be used to register for events involved with asset playback.  See the section [[#Transport Events API|Transport Events API]].&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Prev()====&lt;br /&gt;
Transport.Prev() can be used to press the &amp;quot;Previous Track&amp;quot; button on the Winamp player.  Invoking Prev() while an asset is already playing will cause the previous asset to begin playback immediately.  Invoking Prev() while the player is stopped will cause the previous asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Prev();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Prev();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Play()====&lt;br /&gt;
Transport.Play() can be used to press the &amp;quot;Play&amp;quot; button on the Winamp player.  Invoking Play() on an asset already playing will cause the asset to restart playback.  Pressing Play() on a paused asset will cause it to begin playing from its current position.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Play();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Pause()====&lt;br /&gt;
Transport.Pause() can be used to press the &amp;quot;Pause&amp;quot; button on the Winamp player.  Issuing Pause() again, or Play() will cause the asset to continue to play from the location where it was paused.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Pause();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Pause();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Stop()====&lt;br /&gt;
Transport.Stop() can be used to press the &amp;quot;Stop&amp;quot; button on the Winamp player.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Stop();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Stop();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
====Next()====&lt;br /&gt;
Transport.Next() can be used to press the &amp;quot;Next Track&amp;quot; button on the Winamp player.  Invoking Next() while the player is stopped will cause the next asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Next();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Next();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
Transport.GetMetadata() can be used to fetch metadata for the currently playing asset.  The &amp;quot;tag&amp;quot; parameter is specific to different asset encoding formats so a knowledge of the metadata field names is necessary to request specific data about an asset.  Some field names are common but others are specific to the encoding format of the asset.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(tag);&lt;br /&gt;
 where:&lt;br /&gt;
      '''tag''' = (string) identifier for the metadata to be returned.&lt;br /&gt;
Example:&lt;br /&gt;
 var metaStr = window.external.Transport.GetMetadata(&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A string value containing the requested metadata.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====bool shuffle====&lt;br /&gt;
Transport.shuffle provides access to the Winamp client shuffle &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isShuffling = window.external.Transport.shuffle; // get shuffle state&lt;br /&gt;
  window.external.Transport.shuffle = true;            // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
====bool repeat====&lt;br /&gt;
Transport.repeat provides access to the Winamp client repeat &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isRepeating = window.external.Transport.repeat; // get repeat state&lt;br /&gt;
  window.external.Transport.repeat = false;           // turns off repeat&lt;br /&gt;
&lt;br /&gt;
====int position====&lt;br /&gt;
Transport.position provides access to the position being played within the current asset.  Setting this value can change the location where playback occurs. position is in milliseconds.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var position = window.external.Transport.position; // get position in current track&lt;br /&gt;
  window.external.Transport.position = 221559;       // move playback of the current track &lt;br /&gt;
                                                     // to the specified position.&lt;br /&gt;
&lt;br /&gt;
====bool playing (read only) ====&lt;br /&gt;
Transport.playing indicates whether the Winamp Player is currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPlaying = window.external.Transport.playing; // is player playing?&lt;br /&gt;
&lt;br /&gt;
====bool paused (read only) ====&lt;br /&gt;
Transport.paused indicates whether the Winamp Player has been paused.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPaused = window.external.Transport.paused; // is player paused?&lt;br /&gt;
&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
Transport.length provides access to the length in seconds of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var length = window.external.Transport.length; // get length of current track in secs&lt;br /&gt;
&lt;br /&gt;
====string url (read only)====&lt;br /&gt;
Transport.url provides access to the URL (or filename) of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var url = window.external.Transport.url; // get url of current track&lt;br /&gt;
&lt;br /&gt;
====string title (read only)====&lt;br /&gt;
Transport.title provides access to the title of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var title = window.external.Transport.title; // get title of current track&lt;br /&gt;
&lt;br /&gt;
==Transport Events API==&lt;br /&gt;
The Event mechanism of the Transport API allows javascript programmers to specify a callback method that will be invoked whenever certain Transport events take place.  An Event object is passed back to the method from which properties can be accessed that provide more information about the event.&lt;br /&gt;
&lt;br /&gt;
===RegisterForEvents()===&lt;br /&gt;
The RegisterForEvents() method can be used to specify a JavaScript function that is to be called when any Transport Events occur.  An event object is passed that indicates the type of event.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean RegisterForEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.RegisterForEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===UnregisterFromEvents()===&lt;br /&gt;
The UnregisterFromEvents() method is used to stop receiving notifications about Transport events.&lt;br /&gt;
&lt;br /&gt;
Note:  The original handler used in RegisterForEvents() must be passed back into UnregisterFromEvents().&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean UnregisterFromEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.UnregisterFromEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Events===&lt;br /&gt;
The Transport API Event mechanism requires a JavaScript callback method that accepts a single parameter, a reference to a function.  This function will be invoked with an &amp;quot;event&amp;quot; object that will indicate the type of event that occurred as well as contain properties containing more information about the event.&lt;br /&gt;
&lt;br /&gt;
====OnStop====&lt;br /&gt;
The OnStop event is triggered when the Winamp client is stopped.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
integer event.position = contains the position within the file where the &amp;quot;Stop&amp;quot; was issued.  position is the number of milliseconds from the start of the asset.&lt;br /&gt;
&lt;br /&gt;
====OnPlay====&lt;br /&gt;
The OnPlay event is triggered when the Winamp client begins playback.  If the client is paused and then restarted by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
string event.filename = contains the filename/URL of the asset starting playback.&lt;br /&gt;
&lt;br /&gt;
====OnPause====&lt;br /&gt;
The OnPause event is triggered when the Winamp client is paused or unpaused.  If the client is started after being paused, by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
boolean event.paused = true (the player was paused), false (the player was unpaused)&lt;br /&gt;
&lt;br /&gt;
====OnEndOfFile====&lt;br /&gt;
The OnEndOfFile event is triggered when the player reaches the end of a track.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
===Callback function===&lt;br /&gt;
The callback function is invoked whenever a Transport event is detected.  The callback function is specified in both the RegisterForEvents() and UnregisterFromEvents() methods.  The method takes a single parameter, which is loaded with an object identifying the event that occurred.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 function EventHandler(event){&lt;br /&gt;
 {&lt;br /&gt;
     if (event.event == &amp;quot;OnStop&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnStop: position=&amp;quot; + event.position);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnEndOfFile&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnEndOfFile&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPause&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPause: paused=&amp;quot; + event.paused);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPlay&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPlay: filename=&amp;quot; + event.filename);&lt;br /&gt;
     }&lt;br /&gt;
     else {&lt;br /&gt;
       alert(&amp;quot;Unrecognized Event received&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== PlayQueue API ==&lt;br /&gt;
Provides access to the play queue (&amp;quot;Winamp Playlist&amp;quot;).  If you need access to the currently playing song, use the Transport API instead.&lt;br /&gt;
&lt;br /&gt;
Note that the Play Queue is the list of assets that are scheduled to be played by the Winamp client.  This is not necessarily the same as a user playlist.  Once placed in the play queue, assets can be rearrainged or deleted from the play queue without affecting a user playlist.  Individual assets can be placed in the play queue without being contained within a user playlist.  Additionally, after adding a playlist to the play queue, changes to the playlist will not affect the assets in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Play()====&lt;br /&gt;
The PlayQueue.Play() method stops playback, clears the play queue, enqueues the asset specified by the URL and starts playback.  If the URL cannot be found, playback will stop, the play queue will be cleared, the URL (or title and length) will appear in the queue but playback will not be started. &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play(URL);&lt;br /&gt;
 bool Play(URL, title);&lt;br /&gt;
 bool Play(URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Play(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Enqueue()====&lt;br /&gt;
PlayQueue.Enqueue() is used to add an asset to the play queue.  The selected asset is added to the bottom of the queue and current playback is not interrupted.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Enqueue(URL);&lt;br /&gt;
 bool Enqueue(URL, title);&lt;br /&gt;
 bool Enqueue(URL, title, length);&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Enqueue(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Insert()====&lt;br /&gt;
The PlayQueue.Insert() method can add an asset to the play queue at a specific index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Insert(position, URL);&lt;br /&gt;
 bool Insert(position, URL, title);&lt;br /&gt;
 bool Insert(position, URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
      '''position''' = (integer) a zero based number indicating the location within&lt;br /&gt;
           the play queue to insert the new asset.&lt;br /&gt;
           Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
                 queue is at position 0.&lt;br /&gt;
      '''url''' = (string) the URL of the asset to be added&lt;br /&gt;
      '''title''' = (string) the title to be displayed in the Play Queue.&lt;br /&gt;
      '''length''' = (integer) the length of the asset to be displayed in &lt;br /&gt;
           the play queue.&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Insert(1, &amp;quot;c:\\mySongs\\mySong.mp3&amp;quot;,300);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====ClearQueue()====&lt;br /&gt;
The PlayQueue.ClearQueue() method removes all assets from the play queue.  This does not stop the current playback.  ClearQueue is commonly used to prepare the Play Queue for the addition of new assets.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool ClearQueue()&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.ClearQueue();&lt;br /&gt;
&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
PlayQueue.GetMetadata() can be used to obtain asset metadata about an asset in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetMetadata(position, metadatatag);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position 0.&lt;br /&gt;
   '''metadatatag''' - (string) is a tag describing which metadata is requested.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var mdata = window.external.PlayQueue.GetMetadata(2,&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A String that contains the metadata requested for the asset located at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetTitle()====&lt;br /&gt;
PlayQueue.GetTitle() retrieves the title of the asset at the specified position within the play queue.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var title = window.external.PlayQueue.GetTitle(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the Title of the asset at the requested position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetURL()====&lt;br /&gt;
PlayQueue.GetURL() is used to obtain the URL from the asset at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetURL(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var url = window.external.PlayQueue.GetURL(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the URL of the asset at the rquested position in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
PlayQueue.length contains the length of the current play queue&lt;br /&gt;
&lt;br /&gt;
====int cursor====&lt;br /&gt;
PlayQueue.cursor provides access to the position of the currently playing asset within the play queue.  This cursor is 0 based, meaning that the first asset in the Play Queue has a cursor value of 0.  Valid values range from 0 to the length of the play queue minus one.&lt;br /&gt;
&lt;br /&gt;
If this value is changed before playback is started, the next asset to play will be the one assigned to this property.  However, if a song is already playing and this property is changed, the current asset will continue to play even though this property has been updated.  At the point that the current asset playback completes, the player will increment the cursor position and play the next asset in the queue rather than the one to which cursor was set.  So, for example, to specify the next asset to play while an asset is currently playing, set the cursor property to the position of the asset to play minus one.&lt;br /&gt;
&lt;br /&gt;
== Playlists API == &lt;br /&gt;
The Playlists API is used to process user playlists.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetPlaylists()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Array GetPlaylists();&lt;br /&gt;
Example:&lt;br /&gt;
 var playlists = window.external.Playlists.GetPlaylists();&lt;br /&gt;
Return Value:&lt;br /&gt;
A array-like object that can be used to examine all user playlists.&lt;br /&gt;
&lt;br /&gt;
Each element of the array represents a user playlist and contains the following properties&lt;br /&gt;
*filename - filename of the playlist&lt;br /&gt;
*title - name of the playlist&lt;br /&gt;
*playlistId - a unique identifier for the playlist, so you can retrieve it later.  Also used with OpenPlaylist/SavePlaylist&lt;br /&gt;
*length - total length (time) in seconds.  Cached data - not guaranteed to be accurate&lt;br /&gt;
*numitems - number of items in the playlist.  Cached data - not guaranteed to be accurate&lt;br /&gt;
&lt;br /&gt;
====OpenPlaylist()====&lt;br /&gt;
Playlists.OpenPlaylist() returns a Playlist object for the specified playlist ID.  You must use &lt;br /&gt;
Playlists.GetPlaylists() before issuing this request.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Playlist OpenPlaylist(playlistId);&lt;br /&gt;
 where:&lt;br /&gt;
   '''playlistId''' - (string) the Id of the playlist to be opened.&lt;br /&gt;
Example:&lt;br /&gt;
 var playlist1 = window.external.Playlists.OpenPlaylist(playlistId);&lt;br /&gt;
Return Value:&lt;br /&gt;
The Playlist object with the specified playistId.&lt;br /&gt;
&lt;br /&gt;
====SavePlaylist()====&lt;br /&gt;
Playlists.SavePlaylist() saves the specified playlist object with the specified ID.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool SavePlaylist(playlistId, playlist_to_save);&lt;br /&gt;
 where:&lt;br /&gt;
    '''playlistId''' (string) is the id of the playlist to be saved.&lt;br /&gt;
    '''playlist_to_save''' (Playlist) is the Playlist object to be saved.&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Playlists.SavePlaylist(playlistId, pl);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Playlist Object ===&lt;br /&gt;
Playlist objects can be created/returned by the OpenPlaylist() method as well as various other APIs.&lt;br /&gt;
&lt;br /&gt;
====Methods====&lt;br /&gt;
=====GetItemFilename()=====&lt;br /&gt;
The GetItemFilename() method retrieves the filename/URL of the item at the specified index into the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemFilename(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the filename&lt;br /&gt;
                   should be returned.  &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var filename = playlst.GetItemFilename(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the filename/URL of a particular item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemTitle()=====&lt;br /&gt;
The GetItemTitle() method returns the title of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the title&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var title = playlst.GetItemTitle(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The song title of the given item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemLength()=====&lt;br /&gt;
The GetItemLength() method retrieves the play length of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
 Number GetItemLength(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the length&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var itemLength = playlst.GetItemLength(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A number specifying the play length of the asset, in milliseconds.&lt;br /&gt;
&lt;br /&gt;
=====Reverse()=====&lt;br /&gt;
The Reverse() method reverses the order of the assets within a playlist, i.e., the first becomes last and the second becomes second to last, etc.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Reverse();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Reverse();&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=====Swap()=====&lt;br /&gt;
The Swap() method exchanges the assets at the two specified positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Swap(Number position1, Number position2)&lt;br /&gt;
 where: &lt;br /&gt;
   '''position1''' = (number) the index of the first item to be swapped.&lt;br /&gt;
   '''position2''' = (number) the index of the second item to be swapped.&lt;br /&gt;
   Note: position1 and position2 are &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Swap(0,1);&lt;br /&gt;
&lt;br /&gt;
=====Randomize()=====&lt;br /&gt;
The Randomize() method re-arranges the order of the playlist, placing the assets in random positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Randomize();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Randomize();&lt;br /&gt;
&lt;br /&gt;
=====Remove()=====&lt;br /&gt;
The Remove() method removes an asset from the playlist.  Subsequent assets are moved to lower number positions in the array.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Remove(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) the position of the asset to be removed.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Remove(0);&lt;br /&gt;
&lt;br /&gt;
=====SortByTitle()=====&lt;br /&gt;
The SortByTitle() method re-arrainges the order of the playlist so that it is alphabetical order by title.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByTitle();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByTitle();&lt;br /&gt;
&lt;br /&gt;
=====SortByFilename()=====&lt;br /&gt;
The SortByFilename() method re-arrainges the order of the playlist so that it is alphabetical order by filename.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByFilename();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByFilename();&lt;br /&gt;
&lt;br /&gt;
=====SetItemFilename()=====&lt;br /&gt;
Sets the filename of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 playlistObj.SetItemFilename(position, filename);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''filename''' = (string) the new filename &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetFilename(0, &amp;quot;c:\\\\myfavorites\\myfavsong.mp3&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemTitle()=====&lt;br /&gt;
Sets the title of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SetItemTitle(position, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''title''' = (string) the new title &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemTitle(0, &amp;quot;My Favorite Title&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemLength()=====&lt;br /&gt;
Sets the length of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 SetItemLength(position, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''length''' = (number) the new length &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemLength(0, 1000);&lt;br /&gt;
&lt;br /&gt;
=====InsertURL()=====&lt;br /&gt;
Inserts the specified asset in front of the asset at the specified position.  That and subsequent items are &amp;quot;pushed&amp;quot; to a higher position in the array.&lt;br /&gt;
&lt;br /&gt;
 InsertURL(position, url);&lt;br /&gt;
 InsertURL(position, url, title);&lt;br /&gt;
 InsertURL(position, url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position within the playlist before which to insert the asset&lt;br /&gt;
   '''url''' = (string) the URL of the asset to be inserted&lt;br /&gt;
   '''title''' = (string) title of the asset to be inserted&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be inserted&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====AppendURL()=====&lt;br /&gt;
The Playlist.AppendURL() method appends an asset URL to the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.AppendURL(url);&lt;br /&gt;
 Playlist.AppendURL(url, title);&lt;br /&gt;
 Playlist.AppendURL(url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) the URL to the asset to be appended&lt;br /&gt;
   '''title''' = (string) title of the asset to be appended&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be appended&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====Clear()=====&lt;br /&gt;
The Playlist.Clear() method will remove all assets from the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.Clear();&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful&lt;br /&gt;
&lt;br /&gt;
====Properties====&lt;br /&gt;
=====int numitems (read only)=====&lt;br /&gt;
The Playlist.numitems property contains the number of assets within the playlist.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Playlist Manager API ==&lt;br /&gt;
The Playlist Manager API provides methods to read and write playlists from permanent storage.&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bookmarks API ==&lt;br /&gt;
The Bookmarks API provides methods to manage bookmarks.&lt;br /&gt;
===Methods===&lt;br /&gt;
====Add()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean Add(url, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) The url of the asset to be bookmarked.&lt;br /&gt;
   '''title''' = (string) A suitable title to be used within the bookmark.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Bookmark.Add(&amp;quot;c:\myfavs\songstocodeby.mp3&amp;quot;, &lt;br /&gt;
     &amp;quot;Songs To Code By&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Podcasts API ==&lt;br /&gt;
The Podcasts API provides methods to manage Podcasts.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Subscribe()====&lt;br /&gt;
The Podcasts.Subscribe() method is used to add a channel to the list of podcast subscriptions, automatically subscribe to the podcast and begin downloading of the available episodes.  Once downloaded the episodes can be selected for playback.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Subscribe(url);&lt;br /&gt;
 where:&lt;br /&gt;
     '''url''' = (string) the Podcast URL to subscribe to.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PodCasts.Subscribe(&amp;lt;nowiki&amp;gt;&amp;quot;http://services.winamp.com/rss/news&amp;quot;&amp;lt;/nowiki&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Config API ==&lt;br /&gt;
The Config API provides a means by which properties can be saved.  Properties added using the Config API are persistent across Winamp launches.&lt;br /&gt;
&lt;br /&gt;
===Adding and Retrieving Properties===&lt;br /&gt;
Adding a property is accomplished by identifying a property and assigning it a value.  Once assigned, the value can be retrieved like any other objects properties.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 window.external.Config.myProperty = &amp;quot;Test&amp;quot;;&lt;br /&gt;
 var myProp = window.external.Config.myProperty;  // myProp is set to &amp;quot;Test&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===Storing and Retrieving advanced data types===&lt;br /&gt;
Internally, all properties are stored as strings.  If you need to store datatypes more advanced than String, Number, or Boolean, it is recommended that you create a JSON string out of your data type.&lt;br /&gt;
&lt;br /&gt;
== Security API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
The Security.GetActionAuthorization() method can be used to determine whether a user has previously allowed or denied the functioning of a particular API's methods.  Group strings match API names.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 number Security.GetActionAuthorization(group);&lt;br /&gt;
 where:&lt;br /&gt;
    group = (string) Name of API to check for permission.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Security.GetActionAuthorization(&amp;quot;Transport&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return Data:&lt;br /&gt;
*-1 = Either the user has not specified whether to allow/deny use of this API or the action usage is unrestricted. &lt;br /&gt;
*0  = The user has previously specified to deny use of this API/method.&lt;br /&gt;
*1  = The user has previously specified to allow use of this API/method.&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Transport – Access to the currently playing track, and play controls (play, stop, seek, etc)&lt;br /&gt;
&lt;br /&gt;
PlayQueue – Access to the play queue (Winamp Playlist)&lt;br /&gt;
&lt;br /&gt;
Application – general Winamp information – version #, language pack&lt;br /&gt;
&lt;br /&gt;
Playlists – access to the media library playlists&lt;br /&gt;
&lt;br /&gt;
Bookmarks – access to the user’s bookmarks (place to bookmark radio streams, etc)&lt;br /&gt;
&lt;br /&gt;
Skin – access to information about the user’s skin – colors, fonts, etc.&lt;br /&gt;
&lt;br /&gt;
MediaCore – access to media playback information, such as supported extensions&lt;br /&gt;
&lt;br /&gt;
Podcasts – access to the user’s media library podcasts&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== MediaCore API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
==== IsRegisteredExtension() ====&lt;br /&gt;
MediaCore.IsRegisteredExtension() method can be used to determine if the Winamp client is able to playback a specific format.  The file extension of the asset usually indicates the format.  This method is important since Winamp support for different formats is contained within plugins which may or may not exist for use.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean IsRegisteredExtension(ext);&lt;br /&gt;
 where:&lt;br /&gt;
   '''ext''' = (string) identifies the format to be queried for support in the form of a &lt;br /&gt;
       character string of the extension (a starting period is optional).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var canPlay = window.external.MediaCore.IsRegisteredExtension(&amp;quot;mp3&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
Boolean value indicating whether the format is supported.&lt;br /&gt;
&lt;br /&gt;
==== GetMetadata() ====&lt;br /&gt;
MediaCore.GetMetadata() method can be used to obtain metadata about an asset.  This method differs from Transport.GetMetadata() in that the asset does not have to be currently playing.  It differs from PlayQueue.GetMetadata() in that it doesn't have to be present in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(url, tag);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be retrieved.&lt;br /&gt;
    '''tag''' = (string) the specific piece of metadata to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var art = window.external.MediaCore.GetMetadata(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the metadata requested.&lt;br /&gt;
&lt;br /&gt;
==== AddMetadataHook() ====&lt;br /&gt;
MediaCore.AddMetadataHook() method can be used to add or override metadata for an asset.  For example, some assets such as those that are streamed may not contain metadata.  This method allows the online service to add metadata for the specified asset.  Subsequent GetMetadata() methods will return this information.  Online services can override the metadata present within an asset using this method.  This method can be used by services that define or can obtain their own metadata for the assets they provide rather than rely on what might or might not be present in the asset itself.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string AddMetadataHook(url, tag, value);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be added.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be added.&lt;br /&gt;
    '''value''' - (string) the value of the metadata key being added.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.AddMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;,&amp;quot;myself&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
==== RemoveMetadataHook() ====&lt;br /&gt;
MediaCore.RemoveMetadataHook() method can be used to remove metadata added through the AddMetadataHook() method.  Subsequent GetMetadata() requests will return whatever metadata was available previously, if any.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string RemoveMetadataHook(url, tag);&lt;br /&gt;
 string RemoveMetadataHook(url);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be removed.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be removed.&lt;br /&gt;
&lt;br /&gt;
If only the url parameter is provided, all metadata added with AddMetadataHook() for the specified url will be removed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.RemoveMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== History API ==&lt;br /&gt;
The History branch of the Media Library pane is actually a database containing information about previously played assets.  The History API allows a service to search and retrieve information from this database.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
==== Query() ====&lt;br /&gt;
Prototype:&lt;br /&gt;
 results = History.Query(queryString);&lt;br /&gt;
 where:&lt;br /&gt;
   '''queryString''' = a properly formed string to match data to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var results = window.external.History.Query(&amp;quot;LASTPLAYED&amp;lt;[now]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
An &amp;quot;array-like&amp;quot; object that contains the results of the query.&lt;br /&gt;
&lt;br /&gt;
Each entry of the array contains the following properties:&lt;br /&gt;
* String filename&lt;br /&gt;
* String title&lt;br /&gt;
* Number length&lt;br /&gt;
* Number playcount&lt;br /&gt;
* Date lastplay&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fields:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date and time when this asset was last played.&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of times the asset has been played. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Local Media API  (test)==&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The LocalMedia API allows a service to search the assets within the Local Media branch of the Media Library.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
Prototype:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
returns an array of objects that match the specified criteria of the query string.&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| TYPE&lt;br /&gt;
| 0 for audio files, 1 for video files&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| ARTIST&lt;br /&gt;
| Artist&lt;br /&gt;
|-&lt;br /&gt;
| ALBUM&lt;br /&gt;
| Album&lt;br /&gt;
|-&lt;br /&gt;
| ALBUMARTIST&lt;br /&gt;
| Album Artist&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| TRACKNO&lt;br /&gt;
| Track number of file&lt;br /&gt;
|-&lt;br /&gt;
| GENRE&lt;br /&gt;
| Genre&lt;br /&gt;
|-&lt;br /&gt;
| YEAR&lt;br /&gt;
| Year&lt;br /&gt;
|-&lt;br /&gt;
| COMMENT&lt;br /&gt;
| Comment&lt;br /&gt;
|-&lt;br /&gt;
| COMPOSER&lt;br /&gt;
| Composer&lt;br /&gt;
|-&lt;br /&gt;
| DISC&lt;br /&gt;
| Disc number of a CD set&lt;br /&gt;
|-&lt;br /&gt;
| FILESIZE&lt;br /&gt;
| File size, in kilobytes&lt;br /&gt;
|-&lt;br /&gt;
| FILETIME&lt;br /&gt;
| Last known file date/time on disk&lt;br /&gt;
|-&lt;br /&gt;
| FOLDER&lt;br /&gt;
| Containing folder&lt;br /&gt;
|-&lt;br /&gt;
| LASTUPD&lt;br /&gt;
| Date/time of file imported to library or modified in library&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date/time of last play&lt;br /&gt;
|-&lt;br /&gt;
| RATING&lt;br /&gt;
| Rating value (1-5, or 0 or empty for unrated)&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of plays&lt;br /&gt;
|-&lt;br /&gt;
| PUBLISHER&lt;br /&gt;
| Publisher or record label&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_ALBUM_GAIN&lt;br /&gt;
| ReplayGain Album Gain&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_TRACK_GAIN&lt;br /&gt;
| ReplayGain Track Gain&lt;br /&gt;
|-&lt;br /&gt;
| BITRATE&lt;br /&gt;
| Bitrate (in KBPS)&lt;br /&gt;
|-&lt;br /&gt;
| TRACKS&lt;br /&gt;
| Total number of tracks on the disc&lt;br /&gt;
|-&lt;br /&gt;
| DISCS&lt;br /&gt;
| Total number of discs in the set&lt;br /&gt;
|-&lt;br /&gt;
| ISPODCAST&lt;br /&gt;
| 1 for a podcast episode, 0 otherwise&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTCHANNEL&lt;br /&gt;
| The name of the channel for a podcast&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTPUBDATE&lt;br /&gt;
| Date/time when the podcast was published&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Field Names:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Comparison Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Application API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
====LaunchURL()====&lt;br /&gt;
The Application.LaunchURL() method launches a URL in the bento browser&lt;br /&gt;
or default browser.  The default browser is launched if force_external = true or in skins that don't define a browser.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean LaunchURL(url, force_external);&lt;br /&gt;
 where:&lt;br /&gt;
      '''url''' = (string) The url to open in the browser&lt;br /&gt;
      '''force_external''' = (boolean) will force the url to be displayed in a browser&lt;br /&gt;
           outside of the Winamp client.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &lt;br /&gt;
 var rc = LaunchURL(&amp;lt;nowiki&amp;gt;&amp;quot;http://www.winamp.com&amp;quot;&amp;lt;/nowiki&amp;gt;, true); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int version (read only)====   &lt;br /&gt;
The version property returns the version number of the browser control within the Winamp client as an integer, e.g. 555 for 5.55,  560 for 5.6&lt;br /&gt;
====string versionstring (read only)====&lt;br /&gt;
The versionstring property returns the version number of the browser control within the Winamp client as a string, e.g. &amp;quot;5.55&amp;quot; for 5.55&lt;br /&gt;
====string language (read only) ====&lt;br /&gt;
Language identifier from the currently installed language pack.  Follows ISO 639-1 two letter language codes&lt;br /&gt;
&lt;br /&gt;
====string languagepack (read only) ====&lt;br /&gt;
Language pack identifier from the currently installed language pack.  follows the form&lt;br /&gt;
lc-CC&lt;br /&gt;
where lc is the two letter ISO 639-1 language code&lt;br /&gt;
and CC is the two letter ISO 3166 country code.&lt;br /&gt;
&lt;br /&gt;
Note: do not count on the country code being the same as the user's current location.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Security API ==&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
  GetActionAuthorization(group, action);&lt;br /&gt;
  where:&lt;br /&gt;
      '''group''' = (string) a group of related methods, i.e. the API name.&lt;br /&gt;
      '''action''' = (string) a specific method within a group.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var auth = window.external.Security.GetActionAuthorization(&amp;quot;application&amp;quot;, &lt;br /&gt;
           &amp;quot;launchurl&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value: an integer representing the following results&lt;br /&gt;
&lt;br /&gt;
*ACTION_UNDEFINED = -1,&lt;br /&gt;
*ACTION_DISALLOWED = 0,&lt;br /&gt;
*ACTION_PROMPT = 1,&lt;br /&gt;
*ACTION_ALLOWED = 2,&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Skin API ==&lt;br /&gt;
&lt;br /&gt;
The skin color API is a bit of a challenge.  This API reflects some the idiosyncrasies of the underlying skinning system.  &amp;quot;Classic&amp;quot; skins define a palette of 24 colors for the skin and an additional 6 colors for the playlist editor.  &amp;quot;Modern&amp;quot; skins define these as well as any number of other colors retrievable by name (e.g. wasabi.tree.text for the text color on tree views).  A website relying on any of these extra &amp;quot;named&amp;quot; colors should be careful to implement a fallback color based on the classic palette, as no named colors exist in classic skins!&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetClassicColor()====&lt;br /&gt;
The Skin.GetClassicColor() method is used to retrieve color information regarding different Skin UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetClassicColor(classiccolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''classiccolornumber''' = (integer) A number in the range 0-23 identifying the Skin's UI element &lt;br /&gt;
         for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var wndBgColor = window.external.Skin.GetClassicColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Skin UI element.&lt;br /&gt;
&lt;br /&gt;
====Classic Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|  0 &lt;br /&gt;
| Item Background&lt;br /&gt;
|-&lt;br /&gt;
|  1 &lt;br /&gt;
| Item Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  2 &lt;br /&gt;
| Window Background&lt;br /&gt;
|-&lt;br /&gt;
|  3 &lt;br /&gt;
| Button Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  4 &lt;br /&gt;
| Window Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  5 &lt;br /&gt;
| Hilite&lt;br /&gt;
|-&lt;br /&gt;
|  6 &lt;br /&gt;
| Selection&lt;br /&gt;
|-&lt;br /&gt;
|  7 &lt;br /&gt;
| List Header Background&lt;br /&gt;
|-&lt;br /&gt;
|  8 &lt;br /&gt;
| List Header Text&lt;br /&gt;
|-&lt;br /&gt;
|  9 &lt;br /&gt;
| List Header Frame Top&lt;br /&gt;
|-&lt;br /&gt;
| 10 &lt;br /&gt;
| List Header Frame Middle&lt;br /&gt;
|-&lt;br /&gt;
| 11 &lt;br /&gt;
| List Header Frame Bottom&lt;br /&gt;
|-&lt;br /&gt;
| 12 &lt;br /&gt;
| List Header Empty Background&lt;br /&gt;
|-&lt;br /&gt;
| 13 &lt;br /&gt;
| Scrollbar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 14 &lt;br /&gt;
| Scrollbar Background&lt;br /&gt;
|-&lt;br /&gt;
| 15 &lt;br /&gt;
| Scrollbar Inverse Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 16 &lt;br /&gt;
| Scrollbar Inverse Background&lt;br /&gt;
|-&lt;br /&gt;
| 17 &lt;br /&gt;
| Scrollbar Dead Area&lt;br /&gt;
|-&lt;br /&gt;
| 18 &lt;br /&gt;
| Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 19 &lt;br /&gt;
| Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 20 &lt;br /&gt;
| Inactive Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 21 &lt;br /&gt;
| Inactive Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 22 &lt;br /&gt;
| Alternating Item Background&lt;br /&gt;
|-&lt;br /&gt;
| 23 &lt;br /&gt;
| Alternating Item Foreground&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetPlaylistColor()====&lt;br /&gt;
The Skin.GetPlaylistColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetPlaylistColor(playlistcolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''playlistcolornumber''' = (integer) a number in the range 0-5 identifying the Playlist's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var normalBgColor = window.external.Skin.GetPlaylistColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Playlist Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 &lt;br /&gt;
| Normal&lt;br /&gt;
|-&lt;br /&gt;
| 1 &lt;br /&gt;
| Current&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Normal Background&lt;br /&gt;
|-&lt;br /&gt;
| 3 &lt;br /&gt;
| Selected Background&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Video Window Status Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 5 &lt;br /&gt;
| Video Window Status Bar Background&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetSkinColor()====&lt;br /&gt;
The Skin.GetSkinColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetSkinColor(skincolorname);&lt;br /&gt;
  where:&lt;br /&gt;
    '''skincolorname''' = (string) identifying the Skin's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var buttonTextColor = window.external.Skin.GetSkinColor(&amp;quot;wasabi.button.text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Skin Color Names====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.item.selected.fg&amp;quot;&lt;br /&gt;
|Selected item text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.column.separator&amp;quot; &lt;br /&gt;
|Color of line between columns&lt;br /&gt;
|-&lt;br /&gt;
|'''Item Lists, Lists with playable items'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.current&amp;quot;  &lt;br /&gt;
|Currently playing outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.focus&amp;quot;  &lt;br /&gt;
|Focused item dashed outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.selborder&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|'''Message box'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.msgBox.background&amp;quot;   &lt;br /&gt;
|Messagebox background color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.text&amp;quot;  &lt;br /&gt;
|Text object &amp;amp; message box text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.background&amp;quot;   &lt;br /&gt;
|Text object &amp;amp; message box text background color&lt;br /&gt;
|-&lt;br /&gt;
|'''Buttons'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.text&amp;quot;  &lt;br /&gt;
|Buttons text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.hiliteText&amp;quot; &lt;br /&gt;
|Buttons hilite text color, used by tab windows&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.dimmedText&amp;quot;  &lt;br /&gt;
|Buttons dimmed text color, when disabled&lt;br /&gt;
|-&lt;br /&gt;
|'''Popup menus'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.text&amp;quot;  &lt;br /&gt;
|Menu items text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.hiliteText&amp;quot;  &lt;br /&gt;
|Hilited item text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.dimmedText&amp;quot;  &lt;br /&gt;
|Disabled item text color&lt;br /&gt;
|-&lt;br /&gt;
|'''Components'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.foreground&amp;quot;  &lt;br /&gt;
|Old title bar text color when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.border&amp;quot;  &lt;br /&gt;
|Old title bar text outline when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|'''Labeled Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.foreground&amp;quot;  &lt;br /&gt;
|Text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.background&amp;quot; &lt;br /&gt;
|Text drop shadow color&lt;br /&gt;
|-&lt;br /&gt;
|'''Edit Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.selection&amp;quot;  &lt;br /&gt;
|Selected text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.text&amp;quot; &lt;br /&gt;
|Text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.background&amp;quot;  &lt;br /&gt;
|Text background&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color.inverse&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====string name (test)====&lt;br /&gt;
The Skin.name property gives access to the name of skin currently in use.  Changing this value will change the skin displayed for the player.&lt;br /&gt;
&lt;br /&gt;
====string font (read only)====&lt;br /&gt;
The Skin.font property provides the font name currently used in the player.&lt;br /&gt;
&lt;br /&gt;
====string fontsize (read only)====&lt;br /&gt;
The Skin.fontsize property provides the size of the font currently used in the player.&lt;br /&gt;
&lt;br /&gt;
== Metadata tag names ==&lt;br /&gt;
&lt;br /&gt;
When retrieving metadata through Winamp, a freeform string is passed.  The popular file formats (MP3, WMA, FLAC, M4A) will respond uniformly to a common base of strings.  However, each file format is idiosyncratic in how metadata is stored.  Some file types will respond to additional strings which are not documented here.&lt;br /&gt;
&lt;br /&gt;
Remember that the metadata is only as good as the tagging in the file itself.  A poorly tagged track will return poor metadata.&lt;br /&gt;
&lt;br /&gt;
Common metadata tags&lt;br /&gt;
 bitrate&lt;br /&gt;
 length&lt;br /&gt;
 type&lt;br /&gt;
 title&lt;br /&gt;
 artist&lt;br /&gt;
 albumartist&lt;br /&gt;
 album&lt;br /&gt;
 genre&lt;br /&gt;
 year&lt;br /&gt;
 disc&lt;br /&gt;
 publisher&lt;br /&gt;
 comment&lt;br /&gt;
 track&lt;br /&gt;
 composer&lt;br /&gt;
 conductor&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework</id>
		<title>Complete JavaScript API technology framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework"/>
				<updated>2009-07-01T16:10:17Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Play() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
[[Category:Winamp]]&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
The purpose of the Winamp Online Service API is to allow Winamp Online Services to interact with the Winamp client in order to provide service developers with a way to create custom experiences for their users based on the power of Winamp.  The overall idea is to include exceptional web sites within Winamp Online Services.&lt;br /&gt;
&lt;br /&gt;
The Winamp Online Service API is made up of methods that can be called from scripts within web pages rendered by the Winamp client.  The API can be invoked using any scripting language supported by the Microsoft Internet Explorer web browser (5.5 and above).  For simplicity, examples in this document will use JavaScript.&lt;br /&gt;
&lt;br /&gt;
==Setup==&lt;br /&gt;
The Winamp Online Services API is designed to allow web pages, hosted (displayed) within the embedded browser of the Winamp client, to access the functionality of the client.  There are several steps necessary to allow this to take place.&lt;br /&gt;
&lt;br /&gt;
#Make sure you have the latest version of the Winamp client that supports online services.&lt;br /&gt;
#Make sure you have the latest version of the ml_webdev plugin (ml_webdev.dll).  The presence of this plugin will create a &amp;quot;Web Dev Test Platform&amp;quot; within the Medial Library pane.&lt;br /&gt;
#In order to change the starting web page for the online service, start the Winamp client and configure the plugin.  &lt;br /&gt;
##Select Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;Media Library.  &lt;br /&gt;
##Select &amp;quot;API 2 Test Platform&amp;quot; and press &amp;quot;Configure selected plugin&amp;quot;.  &lt;br /&gt;
##On the Web Dev Preferences dialog, set the URL field to the URL of the initial web page for the online service.  For example, &amp;lt;nowiki&amp;gt;file://c:\myonlineservice\webdev.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
#Click on &amp;quot;Web Dev Test Platform&amp;quot; in the Media Library.  You may have to right click and choose refresh to see the new web page.&lt;br /&gt;
&lt;br /&gt;
You should now see the initial page of your online service in the Winamp embedded browser.&lt;br /&gt;
&lt;br /&gt;
==window.external==&lt;br /&gt;
The Winamp JavaScript API can be accessed through the window.external object in the Document Object Model (DOM) exposed by the IE browser control embedded within the Winamp client.  The API methods can only be accessed thru the Winamp client and are not available if the web page is displayed outside of the client.&lt;br /&gt;
&lt;br /&gt;
The invocation of all methods follow this form&lt;br /&gt;
 window.external.'''''API'''''.'''''Method'''''&lt;br /&gt;
&lt;br /&gt;
Properties can also be accessed using a similar form:&lt;br /&gt;
 window.external.'''''API'''''.'''''Property'''''&lt;br /&gt;
&lt;br /&gt;
Where ''API'' is a singleton class that defines a group of related methods (i.e., functionality).  For example, Transport (Stop, Play, Next, etc) which controls the &amp;quot;buttons&amp;quot; of the Winamp player. &lt;br /&gt;
&lt;br /&gt;
''Method'' is a function you can call as part of a particular API.  For example the following call will stop the Winamp client:&lt;br /&gt;
 window.external.Transport.Stop();&lt;br /&gt;
&lt;br /&gt;
''Property'' is an internal variable for the particular API that can be queried and in some cases set.  For example the following will provide access to the Winamp client shuffle &amp;quot;button&amp;quot;:&lt;br /&gt;
 var shuffle = window.external.Transport.shuffle;  // gets the current state&lt;br /&gt;
     OR&lt;br /&gt;
 window.external.Transport.shuffle = true;         // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
See the documentation on each API below for a complete list of methods and properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == Security Warnings ==&lt;br /&gt;
Using the Winamp JavaScript API, an online service web page has access to much more information (read: power) than a normal web page.  For example, playlists can be enumerated, and metadata for songs can be retrieved.  In order to control these capabilities a security system was implemented so that users are informed whenever an online service first attempts to use an API method or access a property.  For example, when an online service attempts to stop playback for the very first time, the user will be notified and asked whether the service should be allowed to do this.&lt;br /&gt;
&lt;br /&gt;
Note that this security model maintains user choices based on service ID so that the user will be prompted each time a service tries to invoke methods or access properties.  In addition, online services updated through the Winamp Online Service submission process, receive new service IDs, causing the users to be prompted again.&lt;br /&gt;
&lt;br /&gt;
A dialog is presented to the user that describes the action about to be performed and forces the user to choose whether the action should be Allowed or Denied.  A third button let's a user to indicate &amp;quot;Always Allow&amp;quot;.  If the user selects this button, the API will no longer prompt the user for this action (for this particular online service).  &lt;br /&gt;
&lt;br /&gt;
Be aware that choices for certain APIs will affect the entire API and all of its methods and properties.  For example, choosing &amp;quot;Always Allow&amp;quot; for Transport.Stop() will also always allow access to the other Tranport methods/properties.  Certain other APIs, such as the Application API affect only the action being attempted.  Some API methods and properties are considered inconsequential and not governed by this security model at all.  The scope of the user's choice will be described within the dialog.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transport API ==&lt;br /&gt;
The Transport API is used to control the Winamp client.  &amp;quot;Transport controls&amp;quot; was the name given to the buttons on the front panel that controlled hardware devices.  This name is used in Winamp for the same purpose.  It is also used to access information about the currently playing song.&lt;br /&gt;
&lt;br /&gt;
The Transport API can also be used to register for events involved with asset playback.  See the section [[#Transport Events API|Transport Events API]].&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Prev()====&lt;br /&gt;
Transport.Prev() can be used to press the &amp;quot;Previous Track&amp;quot; button on the Winamp player.  Invoking Prev() while an asset is already playing will cause the previous asset to begin playback immediately.  Invoking Prev() while the player is stopped will cause the previous asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Prev();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Prev();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Play()====&lt;br /&gt;
Transport.Play() can be used to press the &amp;quot;Play&amp;quot; button on the Winamp player.  Invoking Play() on an asset already playing will cause the asset to restart playback.  Pressing Play() on a paused asset will cause it to begin playing from its current position.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Play();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Pause()====&lt;br /&gt;
Transport.Pause() can be used to press the &amp;quot;Pause&amp;quot; button on the Winamp player.  Issuing Pause() again, or Play() will cause the asset to continue to play from the location where it was paused.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Pause();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Pause();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Stop()====&lt;br /&gt;
Transport.Stop() can be used to press the &amp;quot;Stop&amp;quot; button on the Winamp player.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Stop();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Stop();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
====Next()====&lt;br /&gt;
Transport.Next() can be used to press the &amp;quot;Next Track&amp;quot; button on the Winamp player.  Invoking Next() while the player is stopped will cause the next asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Next();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Next();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
Transport.GetMetadata() can be used to fetch metadata for the currently playing asset.  The &amp;quot;tag&amp;quot; parameter is specific to different asset encoding formats so a knowledge of the metadata field names is necessary to request specific data about an asset.  Some field names are common but others are specific to the encoding format of the asset.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(tag);&lt;br /&gt;
 where:&lt;br /&gt;
      '''tag''' = (string) identifier for the metadata to be returned.&lt;br /&gt;
Example:&lt;br /&gt;
 var metaStr = window.external.Transport.GetMetadata(&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A string value containing the requested metadata.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====bool shuffle====&lt;br /&gt;
Transport.shuffle provides access to the Winamp client shuffle &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isShuffling = window.external.Transport.shuffle; // get shuffle state&lt;br /&gt;
  window.external.Transport.shuffle = true;            // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
====bool repeat====&lt;br /&gt;
Transport.repeat provides access to the Winamp client repeat &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isRepeating = window.external.Transport.repeat; // get repeat state&lt;br /&gt;
  window.external.Transport.repeat = false;           // turns off repeat&lt;br /&gt;
&lt;br /&gt;
====int position====&lt;br /&gt;
Transport.position provides access to the position being played within the current asset.  Setting this value can change the location where playback occurs. position is in milliseconds.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var position = window.external.Transport.position; // get position in current track&lt;br /&gt;
  window.external.Transport.position = 221559;       // move playback of the current track &lt;br /&gt;
                                                     // to the specified position.&lt;br /&gt;
&lt;br /&gt;
====bool playing (read only) ====&lt;br /&gt;
Transport.playing indicates whether the Winamp Player is currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPlaying = window.external.Transport.playing; // is player playing?&lt;br /&gt;
&lt;br /&gt;
====bool paused (read only) ====&lt;br /&gt;
Transport.paused indicates whether the Winamp Player has been paused.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPaused = window.external.Transport.paused; // is player paused?&lt;br /&gt;
&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
Transport.length provides access to the length in seconds of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var length = window.external.Transport.length; // get length of current track in secs&lt;br /&gt;
&lt;br /&gt;
====string url (read only)====&lt;br /&gt;
Transport.url provides access to the URL (or filename) of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var url = window.external.Transport.url; // get url of current track&lt;br /&gt;
&lt;br /&gt;
====string title (read only)====&lt;br /&gt;
Transport.title provides access to the title of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var title = window.external.Transport.title; // get title of current track&lt;br /&gt;
&lt;br /&gt;
==Transport Events API==&lt;br /&gt;
The Event mechanism of the Transport API allows javascript programmers to specify a callback method that will be invoked whenever certain Transport events take place.  An Event object is passed back to the method from which properties can be accessed that provide more information about the event.&lt;br /&gt;
&lt;br /&gt;
===RegisterForEvents()===&lt;br /&gt;
The RegisterForEvents() method can be used to specify a JavaScript function that is to be called when any Transport Events occur.  An event object is passed that indicates the type of event.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean RegisterForEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.RegisterForEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===UnregisterFromEvents()===&lt;br /&gt;
The UnregisterFromEvents() method is used to stop receiving notifications about Transport events.&lt;br /&gt;
&lt;br /&gt;
Note:  The original handler used in RegisterForEvents() must be passed back into UnregisterFromEvents().&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean UnregisterFromEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.UnregisterFromEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Events===&lt;br /&gt;
The Transport API Event mechanism requires a JavaScript callback method that accepts a single parameter, a reference to a function.  This function will be invoked with an &amp;quot;event&amp;quot; object that will indicate the type of event that occurred as well as contain properties containing more information about the event.&lt;br /&gt;
&lt;br /&gt;
====OnStop====&lt;br /&gt;
The OnStop event is triggered when the Winamp client is stopped.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
integer event.position = contains the position within the file where the &amp;quot;Stop&amp;quot; was issued.  position is the number of milliseconds from the start of the asset.&lt;br /&gt;
&lt;br /&gt;
====OnPlay====&lt;br /&gt;
The OnPlay event is triggered when the Winamp client begins playback.  If the client is paused and then restarted by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
string event.filename = contains the filename/URL of the asset starting playback.&lt;br /&gt;
&lt;br /&gt;
====OnPause====&lt;br /&gt;
The OnPause event is triggered when the Winamp client is paused or unpaused.  If the client is started after being paused, by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
boolean event.paused = true (the player was paused), false (the player was unpaused)&lt;br /&gt;
&lt;br /&gt;
====OnEndOfFile====&lt;br /&gt;
The OnEndOfFile event is triggered when the player reaches the end of a track.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
===Callback function===&lt;br /&gt;
The callback function is invoked whenever a Transport event is detected.  The callback function is specified in both the RegisterForEvents() and UnregisterFromEvents() methods.  The method takes a single parameter, which is loaded with an object identifying the event that occurred.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 function EventHandler(event){&lt;br /&gt;
 {&lt;br /&gt;
     if (event.event == &amp;quot;OnStop&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnStop: position=&amp;quot; + event.position);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnEndOfFile&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnEndOfFile&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPause&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPause: paused=&amp;quot; + event.paused);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPlay&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPlay: filename=&amp;quot; + event.filename);&lt;br /&gt;
     }&lt;br /&gt;
     else {&lt;br /&gt;
       alert(&amp;quot;Unrecognized Event received&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== PlayQueue API ==&lt;br /&gt;
Provides access to the play queue (&amp;quot;Winamp Playlist&amp;quot;).  If you need access to the currently playing song, use the Transport API instead.&lt;br /&gt;
&lt;br /&gt;
Note that the Play Queue is the list of assets that are scheduled to be played by the Winamp client.  This is not necessarily the same as a user playlist.  Once placed in the play queue, assets can be rearrainged or deleted from the play queue without affecting a user playlist.  Individual assets can be placed in the play queue without being contained within a user playlist.  Additionally, after adding a playlist to the play queue, changes to the playlist will not affect the assets in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Play()====&lt;br /&gt;
The PlayQueue.Play() method stops playback, clears the play queue, enqueues the asset specified by the URL and starts playback.  If the URL cannot be found, playback will stop, the play queue will be cleared, the URL (or title and length) will appear in the queue but playback will not be started. &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play(URL);&lt;br /&gt;
 bool Play(URL, title);&lt;br /&gt;
 bool Play(URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Play(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Enqueue()====&lt;br /&gt;
PlayQueue.Enqueue() is used to add an asset to the play queue.  The selected asset is added to the bottom of the queue and current playback is not interrupted.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Enqueue(URL);&lt;br /&gt;
 bool Enqueue(URL, title);&lt;br /&gt;
 bool Enqueue(URL, title, length);&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.extern.PlayQueue.Enqueue(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Insert()====&lt;br /&gt;
The PlayQueue.Insert() method can add an asset to the play queue at a specific index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Insert(position, URL);&lt;br /&gt;
 bool Insert(position, URL, title);&lt;br /&gt;
 bool Insert(position, URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
      '''position''' = (integer) a zero based number indicating the location within&lt;br /&gt;
           the play queue to insert the new asset.&lt;br /&gt;
           Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
                 queue is at position 0.&lt;br /&gt;
      '''url''' = (string) the URL of the asset to be added&lt;br /&gt;
      '''title''' = (string) the title to be displayed in the Play Queue.&lt;br /&gt;
      '''length''' = (integer) the length of the asset to be displayed in &lt;br /&gt;
           the play queue.&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Insert(1, &amp;quot;c:\\mySongs\\mySong.mp3&amp;quot;,300);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====ClearQueue()====&lt;br /&gt;
The PlayQueue.ClearQueue() method removes all assets from the play queue.  This does not stop the current playback.  ClearQueue is commonly used to prepare the Play Queue for the addition of new assets.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool ClearQueue()&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.ClearQueue();&lt;br /&gt;
&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
PlayQueue.GetMetadata() can be used to obtain asset metadata about an asset in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetMetadata(position, metadatatag);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position 0.&lt;br /&gt;
   '''metadatatag''' - (string) is a tag describing which metadata is requested.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var mdata = window.external.PlayQueue.GetMetadata(2,&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A String that contains the metadata requested for the asset located at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetTitle()====&lt;br /&gt;
PlayQueue.GetTitle() retrieves the title of the asset at the specified position within the play queue.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var title = window.external.PlayQueue.GetTitle(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the Title of the asset at the requested position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetURL()====&lt;br /&gt;
PlayQueue.GetURL() is used to obtain the URL from the asset at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetURL(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var url = window.external.PlayQueue.GetURL(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the URL of the asset at the rquested position in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
PlayQueue.length contains the length of the current play queue&lt;br /&gt;
&lt;br /&gt;
====int cursor====&lt;br /&gt;
PlayQueue.cursor provides access to the position of the currently playing asset within the play queue.  This cursor is 0 based, meaning that the first asset in the Play Queue has a cursor value of 0.  Valid values range from 0 to the length of the play queue minus one.&lt;br /&gt;
&lt;br /&gt;
If this value is changed before playback is started, the next asset to play will be the one assigned to this property.  However, if a song is already playing and this property is changed, the current asset will continue to play even though this property has been updated.  At the point that the current asset playback completes, the player will increment the cursor position and play the next asset in the queue rather than the one to which cursor was set.  So, for example, to specify the next asset to play while an asset is currently playing, set the cursor property to the position of the asset to play minus one.&lt;br /&gt;
&lt;br /&gt;
== Playlists API == &lt;br /&gt;
The Playlists API is used to process user playlists.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetPlaylists()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Array GetPlaylists();&lt;br /&gt;
Example:&lt;br /&gt;
 var playlists = window.external.Playlists.GetPlaylists();&lt;br /&gt;
Return Value:&lt;br /&gt;
A array-like object that can be used to examine all user playlists.&lt;br /&gt;
&lt;br /&gt;
Each element of the array represents a user playlist and contains the following properties&lt;br /&gt;
*filename - filename of the playlist&lt;br /&gt;
*title - name of the playlist&lt;br /&gt;
*playlistId - a unique identifier for the playlist, so you can retrieve it later.  Also used with OpenPlaylist/SavePlaylist&lt;br /&gt;
*length - total length (time) in seconds.  Cached data - not guaranteed to be accurate&lt;br /&gt;
*numitems - number of items in the playlist.  Cached data - not guaranteed to be accurate&lt;br /&gt;
&lt;br /&gt;
====OpenPlaylist()====&lt;br /&gt;
Playlists.OpenPlaylist() returns a Playlist object for the specified playlist ID.  You must use &lt;br /&gt;
Playlists.GetPlaylists() before issuing this request.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Playlist OpenPlaylist(playlistId);&lt;br /&gt;
 where:&lt;br /&gt;
   '''playlistId''' - (string) the Id of the playlist to be opened.&lt;br /&gt;
Example:&lt;br /&gt;
 var playlist1 = window.external.Playlists.OpenPlaylist(playlistId);&lt;br /&gt;
Return Value:&lt;br /&gt;
The Playlist object with the specified playistId.&lt;br /&gt;
&lt;br /&gt;
====SavePlaylist()====&lt;br /&gt;
Playlists.SavePlaylist() saves the specified playlist object with the specified ID.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool SavePlaylist(playlistId, playlist_to_save);&lt;br /&gt;
 where:&lt;br /&gt;
    '''playlistId''' (string) is the id of the playlist to be saved.&lt;br /&gt;
    '''playlist_to_save''' (Playlist) is the Playlist object to be saved.&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Playlists.SavePlaylist(playlistId, pl);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Playlist Object ===&lt;br /&gt;
Playlist objects can be created/returned by the OpenPlaylist() method as well as various other APIs.&lt;br /&gt;
&lt;br /&gt;
====Methods====&lt;br /&gt;
=====GetItemFilename()=====&lt;br /&gt;
The GetItemFilename() method retrieves the filename/URL of the item at the specified index into the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemFilename(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the filename&lt;br /&gt;
                   should be returned.  &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var filename = playlst.GetItemFilename(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the filename/URL of a particular item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemTitle()=====&lt;br /&gt;
The GetItemTitle() method returns the title of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the title&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var title = playlst.GetItemTitle(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The song title of the given item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemLength()=====&lt;br /&gt;
The GetItemLength() method retrieves the play length of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
 Number GetItemLength(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the length&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var itemLength = playlst.GetItemLength(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A number specifying the play length of the asset, in milliseconds.&lt;br /&gt;
&lt;br /&gt;
=====Reverse()=====&lt;br /&gt;
The Reverse() method reverses the order of the assets within a playlist, i.e., the first becomes last and the second becomes second to last, etc.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Reverse();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Reverse();&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=====Swap()=====&lt;br /&gt;
The Swap() method exchanges the assets at the two specified positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Swap(Number position1, Number position2)&lt;br /&gt;
 where: &lt;br /&gt;
   '''position1''' = (number) the index of the first item to be swapped.&lt;br /&gt;
   '''position2''' = (number) the index of the second item to be swapped.&lt;br /&gt;
   Note: position1 and position2 are &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Swap(0,1);&lt;br /&gt;
&lt;br /&gt;
=====Randomize()=====&lt;br /&gt;
The Randomize() method re-arranges the order of the playlist, placing the assets in random positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Randomize();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Randomize();&lt;br /&gt;
&lt;br /&gt;
=====Remove()=====&lt;br /&gt;
The Remove() method removes an asset from the playlist.  Subsequent assets are moved to lower number positions in the array.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Remove(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) the position of the asset to be removed.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Remove(0);&lt;br /&gt;
&lt;br /&gt;
=====SortByTitle()=====&lt;br /&gt;
The SortByTitle() method re-arrainges the order of the playlist so that it is alphabetical order by title.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByTitle();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByTitle();&lt;br /&gt;
&lt;br /&gt;
=====SortByFilename()=====&lt;br /&gt;
The SortByFilename() method re-arrainges the order of the playlist so that it is alphabetical order by filename.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByFilename();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByFilename();&lt;br /&gt;
&lt;br /&gt;
=====SetItemFilename()=====&lt;br /&gt;
Sets the filename of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 playlistObj.SetItemFilename(position, filename);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''filename''' = (string) the new filename &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetFilename(0, &amp;quot;c:\\\\myfavorites\\myfavsong.mp3&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemTitle()=====&lt;br /&gt;
Sets the title of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SetItemTitle(position, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''title''' = (string) the new title &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemTitle(0, &amp;quot;My Favorite Title&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemLength()=====&lt;br /&gt;
Sets the length of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 SetItemLength(position, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''length''' = (number) the new length &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemLength(0, 1000);&lt;br /&gt;
&lt;br /&gt;
=====InsertURL()=====&lt;br /&gt;
Inserts the specified asset in front of the asset at the specified position.  That and subsequent items are &amp;quot;pushed&amp;quot; to a higher position in the array.&lt;br /&gt;
&lt;br /&gt;
 InsertURL(position, url);&lt;br /&gt;
 InsertURL(position, url, title);&lt;br /&gt;
 InsertURL(position, url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position within the playlist before which to insert the asset&lt;br /&gt;
   '''url''' = (string) the URL of the asset to be inserted&lt;br /&gt;
   '''title''' = (string) title of the asset to be inserted&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be inserted&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====AppendURL()=====&lt;br /&gt;
The Playlist.AppendURL() method appends an asset URL to the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.AppendURL(url);&lt;br /&gt;
 Playlist.AppendURL(url, title);&lt;br /&gt;
 Playlist.AppendURL(url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) the URL to the asset to be appended&lt;br /&gt;
   '''title''' = (string) title of the asset to be appended&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be appended&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====Clear()=====&lt;br /&gt;
The Playlist.Clear() method will remove all assets from the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.Clear();&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful&lt;br /&gt;
&lt;br /&gt;
====Properties====&lt;br /&gt;
=====int numitems (read only)=====&lt;br /&gt;
The Playlist.numitems property contains the number of assets within the playlist.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Playlist Manager API ==&lt;br /&gt;
The Playlist Manager API provides methods to read and write playlists from permanent storage.&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bookmarks API ==&lt;br /&gt;
The Bookmarks API provides methods to manage bookmarks.&lt;br /&gt;
===Methods===&lt;br /&gt;
====Add()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean Add(url, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) The url of the asset to be bookmarked.&lt;br /&gt;
   '''title''' = (string) A suitable title to be used within the bookmark.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Bookmark.Add(&amp;quot;c:\myfavs\songstocodeby.mp3&amp;quot;, &lt;br /&gt;
     &amp;quot;Songs To Code By&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Podcasts API ==&lt;br /&gt;
The Podcasts API provides methods to manage Podcasts.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Subscribe()====&lt;br /&gt;
The Podcasts.Subscribe() method is used to add a channel to the list of podcast subscriptions, automatically subscribe to the podcast and begin downloading of the available episodes.  Once downloaded the episodes can be selected for playback.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Subscribe(url);&lt;br /&gt;
 where:&lt;br /&gt;
     '''url''' = (string) the Podcast URL to subscribe to.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PodCasts.Subscribe(&amp;lt;nowiki&amp;gt;&amp;quot;http://services.winamp.com/rss/news&amp;quot;&amp;lt;/nowiki&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Config API ==&lt;br /&gt;
The Config API provides a means by which properties can be saved.  Properties added using the Config API are persistent across Winamp launches.&lt;br /&gt;
&lt;br /&gt;
===Adding and Retrieving Properties===&lt;br /&gt;
Adding a property is accomplished by identifying a property and assigning it a value.  Once assigned, the value can be retrieved like any other objects properties.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 window.external.Config.myProperty = &amp;quot;Test&amp;quot;;&lt;br /&gt;
 var myProp = window.external.Config.myProperty;  // myProp is set to &amp;quot;Test&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===Storing and Retrieving advanced data types===&lt;br /&gt;
Internally, all properties are stored as strings.  If you need to store datatypes more advanced than String, Number, or Boolean, it is recommended that you create a JSON string out of your data type.&lt;br /&gt;
&lt;br /&gt;
== Security API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
The Security.GetActionAuthorization() method can be used to determine whether a user has previously allowed or denied the functioning of a particular API's methods.  Group strings match API names.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 number Security.GetActionAuthorization(group);&lt;br /&gt;
 where:&lt;br /&gt;
    group = (string) Name of API to check for permission.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Security.GetActionAuthorization(&amp;quot;Transport&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return Data:&lt;br /&gt;
*-1 = Either the user has not specified whether to allow/deny use of this API or the action usage is unrestricted. &lt;br /&gt;
*0  = The user has previously specified to deny use of this API/method.&lt;br /&gt;
*1  = The user has previously specified to allow use of this API/method.&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Transport – Access to the currently playing track, and play controls (play, stop, seek, etc)&lt;br /&gt;
&lt;br /&gt;
PlayQueue – Access to the play queue (Winamp Playlist)&lt;br /&gt;
&lt;br /&gt;
Application – general Winamp information – version #, language pack&lt;br /&gt;
&lt;br /&gt;
Playlists – access to the media library playlists&lt;br /&gt;
&lt;br /&gt;
Bookmarks – access to the user’s bookmarks (place to bookmark radio streams, etc)&lt;br /&gt;
&lt;br /&gt;
Skin – access to information about the user’s skin – colors, fonts, etc.&lt;br /&gt;
&lt;br /&gt;
MediaCore – access to media playback information, such as supported extensions&lt;br /&gt;
&lt;br /&gt;
Podcasts – access to the user’s media library podcasts&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== MediaCore API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
==== IsRegisteredExtension() ====&lt;br /&gt;
MediaCore.IsRegisteredExtension() method can be used to determine if the Winamp client is able to playback a specific format.  The file extension of the asset usually indicates the format.  This method is important since Winamp support for different formats is contained within plugins which may or may not exist for use.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean IsRegisteredExtension(ext);&lt;br /&gt;
 where:&lt;br /&gt;
   '''ext''' = (string) identifies the format to be queried for support in the form of a &lt;br /&gt;
       character string of the extension (a starting period is optional).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var canPlay = window.external.MediaCore.IsRegisteredExtension(&amp;quot;mp3&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
Boolean value indicating whether the format is supported.&lt;br /&gt;
&lt;br /&gt;
==== GetMetadata() ====&lt;br /&gt;
MediaCore.GetMetadata() method can be used to obtain metadata about an asset.  This method differs from Transport.GetMetadata() in that the asset does not have to be currently playing.  It differs from PlayQueue.GetMetadata() in that it doesn't have to be present in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(url, tag);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be retrieved.&lt;br /&gt;
    '''tag''' = (string) the specific piece of metadata to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var art = window.external.MediaCore.GetMetadata(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the metadata requested.&lt;br /&gt;
&lt;br /&gt;
==== AddMetadataHook() ====&lt;br /&gt;
MediaCore.AddMetadataHook() method can be used to add or override metadata for an asset.  For example, some assets such as those that are streamed may not contain metadata.  This method allows the online service to add metadata for the specified asset.  Subsequent GetMetadata() methods will return this information.  Online services can override the metadata present within an asset using this method.  This method can be used by services that define or can obtain their own metadata for the assets they provide rather than rely on what might or might not be present in the asset itself.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string AddMetadataHook(url, tag, value);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be added.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be added.&lt;br /&gt;
    '''value''' - (string) the value of the metadata key being added.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.AddMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;,&amp;quot;myself&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
==== RemoveMetadataHook() ====&lt;br /&gt;
MediaCore.RemoveMetadataHook() method can be used to remove metadata added through the AddMetadataHook() method.  Subsequent GetMetadata() requests will return whatever metadata was available previously, if any.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string RemoveMetadataHook(url, tag);&lt;br /&gt;
 string RemoveMetadataHook(url);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be removed.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be removed.&lt;br /&gt;
&lt;br /&gt;
If only the url parameter is provided, all metadata added with AddMetadataHook() for the specified url will be removed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.RemoveMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== History API ==&lt;br /&gt;
The History branch of the Media Library pane is actually a database containing information about previously played assets.  The History API allows a service to search and retrieve information from this database.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
==== Query() ====&lt;br /&gt;
Prototype:&lt;br /&gt;
 results = History.Query(queryString);&lt;br /&gt;
 where:&lt;br /&gt;
   '''queryString''' = a properly formed string to match data to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var results = window.external.History.Query(&amp;quot;LASTPLAYED&amp;lt;[now]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
An &amp;quot;array-like&amp;quot; object that contains the results of the query.&lt;br /&gt;
&lt;br /&gt;
Each entry of the array contains the following properties:&lt;br /&gt;
* String filename&lt;br /&gt;
* String title&lt;br /&gt;
* Number length&lt;br /&gt;
* Number playcount&lt;br /&gt;
* Date lastplay&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fields:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date and time when this asset was last played.&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of times the asset has been played. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Local Media API  (test)==&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The LocalMedia API allows a service to search the assets within the Local Media branch of the Media Library.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
Prototype:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
returns an array of objects that match the specified criteria of the query string.&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| TYPE&lt;br /&gt;
| 0 for audio files, 1 for video files&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| ARTIST&lt;br /&gt;
| Artist&lt;br /&gt;
|-&lt;br /&gt;
| ALBUM&lt;br /&gt;
| Album&lt;br /&gt;
|-&lt;br /&gt;
| ALBUMARTIST&lt;br /&gt;
| Album Artist&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| TRACKNO&lt;br /&gt;
| Track number of file&lt;br /&gt;
|-&lt;br /&gt;
| GENRE&lt;br /&gt;
| Genre&lt;br /&gt;
|-&lt;br /&gt;
| YEAR&lt;br /&gt;
| Year&lt;br /&gt;
|-&lt;br /&gt;
| COMMENT&lt;br /&gt;
| Comment&lt;br /&gt;
|-&lt;br /&gt;
| COMPOSER&lt;br /&gt;
| Composer&lt;br /&gt;
|-&lt;br /&gt;
| DISC&lt;br /&gt;
| Disc number of a CD set&lt;br /&gt;
|-&lt;br /&gt;
| FILESIZE&lt;br /&gt;
| File size, in kilobytes&lt;br /&gt;
|-&lt;br /&gt;
| FILETIME&lt;br /&gt;
| Last known file date/time on disk&lt;br /&gt;
|-&lt;br /&gt;
| FOLDER&lt;br /&gt;
| Containing folder&lt;br /&gt;
|-&lt;br /&gt;
| LASTUPD&lt;br /&gt;
| Date/time of file imported to library or modified in library&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date/time of last play&lt;br /&gt;
|-&lt;br /&gt;
| RATING&lt;br /&gt;
| Rating value (1-5, or 0 or empty for unrated)&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of plays&lt;br /&gt;
|-&lt;br /&gt;
| PUBLISHER&lt;br /&gt;
| Publisher or record label&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_ALBUM_GAIN&lt;br /&gt;
| ReplayGain Album Gain&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_TRACK_GAIN&lt;br /&gt;
| ReplayGain Track Gain&lt;br /&gt;
|-&lt;br /&gt;
| BITRATE&lt;br /&gt;
| Bitrate (in KBPS)&lt;br /&gt;
|-&lt;br /&gt;
| TRACKS&lt;br /&gt;
| Total number of tracks on the disc&lt;br /&gt;
|-&lt;br /&gt;
| DISCS&lt;br /&gt;
| Total number of discs in the set&lt;br /&gt;
|-&lt;br /&gt;
| ISPODCAST&lt;br /&gt;
| 1 for a podcast episode, 0 otherwise&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTCHANNEL&lt;br /&gt;
| The name of the channel for a podcast&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTPUBDATE&lt;br /&gt;
| Date/time when the podcast was published&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Field Names:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Comparison Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Application API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
====LaunchURL()====&lt;br /&gt;
The Application.LaunchURL() method launches a URL in the bento browser&lt;br /&gt;
or default browser.  The default browser is launched if force_external = true or in skins that don't define a browser.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean LaunchURL(url, force_external);&lt;br /&gt;
 where:&lt;br /&gt;
      '''url''' = (string) The url to open in the browser&lt;br /&gt;
      '''force_external''' = (boolean) will force the url to be displayed in a browser&lt;br /&gt;
           outside of the Winamp client.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &lt;br /&gt;
 var rc = LaunchURL(&amp;lt;nowiki&amp;gt;&amp;quot;http://www.winamp.com&amp;quot;&amp;lt;/nowiki&amp;gt;, true); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int version (read only)====   &lt;br /&gt;
The version property returns the version number of the browser control within the Winamp client as an integer, e.g. 555 for 5.55,  560 for 5.6&lt;br /&gt;
====string versionstring (read only)====&lt;br /&gt;
The versionstring property returns the version number of the browser control within the Winamp client as a string, e.g. &amp;quot;5.55&amp;quot; for 5.55&lt;br /&gt;
====string language (read only) ====&lt;br /&gt;
Language identifier from the currently installed language pack.  Follows ISO 639-1 two letter language codes&lt;br /&gt;
&lt;br /&gt;
====string languagepack (read only) ====&lt;br /&gt;
Language pack identifier from the currently installed language pack.  follows the form&lt;br /&gt;
lc-CC&lt;br /&gt;
where lc is the two letter ISO 639-1 language code&lt;br /&gt;
and CC is the two letter ISO 3166 country code.&lt;br /&gt;
&lt;br /&gt;
Note: do not count on the country code being the same as the user's current location.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Security API ==&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
  GetActionAuthorization(group, action);&lt;br /&gt;
  where:&lt;br /&gt;
      '''group''' = (string) a group of related methods, i.e. the API name.&lt;br /&gt;
      '''action''' = (string) a specific method within a group.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var auth = window.external.Security.GetActionAuthorization(&amp;quot;application&amp;quot;, &lt;br /&gt;
           &amp;quot;launchurl&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value: an integer representing the following results&lt;br /&gt;
&lt;br /&gt;
*ACTION_UNDEFINED = -1,&lt;br /&gt;
*ACTION_DISALLOWED = 0,&lt;br /&gt;
*ACTION_PROMPT = 1,&lt;br /&gt;
*ACTION_ALLOWED = 2,&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Skin API ==&lt;br /&gt;
&lt;br /&gt;
The skin color API is a bit of a challenge.  This API reflects some the idiosyncrasies of the underlying skinning system.  &amp;quot;Classic&amp;quot; skins define a palette of 24 colors for the skin and an additional 6 colors for the playlist editor.  &amp;quot;Modern&amp;quot; skins define these as well as any number of other colors retrievable by name (e.g. wasabi.tree.text for the text color on tree views).  A website relying on any of these extra &amp;quot;named&amp;quot; colors should be careful to implement a fallback color based on the classic palette, as no named colors exist in classic skins!&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetClassicColor()====&lt;br /&gt;
The Skin.GetClassicColor() method is used to retrieve color information regarding different Skin UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetClassicColor(classiccolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''classiccolornumber''' = (integer) A number in the range 0-23 identifying the Skin's UI element &lt;br /&gt;
         for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var wndBgColor = window.external.Skin.GetClassicColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Skin UI element.&lt;br /&gt;
&lt;br /&gt;
====Classic Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|  0 &lt;br /&gt;
| Item Background&lt;br /&gt;
|-&lt;br /&gt;
|  1 &lt;br /&gt;
| Item Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  2 &lt;br /&gt;
| Window Background&lt;br /&gt;
|-&lt;br /&gt;
|  3 &lt;br /&gt;
| Button Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  4 &lt;br /&gt;
| Window Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  5 &lt;br /&gt;
| Hilite&lt;br /&gt;
|-&lt;br /&gt;
|  6 &lt;br /&gt;
| Selection&lt;br /&gt;
|-&lt;br /&gt;
|  7 &lt;br /&gt;
| List Header Background&lt;br /&gt;
|-&lt;br /&gt;
|  8 &lt;br /&gt;
| List Header Text&lt;br /&gt;
|-&lt;br /&gt;
|  9 &lt;br /&gt;
| List Header Frame Top&lt;br /&gt;
|-&lt;br /&gt;
| 10 &lt;br /&gt;
| List Header Frame Middle&lt;br /&gt;
|-&lt;br /&gt;
| 11 &lt;br /&gt;
| List Header Frame Bottom&lt;br /&gt;
|-&lt;br /&gt;
| 12 &lt;br /&gt;
| List Header Empty Background&lt;br /&gt;
|-&lt;br /&gt;
| 13 &lt;br /&gt;
| Scrollbar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 14 &lt;br /&gt;
| Scrollbar Background&lt;br /&gt;
|-&lt;br /&gt;
| 15 &lt;br /&gt;
| Scrollbar Inverse Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 16 &lt;br /&gt;
| Scrollbar Inverse Background&lt;br /&gt;
|-&lt;br /&gt;
| 17 &lt;br /&gt;
| Scrollbar Dead Area&lt;br /&gt;
|-&lt;br /&gt;
| 18 &lt;br /&gt;
| Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 19 &lt;br /&gt;
| Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 20 &lt;br /&gt;
| Inactive Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 21 &lt;br /&gt;
| Inactive Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 22 &lt;br /&gt;
| Alternating Item Background&lt;br /&gt;
|-&lt;br /&gt;
| 23 &lt;br /&gt;
| Alternating Item Foreground&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetPlaylistColor()====&lt;br /&gt;
The Skin.GetPlaylistColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetPlaylistColor(playlistcolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''playlistcolornumber''' = (integer) a number in the range 0-5 identifying the Playlist's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var normalBgColor = window.external.Skin.GetPlaylistColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Playlist Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 &lt;br /&gt;
| Normal&lt;br /&gt;
|-&lt;br /&gt;
| 1 &lt;br /&gt;
| Current&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Normal Background&lt;br /&gt;
|-&lt;br /&gt;
| 3 &lt;br /&gt;
| Selected Background&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Video Window Status Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 5 &lt;br /&gt;
| Video Window Status Bar Background&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetSkinColor()====&lt;br /&gt;
The Skin.GetSkinColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetSkinColor(skincolorname);&lt;br /&gt;
  where:&lt;br /&gt;
    '''skincolorname''' = (string) identifying the Skin's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var buttonTextColor = window.external.Skin.GetSkinColor(&amp;quot;wasabi.button.text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Skin Color Names====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.item.selected.fg&amp;quot;&lt;br /&gt;
|Selected item text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.column.separator&amp;quot; &lt;br /&gt;
|Color of line between columns&lt;br /&gt;
|-&lt;br /&gt;
|'''Item Lists, Lists with playable items'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.current&amp;quot;  &lt;br /&gt;
|Currently playing outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.focus&amp;quot;  &lt;br /&gt;
|Focused item dashed outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.selborder&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|'''Message box'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.msgBox.background&amp;quot;   &lt;br /&gt;
|Messagebox background color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.text&amp;quot;  &lt;br /&gt;
|Text object &amp;amp; message box text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.background&amp;quot;   &lt;br /&gt;
|Text object &amp;amp; message box text background color&lt;br /&gt;
|-&lt;br /&gt;
|'''Buttons'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.text&amp;quot;  &lt;br /&gt;
|Buttons text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.hiliteText&amp;quot; &lt;br /&gt;
|Buttons hilite text color, used by tab windows&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.dimmedText&amp;quot;  &lt;br /&gt;
|Buttons dimmed text color, when disabled&lt;br /&gt;
|-&lt;br /&gt;
|'''Popup menus'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.text&amp;quot;  &lt;br /&gt;
|Menu items text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.hiliteText&amp;quot;  &lt;br /&gt;
|Hilited item text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.dimmedText&amp;quot;  &lt;br /&gt;
|Disabled item text color&lt;br /&gt;
|-&lt;br /&gt;
|'''Components'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.foreground&amp;quot;  &lt;br /&gt;
|Old title bar text color when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.border&amp;quot;  &lt;br /&gt;
|Old title bar text outline when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|'''Labeled Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.foreground&amp;quot;  &lt;br /&gt;
|Text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.background&amp;quot; &lt;br /&gt;
|Text drop shadow color&lt;br /&gt;
|-&lt;br /&gt;
|'''Edit Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.selection&amp;quot;  &lt;br /&gt;
|Selected text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.text&amp;quot; &lt;br /&gt;
|Text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.background&amp;quot;  &lt;br /&gt;
|Text background&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color.inverse&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====string name (test)====&lt;br /&gt;
The Skin.name property gives access to the name of skin currently in use.  Changing this value will change the skin displayed for the player.&lt;br /&gt;
&lt;br /&gt;
====string font (read only)====&lt;br /&gt;
The Skin.font property provides the font name currently used in the player.&lt;br /&gt;
&lt;br /&gt;
====string fontsize (read only)====&lt;br /&gt;
The Skin.fontsize property provides the size of the font currently used in the player.&lt;br /&gt;
&lt;br /&gt;
== Metadata tag names ==&lt;br /&gt;
&lt;br /&gt;
When retrieving metadata through Winamp, a freeform string is passed.  The popular file formats (MP3, WMA, FLAC, M4A) will respond uniformly to a common base of strings.  However, each file format is idiosyncratic in how metadata is stored.  Some file types will respond to additional strings which are not documented here.&lt;br /&gt;
&lt;br /&gt;
Remember that the metadata is only as good as the tagging in the file itself.  A poorly tagged track will return poor metadata.&lt;br /&gt;
&lt;br /&gt;
Common metadata tags&lt;br /&gt;
 bitrate&lt;br /&gt;
 length&lt;br /&gt;
 type&lt;br /&gt;
 title&lt;br /&gt;
 artist&lt;br /&gt;
 albumartist&lt;br /&gt;
 album&lt;br /&gt;
 genre&lt;br /&gt;
 year&lt;br /&gt;
 disc&lt;br /&gt;
 publisher&lt;br /&gt;
 comment&lt;br /&gt;
 track&lt;br /&gt;
 composer&lt;br /&gt;
 conductor&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-06-25T21:05:03Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Testing the plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (TODO: can someone confirm this?!  CONFIRMED, the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define GPPHDR_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  char *description;             // name/title of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // (?)&lt;br /&gt;
  HINSTANCE hDllInstance;        // (?)&lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
extern winampGeneralPurposePlugin *gen_plugins[256];&lt;br /&gt;
typedef winampGeneralPurposePlugin * (*winampGeneralPurposePluginGetter)();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  GPPHDR_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project. &lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
# Click on your plugin to hilight it and then select the 'Configure Selected Plugin' button.  This should cause the 'config' message to appear.&lt;br /&gt;
# If you exit Winamp, you should now see the Quit message pop up as the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\winamp_imms.cpp(29) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\winamp_imms.cpp(41) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide</id>
		<title>Beginner's Basic Plugin Guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Beginner%27s_Basic_Plugin_Guide"/>
				<updated>2009-06-25T20:42:16Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: /* Creating a project */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;So you want to write a plugin for Winamp but don't know where to start? This is the page for you. We'll walk you through creating a very basic plugin that does '''nothing'''. You can then expand on the code to do whatever you want.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
This guide assumes you're developing using Visual Studio in a Windows environment. It also assumes you have some familiarity with programming. For people that don't, try using google. We'll have to expand this guide in the future to give out more pointers.&lt;br /&gt;
&lt;br /&gt;
== Basic credits ==&lt;br /&gt;
The following code has been created based on samples from [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=128915 several] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=82651 forum] [http://forums.winamp.com/showthread.php?s=&amp;amp;threadid=103667 threads]. Many thanks go out to forum members Kaboon, kichik, baafie, burek021, and bananskib for their code examples and advice.&lt;br /&gt;
&lt;br /&gt;
== What you need ==&lt;br /&gt;
To begin, you'll need a tool that lets you write code. Check out the [[Plug-in_Developer#Tools|Tools]] page. You can get a free copy of Visual Studio C++ Express [http://www.microsoft.com/Express/ here]. You'll probably also want a copy of Winamp itself, to test your plugin; you can get that on the Winamp site [http://www.winamp.com/player here].&lt;br /&gt;
&lt;br /&gt;
# Download [http://www.microsoft.com/Express/ Visual C++ Express].&lt;br /&gt;
# Double-click the file (it's probably called something like 'vcsetup.exe') and run the installer.&lt;br /&gt;
# You're practically good to go!&lt;br /&gt;
&lt;br /&gt;
== Creating a project ==&lt;br /&gt;
The first thing we need to do is create a place to store our code. In Visual Studio this is called a 'project'.&lt;br /&gt;
&lt;br /&gt;
# Launch Visual Studio by clicking Start -&amp;gt; Programs -&amp;gt; Microsoft Visual C++ Express Edition -&amp;gt; Microsoft Visual C++ Express Edition&lt;br /&gt;
# When Visual Studio opens, select File -&amp;gt; New -&amp;gt; Project&lt;br /&gt;
# For creating Winamp plugins, we want to create code that compiles into a .dll, which Visual Studio 2008 refers to as a &amp;quot;Class Library&amp;quot;. So in the 'New Project' window select Visual C++ -&amp;gt; CLR -&amp;gt; Class Library.&lt;br /&gt;
# Give your project a name (see below) and select a location.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Winamp classifies plugins based on the first part of their .dll filename, so you will need to properly name the file if you want Winamp to recognize it (TODO: can someone confirm this?!  CONFIRMED, the Winamp client searches for and loads plugins based on the first part of their filenames.  This saves time and space instead of loading all dlls and then detecting which ones are real plugins). Thus, to make our basic plugin we want to name the first part of the file 'gen_'. '''Be sure to start your plugin name with 'gen_' to make it work properly.'''&lt;br /&gt;
&lt;br /&gt;
All of the examples in this guide will assume you named your plugin 'gen_myplugin', but you can call it whatever you like as long as it starts with 'gen_' (for generic plugin) and ends with '.dll'.&lt;br /&gt;
&lt;br /&gt;
Once you click okay Visual Studio should create a bunch of boilerplate code for you, and throw some files in your project with names like &amp;quot;resource.h&amp;quot;, &amp;quot;stdafx.h&amp;quot;, &amp;quot;AssemblyInfo.cpp&amp;quot;, and so on. The main files we want to work with are called 'gen_myplugin.h' and 'gen_myplugin.cpp'. If you double-click to view them you should see code that looks something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// gen_myplugin.h&lt;br /&gt;
&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
using namespace System;&lt;br /&gt;
&lt;br /&gt;
namespace gen_myplugin {&lt;br /&gt;
&lt;br /&gt;
	public ref class Class1&lt;br /&gt;
	{&lt;br /&gt;
		// TODO: Add your methods for this class here.&lt;br /&gt;
	};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// This is the main DLL file.&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end contents of gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We want to edit these files to make a basic plugin.&lt;br /&gt;
&lt;br /&gt;
== Creating a basic plugin ==&lt;br /&gt;
&lt;br /&gt;
=== Basic plugin code ===&lt;br /&gt;
To create your plugin, just copy/paste the following code into gen_myplugin.h and gen_myplugin.cpp.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#ifndef gen_myplugin_h&lt;br /&gt;
//---------------------------------------------------------------------------&lt;br /&gt;
#define gen_myplugin_h&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// plugin version (don't touch this)&lt;br /&gt;
#define GPPHDR_VER 0x10&lt;br /&gt;
&lt;br /&gt;
// plugin name/title (change this to something you like)&lt;br /&gt;
#define GPPHDR_NAME &amp;quot;My first generic Winamp plugin!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// main structure with plugin information, version, name...&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   // version of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  char *description;             // name/title of the plugin, defined in &amp;quot;gen_empty.h&amp;quot;&lt;br /&gt;
  int (*init)();                 // function which will be executed on init event&lt;br /&gt;
  void (*config)();              // function which will be executed on config event&lt;br /&gt;
  void (*quit)();                // function which will be executed on quit event&lt;br /&gt;
  HWND hwndParent;               // (?)&lt;br /&gt;
  HINSTANCE hDllInstance;        // (?)&lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
extern winampGeneralPurposePlugin *gen_plugins[256];&lt;br /&gt;
typedef winampGeneralPurposePlugin * (*winampGeneralPurposePluginGetter)();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.h&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
&lt;br /&gt;
Winamp generic plugin template code.&lt;br /&gt;
This code should be just the basics needed to get a plugin up and running.&lt;br /&gt;
You can then expand the code to build your own plugin.&lt;br /&gt;
&lt;br /&gt;
Updated details compiled June 2009 by culix, based on the excellent code examples&lt;br /&gt;
and advice of forum members Kaboon, kichik, baafie, burek021, and bananskib.&lt;br /&gt;
Thanks for the help everyone!&lt;br /&gt;
&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;stdafx.h&amp;quot;&lt;br /&gt;
#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;
#include &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// these are callback functions/events which will be called by Winamp&lt;br /&gt;
int  init(void);&lt;br /&gt;
void config(void);&lt;br /&gt;
void quit(void);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// this structure contains plugin information, version, name...&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
  GPPHDR_VER,  // version of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  GPPHDR_NAME, // name/title of the plugin, defined in &amp;quot;gen_myplugin.h&amp;quot;&lt;br /&gt;
  init,        // function name which will be executed on init event&lt;br /&gt;
  config,      // function name which will be executed on config event&lt;br /&gt;
  quit,        // function name which will be executed on quit event&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// event functions follow&lt;br /&gt;
&lt;br /&gt;
int init() {&lt;br /&gt;
  //A basic messagebox that tells you the 'init' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you start Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Init event triggered for gen_myplugin. Plugin installed successfully!&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void config() {&lt;br /&gt;
  //A basic messagebox that tells you the 'config' event has been triggered.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(plugin.hwndParent, L&amp;quot;Config event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void quit() {&lt;br /&gt;
  //A basic messagebox that tells you the 'quit' event has been triggered.&lt;br /&gt;
  //If everything works you should see this message when you quit Winamp once your plugin has been installed.&lt;br /&gt;
  //You can change this later to do whatever you want (including nothing)&lt;br /&gt;
  MessageBox(0, L&amp;quot;Quit event triggered for gen_myplugin.&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// This is an export function called by winamp which returns this plugin info.&lt;br /&gt;
// We wrap the code in 'extern &amp;quot;C&amp;quot;' to ensure the export isn't mangled if used in a CPP file.&lt;br /&gt;
extern &amp;quot;C&amp;quot; __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {&lt;br /&gt;
  return &amp;amp;plugin;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;end basic gen_myplugin.cpp&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Edit dependencies ===&lt;br /&gt;
&lt;br /&gt;
By default Visual Studio removes some files we need to compile our code. Let's add those back in:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project (the folder called 'gen_myplugin' in the Solution Explorer window on the left) and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)', so the box is blank.&lt;br /&gt;
# Click 'Apply', then 'OK', and then save your project. &lt;br /&gt;
&lt;br /&gt;
=== Compiling the code ===&lt;br /&gt;
&lt;br /&gt;
Once you have pasted this code into your .h and .cpp files, save your changes and compile the project. You can do this by pressing F7, or selecting Build -&amp;gt; Build Solution. If everything works, you should see some messages in Visual Studio's 'Output' window, with the final line saying something like&lt;br /&gt;
&lt;br /&gt;
&amp;quot;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If so, congratulations! You have built your first plugin :) If instead you get an error message, please see the [[Beginner's Basic Plugin Guide#Troubleshooting|Troubleshooting]] section below.&lt;br /&gt;
&lt;br /&gt;
=== Testing the plugin ===&lt;br /&gt;
&lt;br /&gt;
If your project builds successfully, it will output a file called 'gen_myplugin.dll' into a 'Debug' or 'Release' folder in the same location you created your project. Look for that file now. We want to copy this file to C:\Program Files\Winamp\Plugins\, which is the folder Winamp examines to find all of its plugins.&lt;br /&gt;
&lt;br /&gt;
# Copy your plugin .dll file into C:\Program Files\Winamp\Plugins\&lt;br /&gt;
# Close and re-open Winamp. If your plugin is installed correctly, you should see a popup window with the Init message you typed inside gen_myplugin.cpp. If so, congrats! Your plugin works.&lt;br /&gt;
# You can check to see your plugin name by clicking Options -&amp;gt; Preferences -&amp;gt; Plugins -&amp;gt; General purpose. Your plugin name should appear in that window.&lt;br /&gt;
&lt;br /&gt;
If you exit Winamp, you should now also see a Quit message pop up when the program exits.&lt;br /&gt;
&lt;br /&gt;
== What's next? ==&lt;br /&gt;
&lt;br /&gt;
So what's next? We don't know. More guides still need to be written. Eventually there may be a guide for each type of plugin: [[Input_Plugin|Input]], [[Output_Plugin|Output]], [[Visualization_Plugin|Visualization]], [[DSP_Plugin|Audio Effect/DSP]], [[General_Purpose_Plugin|General Purpose]], [[Media_Library_Plugin|Media Library]] and [[Portable_Plugin|Portables]].&lt;br /&gt;
&lt;br /&gt;
If you're looking to write a plugin, you may want to start by reading through the [[SDK_Contents]] and trying to find a code example that's similar to what you want to do.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
* '''I get an error message that looks like:'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2028: unresolved token (0A00001D) &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall &lt;br /&gt;
MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot;&lt;br /&gt;
 (?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&lt;br /&gt;
1&amp;gt;winamp_imms.obj : error LNK2019: unresolved external symbol &amp;quot;extern &amp;quot;C&amp;quot; int __stdcall&lt;br /&gt;
 MessageBoxW(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; (?MessageBoxW@@$$J216YGHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
 referenced in function &amp;quot;extern &amp;quot;C&amp;quot; int __cdecl MessageBox(struct HWND__ *,wchar_t const *,wchar_t const *,unsigned int)&amp;quot; &lt;br /&gt;
(?MessageBox@@$$J0YAHPAUHWND__@@PB_W1I@Z)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' By default Visual Studio Express 2008 doesn't include some files you need in the linker. For example, with our basic code we include windows.h, which is part of user32.dll. However, there is usually a '$(NoInherit)' command in our linker options that tell us not to include user32.dll. To fix this, try the following:&lt;br /&gt;
&lt;br /&gt;
# Right-click on your project and select Properties&lt;br /&gt;
# Expand the options to select Configuration Properties -&amp;gt; Linker -&amp;gt; Input&lt;br /&gt;
# In the &amp;quot;Additional Dependancies&amp;quot; box, delete the text that says '$(NoInherit)'.&lt;br /&gt;
# Save and recompile&lt;br /&gt;
&lt;br /&gt;
For more information see [http://stackoverflow.com/questions/739952/c-cli-linker-gives-unresolved-token-for-win32-function here] and [http://stackoverflow.com/questions/721387/i-get-lnk2028-when-trying-to-wrap-native-c-class-using-managed-c here].&lt;br /&gt;
&lt;br /&gt;
* '''* I get an error like'''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;1&amp;gt;.\winamp_imms.cpp(29) : error C2146: syntax error : missing ';' before identifier 'plugin'&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' This could be a namespace error. On this line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we are creating a variable called 'plugin'. The variable's type, rather than being an integer ('int'), floating point number ('float'), or some other type, is of type 'winampGeneralPurposePlugin', which is a type we have created. This type is created in the header file with the code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef struct {&lt;br /&gt;
  int version;                   &lt;br /&gt;
  char *description;             &lt;br /&gt;
  int (*init)();                 &lt;br /&gt;
  void (*config)();              &lt;br /&gt;
  void (*quit)();                &lt;br /&gt;
  HWND hwndParent;               &lt;br /&gt;
  HINSTANCE hDllInstance;        &lt;br /&gt;
} winampGeneralPurposePlugin;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you used Visual Studio's auto-generated code, you might have a line that looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
namespace myplugin {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this line is telling Visual Studio to put everything inside the 'myplugin' namespace (read up on namespaces [http://en.wikipedia.org/wiki/Namespace here]). We get rid of the default boilerplate code, including the namespace, to make everything work.&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can change the declaration of the 'plugin' variable to say&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
myplugin::winampGeneralPurposePlugin plugin = {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Visual Studio where to look for the winampGeneralPurposePlugin type (i.e., to look inside the 'myplugin' namespace). If you are new to programming or plugin creation, however, you probably don't need (or want) to mess with namespaces.&lt;br /&gt;
&lt;br /&gt;
* '''I get an error like'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1&amp;gt;.\winamp_imms.cpp(41) : error C2664: 'MessageBox' : cannot convert parameter 2 from 'const char [5]' to 'LPCTSTR'&lt;br /&gt;
1&amp;gt;        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:'''Answer:''' You need to change the string you pass to the MessageBox function to be of the right type. See the MSDN FAQ entry [http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb here]. You can most likely fix this by putting a capital 'L' in front of the string.&lt;br /&gt;
&lt;br /&gt;
e.g. change &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, &amp;quot;Somestring&amp;quot;, &amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt; to &amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;MessageBox(plugin.hwndParent, L&amp;quot;Somestring&amp;quot;, L&amp;quot;&amp;quot;, MB_OK);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: What's the right way of doing this for plugins?&lt;br /&gt;
&lt;br /&gt;
* '''My plugin isn't working / My plugin doesn't show up in the Preferences menu.'''&lt;br /&gt;
&lt;br /&gt;
:'''Answer:'''Did you name your plugin with the correct prefix, such as 'gen_myplugin'? If not it may not show up in the window.&lt;br /&gt;
&lt;br /&gt;
TODO: How about other names/plugins? What's the real answer?&lt;br /&gt;
&lt;br /&gt;
[[Category:Articles]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Online_Service_Security_Prompts</id>
		<title>Online Service Security Prompts</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Online_Service_Security_Prompts"/>
				<updated>2009-01-22T15:48:07Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: New page: '''Breadcrumb''' -- Wiki Main : Skin Developer : Visual Developer : Plug-in Developer : Online Service Developer : Articles Page : [[Developers F...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Category:Winamp]]&lt;br /&gt;
==Winamp Online Services Security==&lt;br /&gt;
 &lt;br /&gt;
Winamp Online Services is a powerful new way for web developers to create engaging content for millions of Winamp users. However, with great power comes great responsibility.  Since online services have access to more information from the Winamp client than an ordinary web page, it is very important that we provide some mechanism to provide security for the users.  &lt;br /&gt;
 &lt;br /&gt;
There are certain activities that online services can perform that are not considered a security risk   For example, examining the current position of a song being played.   However, for others a security dialog will be presented whenever a service tries to perform the action for the first time.    &lt;br /&gt;
 &lt;br /&gt;
===Security Dialog Prompts===&lt;br /&gt;
 &lt;br /&gt;
Security prompts contain a description of the action being attempted, an indication as to what API the action belongs, allow and deny buttons as well as a checkbox.  &lt;br /&gt;
 &lt;br /&gt;
Replies, either Allow or Deny, to security prompts are saved for each online service.&lt;br /&gt;
 &lt;br /&gt;
====Allow====&lt;br /&gt;
Allows the online service to perform the action.  It will also automatically ALLOW other, related actions.  The list below will identify which actions are related.&lt;br /&gt;
 &lt;br /&gt;
====Deny====&lt;br /&gt;
Does NOT allow the online service to perform the action.  It will also automatically DENY other related actions.&lt;br /&gt;
 &lt;br /&gt;
====Use this response for all security requests for this service==== &lt;br /&gt;
When this checkbox is checked, the choice (Allow or Deny) will be used as the response to all subsequent security prompts for this service.  This is a quick way to indicate that a particular online service should be allowed or denied (depending on the button pressed) to perform all actions.&lt;br /&gt;
 &lt;br /&gt;
===Grouping APIs by Security Prompt===&lt;br /&gt;
 &lt;br /&gt;
The following APIs and methods will cause a security prompt to appear the first time each service attempts to invoke them.  Security responses for each message will then be used automatically for the other api methods listed.:&lt;br /&gt;
====This service is trying to control playback====&lt;br /&gt;
*API: Transport&lt;br /&gt;
*Methods: Prev(), Play(), Stop(), Pause(), Next()&lt;br /&gt;
*Description:  The online service is attempting to Play, Stop, Pause, Jump to the previous track, or Jump to the next track.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to monitor playback events====&lt;br /&gt;
*API: Transport&lt;br /&gt;
*Methods: RegisterForEvents()&lt;br /&gt;
*Description: The online service is requesting to be notified when playback events occur.  The possible events are Play, Pause, Stop, End of File.  Note these events will occur whether initiated from scripts or from the user clicking on the buttons themselves.  Some events carry additional information:&lt;br /&gt;
**Play provides the filename/URL of the asset being played.&lt;br /&gt;
**Stop provides the current position where playback was halted.  End of File indicates that the end of the asset has been reached.  &lt;br /&gt;
**Pause provides a flag indicating whether the player was paused or unpaused.&lt;br /&gt;
**End of File happens at the end of an asset before the next one is played.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to get information about the currently playing song====&lt;br /&gt;
*API: Transport&lt;br /&gt;
*Methods: GetMetadata()&lt;br /&gt;
*Description: The online service is requesting &amp;quot;Metadata&amp;quot; information from the current asset.  &amp;quot;Metadata&amp;quot; is additional information that MAY be part of the asset, such as author or title, that is not actually part of the song itself.  The existence of metadata depends on the format of the data and whether it was added when the asset was digitized.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access your active playlist====&lt;br /&gt;
*API: PlayQueue&lt;br /&gt;
*Methods: Play(), Enqueue(), Insert(), ClearQueue()&lt;br /&gt;
*Description: The online service is trying to alter the Play Queue.  It may be trying to play a single asset, add assets to the queue or clear the queue.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to get information about an item in your Play Queue.====&lt;br /&gt;
*API: PlayQueue&lt;br /&gt;
*Methods: GetMetadata(), GetTitle(), GetURL()&lt;br /&gt;
*Description: The service is trying to gather information about an asset within the play queue.  &lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access the playlists in your media library====&lt;br /&gt;
*API: PlayLists&lt;br /&gt;
*Methods: GetPlaylists(), OpenPlaylist(), SavePlaylist()&lt;br /&gt;
*Description: The online service is trying to obtain a list of all Winamp playlists known to your Winamp client.  It may also be trying to open a playlist to manipulate the assets within or it may be trying to save a modified playlist.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access your bookmarks====&lt;br /&gt;
*API: Bookmarks:&lt;br /&gt;
*Methods:  Add()&lt;br /&gt;
*Description: The online service is trying to create a bookmark in your Media Library Bookmarks.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to subscribe you to a podcast====&lt;br /&gt;
*API: Podcasts&lt;br /&gt;
*Methods: Add()&lt;br /&gt;
*Description: The online service is trying to subscribe to a podcast and add an entry in your Media Library Podcasts&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to provide metadata to Winamp====&lt;br /&gt;
*API: MediaCore&lt;br /&gt;
*Methods: AddMetadataHook()&lt;br /&gt;
*Description: The online service is trying to add metadata for an asset.  This might be useful if the online service can provide better metadata than comes as part of the asset itself.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access information about media supported by Winamp.====&lt;br /&gt;
*API: MediaCore&lt;br /&gt;
*Methods: isRegisteredExtension()&lt;br /&gt;
*Description: The service is trying to determine if the Winamp client supports a certain encoding formation, for example &amp;quot;mp3&amp;quot;.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access information about media on your computer.====&lt;br /&gt;
*API: MediaCore&lt;br /&gt;
*Methods: GetMetadata()&lt;br /&gt;
*Description: The online service is attempting to get metadata from an asset.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access your playback history====&lt;br /&gt;
*API: History&lt;br /&gt;
*Methods: Query()&lt;br /&gt;
*Description: The Winamp History is a collection of information about the assets you play, how many times they were played and when was the last time they were played.  It is used to determine what the users favorite songs are.  &lt;br /&gt;
 &lt;br /&gt;
====This service is trying to launch a website in the browser====&lt;br /&gt;
*API: Application&lt;br /&gt;
*Methods: LaunchURL()&lt;br /&gt;
*Description: The online service is trying to launch a new web site in the browser.  The browser may be internal to Winamp, which means it could be an online service or it could be launched in an external browser where it does  not benefit from the online services api calls.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access information about Winamp====&lt;br /&gt;
*API: Application&lt;br /&gt;
*Properties: version, versionstring, language, languagepack&lt;br /&gt;
*Description: The online service is trying to gather information regarding the version of Winamp or the language pack that is being used by Winamp.&lt;br /&gt;
 &lt;br /&gt;
====This service is trying to access your skin settings====&lt;br /&gt;
*API: Skins&lt;br /&gt;
*Methods: GetClassicColor(), GetPlaylistColor(), GetSkinColor()&lt;br /&gt;
*Description: The online service is trying to obtain information regarding the current skin used by the Winamp client.  This could be used to sychronize the colors of the service with that of the Winamp player.&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework</id>
		<title>Complete JavaScript API technology framework</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Complete_JavaScript_API_technology_framework"/>
				<updated>2009-01-22T15:38:19Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: New page: '''Breadcrumb''' -- Wiki Main : Skin Developer : Visual Developer : Plug-in Developer : Online Service Developer : Articles Page : [[Developers F...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
[[Category:Winamp]]&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
The purpose of the Winamp Online Service API is to allow Winamp Online Services to interact with the Winamp client in order to provide service developers with a way to create custom experiences for their users based on the power of Winamp.  The overall idea is to include exceptional web sites within Winamp Online Services.&lt;br /&gt;
&lt;br /&gt;
The Winamp Online Service API is made up of methods that can be called from scripts within web pages rendered by the Winamp client.  The API can be invoked using any scripting language supported by the Microsoft Internet Explorer web browser (5.5 and above).  For simplicity, examples in this document will use JavaScript.&lt;br /&gt;
&lt;br /&gt;
==Setup==&lt;br /&gt;
The Winamp Online Services API is designed to allow web pages, hosted (displayed) within the embedded browser of the Winamp client, to access the functionality of the client.  There are several steps necessary to allow this to take place.&lt;br /&gt;
&lt;br /&gt;
#Make sure you have the latest version of the Winamp client that supports online services.&lt;br /&gt;
#Make sure you have the latest version of the ml_webdev plugin (ml_webdev.dll).  The presence of this plugin will create a &amp;quot;Web Dev Test Platform&amp;quot; within the Medial Library pane.&lt;br /&gt;
#In order to change the starting web page for the online service, start the Winamp client and configure the plugin.  &lt;br /&gt;
##Select Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;Media Library.  &lt;br /&gt;
##Select &amp;quot;API 2 Test Platform&amp;quot; and press &amp;quot;Configure selected plugin&amp;quot;.  &lt;br /&gt;
##On the Web Dev Preferences dialog, set the URL field to the URL of the initial web page for the online service.  For example, &amp;lt;nowiki&amp;gt;file://c:\myonlineservice\webdev.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
#Click on &amp;quot;Web Dev Test Platform&amp;quot; in the Media Library.  You may have to right click and choose refresh to see the new web page.&lt;br /&gt;
&lt;br /&gt;
You should now see the initial page of your online service in the Winamp embedded browser.&lt;br /&gt;
&lt;br /&gt;
==window.external==&lt;br /&gt;
The Winamp JavaScript API can be accessed through the window.external object in the Document Object Model (DOM) exposed by the IE browser control embedded within the Winamp client.  The API methods can only be accessed thru the Winamp client and are not available if the web page is displayed outside of the client.&lt;br /&gt;
&lt;br /&gt;
The invocation of all methods follow this form&lt;br /&gt;
 window.external.'''''API'''''.'''''Method'''''&lt;br /&gt;
&lt;br /&gt;
Properties can also be accessed using a similar form:&lt;br /&gt;
 window.external.'''''API'''''.'''''Property'''''&lt;br /&gt;
&lt;br /&gt;
Where ''API'' is a singleton class that defines a group of related methods (i.e., functionality).  For example, Transport (Stop, Play, Next, etc) which controls the &amp;quot;buttons&amp;quot; of the Winamp player. &lt;br /&gt;
&lt;br /&gt;
''Method'' is a function you can call as part of a particular API.  For example the following call will stop the Winamp client:&lt;br /&gt;
 window.external.Transport.Stop();&lt;br /&gt;
&lt;br /&gt;
''Property'' is an internal variable for the particular API that can be queried and in some cases set.  For example the following will provide access to the Winamp client shuffle &amp;quot;button&amp;quot;:&lt;br /&gt;
 var shuffle = window.external.Transport.shuffle;  // gets the current state&lt;br /&gt;
     OR&lt;br /&gt;
 window.external.Transport.shuffle = true;         // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
See the documentation on each API below for a complete list of methods and properties.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- == Security Warnings ==&lt;br /&gt;
Using the Winamp JavaScript API, an online service web page has access to much more information (read: power) than a normal web page.  For example, playlists can be enumerated, and metadata for songs can be retrieved.  In order to control these capabilities a security system was implemented so that users are informed whenever an online service first attempts to use an API method or access a property.  For example, when an online service attempts to stop playback for the very first time, the user will be notified and asked whether the service should be allowed to do this.&lt;br /&gt;
&lt;br /&gt;
Note that this security model maintains user choices based on service ID so that the user will be prompted each time a service tries to invoke methods or access properties.  In addition, online services updated through the Winamp Online Service submission process, receive new service IDs, causing the users to be prompted again.&lt;br /&gt;
&lt;br /&gt;
A dialog is presented to the user that describes the action about to be performed and forces the user to choose whether the action should be Allowed or Denied.  A third button let's a user to indicate &amp;quot;Always Allow&amp;quot;.  If the user selects this button, the API will no longer prompt the user for this action (for this particular online service).  &lt;br /&gt;
&lt;br /&gt;
Be aware that choices for certain APIs will affect the entire API and all of its methods and properties.  For example, choosing &amp;quot;Always Allow&amp;quot; for Transport.Stop() will also always allow access to the other Tranport methods/properties.  Certain other APIs, such as the Application API affect only the action being attempted.  Some API methods and properties are considered inconsequential and not governed by this security model at all.  The scope of the user's choice will be described within the dialog.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transport API ==&lt;br /&gt;
The Transport API is used to control the Winamp client.  &amp;quot;Transport controls&amp;quot; was the name given to the buttons on the front panel that controlled hardware devices.  This name is used in Winamp for the same purpose.  It is also used to access information about the currently playing song.&lt;br /&gt;
&lt;br /&gt;
The Transport API can also be used to register for events involved with asset playback.  See the section [[#Transport Events API|Transport Events API]].&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Prev()====&lt;br /&gt;
Transport.Prev() can be used to press the &amp;quot;Previous Track&amp;quot; button on the Winamp player.  Invoking Prev() while an asset is already playing will cause the previous asset to begin playback immediately.  Invoking Prev() while the player is stopped will cause the previous asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Prev();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Prev();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Play()====&lt;br /&gt;
Transport.Play() can be used to press the &amp;quot;Play&amp;quot; button on the Winamp player.  Invoking Play() on an asset already playing will cause the asset to restart playback.  Pressing Play() on a paused asset will cause it to begin playing from its current position.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Play();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Pause()====&lt;br /&gt;
Transport.Pause() can be used to press the &amp;quot;Pause&amp;quot; button on the Winamp player.  Issuing Pause() again, or Play() will cause the asset to continue to play from the location where it was paused.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Pause();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Pause();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Stop()====&lt;br /&gt;
Transport.Stop() can be used to press the &amp;quot;Stop&amp;quot; button on the Winamp player.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Stop();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Stop();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
====Next()====&lt;br /&gt;
Transport.Next() can be used to press the &amp;quot;Next Track&amp;quot; button on the Winamp player.  Invoking Next() while the player is stopped will cause the next asset to play next time playback starts.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Next();&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.Next();&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
Transport.GetMetadata() can be used to fetch metadata for the currently playing asset.  The &amp;quot;tag&amp;quot; parameter is specific to different asset encoding formats so a knowledge of the metadata field names is necessary to request specific data about an asset.  Some field names are common but others are specific to the encoding format of the asset.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(tag);&lt;br /&gt;
 where:&lt;br /&gt;
      '''tag''' = (string) identifier for the metadata to be returned.&lt;br /&gt;
Example:&lt;br /&gt;
 var metaStr = window.external.Transport.GetMetadata(&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A string value containing the requested metadata.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====bool shuffle====&lt;br /&gt;
Transport.shuffle provides access to the Winamp client shuffle &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isShuffling = window.external.Transport.shuffle; // get shuffle state&lt;br /&gt;
  window.external.Transport.shuffle = true;            // turns on shuffle&lt;br /&gt;
&lt;br /&gt;
====bool repeat====&lt;br /&gt;
Transport.repeat provides access to the Winamp client repeat &amp;quot;button&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isRepeating = window.external.Transport.repeat; // get repeat state&lt;br /&gt;
  window.external.Transport.repeat = false;           // turns off repeat&lt;br /&gt;
&lt;br /&gt;
====int position====&lt;br /&gt;
Transport.position provides access to the position being played within the current asset.  Setting this value can change the location where playback occurs. position is in milliseconds.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var position = window.external.Transport.position; // get position in current track&lt;br /&gt;
  window.external.Transport.position = 221559;       // move playback of the current track &lt;br /&gt;
                                                     // to the specified position.&lt;br /&gt;
&lt;br /&gt;
====bool playing (read only) ====&lt;br /&gt;
Transport.playing indicates whether the Winamp Player is currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPlaying = window.external.Transport.playing; // is player playing?&lt;br /&gt;
&lt;br /&gt;
====bool paused (read only) ====&lt;br /&gt;
Transport.paused indicates whether the Winamp Player has been paused.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var isPaused = window.external.Transport.paused; // is player paused?&lt;br /&gt;
&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
Transport.length provides access to the length in seconds of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var length = window.external.Transport.length; // get length of current track in secs&lt;br /&gt;
&lt;br /&gt;
====string url (read only)====&lt;br /&gt;
Transport.url provides access to the URL (or filename) of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var url = window.external.Transport.url; // get url of current track&lt;br /&gt;
&lt;br /&gt;
====string title (read only)====&lt;br /&gt;
Transport.title provides access to the title of the track currently playing.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var title = window.external.Transport.title; // get title of current track&lt;br /&gt;
&lt;br /&gt;
==Transport Events API==&lt;br /&gt;
The Event mechanism of the Transport API allows javascript programmers to specify a callback method that will be invoked whenever certain Transport events take place.  An Event object is passed back to the method from which properties can be accessed that provide more information about the event.&lt;br /&gt;
&lt;br /&gt;
===RegisterForEvents()===&lt;br /&gt;
The RegisterForEvents() method can be used to specify a JavaScript function that is to be called when any Transport Events occur.  An event object is passed that indicates the type of event.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean RegisterForEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.RegisterForEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===UnregisterFromEvents()===&lt;br /&gt;
The UnregisterFromEvents() method is used to stop receiving notifications about Transport events.&lt;br /&gt;
&lt;br /&gt;
Note:  The original handler used in RegisterForEvents() must be passed back into UnregisterFromEvents().&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean UnregisterFromEvents(handler);&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Transport.UnregisterFromEvents(EventHandler);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Events===&lt;br /&gt;
The Transport API Event mechanism requires a JavaScript callback method that accepts a single parameter, a reference to a function.  This function will be invoked with an &amp;quot;event&amp;quot; object that will indicate the type of event that occurred as well as contain properties containing more information about the event.&lt;br /&gt;
&lt;br /&gt;
====OnStop====&lt;br /&gt;
The OnStop event is triggered when the Winamp client is stopped.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
integer event.position = contains the position within the file where the &amp;quot;Stop&amp;quot; was issued.  position is the number of milliseconds from the start of the asset.&lt;br /&gt;
&lt;br /&gt;
====OnPlay====&lt;br /&gt;
The OnPlay event is triggered when the Winamp client begins playback.  If the client is paused and then restarted by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
string event.filename = contains the filename/URL of the asset starting playback.&lt;br /&gt;
&lt;br /&gt;
====OnPause====&lt;br /&gt;
The OnPause event is triggered when the Winamp client is paused or unpaused.  If the client is started after being paused, by &amp;quot;pressing Play&amp;quot;, the OnPause event is triggered rather than an OnPlay event.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
boolean event.paused = true (the player was paused), false (the player was unpaused)&lt;br /&gt;
&lt;br /&gt;
====OnEndOfFile====&lt;br /&gt;
The OnEndOfFile event is triggered when the player reaches the end of a track.&lt;br /&gt;
&lt;br /&gt;
=====properties=====&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
===Callback function===&lt;br /&gt;
The callback function is invoked whenever a Transport event is detected.  The callback function is specified in both the RegisterForEvents() and UnregisterFromEvents() methods.  The method takes a single parameter, which is loaded with an object identifying the event that occurred.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 function EventHandler(event){&lt;br /&gt;
 {&lt;br /&gt;
     if (event.event == &amp;quot;OnStop&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnStop: position=&amp;quot; + event.position);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnEndOfFile&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnEndOfFile&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPause&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPause: paused=&amp;quot; + event.paused);&lt;br /&gt;
     }&lt;br /&gt;
     else if (event.event == &amp;quot;OnPlay&amp;quot;){&lt;br /&gt;
       alert(&amp;quot;OnPlay: filename=&amp;quot; + event.filename);&lt;br /&gt;
     }&lt;br /&gt;
     else {&lt;br /&gt;
       alert(&amp;quot;Unrecognized Event received&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== PlayQueue API ==&lt;br /&gt;
Provides access to the play queue (&amp;quot;Winamp Playlist&amp;quot;).  If you need access to the currently playing song, use the Transport API instead.&lt;br /&gt;
&lt;br /&gt;
Note that the Play Queue is the list of assets that are scheduled to be played by the Winamp client.  This is not necessarily the same as a user playlist.  Once placed in the play queue, assets can be rearrainged or deleted from the play queue without affecting a user playlist.  Individual assets can be placed in the play queue without being contained within a user playlist.  Additionally, after adding a playlist to the play queue, changes to the playlist will not affect the assets in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Play()====&lt;br /&gt;
The PlayQueue.Play() method stops playback, clears the play queue, enqueues the asset specified by the URL and starts playback.  If the URL cannot be found, playback will stop, the play queue will be cleared, the URL (or title and length) will appear in the queue but playback will not be started. &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Play(URL);&lt;br /&gt;
 bool Play(URL, title);&lt;br /&gt;
 bool Play(URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.extern.PlayQueue.Play(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Enqueue()====&lt;br /&gt;
PlayQueue.Enqueue() is used to add an asset to the play queue.  The selected asset is added to the bottom of the queue and current playback is not interrupted.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Enqueue(URL);&lt;br /&gt;
 bool Enqueue(URL, title);&lt;br /&gt;
 bool Enqueue(URL, title, length);&lt;br /&gt;
     '''URL''' = (string) identifies the location of the asset, for a file that is&lt;br /&gt;
       local or on an attached network drive this would be the fully&lt;br /&gt;
       qualified path and filename.  For files served from a web server,&lt;br /&gt;
       it would be the http URL.&lt;br /&gt;
     '''title''' = (string) used as the title when initially placed in&lt;br /&gt;
       the play queue.  &lt;br /&gt;
     '''length''' = (integer) used as the length when initially place&lt;br /&gt;
       in the play queue&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.extern.PlayQueue.Enqueue(&amp;quot;c:\\Winamp\\01 - Hello.mp3&amp;quot;,&lt;br /&gt;
    &amp;quot;My Cool Title&amp;quot;,1024);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====Insert()====&lt;br /&gt;
The PlayQueue.Insert() method can add an asset to the play queue at a specific index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Insert(position, URL);&lt;br /&gt;
 bool Insert(position, URL, title);&lt;br /&gt;
 bool Insert(position, URL, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
      '''position''' = (integer) a zero based number indicating the location within&lt;br /&gt;
           the play queue to insert the new asset.&lt;br /&gt;
           Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
                 queue is at position 0.&lt;br /&gt;
      '''url''' = (string) the URL of the asset to be added&lt;br /&gt;
      '''title''' = (string) the title to be displayed in the Play Queue.&lt;br /&gt;
      '''length''' = (integer) the length of the asset to be displayed in &lt;br /&gt;
           the play queue.&lt;br /&gt;
&lt;br /&gt;
Note, title and length are displayed in the play queue to identify what is to be played.  In order to reduce network activity, the real title and length are only accessed (using the URL) when the asset is about to commence playback.  At this point the title and length are updated to their real values.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.Insert(1, &amp;quot;c:\\mySongs\\mySong.mp3&amp;quot;,300);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====ClearQueue()====&lt;br /&gt;
The PlayQueue.ClearQueue() method removes all assets from the play queue.  This does not stop the current playback.  ClearQueue is commonly used to prepare the Play Queue for the addition of new assets.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool ClearQueue()&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PlayQueue.ClearQueue();&lt;br /&gt;
&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
====GetMetadata()====&lt;br /&gt;
PlayQueue.GetMetadata() can be used to obtain asset metadata about an asset in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetMetadata(position, metadatatag);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position 0.&lt;br /&gt;
   '''metadatatag''' - (string) is a tag describing which metadata is requested.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var mdata = window.external.PlayQueue.GetMetadata(2,&amp;quot;artist&amp;quot;);&lt;br /&gt;
Return Value:&lt;br /&gt;
A String that contains the metadata requested for the asset located at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetTitle()====&lt;br /&gt;
PlayQueue.GetTitle() retrieves the title of the asset at the specified position within the play queue.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var title = window.external.PlayQueue.GetTitle(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the Title of the asset at the requested position in the play queue&lt;br /&gt;
&lt;br /&gt;
====GetURL()====&lt;br /&gt;
PlayQueue.GetURL() is used to obtain the URL from the asset at the specified position in the play queue&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetURL(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' - (integer) is the position of the asset within the playlist.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     queue is at position &amp;quot;0&amp;quot;.&lt;br /&gt;
Example:&lt;br /&gt;
 var url = window.external.PlayQueue.GetURL(1);&lt;br /&gt;
Return value:&lt;br /&gt;
A String containing the URL of the asset at the rquested position in the play queue.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int length (read only)====&lt;br /&gt;
PlayQueue.length contains the length of the current play queue&lt;br /&gt;
&lt;br /&gt;
====int cursor====&lt;br /&gt;
PlayQueue.cursor provides access to the position of the currently playing asset within the play queue.  This cursor is 0 based, meaning that the first asset in the Play Queue has a cursor value of 0.  Valid values range from 0 to the length of the play queue minus one.&lt;br /&gt;
&lt;br /&gt;
If this value is changed before playback is started, the next asset to play will be the one assigned to this property.  However, if a song is already playing and this property is changed, the current asset will continue to play even though this property has been updated.  At the point that the current asset playback completes, the player will increment the cursor position and play the next asset in the queue rather than the one to which cursor was set.  So, for example, to specify the next asset to play while an asset is currently playing, set the cursor property to the position of the asset to play minus one.&lt;br /&gt;
&lt;br /&gt;
== Playlists API == &lt;br /&gt;
The Playlists API is used to process user playlists.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetPlaylists()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Array GetPlaylists();&lt;br /&gt;
Example:&lt;br /&gt;
 var playlists = window.external.Playlists.GetPlaylists();&lt;br /&gt;
Return Value:&lt;br /&gt;
A array-like object that can be used to examine all user playlists.&lt;br /&gt;
&lt;br /&gt;
Each element of the array represents a user playlist and contains the following properties&lt;br /&gt;
*filename - filename of the playlist&lt;br /&gt;
*title - name of the playlist&lt;br /&gt;
*playlistId - a unique identifier for the playlist, so you can retrieve it later.  Also used with OpenPlaylist/SavePlaylist&lt;br /&gt;
*length - total length (time) in seconds.  Cached data - not guaranteed to be accurate&lt;br /&gt;
*numitems - number of items in the playlist.  Cached data - not guaranteed to be accurate&lt;br /&gt;
&lt;br /&gt;
====OpenPlaylist()====&lt;br /&gt;
Playlists.OpenPlaylist() returns a Playlist object for the specified playlist ID.  You must use &lt;br /&gt;
Playlists.GetPlaylists() before issuing this request.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Playlist OpenPlaylist(playlistId);&lt;br /&gt;
 where:&lt;br /&gt;
   '''playlistId''' - (string) the Id of the playlist to be opened.&lt;br /&gt;
Example:&lt;br /&gt;
 var playlist1 = window.external.Playlists.OpenPlaylist(playlistId);&lt;br /&gt;
Return Value:&lt;br /&gt;
The Playlist object with the specified playistId.&lt;br /&gt;
&lt;br /&gt;
====SavePlaylist()====&lt;br /&gt;
Playlists.SavePlaylist() saves the specified playlist object with the specified ID.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool SavePlaylist(playlistId, playlist_to_save);&lt;br /&gt;
 where:&lt;br /&gt;
    '''playlistId''' (string) is the id of the playlist to be saved.&lt;br /&gt;
    '''playlist_to_save''' (Playlist) is the Playlist object to be saved.&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Playlists.SavePlaylist(playlistId, pl);&lt;br /&gt;
Return Value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Playlist Object ===&lt;br /&gt;
Playlist objects can be created/returned by the OpenPlaylist() method as well as various other APIs.&lt;br /&gt;
&lt;br /&gt;
====Methods====&lt;br /&gt;
=====GetItemFilename()=====&lt;br /&gt;
The GetItemFilename() method retrieves the filename/URL of the item at the specified index into the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemFilename(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the filename&lt;br /&gt;
                   should be returned.  &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var filename = playlst.GetItemFilename(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the filename/URL of a particular item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemTitle()=====&lt;br /&gt;
The GetItemTitle() method returns the title of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 String GetItemTitle(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the title&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var title = playlst.GetItemTitle(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The song title of the given item in the playlist&lt;br /&gt;
&lt;br /&gt;
=====GetItemLength()=====&lt;br /&gt;
The GetItemLength() method retrieves the play length of the asset at the requested index.&lt;br /&gt;
&lt;br /&gt;
 Number GetItemLength(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the item in the playlist for which the length&lt;br /&gt;
                   should be returned.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var itemLength = playlst.GetItemLength(0);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A number specifying the play length of the asset, in milliseconds.&lt;br /&gt;
&lt;br /&gt;
=====Reverse()=====&lt;br /&gt;
The Reverse() method reverses the order of the assets within a playlist, i.e., the first becomes last and the second becomes second to last, etc.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Reverse();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Reverse();&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=====Swap()=====&lt;br /&gt;
The Swap() method exchanges the assets at the two specified positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Swap(Number position1, Number position2)&lt;br /&gt;
 where: &lt;br /&gt;
   '''position1''' = (number) the index of the first item to be swapped.&lt;br /&gt;
   '''position2''' = (number) the index of the second item to be swapped.&lt;br /&gt;
   Note: position1 and position2 are &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Swap(0,1);&lt;br /&gt;
&lt;br /&gt;
=====Randomize()=====&lt;br /&gt;
The Randomize() method re-arranges the order of the playlist, placing the assets in random positions.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Randomize();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Randomize();&lt;br /&gt;
&lt;br /&gt;
=====Remove()=====&lt;br /&gt;
The Remove() method removes an asset from the playlist.  Subsequent assets are moved to lower number positions in the array.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 Remove(position);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) the position of the asset to be removed.&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.Remove(0);&lt;br /&gt;
&lt;br /&gt;
=====SortByTitle()=====&lt;br /&gt;
The SortByTitle() method re-arrainges the order of the playlist so that it is alphabetical order by title.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByTitle();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByTitle();&lt;br /&gt;
&lt;br /&gt;
=====SortByFilename()=====&lt;br /&gt;
The SortByFilename() method re-arrainges the order of the playlist so that it is alphabetical order by filename.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SortByFilename();&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SortByFilename();&lt;br /&gt;
&lt;br /&gt;
=====SetItemFilename()=====&lt;br /&gt;
Sets the filename of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 playlistObj.SetItemFilename(position, filename);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''filename''' = (string) the new filename &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetFilename(0, &amp;quot;c:\\\\myfavorites\\myfavsong.mp3&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemTitle()=====&lt;br /&gt;
Sets the title of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 SetItemTitle(position, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''title''' = (string) the new title &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemTitle(0, &amp;quot;My Favorite Title&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
=====SetItemLength()=====&lt;br /&gt;
Sets the length of the asset at the specified location in the playlist.&lt;br /&gt;
&lt;br /&gt;
 SetItemLength(position, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position of the entry in the playlist to alter the filename&lt;br /&gt;
   '''length''' = (number) the new length &lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = playlst.SetItemLength(0, 1000);&lt;br /&gt;
&lt;br /&gt;
=====InsertURL()=====&lt;br /&gt;
Inserts the specified asset in front of the asset at the specified position.  That and subsequent items are &amp;quot;pushed&amp;quot; to a higher position in the array.&lt;br /&gt;
&lt;br /&gt;
 InsertURL(position, url);&lt;br /&gt;
 InsertURL(position, url, title);&lt;br /&gt;
 InsertURL(position, url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''position''' = (number) position within the playlist before which to insert the asset&lt;br /&gt;
   '''url''' = (string) the URL of the asset to be inserted&lt;br /&gt;
   '''title''' = (string) title of the asset to be inserted&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be inserted&lt;br /&gt;
   Note: Position is &amp;quot;zero based&amp;quot; so the first entry in the &lt;br /&gt;
     playlist is at position 0.&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====AppendURL()=====&lt;br /&gt;
The Playlist.AppendURL() method appends an asset URL to the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.AppendURL(url);&lt;br /&gt;
 Playlist.AppendURL(url, title);&lt;br /&gt;
 Playlist.AppendURL(url, title, length);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) the URL to the asset to be appended&lt;br /&gt;
   '''title''' = (string) title of the asset to be appended&lt;br /&gt;
   '''length''' = (number) length (milliseconds) of the asset to be appended&lt;br /&gt;
   Note: title and length are user specified and do not have to match&lt;br /&gt;
   the actual values of the asset.  When the asset is played, the &lt;br /&gt;
   values will be replaced in the Play Queue when the URL is opened &lt;br /&gt;
   for playback but will othewise retain the above values in the &lt;br /&gt;
   playlist.&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
=====Clear()=====&lt;br /&gt;
The Playlist.Clear() method will remove all assets from the playlist.&lt;br /&gt;
&lt;br /&gt;
 Playlist.Clear();&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful&lt;br /&gt;
&lt;br /&gt;
====Properties====&lt;br /&gt;
=====int numitems (read only)=====&lt;br /&gt;
The Playlist.numitems property contains the number of assets within the playlist.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Playlist Manager API ==&lt;br /&gt;
The Playlist Manager API provides methods to read and write playlists from permanent storage.&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bookmarks API ==&lt;br /&gt;
The Bookmarks API provides methods to manage bookmarks.&lt;br /&gt;
===Methods===&lt;br /&gt;
====Add()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean Add(url, title);&lt;br /&gt;
 where:&lt;br /&gt;
   '''url''' = (string) The url of the asset to be bookmarked.&lt;br /&gt;
   '''title''' = (string) A suitable title to be used within the bookmark.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Bookmark.Add(&amp;quot;c:\myfavs\songstocodeby.mp3&amp;quot;, &lt;br /&gt;
     &amp;quot;Songs To Code By&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Podcasts API ==&lt;br /&gt;
The Podcasts API provides methods to manage Podcasts.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====Subscribe()====&lt;br /&gt;
The Podcasts.Subscribe() method is used to add a channel to the list of podcast subscriptions, automatically subscribe to the podcast and begin downloading of the available episodes.  Once downloaded the episodes can be selected for playback.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 bool Subscribe(url);&lt;br /&gt;
 where:&lt;br /&gt;
     '''url''' = (string) the Podcast URL to subscribe to.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.PodCasts.Subscribe(&amp;lt;nowiki&amp;gt;&amp;quot;http://services.winamp.com/rss/news&amp;quot;&amp;lt;/nowiki&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== Config API ==&lt;br /&gt;
The Config API provides a means by which properties can be saved.  Properties added using the Config API are persistent across Winamp launches.&lt;br /&gt;
&lt;br /&gt;
===Adding and Retrieving Properties===&lt;br /&gt;
Adding a property is accomplished by identifying a property and assigning it a value.  Once assigned, the value can be retrieved like any other objects properties.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 window.external.Config.myProperty = &amp;quot;Test&amp;quot;;&lt;br /&gt;
 var myProp = window.external.Config.myProperty;  // myProp is set to &amp;quot;Test&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===Storing and Retrieving advanced data types===&lt;br /&gt;
Internally, all properties are stored as strings.  If you need to store datatypes more advanced than String, Number, or Boolean, it is recommended that you create a JSON string out of your data type.&lt;br /&gt;
&lt;br /&gt;
== Security API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
The Security.GetActionAuthorization() method can be used to determine whether a user has previously allowed or denied the functioning of a particular API's methods.  Group strings match API names.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 number Security.GetActionAuthorization(group);&lt;br /&gt;
 where:&lt;br /&gt;
    group = (string) Name of API to check for permission.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.Security.GetActionAuthorization(&amp;quot;Transport&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return Data:&lt;br /&gt;
*-1 = Either the user has not specified whether to allow/deny use of this API or the action usage is unrestricted. &lt;br /&gt;
*0  = The user has previously specified to deny use of this API/method.&lt;br /&gt;
*1  = The user has previously specified to allow use of this API/method.&lt;br /&gt;
&amp;lt;!-- &lt;br /&gt;
Transport – Access to the currently playing track, and play controls (play, stop, seek, etc)&lt;br /&gt;
&lt;br /&gt;
PlayQueue – Access to the play queue (Winamp Playlist)&lt;br /&gt;
&lt;br /&gt;
Application – general Winamp information – version #, language pack&lt;br /&gt;
&lt;br /&gt;
Playlists – access to the media library playlists&lt;br /&gt;
&lt;br /&gt;
Bookmarks – access to the user’s bookmarks (place to bookmark radio streams, etc)&lt;br /&gt;
&lt;br /&gt;
Skin – access to information about the user’s skin – colors, fonts, etc.&lt;br /&gt;
&lt;br /&gt;
MediaCore – access to media playback information, such as supported extensions&lt;br /&gt;
&lt;br /&gt;
Podcasts – access to the user’s media library podcasts&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== MediaCore API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
==== IsRegisteredExtension() ====&lt;br /&gt;
MediaCore.IsRegisteredExtension() method can be used to determine if the Winamp client is able to playback a specific format.  The file extension of the asset usually indicates the format.  This method is important since Winamp support for different formats is contained within plugins which may or may not exist for use.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean IsRegisteredExtension(ext);&lt;br /&gt;
 where:&lt;br /&gt;
   '''ext''' = (string) identifies the format to be queried for support in the form of a &lt;br /&gt;
       character string of the extension (a starting period is optional).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var canPlay = window.external.MediaCore.IsRegisteredExtension(&amp;quot;mp3&amp;quot;); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
Boolean value indicating whether the format is supported.&lt;br /&gt;
&lt;br /&gt;
==== GetMetadata() ====&lt;br /&gt;
MediaCore.GetMetadata() method can be used to obtain metadata about an asset.  This method differs from Transport.GetMetadata() in that the asset does not have to be currently playing.  It differs from PlayQueue.GetMetadata() in that it doesn't have to be present in the play queue.  &lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string GetMetadata(url, tag);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be retrieved.&lt;br /&gt;
    '''tag''' = (string) the specific piece of metadata to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var art = window.external.MediaCore.GetMetadata(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A string containing the metadata requested.&lt;br /&gt;
&lt;br /&gt;
==== AddMetadataHook() ====&lt;br /&gt;
MediaCore.AddMetadataHook() method can be used to add or override metadata for an asset.  For example, some assets such as those that are streamed may not contain metadata.  This method allows the online service to add metadata for the specified asset.  Subsequent GetMetadata() methods will return this information.  Online services can override the metadata present within an asset using this method.  This method can be used by services that define or can obtain their own metadata for the assets they provide rather than rely on what might or might not be present in the asset itself.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string AddMetadataHook(url, tag, value);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be added.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be added.&lt;br /&gt;
    '''value''' - (string) the value of the metadata key being added.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.AddMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;,&amp;quot;myself&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
==== RemoveMetadataHook() ====&lt;br /&gt;
MediaCore.RemoveMetadataHook() method can be used to remove metadata added through the AddMetadataHook() method.  Subsequent GetMetadata() requests will return whatever metadata was available previously, if any.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 string RemoveMetadataHook(url, tag);&lt;br /&gt;
 string RemoveMetadataHook(url);&lt;br /&gt;
 where:&lt;br /&gt;
    '''url''' = (string) containing the URL for which metadata is to be removed.&lt;br /&gt;
    '''tag''' = (string) the specific metadata key for which a value will be removed.&lt;br /&gt;
&lt;br /&gt;
If only the url parameter is provided, all metadata added with AddMetadataHook() for the specified url will be removed.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var rc = window.external.MediaCore.RemoveMetadataHook(&lt;br /&gt;
         &amp;quot;c:\\my favs\\myfavorite.mp3&amp;quot;,&amp;quot;artist&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value that indicates whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
== History API ==&lt;br /&gt;
The History branch of the Media Library pane is actually a database containing information about previously played assets.  The History API allows a service to search and retrieve information from this database.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
==== Query() ====&lt;br /&gt;
Prototype:&lt;br /&gt;
 results = History.Query(queryString);&lt;br /&gt;
 where:&lt;br /&gt;
   '''queryString''' = a properly formed string to match data to be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 var results = window.external.History.Query(&amp;quot;LASTPLAYED&amp;lt;[now]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
An &amp;quot;array-like&amp;quot; object that contains the results of the query.&lt;br /&gt;
&lt;br /&gt;
Each entry of the array contains the following properties:&lt;br /&gt;
* String filename&lt;br /&gt;
* String title&lt;br /&gt;
* Number length&lt;br /&gt;
* Number playcount&lt;br /&gt;
* Date lastplay&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fields:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date and time when this asset was last played.&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of times the asset has been played. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Local Media API  (test)==&lt;br /&gt;
&lt;br /&gt;
===TBD===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The LocalMedia API allows a service to search the assets within the Local Media branch of the Media Library.  By specifying a query string, Winamp will return an array of objects that match the values specified in the query.&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
Prototype:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 xx&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
returns an array of objects that match the specified criteria of the query string.&lt;br /&gt;
&lt;br /&gt;
'''Query String format:'''&lt;br /&gt;
&amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [&amp;lt;logic operator&amp;gt; &amp;lt;field&amp;gt; &amp;lt;comparison&amp;gt; [value] [...]]&lt;br /&gt;
&lt;br /&gt;
'''Comparison Operators:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyword&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| TYPE&lt;br /&gt;
| 0 for audio files, 1 for video files&lt;br /&gt;
|-&lt;br /&gt;
| FILENAME&lt;br /&gt;
| Full filename (including path)&lt;br /&gt;
|-&lt;br /&gt;
| LENGTH&lt;br /&gt;
| Length, in seconds (or hh:mm:ss)&lt;br /&gt;
|-&lt;br /&gt;
| ARTIST&lt;br /&gt;
| Artist&lt;br /&gt;
|-&lt;br /&gt;
| ALBUM&lt;br /&gt;
| Album&lt;br /&gt;
|-&lt;br /&gt;
| ALBUMARTIST&lt;br /&gt;
| Album Artist&lt;br /&gt;
|-&lt;br /&gt;
| TITLE&lt;br /&gt;
| Title&lt;br /&gt;
|-&lt;br /&gt;
| TRACKNO&lt;br /&gt;
| Track number of file&lt;br /&gt;
|-&lt;br /&gt;
| GENRE&lt;br /&gt;
| Genre&lt;br /&gt;
|-&lt;br /&gt;
| YEAR&lt;br /&gt;
| Year&lt;br /&gt;
|-&lt;br /&gt;
| COMMENT&lt;br /&gt;
| Comment&lt;br /&gt;
|-&lt;br /&gt;
| COMPOSER&lt;br /&gt;
| Composer&lt;br /&gt;
|-&lt;br /&gt;
| DISC&lt;br /&gt;
| Disc number of a CD set&lt;br /&gt;
|-&lt;br /&gt;
| FILESIZE&lt;br /&gt;
| File size, in kilobytes&lt;br /&gt;
|-&lt;br /&gt;
| FILETIME&lt;br /&gt;
| Last known file date/time on disk&lt;br /&gt;
|-&lt;br /&gt;
| FOLDER&lt;br /&gt;
| Containing folder&lt;br /&gt;
|-&lt;br /&gt;
| LASTUPD&lt;br /&gt;
| Date/time of file imported to library or modified in library&lt;br /&gt;
|-&lt;br /&gt;
| LASTPLAY&lt;br /&gt;
| Date/time of last play&lt;br /&gt;
|-&lt;br /&gt;
| RATING&lt;br /&gt;
| Rating value (1-5, or 0 or empty for unrated)&lt;br /&gt;
|-&lt;br /&gt;
| PLAYCOUNT&lt;br /&gt;
| Number of plays&lt;br /&gt;
|-&lt;br /&gt;
| PUBLISHER&lt;br /&gt;
| Publisher or record label&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_ALBUM_GAIN&lt;br /&gt;
| ReplayGain Album Gain&lt;br /&gt;
|-&lt;br /&gt;
| REPLAYGAIN_TRACK_GAIN&lt;br /&gt;
| ReplayGain Track Gain&lt;br /&gt;
|-&lt;br /&gt;
| BITRATE&lt;br /&gt;
| Bitrate (in KBPS)&lt;br /&gt;
|-&lt;br /&gt;
| TRACKS&lt;br /&gt;
| Total number of tracks on the disc&lt;br /&gt;
|-&lt;br /&gt;
| DISCS&lt;br /&gt;
| Total number of discs in the set&lt;br /&gt;
|-&lt;br /&gt;
| ISPODCAST&lt;br /&gt;
| 1 for a podcast episode, 0 otherwise&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTCHANNEL&lt;br /&gt;
| The name of the channel for a podcast&lt;br /&gt;
|-&lt;br /&gt;
| PODCASTPUBDATE&lt;br /&gt;
| Date/time when the podcast was published&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Field Names:'''&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Comparison Operator&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| '='&lt;br /&gt;
| String or integer equals value&lt;br /&gt;
|-&lt;br /&gt;
| '!='&lt;br /&gt;
| String or integer does not equal value	&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;'&lt;br /&gt;
| String or integer is less than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;'&lt;br /&gt;
| String or integer is greater than value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;lt;='&lt;br /&gt;
| String or integer is less than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| '&amp;gt;='&lt;br /&gt;
| String or integer is greater than or equal to value&lt;br /&gt;
|-&lt;br /&gt;
| HAS&lt;br /&gt;
| String contains value&lt;br /&gt;
|-&lt;br /&gt;
| NOTHAS&lt;br /&gt;
| String does not contain value&lt;br /&gt;
|-&lt;br /&gt;
| LIKE&lt;br /&gt;
| String is similar to value (&amp;quot;the&amp;quot; and whitespace are ignored)&lt;br /&gt;
|-&lt;br /&gt;
| BEGINS&lt;br /&gt;
| String begins with value&lt;br /&gt;
|-&lt;br /&gt;
| BEGINSLIKE&lt;br /&gt;
| String begins like value&lt;br /&gt;
|-&lt;br /&gt;
| ENDS&lt;br /&gt;
| String ends with value&lt;br /&gt;
|-&lt;br /&gt;
| ISEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is empty&lt;br /&gt;
|-&lt;br /&gt;
| ISNOTEMPTY&lt;br /&gt;
| (no comparison value required) TRUE if &amp;lt;field&amp;gt; is not empty&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Values can be:'''&lt;br /&gt;
*&amp;quot;strings with spaces&amp;quot; or strings_without_spaces&lt;br /&gt;
*integers can be &amp;quot;32&amp;quot; or just 32&lt;br /&gt;
*integers for LENGTH can be a plain integer (seconds), or mm:ss or hh:mm:ss&lt;br /&gt;
*date/timestamps should be [datetime data], which can be either an absolute or relative time. i.e.: [3 weeks ago], [18:15],  [05/30/2003], [yesterday noon], [3 days ago 5 pm], [now], [5 mn before may 30th], etc.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Application API ==&lt;br /&gt;
===Methods===&lt;br /&gt;
&lt;br /&gt;
====LaunchURL()====&lt;br /&gt;
The Application.LaunchURL() method launches a URL in the bento browser&lt;br /&gt;
or default browser.  The default browser is launched if force_external = true or in skins that don't define a browser.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 boolean LaunchURL(url, force_external);&lt;br /&gt;
 where:&lt;br /&gt;
      '''url''' = (string) The url to open in the browser&lt;br /&gt;
      '''force_external''' = (boolean) will force the url to be displayed in a browser&lt;br /&gt;
           outside of the Winamp client.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &lt;br /&gt;
 var rc = LaunchURL(&amp;lt;nowiki&amp;gt;&amp;quot;http://www.winamp.com&amp;quot;&amp;lt;/nowiki&amp;gt;, true); &lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
A boolean value indicating whether the request was successful.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====int version (read only)====   &lt;br /&gt;
The version property returns the version number of the browser control within the Winamp client as an integer, e.g. 555 for 5.55,  560 for 5.6&lt;br /&gt;
====string versionstring (read only)====&lt;br /&gt;
The versionstring property returns the version number of the browser control within the Winamp client as a string, e.g. &amp;quot;5.55&amp;quot; for 5.55&lt;br /&gt;
====string language (read only) ====&lt;br /&gt;
Language identifier from the currently installed language pack.  Follows ISO 639-1 two letter language codes&lt;br /&gt;
&lt;br /&gt;
====string languagepack (read only) ====&lt;br /&gt;
Language pack identifier from the currently installed language pack.  follows the form&lt;br /&gt;
lc-CC&lt;br /&gt;
where lc is the two letter ISO 639-1 language code&lt;br /&gt;
and CC is the two letter ISO 3166 country code.&lt;br /&gt;
&lt;br /&gt;
Note: do not count on the country code being the same as the user's current location.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
== Security API ==&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetActionAuthorization()====&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
  GetActionAuthorization(group, action);&lt;br /&gt;
  where:&lt;br /&gt;
      '''group''' = (string) a group of related methods, i.e. the API name.&lt;br /&gt;
      '''action''' = (string) a specific method within a group.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var auth = window.external.Security.GetActionAuthorization(&amp;quot;application&amp;quot;, &lt;br /&gt;
           &amp;quot;launchurl&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value: an integer representing the following results&lt;br /&gt;
&lt;br /&gt;
*ACTION_UNDEFINED = -1,&lt;br /&gt;
*ACTION_DISALLOWED = 0,&lt;br /&gt;
*ACTION_PROMPT = 1,&lt;br /&gt;
*ACTION_ALLOWED = 2,&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Skin API ==&lt;br /&gt;
&lt;br /&gt;
The skin color API is a bit of a challenge.  This API reflects some the idiosyncrasies of the underlying skinning system.  &amp;quot;Classic&amp;quot; skins define a palette of 24 colors for the skin and an additional 6 colors for the playlist editor.  &amp;quot;Modern&amp;quot; skins define these as well as any number of other colors retrievable by name (e.g. wasabi.tree.text for the text color on tree views).  A website relying on any of these extra &amp;quot;named&amp;quot; colors should be careful to implement a fallback color based on the classic palette, as no named colors exist in classic skins!&lt;br /&gt;
&lt;br /&gt;
===Methods===&lt;br /&gt;
====GetClassicColor()====&lt;br /&gt;
The Skin.GetClassicColor() method is used to retrieve color information regarding different Skin UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetClassicColor(classiccolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''classiccolornumber''' = (integer) A number in the range 0-23 identifying the Skin's UI element &lt;br /&gt;
         for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var wndBgColor = window.external.Skin.GetClassicColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Skin UI element.&lt;br /&gt;
&lt;br /&gt;
====Classic Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|  0 &lt;br /&gt;
| Item Background&lt;br /&gt;
|-&lt;br /&gt;
|  1 &lt;br /&gt;
| Item Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  2 &lt;br /&gt;
| Window Background&lt;br /&gt;
|-&lt;br /&gt;
|  3 &lt;br /&gt;
| Button Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  4 &lt;br /&gt;
| Window Foreground&lt;br /&gt;
|-&lt;br /&gt;
|  5 &lt;br /&gt;
| Hilite&lt;br /&gt;
|-&lt;br /&gt;
|  6 &lt;br /&gt;
| Selection&lt;br /&gt;
|-&lt;br /&gt;
|  7 &lt;br /&gt;
| List Header Background&lt;br /&gt;
|-&lt;br /&gt;
|  8 &lt;br /&gt;
| List Header Text&lt;br /&gt;
|-&lt;br /&gt;
|  9 &lt;br /&gt;
| List Header Frame Top&lt;br /&gt;
|-&lt;br /&gt;
| 10 &lt;br /&gt;
| List Header Frame Middle&lt;br /&gt;
|-&lt;br /&gt;
| 11 &lt;br /&gt;
| List Header Frame Bottom&lt;br /&gt;
|-&lt;br /&gt;
| 12 &lt;br /&gt;
| List Header Empty Background&lt;br /&gt;
|-&lt;br /&gt;
| 13 &lt;br /&gt;
| Scrollbar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 14 &lt;br /&gt;
| Scrollbar Background&lt;br /&gt;
|-&lt;br /&gt;
| 15 &lt;br /&gt;
| Scrollbar Inverse Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 16 &lt;br /&gt;
| Scrollbar Inverse Background&lt;br /&gt;
|-&lt;br /&gt;
| 17 &lt;br /&gt;
| Scrollbar Dead Area&lt;br /&gt;
|-&lt;br /&gt;
| 18 &lt;br /&gt;
| Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 19 &lt;br /&gt;
| Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 20 &lt;br /&gt;
| Inactive Selection Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 21 &lt;br /&gt;
| Inactive Selection Bar Background&lt;br /&gt;
|-&lt;br /&gt;
| 22 &lt;br /&gt;
| Alternating Item Background&lt;br /&gt;
|-&lt;br /&gt;
| 23 &lt;br /&gt;
| Alternating Item Foreground&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetPlaylistColor()====&lt;br /&gt;
The Skin.GetPlaylistColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetPlaylistColor(playlistcolornumber);&lt;br /&gt;
  where:&lt;br /&gt;
    '''playlistcolornumber''' = (integer) a number in the range 0-5 identifying the Playlist's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var normalBgColor = window.external.Skin.GetPlaylistColor(2);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Playlist Color Numbers====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Number&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 &lt;br /&gt;
| Normal&lt;br /&gt;
|-&lt;br /&gt;
| 1 &lt;br /&gt;
| Current&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| Normal Background&lt;br /&gt;
|-&lt;br /&gt;
| 3 &lt;br /&gt;
| Selected Background&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| Video Window Status Bar Foreground&lt;br /&gt;
|-&lt;br /&gt;
| 5 &lt;br /&gt;
| Video Window Status Bar Background&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====GetSkinColor()====&lt;br /&gt;
The Skin.GetSkinColor() method is used to retrieve color information regarding different Playlist UI elements.&lt;br /&gt;
&lt;br /&gt;
Prototype:&lt;br /&gt;
 GetSkinColor(skincolorname);&lt;br /&gt;
  where:&lt;br /&gt;
    '''skincolorname''' = (string) identifying the Skin's UI &lt;br /&gt;
         element for which the color should be returned.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
  var buttonTextColor = window.external.Skin.GetSkinColor(&amp;quot;wasabi.button.text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Return value:&lt;br /&gt;
The HTML color constant used for the specified Playlist UI element.&lt;br /&gt;
&lt;br /&gt;
====Skin Color Names====&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.item.selected.fg&amp;quot;&lt;br /&gt;
|Selected item text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.list.column.separator&amp;quot; &lt;br /&gt;
|Color of line between columns&lt;br /&gt;
|-&lt;br /&gt;
|'''Item Lists, Lists with playable items'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.current&amp;quot;  &lt;br /&gt;
|Currently playing outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.outline.focus&amp;quot;  &lt;br /&gt;
|Focused item dashed outline color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.itemlist.selborder&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|'''Message box'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.msgBox.background&amp;quot;   &lt;br /&gt;
|Messagebox background color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.text&amp;quot;  &lt;br /&gt;
|Text object &amp;amp; message box text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.textBar.background&amp;quot;   &lt;br /&gt;
|Text object &amp;amp; message box text background color&lt;br /&gt;
|-&lt;br /&gt;
|'''Buttons'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.text&amp;quot;  &lt;br /&gt;
|Buttons text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.hiliteText&amp;quot; &lt;br /&gt;
|Buttons hilite text color, used by tab windows&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.button.dimmedText&amp;quot;  &lt;br /&gt;
|Buttons dimmed text color, when disabled&lt;br /&gt;
|-&lt;br /&gt;
|'''Popup menus'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.text&amp;quot;  &lt;br /&gt;
|Menu items text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.hiliteText&amp;quot;  &lt;br /&gt;
|Hilited item text color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.popup.dimmedText&amp;quot;  &lt;br /&gt;
|Disabled item text color&lt;br /&gt;
|-&lt;br /&gt;
|'''Components'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.foreground&amp;quot;  &lt;br /&gt;
|Old title bar text color when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.component.title.border&amp;quot;  &lt;br /&gt;
|Old title bar text outline when using TTF&lt;br /&gt;
|-&lt;br /&gt;
|'''Labeled Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.foreground&amp;quot;  &lt;br /&gt;
|Text foreground color&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.labelwnd.background&amp;quot; &lt;br /&gt;
|Text drop shadow color&lt;br /&gt;
|-&lt;br /&gt;
|'''Edit Windows'''&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.selection&amp;quot;  &lt;br /&gt;
|Selected text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.text&amp;quot; &lt;br /&gt;
|Text&lt;br /&gt;
|-&lt;br /&gt;
|&amp;quot;wasabi.edit.background&amp;quot;  &lt;br /&gt;
|Text background&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|  &amp;quot;wasabi.text.color.inverse&amp;quot; &lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
====string name (test)====&lt;br /&gt;
The Skin.name property gives access to the name of skin currently in use.  Changing this value will change the skin displayed for the player.&lt;br /&gt;
&lt;br /&gt;
====string font (read only)====&lt;br /&gt;
The Skin.font property provides the font name currently used in the player.&lt;br /&gt;
&lt;br /&gt;
====string fontsize (read only)====&lt;br /&gt;
The Skin.fontsize property provides the size of the font currently used in the player.&lt;br /&gt;
&lt;br /&gt;
== Metadata tag names ==&lt;br /&gt;
&lt;br /&gt;
When retrieving metadata through Winamp, a freeform string is passed.  The popular file formats (MP3, WMA, FLAC, M4A) will respond uniformly to a common base of strings.  However, each file format is idiosyncratic in how metadata is stored.  Some file types will respond to additional strings which are not documented here.&lt;br /&gt;
&lt;br /&gt;
Remember that the metadata is only as good as the tagging in the file itself.  A poorly tagged track will return poor metadata.&lt;br /&gt;
&lt;br /&gt;
Common metadata tags&lt;br /&gt;
 bitrate&lt;br /&gt;
 length&lt;br /&gt;
 type&lt;br /&gt;
 title&lt;br /&gt;
 artist&lt;br /&gt;
 albumartist&lt;br /&gt;
 album&lt;br /&gt;
 genre&lt;br /&gt;
 year&lt;br /&gt;
 disc&lt;br /&gt;
 publisher&lt;br /&gt;
 comment&lt;br /&gt;
 track&lt;br /&gt;
 composer&lt;br /&gt;
 conductor&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Online_Service_Developer</id>
		<title>Online Service Developer</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Online_Service_Developer"/>
				<updated>2009-01-22T15:37:35Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: New page: '''Breadcrumb''' -- Wiki Main : Skin Developer : Visual Developer : Plug-in Developer : Online Service Developer : Articles Page : [[Developers F...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
[[Category:Winamp]]&lt;br /&gt;
==The What and Why of Online Services==&lt;br /&gt;
===What is a Winamp Online Service===&lt;br /&gt;
A Winamp online service has several distinctive features.  The first is that it is a web site that appears embedded within the Winamp client.  The second, and more fun feature, is that the web pages so displayed are able to interact with the Winamp Client.  The third is that access to the online services is presented to the large Winamp community as part of the Winamp client's Online Services Gallery.&lt;br /&gt;
&lt;br /&gt;
===Benefits to creating an Online Service===&lt;br /&gt;
There are many benefits for developing an Online Service. Before we delved into the list, the most important benefit is distribution. Winamp is a great distribution platform as it has 77 million unique users every month!!&lt;br /&gt;
&lt;br /&gt;
Hence,&lt;br /&gt;
a) if your website needs page views and more monetization&lt;br /&gt;
b) if your brand needs more eye balls&lt;br /&gt;
c) if your blog needs more readers&lt;br /&gt;
d) if you want to develop an web application which has something to do with music, video, photo, streaming, podcasts, music events, e-commerce, games&lt;br /&gt;
&lt;br /&gt;
then you will never regret making an Online Service in Winamp.&lt;br /&gt;
&lt;br /&gt;
Try it now!&lt;br /&gt;
&lt;br /&gt;
===Integrating Online Services with Winamp===&lt;br /&gt;
The Winamp Online Services API is designed to allow web pages, hosted (displayed) within the embedded browser of the Winamp client.  In order to make this happen you have to do the following:&lt;br /&gt;
&lt;br /&gt;
*Make sure you have the latest version 5.55 (or above) of the Winamp client. You can download the client from this [http://forums.winamp.com/showthread.php?threadid=302079 forum link]&lt;br /&gt;
*Make sure you have the latest version of the ml_webdev plugin (ml_webdev.dll). Get the plugin from this  [http://dev.winamp.com/downloads.php link].  This plugin will create a &amp;quot;Web Dev Test Platform&amp;quot; within the Medial Library pane. It has it's own special installer.&lt;br /&gt;
&lt;br /&gt;
In order to change the starting web page for the online service, start the Winamp client and configure the plugin. &lt;br /&gt;
#Open the Winamp player&lt;br /&gt;
#Select Options-&amp;gt;Preferences-&amp;gt;Plug-ins-&amp;gt;Media Library. &lt;br /&gt;
#Select &amp;quot;API 2 Test Platform&amp;quot; and press &amp;quot;Configure selected plugin&amp;quot;. &lt;br /&gt;
#On the Web Dev Preferences dialog, set the URL field to the URL of the initial web page for the online service. For example, file://c:\myonlineservice\webdev.html &lt;br /&gt;
#Click on &amp;quot;Web Dev Test Platform&amp;quot; in the Media Library. You may have to right click and choose refresh to see the new web page. &lt;br /&gt;
You should now see the initial page of your online service in the Winamp embedded browser.&lt;br /&gt;
&lt;br /&gt;
==Registering an Account==&lt;br /&gt;
While you can start developing an online service immediately, you will need to create a Winamp account before you can submit your service.  To do this follow these steps:&lt;br /&gt;
*Open your favorite web browser and go to http://www.winamp.com&lt;br /&gt;
*Choose &amp;quot;Register&amp;quot; from the top of the page.&lt;br /&gt;
*Enter your First Name.&lt;br /&gt;
*Enter your Last Name.&lt;br /&gt;
*Enter an email address where you can be contacted. (Note: the email must be unique for each registration as this is used as your Login name.)&lt;br /&gt;
*Enter a password to use when you login.&lt;br /&gt;
*Enter your Birthdate.&lt;br /&gt;
*Click on the TERMS link and read the Winamp.com Terms of Use.&lt;br /&gt;
*Click BACK to return to the registration form.&lt;br /&gt;
*Make sure the checkbox is checked to say you've read and agree to the TERMS.&lt;br /&gt;
*Click the &amp;quot;register&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
==Submitting an Online Service==&lt;br /&gt;
===The Submission Process===&lt;br /&gt;
Once you have come up with an amazing idea for an Online Service that uses Winamp, how do you get it into the Winamp Online Services Gallery so that users can start visiting it?  Glad you asked.  First you must start by submitting the service to Winamp.  After being submitted, the service will go through a Winamp internal review process.  If the service passes the review it will then be automatically included in the Winamp Online Services Gallery.&lt;br /&gt;
&lt;br /&gt;
The progress of your service through these steps can be seen through the use of the &amp;quot;My Profile&amp;quot; link at the top of the Winamp.com main page after logging in.&lt;br /&gt;
&lt;br /&gt;
====Submitting an Online Service====&lt;br /&gt;
*Login to www.winamp.com&lt;br /&gt;
**Navigate to www.winamp.com&lt;br /&gt;
**Select &amp;quot;Winamp.com: Login&amp;quot; from the top of the page&lt;br /&gt;
**Enter the email address and password specified when you registered your account.&lt;br /&gt;
**Mouse over the gold &amp;quot;Online Services&amp;quot; button at the top of the screen.&lt;br /&gt;
**Choose &amp;quot;submit an online service&amp;quot; from the buttons in the drop down&lt;br /&gt;
**Make sure you follow the guidelines specified and press &amp;quot;Proceed&amp;quot;.&lt;br /&gt;
**Enter the following information on the form:&lt;br /&gt;
***Service Name (15 characters max) - This name will be displayed on the first line for the service in the Winamp Gallery.&lt;br /&gt;
***Description (750 characters max) - Enter text describing your online service.&lt;br /&gt;
***Online Service URL - Enter the URL to launch your service.&lt;br /&gt;
***Categories - Select two categories so your service can be grouped with other services.&lt;br /&gt;
***Tags - Enter tags so that users can find your service by searching&lt;br /&gt;
***Thumbnail Image (optional, .gif, .jpg, .png, max size 178x75 pixels) - Displayed in the Winamp Gallery.&lt;br /&gt;
***Installer Image (optional, .gif, .jpg, .png, max size, 64x64 pixels - Displayed by Winamp Installer &lt;br /&gt;
***List Icon Image (optional, .gif, .jpg, .pgn, max size: 16x16 pixels - Displayed in the Winamp &amp;quot;Media Library&amp;quot; pane.&lt;br /&gt;
***Country - Select the countries which your online service supports.&lt;br /&gt;
***Language - Select the languages which your online service supports.&lt;br /&gt;
***Customer Support Email Id - An email address where user comments/complaints will be sent.&lt;br /&gt;
***Click and read the Terms and Conditions&lt;br /&gt;
***Check &amp;quot;Agree to Terms and Conditions&lt;br /&gt;
***Click &amp;quot;Finish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=====Categories/Types of Online Services=====&lt;br /&gt;
*Events&lt;br /&gt;
*Streaming&lt;br /&gt;
*Podcasts&lt;br /&gt;
*Photo&lt;br /&gt;
*Music&lt;br /&gt;
*Video&lt;br /&gt;
*Radio&lt;br /&gt;
*E-Commerce&lt;br /&gt;
*Artists&lt;br /&gt;
*Games&lt;br /&gt;
*Internet TV&lt;br /&gt;
*Others&lt;br /&gt;
&lt;br /&gt;
=====Tags Vs. Categories=====&lt;br /&gt;
You can tag/categorize a piece of information in your site and allows this piece of information to be searched and indexed. &lt;br /&gt;
&lt;br /&gt;
So what are categories? Categories help you organize your content under a more familiar taxonomy. By familiar, we mean non-unique and non-personal words; thereby allowing a user to navigate your content with ease knowing what they want. That's the reason why we have fixed the categories. They are Music, Video, Radio, E-Commerce, Photo, Artists, Streaming, Podcast, Games, Internet TV, Events and Other. This will also give you a clear indication on what you can actually create. And if you think you can create something else, there is always the 'Other' category.&lt;br /&gt;
&lt;br /&gt;
Then why do we need tags? Well, you can personalize your Online Service with your own tags. For e.g. for a hypothetical online service Music Shoppe (Let's say) tags can be 'music shoppe', 'music shop', 'buy music', 'music shop', 'music store' whereas categories can be broader like 'music' &amp;amp; 'e-commerce'. All you have to do is make them short, crisp, relevant (search compatible) and small in numbers so that they are relevant.&lt;br /&gt;
&lt;br /&gt;
Tags will be introduced shortly. Till then, please use categories :)&lt;br /&gt;
&lt;br /&gt;
===Monitoring the Status of your Submission with &amp;quot;My Profile&amp;quot;===&lt;br /&gt;
After you have successfully submitted an online service, Winamp will put it through a review process.  You can check the status of your online service by examining the &amp;quot;My Profile&amp;quot; link in the upper right of the screen after logging in to www.winamp.com.&lt;br /&gt;
&lt;br /&gt;
Note that once you go to your profile, there are three links, one for each of the types of submissions you may have made.  Choose &amp;quot;Online Services&amp;quot; to see that type.&lt;br /&gt;
&lt;br /&gt;
The online service will proceed thru the following stages:&lt;br /&gt;
&lt;br /&gt;
#Online Services in Review - The online service has been submitted and is awaiting review&lt;br /&gt;
#Approved Online Services - The service has been reviewed and is waiting to be either published or rejected.  An online service should only stay in this state for a short time.&lt;br /&gt;
#Published Online Services - The online service was found to be acceptable and is now available in the Winamp Gallery.&lt;br /&gt;
#Rejected Online Services - The online service was found to be '''un'''-acceptable and is '''not''' available in the Winamp Gallery.&lt;br /&gt;
&lt;br /&gt;
===Managing your Online Service with &amp;quot;My Profile&amp;quot;===&lt;br /&gt;
Once your online service has been published, there are several things you can do to manage it through the My Profile page.&lt;br /&gt;
&lt;br /&gt;
====Viewing Service Information====&lt;br /&gt;
Each published online service will show the following:&lt;br /&gt;
*Unique ID - A ID that uniquely identifies your online service.&lt;br /&gt;
*Version # - The current version number of your online service.&lt;br /&gt;
*Description - The description you typed when submitting the service.&lt;br /&gt;
*First Published on - Date on which this online service was first published. &lt;br /&gt;
*Last Edited on - Last date this online services was edited.&lt;br /&gt;
*Last Approved on - Last date this online service was approved. &lt;br /&gt;
*Reporting On - A section showing the following statistics&lt;br /&gt;
**Service has been added - The service is available in the gallery.&lt;br /&gt;
**Service has been removed - The service is not available and has been deleted.&lt;br /&gt;
**Service has been accessed - The number of times users have accessed the site through the Winamp Client.&lt;br /&gt;
**Unique Users - The number of views by unique (i.e., new ip addresses) users.&lt;br /&gt;
**Ratings - Average user rating.&lt;br /&gt;
**Number of Ratings - How many users have rated the online service&lt;br /&gt;
**Abuse Reports - How many abuse reports have been sent against this service.&lt;br /&gt;
&lt;br /&gt;
====Editing your Online Service Info====&lt;br /&gt;
My Profile contains an '''EDIT''' button so you can change the details that you entered when you first submitted the online service for review.  This button will take you to a form where you can change these values.  Changing the values will increase the version number of the online service and submit the service for review.&lt;br /&gt;
&lt;br /&gt;
====Removing your Online Service====&lt;br /&gt;
My Profile also has a '''REMOVE''' button so the author can delete the online service.  To reinstate the service you will have to resubmit it.&lt;br /&gt;
&lt;br /&gt;
====Hiding your Online Service====&lt;br /&gt;
'''Hide from Gallery''' will prevent the online service from appearing in the Winamp client online services gallery.  This can be used to temporarily prevent users from subscribing to the service.&lt;br /&gt;
&lt;br /&gt;
==Style Guide==&lt;br /&gt;
Some tips for Online Service developers:&lt;br /&gt;
 &lt;br /&gt;
*Be aware that online services are rendered within the Winamp client browser so make sure you take into account the size available to your service.&lt;br /&gt;
*Make use of the Winamp Javascript API methods.  Online services should exercise the power of the Winamp client to improve user experience.  For example, you might want to use the Skins API to adjust the colors of your service to blend with the client.&lt;br /&gt;
&lt;br /&gt;
==JavaScript APIs==&lt;br /&gt;
Here is a summary of the API methods that can be called from an online service.&lt;br /&gt;
&lt;br /&gt;
For more details on the methods available check out the [[complete JavaScript API technology framework]]&lt;br /&gt;
&lt;br /&gt;
*Transport API&lt;br /&gt;
**Play &lt;br /&gt;
**Stop&lt;br /&gt;
**Pause&lt;br /&gt;
**Advance to next track&lt;br /&gt;
**Back up to previous track&lt;br /&gt;
**Shuffle&lt;br /&gt;
**Repeat&lt;br /&gt;
**Event Notifications - so the web page can tell when the events happen&lt;br /&gt;
***When the player starts playing&lt;br /&gt;
***When the player is stopped&lt;br /&gt;
***When the player is paused&lt;br /&gt;
***When the player reaches the end of a file &lt;br /&gt;
**Metadata - get metadata for currently playing song&lt;br /&gt;
**position - change the playback position of currently playing song&lt;br /&gt;
 &lt;br /&gt;
*Playqueue API&lt;br /&gt;
**The ability to alter the Winamp Queue of songs about to be played.&lt;br /&gt;
***Play - clear the queue and play a song.&lt;br /&gt;
***Enqueue -  add a song to the queue&lt;br /&gt;
***Insert - add a song to the queue at a position&lt;br /&gt;
***Clear - clear the queue&lt;br /&gt;
***Metadata - get metadata for a song in the queue&lt;br /&gt;
 &lt;br /&gt;
*Playlists API&lt;br /&gt;
**Get a list of all playlists&lt;br /&gt;
**Open a playlist for alteration&lt;br /&gt;
**Save a modified playlist&lt;br /&gt;
 &lt;br /&gt;
*Playlist methods - once a playlist is opened these are available.&lt;br /&gt;
**Get and set info about individual items in the playlist&lt;br /&gt;
**Swap two songs&lt;br /&gt;
**Randomize the order of songs&lt;br /&gt;
**Reverse the order of songs&lt;br /&gt;
**Sort By Filename&lt;br /&gt;
**Sort By Title&lt;br /&gt;
**Clear (empty) the playlist&lt;br /&gt;
 &lt;br /&gt;
*Bookmarks API&lt;br /&gt;
**Add a bookmark&lt;br /&gt;
**TBD&lt;br /&gt;
 &lt;br /&gt;
*Podcasts API&lt;br /&gt;
**Subscribe to a Podcast&lt;br /&gt;
**More TBD&lt;br /&gt;
 &lt;br /&gt;
*Secuirty API&lt;br /&gt;
**In place, but not fully ready&lt;br /&gt;
**TBD&lt;br /&gt;
 &lt;br /&gt;
*LocalMedia API&lt;br /&gt;
**TBD&lt;br /&gt;
 &lt;br /&gt;
*History API&lt;br /&gt;
**Query the History DB - retrieve info about songs played previously&lt;br /&gt;
 &lt;br /&gt;
*Config API&lt;br /&gt;
**The ability to store JavaScript properties persistantly.&lt;br /&gt;
 &lt;br /&gt;
*Application API&lt;br /&gt;
**Launch the internal Winamp browser.&lt;br /&gt;
**Launch an external browser.&lt;br /&gt;
**Get the version of the internal browser.&lt;br /&gt;
**Get the language pack info&lt;br /&gt;
 &lt;br /&gt;
*Skins API&lt;br /&gt;
**Retrieve color and font information regarding the currently assigned Winamp client skin.&lt;br /&gt;
 &lt;br /&gt;
*MediaCore API&lt;br /&gt;
**Retrieve metadata for a specified file&lt;br /&gt;
**Determine whether a specific file format (file extension) is supported by the Winamp Client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User Feedback==&lt;br /&gt;
There are several methods by which users can provide feedback on your online service.&lt;br /&gt;
&lt;br /&gt;
===Ratings by Users===&lt;br /&gt;
The Winamp client allows users to rate your online service.  You can see the average rating and the number of times that your service has been rated using the &amp;quot;My Profile&amp;quot; link on winamp.com after logging in.  This way you can tell whether thousands of people adore your service, or perhaps it was a single rating from your best friend.&lt;br /&gt;
===Abuse Reporting===&lt;br /&gt;
Users can also complain if they find something objectionable.  These &amp;quot;abuse reports&amp;quot; may be forwarded to the online service developer to be resolved.  So don't do bad things.  And no, SlyHawk, parcour will not help you here.&lt;br /&gt;
&lt;br /&gt;
==Additional Considerations==&lt;br /&gt;
===Security===&lt;br /&gt;
In order to help protect users from potential abuse by online services, Winamp has implemented a strategy to notify users that a web service is about to issue one of the online service api methods.  The warning message will ask the user whether the method should proceed.  Each security prompt will be applied to the action being requested as well as certain related actions of the same API.  There is also a way to indicate that the selection should be used for ALL other security prompts for the current online service.  This prevents the user from being bombarded with what may sound like repetitive requests.  If the author of the online service upgrades their service, these choices will be carried forward to the new release.&lt;br /&gt;
&lt;br /&gt;
For a more in depth discussion of the security prompts go to [[Online Service Security Prompts]].&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	<entry>
		<id>http://wiki.shoutcast.com/wiki/Main_Page</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://wiki.shoutcast.com/wiki/Main_Page"/>
				<updated>2009-01-22T15:37:05Z</updated>
		
		<summary type="html">&lt;p&gt;SMonty: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Breadcrumb''' -- [[Main_Page|Wiki Main]] : [[Skin Developer]] : [[Visual Developer]] : [[Plug-in Developer]] : [[Online Service Developer]] : [[Articles|Articles Page]] : [[Developers FAQ|FAQ]] : [[Main_Page#Glossary_of_Terms|Glossary]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Welcome ==&lt;br /&gt;
Welcome to Winamp's Developer Network wiki.  By consolidating Winamp documentation, code samples, reference materials, and sample articles, we've created a one-stop shop for all things related to Winamp development. The purpose of this site is to help facilitate the development of [[Skin_Developer|Winamp skins]], [[Plug-in_Developer|plug-ins]],  [[Visual_Developer|visualization presets]] and [[Online_Service_Developer|online services]].  In order to offer the most relevant material (''and since no one is more of an expert than you''), our goal is to present a wiki that is updated, maintained, and moderated by the Winamp developer community.&lt;br /&gt;
&lt;br /&gt;
Why develop for Winamp, you ask?  Besides being a kickass media player with a flexible programming platform, Winamp has a very loyal fan base with over 72 million worldwide users per month. So chances are your creative masterpiece will live well beyond the boundaries of your hard drive.  Now that we've got your creative juices flowing (or at a minimum, appealed to your desire for fame and adoration), you can use the '''Developer Network''' as a springboard for everything you need.  Most importantly, you can [http://www.winamp.com/user/submit upload] your creation and share it with the World. ''(Note: You'll need a winamp.com account to upload).''&lt;br /&gt;
&lt;br /&gt;
=== How to use the Wiki ===&lt;br /&gt;
There are several ways that you can use this wiki.  Use it as a reference guide.  Start sifting through the content to find the information you need to start developing.  If you find out that some key information is missing or you see that something on the site is completely inaccurate, we welcome your contributions.  We'd love for you to update the site with killer content and [[Articles]].  Before you start contributing though, make sure you check out the Developer Network [[Policies &amp;amp; Guidelines]] page and create an account.  By creating an account or logging into the Winamp Developer Network, you are agreeing to our [[Winamp Developer Network Wiki Terms and Conditions|Terms of Service]] and [http://www.winamp.com/legal/privacy Privacy Policy]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you've never edited a wiki before, you might want to check out [http://en.wikipedia.org/wiki/Wikipedia:How_to_edit_a_page Wikipedia: How to edit a page]for some pointers.&lt;br /&gt;
&lt;br /&gt;
== Who Should Use the Wiki ==&lt;br /&gt;
This wiki is for everyone.  Whether you're a seasoned vet, intermediate coder, loyal fan, or even newbie.  Primarily though, it's for Winamp developers and user-contributors who want to be actively engaged in the advancement of the Winamp media player.  Either by leveraging the content of this site to build better '''skins''', '''plug-ins''', '''visualizations''' and '''online services'''; or by sharing your knowledge and expertise with the community.&lt;br /&gt;
&lt;br /&gt;
===Skin Developer===&lt;br /&gt;
To put it as simply as possible, skins change the way your Winamp player looks. If you want to get fancy and say that it changes the GUI (graphical user interface) then you can, but really all you need to know is if you download or create a new skin, Winamp will put on a little mask and pretend to look different.  Check [[Skin Developer]] page for more details.&lt;br /&gt;
&lt;br /&gt;
====Classic Skins====&lt;br /&gt;
Based on the Winamp 2 model, [[Skin_Developer#Creating_Classic_Skins|Classic skins]] are easier to create than Modern skins, but they do not allow the developer to change the form or function of the player. [[Skin_Developer#Creating_Classic_Skins|Classic skins]] developers may only replace a standard set of images that alter the player's visual appearance.&lt;br /&gt;
&lt;br /&gt;
====Modern Skins====&lt;br /&gt;
[[Skin_Developer#Creating_Modern_Skins|Modern skins]] are skins that adhere to the Winamp 3+ skin model. Modern (or freeform) skins offer developers a tremendous amount of flexibility by allowing you to change the player's shape, size, layout, and function. Learn how to create a modern skin for Winamp!&lt;br /&gt;
&lt;br /&gt;
=== Visual Developer===&lt;br /&gt;
You know those funny dancing colors you see when you hear music – and no ''Autumn Moonpuppy'', I’m not talking about that time you &amp;quot;toured&amp;quot; with The Dead.  [[Visual_Developer|Visualizers]] are dynamic add-ons that produce images, colors, and textures that change based elements of the music being played.  Winamp offers two primary visualization platforms (AVS &amp;amp; MilkDrop) allowing you to create different presets.  If you’re feeling invincible, you can even attempt to create your own visualization environment.&lt;br /&gt;
&lt;br /&gt;
=== Plug-in Developer===&lt;br /&gt;
&lt;br /&gt;
[[Plug-in_Developer|Plug-ins]] can pretty much do anything! ...within reason, of course.  You can alter the sound of your music, turn your mobile phone into a Winamp remote control, or if ya’d like, translate Winamp into another language.  Basically, we’ve made the platform flexible enough so that you can craft your idyllic feature and plug it right into Winamp.&lt;br /&gt;
&lt;br /&gt;
'''Types of Plug-ins'''&lt;br /&gt;
&lt;br /&gt;
There are all kinds of categorizes of plug-ins:  Input, Output, Visualization, DSP/Effect, General Purpose, Media Library and Portables. That means, you can go nuts in discovering how a single plug-in can change your life. You can read up on the taxonomy of a plug-in here.&lt;br /&gt;
&lt;br /&gt;
'''Start Creating Your Plug-in'''&lt;br /&gt;
&lt;br /&gt;
If you feel like developing one yourself, you can – &lt;br /&gt;
# Check out the [[Plug-in_Developer#Tools|suggested tools]]&lt;br /&gt;
# Read-up on the [[Plug-in_Developer#SDK_Documentation|SDK documentation]]&lt;br /&gt;
# [http://download.nullsoft.com/winamp/plugin-dev/WA5.55_SDK.exe Download the SDK]&lt;br /&gt;
# Visit the [http://forums.winamp.com/ Winamp Forums]&lt;br /&gt;
# [http://www.winamp.com/user/login Submit your plug-in]. Ain’t it easy?&lt;br /&gt;
&lt;br /&gt;
=== Online Service Developer===&lt;br /&gt;
[[Online_Service_Developer|Online Services]] are web pages that are rendered by the embedded browser within Winamp.  The awesomeness of these pages is that they can interact with the Winamp Player.  In this way a web page can start and stop the player, examine and create playlists, enqueue songs for playback, the colors used in the skin of the player, etc.  We're excited to see what you come up with by merging html web pages and the Winamp player.&lt;br /&gt;
&lt;br /&gt;
== Developer Resources ==&lt;br /&gt;
*[[Articles]] - link consolidation of all articles written by all types of developers&lt;br /&gt;
*[[Plug-in_Developer#SDK_Documentation|SDK Documentation]]&lt;br /&gt;
* Download the SDK&lt;br /&gt;
*[[Developers_FAQ | Frequently Asked Questions]] &lt;br /&gt;
*[[Skin Developer]]&lt;br /&gt;
*[[Visual Developer]]&lt;br /&gt;
*[[Plug-in Developer]]&lt;br /&gt;
*[[Online Service Developer]]&lt;br /&gt;
&lt;br /&gt;
== Glossary of Terms ==&lt;br /&gt;
* '''Agent''' - Winamp's taskbar component. Maintains file type associations.&lt;br /&gt;
&lt;br /&gt;
* '''APE''' - Advanced Plug-in Effect. Third party Effect Module created for AVS.&lt;br /&gt;
&lt;br /&gt;
* '''AVS''' - Advanced Visualization Studio comes bundled with Winamp. Allows endless user customization.&lt;br /&gt;
&lt;br /&gt;
* '''Base Skin''' - The standard skin built into Winamp. Also the downloadable template used to create new skins.&lt;br /&gt;
&lt;br /&gt;
* '''Bookmark''' - Winamp feature that allows quick access to favorite songs or streams.&lt;br /&gt;
&lt;br /&gt;
* '''Codec''' - Short for coder/decoder. A software program for converting between digital data and analog signals. Winamp uses codecs to play many different kinds of audio files.&lt;br /&gt;
&lt;br /&gt;
* '''Developer''' - Any one who creates a skin or writes an application or plug-in for Winamp.&lt;br /&gt;
&lt;br /&gt;
* '''Discussion List''' - A mailing list hosted by Winamp.com to help foster the developer community.&lt;br /&gt;
&lt;br /&gt;
* '''DLL''' - Dynamically Linked Library. A Win32 property that allows Winamp's plug-in architecture.&lt;br /&gt;
&lt;br /&gt;
* '''DoubleSize Mode''' - Winamp option that doubles the width and height of the Main and Equalizer components.&lt;br /&gt;
&lt;br /&gt;
* '''DSP Plug-in''' - A plug-in that manipulates audio data before being sent to the speakers.&lt;br /&gt;
&lt;br /&gt;
* '''Easter Egg''' - A programming term used for a hidden, often humorous feature.&lt;br /&gt;
&lt;br /&gt;
* '''Equalizer''' - Winamp component that allows audio tweaking for optimal sound quality.&lt;br /&gt;
&lt;br /&gt;
* '''FAQ''' - Frequently Asked Questions.&lt;br /&gt;
&lt;br /&gt;
* '''Forum''' - A message board hosted by Winamp.com to help foster the Winamp community.&lt;br /&gt;
&lt;br /&gt;
* '''Flounder''' - Any of various marine flatfishes of the families Bothidae and Pleuronectidae, which include important food fishes.&lt;br /&gt;
&lt;br /&gt;
* '''General Purpose Plug-in''' - A plug-in that does not require access to audio data.&lt;br /&gt;
&lt;br /&gt;
* '''Input Plug-in''' - A plug-in that adds a new file type to Winamp's list of supported types.&lt;br /&gt;
&lt;br /&gt;
* '''IPC''' - Inter-process communication. Basically, anytime one program communicates with another.&lt;br /&gt;
&lt;br /&gt;
* '''Language Pack''' - A special plug-in that translates most Winamp text.&lt;br /&gt;
&lt;br /&gt;
* '''Llama''' - A domesticated South American ruminant mammal (Lama glama) related to the camel, raised for its soft, fleecy wool. The only animal fully endorsed by Nullsoft.&lt;br /&gt;
&lt;br /&gt;
* '''Mini-browser''' - Winamp component that allows internet browsing during audio play.&lt;br /&gt;
&lt;br /&gt;
* '''MP3''' - MPEG-1 Audio Layer 3. A digital audio compression algorithm that acheives a compression factor of about twelve while preserving sound quality.&lt;br /&gt;
&lt;br /&gt;
* '''NSDN''' - Nullsoft Developers Network. The developers source for official Nullsoft information.&lt;br /&gt;
&lt;br /&gt;
* '''NSIS''' - Nullsoft Scriptable Install System. Nullsoft's in-house installer utility. Required for plug-in installation.&lt;br /&gt;
&lt;br /&gt;
* '''Nullsoft''' - Group of benevolent artisans who revolutionize the computer world on a regular basis.&lt;br /&gt;
&lt;br /&gt;
* '''Output Plug-in''' - A plug-in that directs audio flow to one or more destinations.&lt;br /&gt;
&lt;br /&gt;
* '''PiMP''' - Plug-in Mini Packager. Predecessor to NSIS.&lt;br /&gt;
&lt;br /&gt;
* '''PMP''' - Portable Media Player.  Creative Zen, Apple iPod, etc.  Not to be confused with the original name for NSIS (PiMP).&lt;br /&gt;
&lt;br /&gt;
* '''Playlist Editor''' - Winamp component that allows easy sorting and sequencing of audio files.&lt;br /&gt;
&lt;br /&gt;
* '''Plug-in''' - Basis of Winamp architecture. Allows third parties to add functionality to Winamp by &amp;quot;plugging in&amp;quot; additional code.&lt;br /&gt;
&lt;br /&gt;
* '''Preset''' - Visually pleasing sequence of Effect Modules in AVS or Milkdrop.&lt;br /&gt;
&lt;br /&gt;
* '''SDK''' - Software Development Kit. All the tools you need to perform a programming job.&lt;br /&gt;
&lt;br /&gt;
* '''SHOUTcast''' - Nullsoft's internet streaming MP3 solution.&lt;br /&gt;
&lt;br /&gt;
* '''Skin''' - Interchangeable visual interface for Winamp.&lt;br /&gt;
&lt;br /&gt;
* '''Visualization Plug-in''' - A plug-in that uses audio data to drive graphics.&lt;br /&gt;
&lt;br /&gt;
* '''WAL''' - Required format for Modern skins before submittal.&lt;br /&gt;
&lt;br /&gt;
* '''WAV''' - Widely used uncompressed audio format. Usually more than 10X larger than MP3.&lt;br /&gt;
&lt;br /&gt;
* '''Winamp''' - The ultimate high-fidelity music player for Windows 2000/XP/Vista. Winamp supports MP3, CD and other audio formats, not to mention hundreds of plug-ins and thousands of skins.&lt;br /&gt;
&lt;br /&gt;
* '''Winamp.com''' - Official website of Winamp. Houses all approved skins, plug-ins, updates, forums, etc.&lt;br /&gt;
&lt;br /&gt;
* '''WindowShade Mode''' - Winamp option that shrinks most components to a narrow bar with only most basic functionality.&lt;br /&gt;
&lt;br /&gt;
* '''WSZ''' - Required format for Classic skins before submittal.&lt;br /&gt;
&lt;br /&gt;
* '''WVS''' - Obsolete name for AVS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== FAQ ==&lt;br /&gt;
Check out the [[Developers FAQ]].  Not to mistaken for the standard frequently asked questions that live on the Winamp Forums (although there may be some overlap.  This FAQ is specific to developers.&lt;br /&gt;
&lt;br /&gt;
==Contribute to the Wiki ==&lt;br /&gt;
Just like the success of Winamp itself, the success of the Developer Network relies on you. We encourage '''everyone''' to contribute.  From the expert developer, to the passionate user.  Your updates, additions, and moderation efforts are critical and we definitely appreciate your efforts making this one of the premier developer sites.&lt;br /&gt;
&lt;br /&gt;
*[[Policies &amp;amp; Guidelines]]&lt;/div&gt;</summary>
		<author><name>SMonty</name></author>	</entry>

	</feed>