Click here to Skip to main content
Licence 
First Posted 14 Jul 2004
Views 113,320
Bookmarked 39 times

Controlling iTunes through COM

By | 14 Jul 2004 | Article
An example of how to utilize COM in C# through a system tray application that controls iTunes

Introduction

Apple's iTunes is a powerful audio library manager and player now available for both Windows and Mac. Its feature set is endless and expanding, and, thankfully, through COM, third-party developers can access a good portion of this, even through the .NET Framework and its interop capabilities.

I have built a simple demo application to demonstrate a variety of the features that are available using the iTunes COM interface. This application, by no means, represents the full power of the interface, but is designed to show the different capabilities. Apple's developer web site has an SDK for the complete COM interface.

My application is a system tray utility for controlling iTunes easily and displaying the currently play track. It calls methods, changes properties, and receives events all through COM. It implements the basic functionality of playing, pausing, stopping and changing the currently playing track as well as popping up a window when the track changes.

Instantiating the iTunes Application

In order to access the features that iTunes has to offer, you must first add a reference to the iTunes COM Library to your project. Right click on your project in the Solution Explorer, choose "Add Reference...". Select the COM tab and find the "iTunes 1.1 Type Library", click "Select" and finally click "OK". You will now see "iTunesLib" under your References list for that project.

Next, in any files that you want to communicate with iTunes in, add the following directive:

using iTunesLib;

In order to control iTunes you must create a new instance if the controlling interface. This interface allows your program to communicate with and control (and be controlled by) and already open instance of iTunes.

private myiTunes = new iTunesAppClass();

Using this myiTunes member, you can access functions like Play(), Pause(), Stop(), and Quit(). If for some reason iTunes is closed and your application continues to try and communicate with it, a COMException will be thrown.

Receiving Events from iTunes

The myiTunes member also allows access to certain events like when a new track starts playing, when the current one stops, etc. To specify a new event handler for one of these events, iTunesLib uses the same delegate model that all other events in C# use:

// Add Event Handler
myiTunes.OnPlayerPlayEvent += new _IiTunesEvents_OnPlayerPlayEventEventHandler(
    myiTunes_OnPlayerPlayEvent);

// Event Handler
protected void myiTunes_OnPlayerPlayEvent(object iTrack)
{
...
}

The iTrack parameter provides information about the currently playing track, but in order to get at this information, we must first cast the iTrack into an IITTrack variable.

string myArtist, myName;

IITTrack myTrack = (IITTrack) iTrack;
myArtist = myTrack.Artist;
myName = myTrack.Name;

This is by no means all of the information available in the IITTrack interface. More information is available in Apple's documentation.

Conclusion

I hope that I have merely whetted you appetite in terms of what can be done with controlling Apple's powerful audio application, iTunes. The possibilities are endless: you can batch convert your media to a different format, organize and manage playlists, and batch rename tracks, among other things. Consult Apple's SDK for more information. It is vague in terms of examples, however it contains information about all of the interfaces, what they do, and what members and functions are accessible through each.

Furthermore, I hope I have introduced you to the idea of COM (component object module) and its potentials within your own work. Whether utilizing other COM components functionality or creating your own COM components, I think you will find that it can be endlessly useful, under the right circumstances.

System Requirements

This software is known to work with the following configuration:

  • Microsoft Windows XP SP1 or later
  • Microsoft .NET Framework 1.1
  • Apple iTunes 4.6

The software may possibly work under different configurations, but this has not be verified to date.

Known Issues

  • AnimateWindow WinAPI function does not work properly for fading in the popup display.
  • Popup window timer does not reset when track is changed while popup is showing.

History

  • 07/14/2004 - Article Released

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

About the Author

Adam Durity

Web Developer

