Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This article describes another alternative for reading and displaying ID3 tags in MP3 files. There are various well documented methods of extracting ID3 tag information from MP3 files available. One of the most useful sites regarding this information is http://www.id3.org. This article will explore the possibility of extracting the same information using Win32 Shell functions.

Background

The Shell32.dll is responsible for a host of functions from launching applications to creating shortcuts and managing printers. You can read more about all the wonderful functionality it offers here. With Windows XP, users get the option of selecting a wide variety of columns to display when Explorer is in "Detail" view. Most of the extra columns are centered around multimedia files such as MP3 tracks and digital pictures. By way of the functionality provided in Shell32.dll, it is possible to display ID3 tag information for MP3 audio files and embedded EXIF information in JPEG picture files.

Using the code

The basic functionality of the ID3 tag reader is implemented as a struct with a single static ReadID3Tags method that returns a user defined MP3File object. It is beneficial to implement legacy COM wrapper functionality in a struct, as struct types get allocated in the heap and hence are exempt from garbage collection. They are also lightweight (compared to object instances), as they relieve the CLR from the task of reference counting.

We begin by adding a reference to Shell32.dll.

The MP3File class is basically a skeleton placeholder for the ID3 information returned from our Shell32 wrapper.

using System;
namespace ShellID3Reader {
    public class MP3File {
        private string fileName;
        private string artistName;
        private string albumName;
        private int trackNumber;
        private string songTitle; 

        public string FileName {
             get{return this.fileName;}
            set{this.fileName = value;}
        }
        public string ArtistName {
            get{return this.artistName;}
            set{this.artistName = value;}
        }
        public string AlbumName {
            get{return this.albumName;}
            set{this.albumName = value;}
        }
        public int TrackNumber {
             get{return this.trackNumber;}
            set{this.trackNumber = value;}
        }
        public string SongTitle {
             get{return this.songTitle;}
            set{this.songTitle = value;}
        }
        public MP3File(){
        }
    }
}

The ShellID3TagReader struct is responsible for reading the ID3 tags from MP3 files. Its takes the full file path and name as an input parameter and returns an instance of MP3File after decorating its properties, with information extracted from the Windows shell.

using System;
namespace ShellID3Reader
{
    public struct ShellID3TagReader
    {
        public static MP3File ReadID3Tags(string FileFullPath){
            MP3File mp3File = new MP3File();

            //parse file name

            string fileName = 
              FileFullPath.Substring(FileFullPath.LastIndexOf("\\")+1);
            //parse file path
            string filePath = 
              FileFullPath.Substring(0,FileFullPath.LastIndexOf("\\"));
            //create shell instance
            Shell32.Shell shell  = new Shell32.ShellClass();
            //set the namespace to file path
            Shell32.Folder folder = shell.NameSpace(filePath);
            //get ahandle to the file
            Shell32.FolderItem folderItem = folder.ParseName(fileName);
            //did we get a handle ?
            if (folderItem !=null){
                mp3File.FileName = fileName;
                //query information from shell regarding file
                mp3File.ArtistName = folder.GetDetailsOf(folderItem,9);
                mp3File.AlbumName = folder.GetDetailsOf(folderItem,17);
                mp3File.SongTitle = folder.GetDetailsOf(folderItem,10);
                mp3File.TrackNumber = 
                  Int32.Parse(folder.GetDetailsOf(folderItem,19));
            }
            //clean ip
            folderItem = null;
            folder = null;
            shell = null;
            //return mp3File instance
            return mp3File;
        }
    }
}

And finally we add the MP3File instance to a ListView for display.

