Archive for Oktober, 2011
Work from the past: Scanflib
When I started studying Computer Sciences and Communication Systems, one of my first courses was an introduction to ANSI-C. To be honest, C is not the easiest language to learn. You have to care a lot about problems which are not even known in typical hobbyists languages of choice. You have to care about memory management, pointers, boundary checks and a lot more which is typically cared for by the compiler, interpreter or virtual machine for most newer languages like Java, the .NET languages or interpreted ones like Python or PHP.
However, on the other hand, C is a great language to learn what’s programming about and to get a deep knowledge and feeling for what a more complex platform might do when you call a “simple looking” function and you are wondering on the impact it has. As a language C is “high” enough to spare you from the pains of assembler and “low” enough to not bedazzle you with shiny functions you actually cannot find out for how they do their magic.
Back to the “historical” part, for me the greatest pain working with ANSI-C was to do user inputs. I always ran into problems when I wanted to read characters, interpret input as an integer or even as a double! So, when my knowledge was good enough, I started developing a pretty small but useful library to ease user inputs – and from the first version on I used it in a lot of projects and, as far as I know, it was in use by several further classes, too. Some days ago I did a little project in C and – although I didn’t use it (I had no user input) – I remembered my little library and so I wanted to post it here. Don’t expect too much, it does no magic and it was one of my first works in C
Basically it provides only four simple functions to be used for reading multiple characters (up to 4096), a single character, an integer or a double value:
int readCharacters(char* buffer, int chars);
int readCharacter( char* buffer);
int readInteger( int* value);
int readDouble( double* value);
The library comes with a short example application (with comments in german
). As usual, the short library is provided “as is” under the MIT license here for download.
iTunes and Windows
Recently I gave you a short introduction in communicating with iTunes from your own objective-c application using the Apple Scripting Bridge. As for several reasons my current development environment is much windows centric than I wish it would be, I came to the idea of checking on how to integrate iTunes in a .NET based application. And, to my surprise, it is nearly as simple as using objective-c – while both have their very own weak-points.
Basically the support for inter-application communication in classical Windows applications is realized using COM, the Component Object Model. COM provides two important technologies to do so: the communication infrastructure and a factory for dynamically allocated objects. The main advantage however is, that COM based objects (which can be both, applications and DLLs) are language- and version-independent. While the first feature offers you the possibility to select a comfortable environment, the latter one eases the pain of supporting multiple versions of the target application – which might become a problem for rapid-evolving applications like iTunes. Although sounding fancy, the latter feature is similar to the approach of scripting bridge: both use a specified interface to communicate and the server application (the COM provider, in this case iTunes) can “decide” if to support the interface or not. As both interfaces, the one for scripting bridge and the one for COM, change quite seldom and so far managed to stay downwards-compatible, this technique is quite future-proof. For more information on COM, see the Wikipedia entry or the MSDN.
Working with COM in C# can be a bit fuzzy and hard to debug sometimes. The most strange paradigm is that you have to work on interfaces only and creating a new “instance of an interface” is not a quite common approach for most developers
. For example, getting the iTunes application COM instance you use:
var app = new iTunesApp();
If you have a quick look in the Object Browser you will find the following entry for iTunesApp:
public interface iTunesApp Member of iTunesLib
If your Visual Studio is revoking to accept iTunesApp you might have missed to add the iTunesLib COM reference. You can add it like any other assembly to your project by just selecting “COM” and then “iTunesLib” in the “Add Reference” dialog instead of browsing for an assembly. So how to get information on the COM supported functions? Simply: jump to the next entry in the object browser, the <pre>iTunesAppClass</pre> which is the “backing” class for the iTunesApp interface. However, keep in mind that the instantiation of iTunesAppClass will always fail – the paradigm is simple to remind: you request the server application (iTunes) to create an instance of iTunesAppClass by telling .NET that you want an object that is interfaced as an iTunesApp.
So, before I will continue with a short example, I’d like to mention some differences. Quite nifty is the COM support for server-side invoked function calls, which might be more common for as “Events”. You can register to a set of events on the iTunes COM interface which provide you instantaneous information on iTunes’ state changes, like playing another track:
this.app = new iTunesApp();
this.app.OnQuittingEvent += this.AppITunesQuitting;
this.app.OnDatabaseChangedEvent += this.AppITunesDatabaseChanged;
this.app.OnPlayerPlayEvent += this.AppITunesPlayerPlay;
this.app.OnPlayerPlayingTrackChangedEvent += this.AppITunesPlayerPlayingTrackChanged;
this.app.OnPlayerStopEvent += this.AppITunesPlayerStop;
So far I couldn’t figure out a technique for objective-c to realize a similiar good state change reporting. A bit more anoying is the implementation of starting and monitoring iTunes. While there is an is-iTunes-running function for objective-c, there is none for COM – and, in case you simply call a COM function, Windows will start iTunes without any further notification. For a bit more comfort you can “simulate” the is-running function by using System.Diagnostics:
public bool IsRunning
{
get
{
var process = Process.GetProcessesByName("iTunes");
return process.Length > 0;
}
}
On the other side of the life-cycle you should always register to the OnQuittingEvent of the COM interface and avoid using COM functions after the event has been sent until iTunes is available again or you want iTunes to startup
. Remember that starting iTunes uses a quite big amount of time and will block the COM function call until done.
OK, so to sum-up and finish let’s have a short example on how to use the COM interface to get the list of user-playlists from iTunes, it’s quite simple:
var enumerator = this.app.Sources.GetEnumerator();
enumerator.MoveNext();
var source = enumerator.Current as IITSource;
if (source == null)
{
return new List<IITPlaylist>();
}
return from IITPlaylist list in source.Playlists
where list.Kind == ITPlaylistKind.ITPlaylistKindUser
select list;
The snipped assumes that “app” is an iTunesApp instance. Then, the Sources property provides access to the iTunes sources, similar to the Scripting Bridge version. In case you prefer the indexing operator for arrays: forget it, they don’t work in this case – you have to use the enumerator. Calling MoveNext once will bring you to the first source which is always the Library (“Mediathek” in German). The rest is simple: check if it is a valid Source and get the Playlists array. Using a bit of LINQ-magic you can filter those playlists that are of the user-kind and then you have all playlists.