Steves Code Corner

Sunday, January 15, 2006

View iPod Nano songs without iTunes, C# Express, Part 5

In the last post, we created the ITunesDBLib class library which allows us to retrieve information from the iTunesDB file and organize that information into useable objects. In this post we'll create the IPodBrowserExampleUI windows forms application, which will use the ITunesDBLib to display it's information to the user.

As with the last post, I won't go through each step to create and add the project to the solution. Instead we'll look at a screen shot of the project and it's classes, and discuss each class and key methods within it. Once again you are free to download the entire source here if you need more information.

Here is a screenshot of the solution with the IPodBrowserExampleUI project selected...


You'll notice that I expanded the References folder so we can see that we have a project reference to the ITunesDBLib. I also expanded the Resources folder since we are using some special icons I downloaded as part of registering my copy of C# Express.

The project itself really only contains two classes: Program and MainDisplay. MainDisplay is actually a partial class and it's two parts are defined in MainDisplay.cs and MainDisplay.Designer.cs. We'll go over these two partial classes in more detail in the next sections. If you are unfamiliar with partial classes however, you may want to check out this article for some background information first.

Program: This is the standard static starting class for a windows forms application. It contains the typical static Main() method that the application looks for when starting.

View Program Code (View)

There's nothing special to note here other than the fact that we are starting the MainDisplay form on the main thread.

MainDisplay (partial class located in the MainDisplay.Designer.cs file): This is the section of the MainDisplay partial class that defines the layout and display of controls on the form - basically the visual logic. Most of this code is autogenerated when you are working in the forms designer, so you should rarely need to come in here. However, I always like to see what Microsoft is doing behind the scenes. It's kind of like looking at your bank statement at the end of the month and saying "my wife spent $50 on what?".

View MainDisplay Code [partial] (View)

MainDisplay (public partial class located in the MainDisplay.cs file): This is the section of the partial class that contains the event logic for the form, and where the real code we need to implement resides.

View MainDisplay Code [public partial] (View)

There are several areas of note in this class, since this is where all the real code is placed. So lets start at the top.

One of the first things we do is declare an instance of the ITunesDBManager...

ITunesDBManager im = new ITunesDBManager();

The im variable can then be used throughout the class to retrieve data from it's underlying objects where necessary.

In the contructor of the class, you'll notice that after we initialize the components, we then run a conditional method called UseDebugPathToIPod. Basically, the purpose of this method is to find out if we are running this code in debug mode (determined by the [Conditional] attribute at run time. If we are, then this method will switch the drive letter of where the iPod is currently residing (typically F: drive). You'll recall that this application is designed to be deployed and run ON the iPod, so in a release version, this method will not be run, and we will use the Environment.CurrentDirectory instead. But during development, you should be testing your code locally (notice I said SHOULD be!).

Also in the constructor, you'll notice that we tie an event handler to the progressEvent event of the ITunesDBManager variable. This is so we can capture it's progress events and display them in a progress bar (I should note that the actual loading of data is so fast this event is not really needed atm, but if the lib were extended, load times could increase and this event might prove more valuable).

MainDisplay_Load: After the constructor, this is the next key method we need to look at. You'll notice that within it we call the LoadITunesDatabase method of the im variable, and pass in the path to the iTunesDB file. All we need to do from this side is figure out where the iTunesDB file is, and the im object will do the rest. Once the im variable has loaded the data and created it's internal objects, we can then get the entire collection of MHIT objects (aka tracks) using the im's TrackList method. We then pass this collection to the LoadTrackList method, which is discussed next.

LoadTrackList: This method is responsible for loading the songs into our grid. It accepts a collection of MHIT objects, and adds the song information to the grid using ListViewItems and their ListViewSubItems. We call the MHIT objects various Get methods (GetAlbum, GetTitle, etc...) to get information from it's underlying MHODString objects, and use those values to populate the list items. Note that the location to the song file is also stored in the tag property (this location does not include the drive letter!).

So that's pretty much all that happens when the form loads. The ITunesDBManager loads the data we need, and we populate our list of songs using the collection of MHIT objects within it. Now that we have our list displayed, we can cover the playing and extracting of song methods.


PlaySongMenuButton_Click: In this event method we allow the user to play a song currently selected in the grid. Basically we get the song subfolder location using the tag property, and then prepend the drive letter to where the subfolder is located on the iPod. Once we have this complete path, we create an instance of the Process object, and tell it to run the file. The Process object basically asks windows to look at the file and use whatever default program it has associated with that file type to open it.