United States United States

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionHow Do I Search The Itune Library? Pinmembercworkman2972919:55 22 Jul '09  
Generalstreaming track from iPod to PC PinmemberHalid Niyaz5:29 23 Aug '06  
GeneralPopup window timer does not reset when track is changed while popup is showing. Pinmemberzelig6:49 26 May '06  
GeneralEvent handling Pinmemberdark_omen13:43 23 Mar '06  
AnswerRe: Event handling Pinmemberndphuong21:08 16 Sep '06  
AnswerRe: Event handling PinmemberChiser9912:02 10 Nov '06  
GeneralUsing with .NET 2.0 Framework PinmemberShawn McCartt14:31 23 Jan '06  
GeneralNot working PinmemberLudo de la Pena8:15 10 Mar '06  
GeneralRe: Not working ? PinmemberLudo de la Pena8:44 10 Mar '06  
GeneralManaging multiple invocations of the COM interop PinmemberDrew Noakes10:58 21 Jan '06  
GeneralRe: Managing multiple invocations of the COM interop PinmemberMember 23587883:24 28 Aug '08  
GeneralRe: Managing multiple invocations of the COM interop PinmemberDrew Noakes5:08 28 Aug '08  
QuestionHide iTunes Pinmembertayspen9:35 11 Nov '05  
QuestionMusic Folder PinmemberTraPpeur8:49 29 Sep '05  
AnswerRe: Music Folder PinmemberAdam Durity17:53 13 Oct '05  
GeneralRe: Music Folder PinmemberTraPpeur0:37 14 Oct '05  
GeneralRe: Music Folder PinmemberErikpro22:43 8 May '07  
GeneralAdding Tracks to iTunes Pinmembersindhoor4:25 5 Jun '05  
GeneralItunes COM Events Pinmemberzx2c414:12 25 Mar '05  
AnswerRe: Itunes COM Events PinmemberpVALIUM0:37 2 Nov '07  
GeneralReceiving Events from iTunes PinsussMatt Berube8:52 6 Sep '04  
GeneralRe: Receiving Events from iTunes Pinmemberzx2c46:26 26 Mar '05  
AnswerRe: Receiving Events from iTunes PinmemberMatt Berube5:08 4 Dec '05  
I was eventually able to get this working, thanks to this[^] newsgroup thread. Here is my code:
 


///////////////////////////////////////////////////////////////////
// in my main dialog
CiTunesEventHandler m_eventHandler; // this is my event handler class
CComPtr m_connectionPoint;
CComQIPtr cpCont(IiTunes);
 
if (cpCont)
{
   if (SUCCEEDED(cpCont->FindConnectionPoint(DIID__IiTunesEvents, &m_connectionPoint)))
   {
      m_connectionPoint->Advise(m_eventHandler.GetIDispatch(FALSE), &m_cookie);
   }
}
m_eventHandler.m_parent = m_hWnd; // so my event handler can pass messages back
// end main dialog
///////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////
// iTunesEventHandler.h
#include "iTunesCOMInterface.h" // from Apple's iTunes SDK
 
// my user defined messages that get passed back to the main dialog
static const UINT UWM_ITUNESKEYS_PLAYER_PLAY_EVENT = ::RegisterWindowMessage(_T("UWM_ITUNESKEYS_PLAYER_PLAY_EVENT"));
static const UINT UWM_ITUNESKEYS_PLAYER_STOP_EVENT = ::RegisterWindowMessage(_T("UWM_ITUNESKEYS_PLAYER_STOP_EVENT"));
static const UINT UWM_ITUNESKEYS_ITUNESABOUTTOPROMPTUSERTOQUIT = ::RegisterWindowMessage(_T("UWM_ITUNESKEYS_ITUNESABOUTTOPROMPTUSERTOQUIT"));
 
class CiTunesEventHandler : public CCmdTarget
{
public:
CiTunesEventHandler();
virtual ~CiTunesEventHandler();
 
// Attributes
public:
HWND m_parent;
 
// Operations
public:
 
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CiTunesEventHandler)
public:
virtual void OnFinalRelease();
//}}AFX_VIRTUAL
 
// Here are the events I've chosen to handle.
// The complete list can be found in the iTunes SDK help file.
DECLARE_MESSAGE_MAP()
// Generated OLE dispatch map functions
//{{AFX_DISPATCH(CiTunesEventHandler)
afx_msg void OnDatabaseChangedEvent(const VARIANT FAR&
deletedObjectIDs, const VARIANT FAR& changedObjectIDs);
afx_msg void OnPlayerPlayEvent(const VARIANT FAR& iTrack);
afx_msg void OnPlayerStopEvent(const VARIANT FAR& iTrack);
afx_msg void OnPlayerPlayingTrackChangedEv(const VARIANT FAR& iTrack);
afx_msg void OnUserInterfaceEnabledEvent();
afx_msg void OnCOMCallsDisabledEvent(short reason);
afx_msg void OnCOMCallsEnabled();
afx_msg void OnQuittingEvent();
afx_msg void OnAboutToPromptUserToQuitEvent();
afx_msg void OnSoundVolumeChangedEvent(long newVolume);
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
 
LPUNKNOWN GetInterfaceHook(const void *piid);
 
};
 
// end iTunesEventHandler.h
///////////////////////////////////////////////////////////////////
 

///////////////////////////////////////////////////////////////////
// iTunesEventHandler.cpp
 
#include "stdafx.h"
#include "iTunesEventHandler.h"
 
CiTunesEventHandler::CiTunesEventHandler()
{
EnableAutomation();
}
 
