Toolroom Tech Blog

Devlopers Digest

Eigene Applikation mit Url starten

click://me

Ein Kunde hat angefragt, ob es möglich wäre, eine Feature in seine (von mir entwickelte :)) Windows-Unternehmenslösung einzubauen, mit der er Links zu Inhalten aus der Applikation per Mail verschicken kann. So wie bei Skype: Try it here! 

Natürlich geht das!

Und so geht's

Gehen wir davon aus, dass wir mit der Url myapp://user/m.muster das Benutzerprofil des Benutzers m.muster in unserer Applikation, deren ausführbare Datei unter C:\Programme\MyApplication\myapplication.exe zu finden ist, öffnen wollen. Dazu sind nur wenige Schritte notwendig:

1) Protokoll registrieren

Zuerst muss Windows das eigene Protokoll mitgeteilt werden, indem folgende Registry Keys angelegt werden:

[HKEY_CLASSES_ROOT\myapp]
@="URL:My Application Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\myapp\shell]

[HKEY_CLASSES_ROOT\myapp\shell\open]

[HKEY_CLASSES_ROOT\myapp\shell\open\command]
@="\"C:\\Programme\\MyApplication\\myapplication.exe\" \"%1\""

Man kann das dann natürlich auch schön im Setup machen :)

Zu beachten ist dabei, dass der Key unter HKEY_CLASSES_ROOT der Protokollname ist (also myapp://). Der Pfad in der letzten Zeile zeigt auf die aufzurufende Datei, und %1 ist der Platzhalter für die aufgerufene Url.

2) Die Applikation vorbereiten

Jetzt muss man der App noch beibringen, mit dem Parameter umzugehen. Grundsätzlich muss man dazu lediglich die Url aus den StartupEventArgs holen und intern auswerten.

In meinem Fall ging das alles sehr schnell, da ich dank MVVM und meiner generischen Genialität (bin ich dann generial?) nur ein paar Aufrufe zu erledigen hatte. Ich schreibe die Parameter ausserdem in eine Queue, die erst dann abgearbeitet wird, sobald das MainWindow initialisiert ist, dann gibts auch keine seltsamen Fehlermeldungen. 

protected override void OnStartup(StartupEventArgs e)
{
    if (e.Args.Length > 0)
        ParamQueue.Enqueue(e.Args[0]);
}

private static void HandleUrlParameter(string url)
{
    if(!Current.Dispatcher.CheckAccess())
    {
        Current.Dispatcher.BeginInvoke(new HandleUrlParameterDelegate(HandleUrlParameter), url);
        return;
    }

    if(!url.StartsWith(string.Format("{0}://", UrlProtocol.ProtocolKey)))
    {
        return;
    }

    url = url.Replace(string.Format("{0}://", UrlProtocol.ProtocolKey), "");

    var data = url.Replace(string.Format("{0}://", UrlProtocol.ProtocolKey), "");
    var parts = data.Split(new []{"/"}, StringSplitOptions.RemoveEmptyEntries);

    try
    {
        switch (parts.Length)
        {
            case 1:
                if (parts[0] == "user") { LoadListView<UserListViewModel, User>(); return;}
                if (parts[0] == "customer") { LoadListView<CustomerListViewModel, Customer>(); return; }
                break;
            case 2:
                if (parts[0] == "user") { LoadEditForm(typeof(UserViewModel), typeof(User), new User { Id = Convert.ToInt64(parts[1]) }); return; }
                if (parts[0] == "customer") { LoadEditForm(typeof(CustomerViewModel), typeof(Customer), new Customer { Id = Convert.ToInt64(parts[1]) }); return; }
                break;
        }
    }
    catch (Exception ex)
    {
                
    }

    MessageBox.Show("Invalid Link");
}

 In diesem Beispiel wird zur Vereinfachung bei jedem Aufruf eine neue Instanz der Applikation gestartet. Um bestehende Instanzen zu verwenden, muss man dann noch die Verwendung einer SingleInstance implementieren. Aber das ist eine andere Geschichte ...

Loading