Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Retrieve the Winamp song title with .NET

0.00/5 (No votes)
5 Jan 2004 1  
An article on Winamp and Windows API

Introduction

Ever needed the current Winamp song title? This article describes how to get it using some simple Windows API functions. For example, you could use this code in a nick name changer for an IM program. This code is only tested with Winamp 5, but should also be compatible with all other Winamp versions.

Using the code

First, you need to find the handle of the Winamp window using FindWindow, which is defined in the API reference as follows:

HWND FindWindow(
      LPCTSTR lpClassName,
      LPCTSTR lpWindowName
);

In C# .NET this function is referenced as follows:

[System.Runtime.InteropServices.DllImport("user32.dll", 
    CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, 
    string lpWindowName);

And in VB .NET:

Private Declare Auto Function FindWindow Lib "user32" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As IntPtr

It is known that the Winamp class name is "Winamp v1.x". It is not required to specify a window name, so we pass vbNullString (VB) or null (C#) in the function call. If a Winamp windows is found, the return value is its handle, else, the function returns NULL (.NET: IntPtr.Null). Once you have found the window handle, you can retrieve the window's text using GetWindowText:

int GetWindowText(
      HWND hWnd,
      LPTSTR lpString,
      int nMaxCount
);
[System.Runtime.InteropServices.DllImport("user32.dll", 
    CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowText(IntPtr hwnd, 
    string lpString, int cch);
Private Declare Auto Function GetWindowText Lib "user32" ( _
    ByVal hwnd As IntPtr, _
    ByVal lpString As String, _
    ByVal cch As Integer) As Integer

The return value of this function is the length of the window text. If the function succeeds, we have the window text containing the song title. The text consists of the track number (in the current playlist), followed by a dot and a space, then the track title and finally the text " - Winamp". When Winamp is paused or stopped, it may end with " - Winamp [Paused]" or " - Winamp [Stopped]". In this case we want the function to return only the state ("Paused" or "Stopped"). In the other case, we remove " - Winamp" from the end of the string and the track number at the beginning. Finally we remove all spaces from the beginning and the end of the resulting string and find the song title!

Complete C# .NET source code

[System.Runtime.InteropServices.DllImport("user32.dll", 
  CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, 
  string lpWindowName);
 
[System.Runtime.InteropServices.DllImport("user32.dll", 
  CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowText(IntPtr hwnd,
  string lpString, int cch);
 
const string lpClassName = "Winamp v1.x";
const string strTtlEnd = " - Winamp";
 
static string GetSongTitle() 
{
      IntPtr hwnd = FindWindow(lpClassName, null);
      if (hwnd.Equals(IntPtr.Zero)) return "Not running";
 
      string lpText = new string((char) 0, 100);
      int intLength = GetWindowText(hwnd, lpText, lpText.Length);
            
      if ((intLength <= 0) || (intLength > lpText.Length)) 
        return "unknown";
 
      string strTitle = lpText.Substring(0, intLength);
      int intName = strTitle.IndexOf(strTtlEnd);
      int intLeft = strTitle.IndexOf("[");
      int intRight = strTitle.IndexOf("]");
 
      if ((intName >= 0) && (intLeft >= 0) && (intName < intLeft) &&
          (intRight >= 0) && (intLeft + 1 < intRight))
            return strTitle.Substring(intLeft + 1, intRight - intLeft - 1);
 
      if ((strTitle.EndsWith(strTtlEnd)) && 
            (strTitle.Length > strTtlEnd.Length))
            strTitle = strTitle.Substring(0, 
                strTitle.Length - strTtlEnd.Length);
 
      int intDot = strTitle.IndexOf(".");
      if ((intDot > 0) && IsNumeric(strTitle.Substring(0, intDot)))
            strTitle = strTitle.Remove(0, intDot + 1);
 
      return strTitle.Trim();
}
 
static bool IsNumeric(string Value)
{
      try 
      {
            double.Parse(Value);
            return true;
      }
      catch
      {
            return false;
      }
}

Complete VB .NET source code

Private Declare Auto Function FindWindow Lib "user32" ( _
  ByVal lpClassName As String, _
  ByVal lpWindowName As String) As IntPtr
Private Declare Auto Function GetWindowText Lib "user32" ( _
   ByVal hwnd As IntPtr, _
   ByVal lpString As String, _
   ByVal cch As Integer) As Integer
 
Private Const lpClassName = "Winamp v1.x"
Private Const strTtlEnd = " - Winamp"
 
Private Function GetWinampSong() As String
    Dim hwnd As IntPtr = FindWindow(lpClassName, vbNullString)
 
    Dim lpText As String
 
    If hwnd.Equals(IntPtr.Zero) Then Return "Not running"
 
    lpText = New String(Chr(0), 100)
    Dim intLength As Integer = GetWindowText(hwnd, lpText, _
      lpText.Length)
 
    If (intLength <= 0) OrElse (intLength > lpText.Length) _
             Then Return "Unknown"
 
    Dim strTitle As String = lpText.Substring(0, intLength)
    Dim intName As Integer = strTitle.IndexOf(strTtlEnd)
    Dim intLeft As Integer = strTitle.IndexOf("[")
    Dim intRight As Integer = strTitle.IndexOf("]")
 
    If (intName >= 0) AndAlso (intLeft >= 0) AndAlso _
            (intName < intLeft) AndAlso _
       (intRight >= 0) AndAlso (intLeft + 1 < intRight) Then _
        Return strTitle.Substring(intLeft + 1, intRight - intLeft - 1)
 
    If (strTitle.EndsWith(strTtlEnd)) AndAlso _
        (strTitle.Length > strTtlEnd.Length) Then _
        strTitle = strTitle.Substring(0, _
          strTitle.Length - strTtlEnd.Length)
 
    Dim intDot As Integer = strTitle.IndexOf(".")
    If (intDot > 0) AndAlso (IsNumeric( _
           strTitle.Substring(0, intDot))) Then _
        strTitle = strTitle.Remove(0, intDot + 1)
 
    Return strTitle.Trim
End Function

Points of Interest

When I first wrote my code I used MarshallAs attributes. I made a mistake by specifying a wrong, but valid argument and spent about one hour looking for the bug. The function GetWindowText always returned 0. In this case, this attribute is not required, so don't use it.

History

  • Original code. Jan 6 2004.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here