private void cmdReadTags_Click(object sender, System.EventArgs e) {
            
    listViewFiles.Columns.Clear();
    listViewFiles.Items.Clear();
    listViewFiles.Columns.Add("FileName",100,HorizontalAlignment.Left); 
    listViewFiles.Columns.Add("ArtistName",100,HorizontalAlignment.Left); 
    listViewFiles.Columns.Add("AlbumName",100,HorizontalAlignment.Left); 
    listViewFiles.Columns.Add("TrackNumber",100,HorizontalAlignment.Left); 
    listViewFiles.Columns.Add("SongTitle",100,HorizontalAlignment.Left); 
            
    DirectoryInfo dir = new DirectoryInfo(textBoxFilePath.Text);
    FileInfo[] files = dir.GetFiles("*.mp3");
    foreach(FileInfo fi in files){
        MP3File mp3File = ShellID3TagReader.ReadID3Tags(fi.FullName);
        ListViewItem itm = new ListViewItem();
        itm.Text = mp3File.FileName;
        itm.SubItems.Add(mp3File.ArtistName);
        itm.SubItems.Add(mp3File.AlbumName );
        itm.SubItems.Add(mp3File.TrackNumber.ToString()) ;
        itm.SubItems.Add(mp3File.SongTitle);
        listViewFiles.Items.Add(itm);
    }
}

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralProblem with multiple artists
Soundman32.2
4:59 28 Aug '08  
Some of the music in my collection has various artists listed.
My whole collection has been tagged with WMP which tags multiple items with a ; so in WMP
Cover to Cover's Composer is "George;Neal Morse;Portnoy"
If I look at the same file in Explorer it shows the composer as "George"

Does anyone know a way of getting the list of composers via shell32? I know I could go to a real mp3 reader, but this seems easier.
GeneralCode that works with Vista and XP, using Shell32
Javawag
7:32 20 Aug '08  
Change your ShellID3TagReader.cs file to this:

using System;

namespace Renamer
{
public struct ShellID3TagReader
{
public static MP3File ReadID3Tags(string FileFullPath){
MP3File mp3File = new MP3File();

//parse file name
string fileName = FileFullPath.Substring(FileFullPath.LastIndexOf("\\")+1);
//parse file path
string filePath = FileFullPath.Substring(0,FileFullPath.LastIndexOf("\\"));
//create shell instance
Shell32.Shell shell = new Shell32.ShellClass();
//set the namespace to file path
Shell32.Folder folder = shell.NameSpace(filePath);
//get ahandle to the file
Shell32.FolderItem folderItem = folder.ParseName(fileName);
//did we get a handle ?
if (folderItem !=null){
mp3File.FileName = fileName;
//query information from shell regarding file
int art = Environment.OSVersion.Version.Major < 6 ? 9 : 13;
int alb = Environment.OSVersion.Version.Major < 6 ? 17 : 14;
int song = Environment.OSVersion.Version.Major < 6 ? 10 : 21;
int trk = Environment.OSVersion.Version.Major < 6 ? 19 : 26;

mp3File.ArtistName = folder.GetDetailsOf(folderItem,art);
mp3File.AlbumName = folder.GetDetailsOf(folderItem,alb);
mp3File.SongTitle = folder.GetDetailsOf(folderItem,song);
try {
mp3File.TrackNumber = Int32.Parse(folder.GetDetailsOf(folderItem, trk));
}
catch { }
}
//clean ip
folderItem = null;
folder = null;
shell = null;
//return mp3File instance
return mp3File;
}
}
}

Bits in bold are bits that are changed - it basically checks if your running vista, and if you are uses vista's indexes.

- Javawag
GeneralIs there any way to retrieve the year?
tequilalove
1:28 28 Apr '08  
I mean shell32 must have a way of retrieving it...
btw, thanks for the code, it sure helped me with my project.
GeneralRe: Is there any way to retrieve the year?
Erhan Hosca
16:56 11 May '08  
year is 18 ...
GeneralIDs seem to have changed in Vista
DylanV
14:41 21 Dec '07  
When I tried to run this on Vista, the IDs (item indexes) appear to have changed. I used these IDs for the info that I needed:

13 (or 20--they were the same for every file I checked) is the artist
14 is the album
21 is the song title
26 is the track number.

I hope that helps anyone that is using this in the future!
GeneralVista item indexes.
DylanV
14:40 21 Dec '07  
When I tried to run this on Vista, the IDs (item indexes) appear to have changed. I used these IDs for the info that I needed:

13 (or 20--they were the same for every file I checked) is the artist
14 is the album
21 is the song title
26 is the track number.

I hope that helps anyone that is using this in the future!
GeneralRe: Vista item indexes.
StephenQF
20:57 25 Jan '09  
Do you know what the rest of the Indexes are for Vista?
GeneralA few tips
reinux
23:16 26 Oct '06  
Nice article. Here's a few C# tips:
-If you can't actually modify a property, don't implement set{}.
-You can do the extraction in the constructor of the class containing the data. This incurs no overhead.
-If the constructor is going to fail for some reason, throw an exception.
-The Shell object is reusable; initialize it once statically and use it for the whole life of the process.
-Use the System.IO.Path methods to extract full path, directory name etc.
-structs are only more efficient, at current, if they are less than 16 bytes, so best practice in this case would be to use classes instead.

Here's how I wrote the class according to your article:
public class Mp3File
{
static Shell shell = new ShellClass();

public Mp3File(string path)
{
this.path = System.IO.Path.GetFullPath(path);
Folder folder = shell.NameSpace(System.IO.Path.GetDirectoryName(path));
FolderItem item = folder.ParseName(System.IO.Path.GetFileName(path));

if (item == null)
throw new System.InvalidOperationException();

this.path = System.IO.Path.GetFullPath(path);
this.artist = folder.GetDetailsOf(item, 9);
this.album = folder.GetDetailsOf(item, 17);
this.title = folder.GetDetailsOf(item, 10);
this.track = folder.GetDetailsOf(item, 19);
}

string path;
public string Path
{
get { return path; }
}

string artist;
public string Artist
{
get { return artist; }
}

string album;
public string Album
{
get { return album; }
}

string title;
public string Title
{
get { return title; }
}

string track;
public string Track
{
get { return track; }
}
}

QuestionWriting ID3 Tag information Using Shell32
getprashanthr
21:22 15 Dec '05  
Iam also facing the same problem. The above article is very helpful.

I am trying to read and write audio metadata. its very easy to Get metadata using "mediaFile.ArtistName = folder.GetDetailsOf(folderItem, n)" but i can't seem to find any methods to Set the values.

Is there any way to write using the same shell32 implementation. Please reply to this message.

Prashanth


C# Newbie

-- modified at 11:56 Friday 16th December, 2005
GeneralReading ID3 Tag from binary files Using Shell32
inams
19:34 1 Dec '05  
Hi,

I went through the code given for reading the ID3 tag and that was really very helpful. I also went through various discussions but what caught by attention was the suggestion of reading ID3 tag from binary file which will be a more generic solution across different OS. Can anyone help me in telling how do we achieve this?


namrata
GeneralRe: Reading ID3 Tag from binary files Using Shell32
Erhan Hosca
16:58 2 Dec '05  
check out the implementations section at http://id3.org

GeneralHow to read .m4a (aac)
tayspen
10:28 21 Oct '05  
How could i read those....i cant find a way Any ideas?
GeneralRe: How to read .m4a (aac)
jesseseger
18:45 2 Jan '10  
Read m4a tags in C#.NET[^]
Generalread/write audio metadata
laurence fass
6:18 20 Sep '05  
I am trying to read and write audio metadata (mp3/wma). its very easy to Get metadata using "mediaFile.ArtistName = folder.GetDetailsOf(folderItem, n)" but i cant seem to find any methods to Set the values. can this be done in the shell? if not, does anyone know an easy way of setting metdata tags?... i have parsed the verbs on an audio file but nothing lets me change the metadata...

Laurence Fass
QuestionRe: read/write audio metadata
getprashanthr
21:20 15 Dec '05  
Iam also facing the same problem. The above article is very helpful.

I am trying to read and write audio metadata (mp3/wma). its very easy to Get metadata using "mediaFile.ArtistName = folder.GetDetailsOf(folderItem, n)" but i can't seem to find any methods to Set the values.

Is there any way to write using the same sheel32 implementation. Please reply to this message.

