Developing a plug(in) for TV Manager

Now that TV Manager has plug-in support, it is time I made a more detailed tutorial on how to make one and the concept behind it.

I designed the plug-in system around the concept of a power adapter and plug. The plug is an extendable socket. When you plug something in, it interfaces (connects) with the system. An adapter converts the plugged-in item into a usable form.

With the TV Manager plug-in system, the idea is very similar. A plug is an extendable socket; it interfaces users with the software. The adapter converts the plugs to a usable form.

The plug system looks for dlls (written in a .NET language) containing a class that inherits the Plug class (can be found in the TVManager_Api.dll assembly, Api.Current.Plug). Plugs are currently only supported on the client side and not on the Windows Home Server.

If you look at the diagram below, you’ll notice that I’ve included a Win7Interop class that brings Windows 7 specific features to TV Manager. This class is accessible via the NotifyIconCom class (can be accessed using the TrayIcon data member).

All classes that are to be accessed from your derived version of Plug need to inherit the MarshalByRefObject class. This is because the client application accesses the plugs via the background service’s .NET remoting connection. In order to be remotely accessed, they have to inherit the MarshalByRefObject class.

Events are hard coded to point to existing event handlers to work around some exceptions that were thrown during development of the plug system. When an event is triggered it calls the specified method in the base class and is then redirected to your derived classes' overridden method.

To install a plug, simply drop the dll(s) containing your code into the TV Manager ‘plugs’ sub-folder. The plug will be loaded upon detection (if it detects a class inheriting from Plug). Once loaded, constructor (as specified in the example code below) is called. When the plug’s dll is deleted, it is unplugged (unloaded). Before being unloaded, the plug’s “Unplug” method is fired. You should use this method to dispose of any data and stop/abort any background threads.

Plug’s can be updated by simply replacing the associated dll; it will unload and then reload the assembly.

I plan to go more into how to create your own plug in my next post regarding TV Manager’s plug-in system. Until then, I’ll leave you to play around with what I’ve given you. In addition, feel free to try out the sample plug I’ve included at the end of this post. I hope someone finds this post useful and decides to extend TV Manager for the better.

Plugin Diagram

Code Snippet

#region

using
System.Windows.Forms;
using Api.Current;
using Api.FS;

#endregion

namespace
EvisPlug
{
    
/// <summary>
    /// A plug for example purposes that doesn't really do much.
    /// </summary>
    public class Elvis : Plug
    {
        
/// <summary>
        /// The plug's creator.
        /// </summary>
        private const string cAuthor = "Elvis";
        
/// <summary>
        /// The plug's name.
        /// </summary>
        private const string cName = "Heaven";

        
/// <summary>
        /// The constructor
        /// Remember to also instantiate the base class
        /// You must use the signature below in order for events to work properly
        /// </summary>
        public Elvis(Watcher fw)
            :
base(fw)
        {
            
/* Set the plug's name and author to
             * constants defined in this class */
            Name = cName;
            Author = cAuthor;
            Welcome();
        }

        
/// <summary>
        /// Occurs when a new file has been created in a watched directory.
        /// </summary>
        /// <param name="fileName">The full path to the file.</param>
        /// <returns>If true, stop execution of the built-in FileFound code</returns>
        public override bool FileFound(string fileName)
        {
            
/* TrayIcon is a remotable NotifyIcon object.
             * Houses frequently used methods to communicate with the tray icon in the client. */

            // Display a balloon tool tip in the client's systray.
            TrayIcon.ShowBalloonTip(2000, "File Found", string.Format("{0} says, your recording has been found.", Author), ToolTipIcon.Info);
            
return true;
        }

        
/// <summary>
        /// Occurs after a new file has been moved.
        /// </summary>
        /// <param name="fileName">The full path to the file.</param>
        public override void FileMoved(string fileName)
        {
            TrayIcon.ShowBalloonTip(2000,
"File Moved", string.Format("{0} says, your recording has been moved.", Author), ToolTipIcon.Info);
        }

        
/// <summary>
        /// Occurs when a new client connects the the service.
        /// </summary>
        public override void ClientConnected()
        {
            
// Let the user know that we've taken over TV Manager..
            Welcome();
        }

        
private void Welcome()
        {
            TrayIcon.ShowBalloonTip(2000,
string.Format("{0} has been freed.", Author), string.Format("{0}'s gate has been unlocked.", Name), ToolTipIcon.Info);
        }

        
/// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged/managed resources.
        /// </summary>
        public override void Unplug()
        {
            
/* Dispose of resources or other objects.
             * This method is called before unloading the plug */

            // In this case, let the user know that the plug is unloading
            TrayIcon.ShowBalloonTip(2000, "God caught up.", string.Format("{0} has left the building. Thank ya, thank ya very much.", Author), ToolTipIcon.Info);
        }
    }