CiTunesEventHandler::~CiTunesEventHandler()
{
}
 
void CiTunesEventHandler::OnFinalRelease()
{
// When the last reference for an automation object is released
// OnFinalRelease is called. The base class will automatically
// deletes the object. Add additional cleanup required for your
// object before calling the base class.
 
CCmdTarget::OnFinalRelease();
}
 
BEGIN_DISPATCH_MAP(CiTunesEventHandler, CCmdTarget)
//{{AFX_DISPATCH_MAP(CiTunesEventHandler)
DISP_FUNCTION(CiTunesEventHandler, "OnDatabaseChangedEvent",
OnDatabaseChangedEvent, VT_EMPTY, VTS_VARIANT VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnPlayerPlayEvent",
OnPlayerPlayEvent, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnPlayerStopEvent",
OnPlayerStopEvent, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnPlayerPlayingTrackChangedEv",
OnPlayerPlayingTrackChangedEv, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnUserInterfaceEnabledEvent",
OnUserInterfaceEnabledEvent, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnCOMCallsDisabledEvent",
OnCOMCallsDisabledEvent, VT_EMPTY, VTS_I2)
DISP_FUNCTION(CiTunesEventHandler, "OnCOMCallsEnabled",
OnCOMCallsEnabled, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnQuittingEvent", OnQuittingEvent,
VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnAboutToPromptUserToQuitEvent",
OnAboutToPromptUserToQuitEvent, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnSoundVolumeChangedEvent",
OnSoundVolumeChangedEvent, VT_EMPTY, VTS_I4)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
 
// Note: we add support for IID_IiTunesEventHandler to support typesafe binding
// from VBA. This IID must match the GUID that is attached to the
// dispinterface in the .ODL file.
 
// {429DD3C8-703E-4188-960E-A9821F14B04C}
 
static const IID IID_IiTunesEventHandler = { 0x429dd3c8, 0x703e, 0x4188, { 0x96, 0xe, 0xa9, 0x82, 0x1f, 0x14, 0xb0, 0x4c } };
 
BEGIN_INTERFACE_MAP(CiTunesEventHandler, CCmdTarget)
INTERFACE_PART(CiTunesEventHandler, IID_IiTunesEventHandler, Dispatch)
END_INTERFACE_MAP()
 
/////////////////////////////////////////////////////////////////////////////
// CiTunesEventHandler message handlers
 
//////////////////////////////////////////////////////////////////////
LPUNKNOWN CiTunesEventHandler::GetInterfaceHook(const void *piid)
{
REFIID iid = *(IID *) piid;
if (iid == DIID__IiTunesEvents)
return GetIDispatch(FALSE);
else
return NULL;
}
 
//////////////////////////////////////////////////////////////////////
void CiTunesEventHandler::OnDatabaseChangedEvent(const VARIANT & /*deletedObjectIDs*/, const VARIANT & /*changedObjectIDs*/)
{
}
 
void CiTunesEventHandler::OnPlayerPlayEvent(const VARIANT& /*iTrack*/)
{
PostMessage(m_parent, UWM_ITUNESKEYS_PLAYER_PLAY_EVENT, 0, 0);
}
 
void CiTunesEventHandler::OnPlayerStopEvent(const VARIANT& /*iTrack*/)
{
PostMessage(m_parent, UWM_ITUNESKEYS_PLAYER_STOP_EVENT, 0, 0);
}
 
void CiTunesEventHandler::OnPlayerPlayingTrackChangedEv(const VARIANT & /*iTrack*/)
{
}
 
void CiTunesEventHandler::OnUserInterfaceEnabledEvent()
{
}
 
void CiTunesEventHandler::OnCOMCallsDisabledEvent(short /*reason*/)
{
}
 
void CiTunesEventHandler::OnCOMCallsEnabled()
{
}
 
void CiTunesEventHandler::OnQuittingEvent()
{
}
 
void CiTunesEventHandler::OnAboutToPromptUserToQuitEvent()
{
PostMessage(m_parent, UWM_ITUNESKEYS_ITUNESABOUTTOPROMPTUSERTOQUIT, 0, 0);
}
 
void CiTunesEventHandler::OnSoundVolumeChangedEvent(long /*newVolume*/)
{
}
 
// end iTunesEventHandler.cpp
///////////////////////////////////////////////////////////////////


QuestionRe: Receiving Events from iTunes Pinmemberslowlyhazeing210:11 5 Dec '05  
AnswerRe: Receiving Events from iTunes PinmemberpVALIUM0:45 2 Nov '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120529.1 | Last Updated 15 Jul 2004
Article Copyright 2004 by Adam Durity
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid