Pulled Apart - Part VIII: Protocol handlers

[Pull Icon]

Note: This is part of a series; you can find the rest of the parts in the series index.

I’ve mentioned previously about Pull's support for protocol handlers (see part 4), which enables the application to subscribe to a feed easily just by clicking a link. Today I will look at how to register protocol handlers.

IE Open/Save Prompt

Protocol Handlers

Registering a protocol handler is one of the simplest things I did in Pull because it is merely a registry key that needs to be added to the system. The registry key follows the pattern below.

Key

Visualisation of the registry setup

The important points (numbered above) are:

  1. This is the protocol you want to register, so if you want to register, say, zune://, then this is zune.
  2. This is a useful description for the default key.
  3. This is a setting named URL Protocol, but the value must remain blank.
  4. This is the path to the icon. For Pull, I just use the default program icon by setting the value to: E:\PortableApps\Pull\Pull.exe,1
  5. This is the command to execute when the URL is clicked. In Pull, this is (note the %1 for the URL parameter): "E:\PortableApps\Pull\Pull.exe" "%1"

The code to do this is rather simple:

public static void Register(string executablePath, string uri)
{
    if (!OurProtocolHandler(uri))
    {
        return;
    }

    using (RegistryKey uriKey = Registry.ClassesRoot.CreateSubKey(uri, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
    {
        uriKey.SetValue(string.Empty, Pull.Properties.Resources.PullPodcastURIHandler);
        uriKey.SetValue("URL Protocol", string.Empty, RegistryValueKind.String);

        using (RegistryKey iconKey = uriKey.CreateSubKey("DefaultIcon", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
        {
            iconKey.SetValue(string.Empty, string.Format(CultureInfo.CurrentCulture, "{0},1", executablePath));
        }

        using (RegistryKey shellKey = uriKey.CreateSubKey("shell", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
        {
            using (RegistryKey openKey = shellKey.CreateSubKey("open", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
            {
                using (RegistryKey commandKey = openKey.CreateSubKey("command", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
                {
                    commandKey.SetValue(string.Empty, string.Format(CultureInfo.CurrentCulture, "\"{0}\" \"%1\"", executablePath));
                }
            }
        }
    }
}

Being a Good Citizen

Pull is aware that some people may have other podcatchers installed, and to ensure it does not steal their protocol handlers, it includes a simple method, OurProtocolHandler, which checks if the protocol is in use. If a protocol is already in use, it does not override it.

private static bool OurProtocolHandler(string uri)
{
    using (RegistryKey uriKey = Registry.ClassesRoot.OpenSubKey(uri))
    {
        if (Registry.ClassesRoot.OpenSubKey(uri) != null)
        {
            return uriKey.GetValue(string.Empty).Equals(Pull.Properties.Resources.PullPodcastURIHandler);
        }
        else
        {
            return true;
        }
    }
}

Final Thoughts

This is one of the easiest parts to get working, but incorporating it into the application is not as simple—something I will cover next.