ExtractSongMenuButton_Click: In this event handler method we allow the user to extract the currently selected song(s) from the list to a target folder they specify. Since several files could be selected and this could be a lengthy operation, we make the button itself checkable, and can therefore allow users to cancel a copy operation by unchecking this button.

The first thing we do is check the checkstate of the button. If it is checked, the user wants to start a copy operation on the selected files, otherwise they are cancelling. After this check we then prompt the user for the destination folder using the GetDestinationDir method. If the user actually specifies a target folder, then we go ahead and copy the files selected using the CopySong method, and give a progress update while we do so. You'll note that in the copy loop, we continually check if the user unchecked the button in case they want to cancel the operation.

CopySong: This method is used to copy songs from the iPod to the users machine. The real value of this method is that is converts the song from it's F0#\XXXX.mp# directory path\name storage structure on the iPod to an organized Artist\Album\Song (using title) format on the target machine. I wont describe too much in this method since much of it is self explainatory. Basically we create the directories needed and copy the song over with the new name.

And that's it! As you can see the UI is fairly small and straight forward. It could definitely use some more robust error handling, and the user could really mess things up if they wanted to, but this is just an example after all.

Final Thoughts

So that's it for the article. I hope you got an idea of what the ITunesDB file is all about, and how you can create objects that represent it's elements and retrieve song information. Though this is just an example built for fun, I hope it provided enough structured and readable code to help you design your own applications. Let me know if you have any questions and comments.

21 Comments:

  • Thanks for the code it helps me alot. Is there a way to add songs to iPod?

    By Anonymous Anonymous, at 8:00 AM  

  • Not with the code in the current state.

    You could however extend it to add songs back to the iTunesDB file (by adding an Add and Write method to the DBNodeBase class for example), but you would also need to add any needed byte properties that aren't currently included in the objects.

    Since this was a very simple demo, I only included the essential byte properties needed to retrieve and build the song objects. So to write song objects back, they would need to have a complete set of bytes that match the correct sequence expected by the iTunesDB database. From samples I've seen online, the way to do this is to delete the iTunesDB file and write a new one (this is actually the way iTunes does it too). Keep in mind though this is dangerous, and you should definitely know what you are doing and make a back-up before trying it!

    Once you have the correct sequence of bytes for each object, you could write the whole structure back to the new iTunesDB file.

    Hope that helps.

    By Blogger Steven Fleming, at 9:03 PM  

  • Hi, putting the .exe and .dll on my ipods root drive (I:\) i get thrown an error.

    The error is


    See the end of this message for details on invoking
    just-in-time (JIT) debugging instead of this dialog box.

    ************** Exception Text **************
    System.IndexOutOfRangeException: Index was outside the bounds of the array.
    at ITunesDBLib.GlobalUtility.UnicodeByteArrayToString(Byte[] characters, Int32 byteIndex, Int32 endIndex)
    at ITunesDBLib.MHODString.Load(Byte[] fileDB, Int32 offset)
    at ITunesDBLib.MHIT.Load(Byte[] fileDB, Int32 offset)
    at ITunesDBLib.MHLT.Load(Byte[] fileDB, Int32 offset)
    at ITunesDBLib.MHSD.Load(Byte[] fileDB, Int32 offset)
    at ITunesDBLib.MHBD.Load(Byte[] fileDB, Int32 offset)
    at ITunesDBLib.ITunesDBManager.LoadITunesDatabase(String pathToDB)
    at iPodBrowserExample.MainDisplay.MainDisplay_Load(Object sender, EventArgs e)
    at System.Windows.Forms.Form.OnLoad(EventArgs e)
    at System.Windows.Forms.Form.OnCreateControl()
    at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
    at System.Windows.Forms.Control.CreateControl()
    at System.Windows.Forms.Control.WmShowWindow(Message& m)
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
    at System.Windows.Forms.ContainerControl.WndProc(Message& m)
    at System.Windows.Forms.Form.WmShowWindow(Message& m)
    at System.Windows.Forms.Form.WndProc(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


    ************** Loaded Assemblies **************
    mscorlib
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
    ----------------------------------------
    IPod Song Browser
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///I:/IPod%20Song%20Browser.exe
    ----------------------------------------
    System.Windows.Forms
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
    ----------------------------------------
    System
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
    ----------------------------------------
    System.Drawing
    Assembly Version: 2.0.0.0
    Win32 Version: 2.0.50727.42 (RTM.050727-4200)
    CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
    ----------------------------------------
    ITunesDBLib
    Assembly Version: 1.0.0.0
    Win32 Version: 1.0.0.0
    CodeBase: file:///I:/ITunesDBLib.DLL
    ----------------------------------------

    ************** JIT Debugging **************
    To enable just-in-time (JIT) debugging, the .config file for this
    application or computer (machine.config) must have the
    jitDebugging value set in the system.windows.forms section.
    The application must also be compiled with debugging
    enabled.

    For example:

    When JIT debugging is enabled, any unhandled exception
    will be sent to the JIT debugger registered on the computer
    rather than be handled by this dialog box.

    Any ideas?

    By Anonymous T, at 1:14 PM  

  • Nevermind, seems that my iTunesDB was corrupt :(. THanks for the great code!.

    By Anonymous T, at 7:50 PM  

  • Playlist support would be a great adddition. Would this be a hard thing to add? Any thoughts on how it could be done?

    By Anonymous Anonymous, at 7:13 PM  

  • Just a heads up. this code doesnt work when there are podcasts on the iPod. Any idea on how this could be fixed?

    By Anonymous Anonymous, at 12:29 PM  

  • Yea, same question as above ^ any ideas would be great!

    By Anonymous Anonymous, at 7:38 PM  

  • Howdy - I've been messing around with your code, trying to access the playlist information, and I think there's a bug in your code...

    In MHBD.cs I've changed the line in the Load() method (Line 101 in my editor, but then i've tweaked it a it) that reads:
    childOffset = headerLength + mhsd.TotalLength; // reset offset for next child.
    to the following:
    childOffset += mhsd.TotalLength; // reset offset for next child.
    and I'm now getting proper access to the playlist nodes (well, if you also remove the "-1" from the "totalChildren - 1" in the for loop...)

    By Anonymous Anonymous, at 12:30 AM  

  • Wierd, I fixed that, and it still crashed here.

    shortlist[count] = characters[byteIndex + x];

    In global utility.cs

    By Anonymous Anonymous, at 3:35 PM  

  • I get the same error as above. Any idea's?

    By Anonymous Anonymous, at 6:24 PM  

  • this was working find but now I have the same problem as above. i get an out of memory error

    By Anonymous Anonymous, at 10:12 AM  

  • Code is no longer available, where can I download from again?

    By Blogger newyuppie, at 4:20 AM  

  • I found this site using [url=http://google.com]google.com[/url] And i want to thank you for your work. You have done really very good site. Great work, great site! Thank you!

    Sorry for offtopic

    By Anonymous Anonymous, at 6:35 PM  

  • By Anonymous Anonymous, at 2:31 PM  

  • Who knows where to download XRumer 5.0 Palladium?
    Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

    By Anonymous Anonymous, at 4:49 AM  

  • Online clarina Order lotrisone Now levitra Now bactrim Free pills daivonex Canadian acai berry

    By Anonymous Anonymous, at 3:11 PM  

  • Hello everyone! Who knows where to upload the film Avatar?
    I even bought the film Avatar for a SMS to http://rsskino.ru/kinofilm/avatar.html , the link was, but download fails, the system will boot quite strange cocoa something.
    Men, advise where to normal as quickly download film avatar?

    By Anonymous Anonymous, at 9:23 AM  

  • [b]Set software LoveBots v 5.2[/b]

    All for a mass mailing dating http://24lux.ru/

    The script is written in php5

    Features:

    [i]registration, account activation
    manual input captures, or the solution through antikapchu
    filling data accounts:
    - Gulf desired photo
    - Инфы about yourself
    - Diary
    - Sexual preference[/i]

    gulyalka on questionnaires spammer on lichku
    - Randomization Posts: replacement of Russian letters in Latin analogues

    optimized to work in a continuous loop
    check-activation-filling-spam check ..

    Updates and support free of charge.

    Price per set 100 wmz

    For the first 10 buyers price 70 wmz (your feedback on the software).

    For shopping I ask in icq: 588889590 Max.

    Scrin program:

    [IMG]http://i066.radikal.ru/1002/9d/a7a68e8c96ee.jpg[/IMG]

    [IMG]http://i054.radikal.ru/1002/19/9db76967c0e5.jpg[/IMG]

    [IMG]http://s003.radikal.ru/i202/1002/24/20716e86512e.jpg[/IMG]

    Flooding in the subject no! Write to feedback after the purchase.

    By Anonymous Anonymous, at 5:41 PM  

  • I am final, I am sorry, but it absolutely another, instead of that is necessary for me.

    By Anonymous Anonymous, at 1:35 PM  

  • Great website, looks very clean and organized. Keep up the good work! antibacterial Read a useful article about tramadol tramadol

    By Anonymous Anonymous, at 3:54 AM  

  • Keep up the good work. general health Read a useful article about tramadol tramadol

    By Anonymous Anonymous, at 3:46 AM  

Post a Comment

<< Home