Prashanth


C# Newbie
GeneralNot Reading Mp3 Tags
empeyg
12:46 15 Jun '05  
I have been experiencing two problems with the project.
When I click on the button to open the folder search screen I receive the following error:
The procedure entry point RtlDuplicateUnicodeString could not be located in the dynamic link library ntdll.dll

The window still loaded so I persisted to locating my files.

When I clicked the Read Tags button, no tags were read. The songs have been tagged by Musicmatch.

I tried several different directories all with the same results.

From my perspective, it doesn't work on a W2K box running .net 2003.

Does anyone have a good mp3 tag reader that can be compiled either as a dll or can be incorporated into a vb.net application? Anyone at all?
mpg
GeneralRe: Not Reading Mp3 Tags
Erhan Hosca
16:13 15 Jun '05  
hi,

yes, the RtlDuplicateCodeString is a known issue that apparently manifests itself when packages that are meant to be installed on WinXP are installed on Win2K .. more on that here
http://www.answers.google.com/answers/threadview?id=366517[^]

as i have already indicated in the article, you may find these other implementations more suitable for your needs .. [^]

Cheers,
GeneralRe: Not Reading Mp3 Tags
Stephen Remde (smremde)
11:34 11 Aug '06  
I got the same problem then i recompiled for x86 only and it worked fine.

Stephen Remde
GeneralDoesn't seem to work on Windows 2000
Ashley van Gerven
19:37 19 Mar '05  
I got an exception: Input string was not in the correct format.

However on windows xp works well (it reads the ID3v2 tags - which is normally quite complicated).
GeneralRe: Doesn't seem to work on Windows 2000
AR123
21:00 20 Apr '05  
I use WindowsXP and it doesnt seem to work here.I also got an exception: Input string was not in correct format.
GeneralRe: Doesn't seem to work on Windows 2000
anonymous
5:09 28 May '05  
I received the same error and on investigation it was because the track number field on some songs was null. A simple error check on this line

mp3File.TrackNumber = Int32.Parse(folder.GetDetailsOf(folderItem,19));

can prevent an app crash and an integer value such as 0 can be entered.
GeneralOther column indexes.. (NT5.1-5.2 ONLY)
Niels Penneman
11:36 19 Feb '04  
enum DetailColumns
{
InfoTip = -1,

Name = 0,
Size = 1,
Type = 2,

DateLastModified = 3,
DateCreated = 4,
DateLastAccessed = 5,

Attributes = 6,
Status = 7,
Owner = 8,

Author = 9,
Title = 10,
Subject = 11,
Category = 12,
Pages = 13,
Comments = 14,

Artist = 16,
AlbumTitle = 17,
Year = 18,
TrackNumber = 19,
Genre = 20,
Duration = 21,
Bitrate = 22,
Protected = 23,

Dimensions = 26,
Width = 27,
Height = 28,

Company = 30,
Description = 31,
FileVersion = 32,
ProductName = 33,
ProductVersion = 34 }


greetz Wink
*Niels Penneman*

Software/Dev Site
Personal Site

GeneralRe: Other column indexes.. (NT5.1-5.2 ONLY)
tayspen
18:17 25 Nov '05  
*Never Mind*

-- modified at 22:45 Tuesday 7th February, 2006
GeneralRe: Other column indexes.. (NT5.1-5.2 ONLY)
StephenQF
14:35 25 Jan '09  
Why is it that the index for Artist is 16 but the code is using 9? Both seem to work. Thanks for the enum and thanks Erhan Hosca for the code.
GeneralItem Indexes
appwiz
16:43 11 Oct '03  
Interesting article. I had a couple of questions;
1. How did you find out the item index for the value you were trying to get using GetDetailsOf()? Specifically, how did you know that the artist name is located at index 9 in this line of code?
mp3File.ArtistName = folder.GetDetailsOf(folderItem,9);

2. Since the Shell32 dll is different for different versions of Windows, will the indexes be different too?

Thanks!

"Know your role"


Last Updated 22 Sep 2003 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010