VB.NET Anwendungsdauer auslesen

VB.NET Anwendungsdauer auslesen
VB.NET Anwendungsdauer auslesen

VB.NET Anwendungsdauer auslesen

In VB.NET die Anwendungsdauer auslesen ist ein Problem, vor Welchem ich heute selbst stand, daher dachte ich, ich teile meine Lösung mit Dir.

Je nach Sicherheitsanforderungen deiner Anwendung, könntest Du basierend auf dieser Zeitmessung zum Beispiel Nutzungsbegrenzungen festlegen.

Beachte, dass es wie fast immer unterschiedliche Wege gibt, diese Problemstellung anzugehen und ich nur eine Möglichkeit zeige.

Schaue doch zu einem anderen Zeitpunkt auch gerne bei diesen Beiträgen vorbei: VB.NET data binding Tutorial, Dein Eigenes TicTacToe Spiel, VB.NET Array.

Meine erste Problemstellung – wo?

Der erste Gedanke, Welcher mich beim Umsetzen dieser Aufgabe begleitete war es, herauszufinden wo ich den Code am besten ansetze.

Am liebsten hätte ich es wie gleich folgend gehabt, um nicht großartig etwas instanziieren und durch z. B. eine Methode initialisieren zu müssen.

Ebenso finde ich das Beispiel relativ einleuchtend, denn es klingt für mich logisch, die verstrichene Zeit der Anwendung, in der Anwendungsklasse zu finden, oder?

Dim timeRunning = Application.GetTimeRunning()
' do something

Erweiterungsmethoden zu Hilfe – oder?

Grundsätzlich könnte man bei dieser Herangehensweise erstmal an Erweiterungsmethoden denken.

Mit Hilfe von Erweiterungsmethoden können wir die bestehenden .NET-Klassen, sowie eigene Klassen um Funktionalitäten erweitern.

Das würde sich für mich dann nach so etwas wie „Plug & Playanfühlen, also hinzufügen und „zack“, läuft!

Winforms Anlauf – VB.NET Anwendungsdauer auslesen

Mein erster Versuch, bzw. der erste Pseudocode (für Winforms) sah also so ähnlich aus:

Imports System.Runtime.CompilerServices

Module modExtensions

    Private ReadOnly StartedAt As Date = Date.Now

    <Extension>
    Public Function GetTimeRunning(app As Application) As TimeSpan
        Dim timeDiff = Date.Now - StartedAt
        Return timeDiff
    End Function

End Module

Klappt leider direkt nicht

Leider können wir Klassen mit Hilfe von Erweiterungsmethoden keine statischen (shared) Methoden hinzufügen.

Das obige Code-Beispiel würde daher die Klasse Applicationum den jeweiligen Code erweitern.

Allerdings kann man die Methode wie erklärt dann nur auf einer Instanz der „Application“-Klasse aufrufen.

Shared„-Methoden sind in Modulen übrigens nicht verwendbar, also nicht gültig.

Eins der Probleme bei WPF gelöst

Mit WPF können wir eines der Probleme einfach lösen, denn WPF kann auf die aktuelle Instanz der Anwendung zugreifen.

Beherbergt in der „Application„-Klasse aus einem anderen Namespace, können wir nun auf die aktuelle Instanz der Anwendung zugreifen.

Somit haben wir jetzt die Möglichkeit, die deklarierte Erweiterungsmethode zu verwenden.

Die Erweiterungsmethode erklärt

Hier erkläre ich Dir kurz die Vorgehensweise der Erweiterungsmethode und zeige Dir das erste Ergebnis.

Vorgehensweise – VB.NET Anwendungsdauer auslesen

Dort siehst Du ein beliebig benanntes Modul, Welches ein privates Feld namens „StartedAt“ besitzt.

Dieses Feld sollte die aktuelle Zeit zum Anwendungsstart widerspiegeln – sollte, aber dazu gleich mehr.

Die „GetTimeRunning“-Funktion führt eine simple Subtraktion von 2 Date (DateTime) Objekten durch.

Dabei wird die Startzeit von der aktuellen Zeit abgezogen, Welche dann die verstrichene Zeit darstellt.

Die Subtraktion der Dates ist von .NET schon implementiert und gibt als Ergebnis ein TimeSpan-Objekt aus.

Das erste Ergebnis

Schaue Dir im folgenden Bild unser erstes Ergebnis der aktuellen Herangehensweise an.

Dabei habe ich mir den Rückgabewert der Funktion einfach 2x mit Verzögerung als String ausgeben lassen.

Das habe ich ganz simpel mit der „WriteLine“-Methode der Debug-Klasse, innerhalb eines ButtonKlicks umgesetzt.

Ausgabe Anwendungsdauer mit Erweiterungsmethode falsch
Ausgabe Anwendungsdauer mit Erweiterungsmethode falsch

Bittere Enttäuschung

Wie die Überschrift schon vermuten lässt, kommen wir mit diesem Beispiel leider nicht an unser gewünschtes Ziel.

Erklären lässt sich das zwar korrekte aber nicht funktionierende Beispiel, mit Hilfe der dahinter liegenden Ausführungslogik von .NET.

Obwohl ich schon vor dem ersten Klick ein wenig gewartet hatte, bekomme ich trotzdem einen komischen Wert.

Das liegt daran, dass das „StartedAt“-Feld des Moduls erst nach erstmaliger Verwendung des Moduls während der Laufzeit initialisiert wird.

Nach ca. 3 weiteren Sekunden habe ich dann erneut auf den Button geklickt und siehe da, ein besseres Ergebnis.

Zu diesem Zeitpunkt war das Feld bereits initialisiert und hatte somit einen korrekten“ Wert.

Negativer Wert

Wie das Feld im ersten Schritt einen negativen Wert generieren konnte verstehe ich allerdings selbst nicht so ganz.

Auch wenn ich einige Vermutungen im Bereich DateTime-MinValue aufstelle, dürften sich Diese eigentlich nicht bewahrheiten.

Denn bevor ich auf das Feld zugreife, müsste Ihm ja trotzdem bereits der auf Modul-Ebene „Date.Now“ Wert zugewiesen sein.

Fokus auf das Wesentliche

Halten wir uns aber nicht weiter damit auf und fokussieren uns auf das Wesentliche.

Das eigentliche Problem mit der hier aufgeführten Möglichkeit ist, dass der Wert erst nach der ersten Verwendung zustande kommt.

Einen möglichen Workaround um das zweite geschilderte Problem, finden wir mit Hilfe der „Process„-Klasse.

Dort speichert die nützliche Eigenschaft StartTime„, den Startzeitpunkt der App in der aktuellen Prozess-Instanz.

Der Code um an die „StartTimedes momentanen Prozesses zu kommen, sieht so aus:

Dim processStartTime = Process.GetCurrentProcess().StartTime

Erweiterungsmethode V2

Wir schreiben unsere Erweiterungsmethode aus dem obigen Code-Snippet also wie folgt um:

Imports System.Runtime.CompilerServices

Module modExtensions

    <Extension>
    Public Function GetTimeRunning(app As Application) As TimeSpan
        Dim timeDiff = Date.Now - Process.GetCurrentProcess().StartTime
        Return timeDiff
    End Function

End Module

Dabei entfernen wir das Feld StartedAt“ und ersetzen dessen Verwendung durch die hier drüber vorgestellte „StartTime„-Eigenschaft der „Process“-Klasse.

Achtung! Bei meiner Recherche bin ich auf diverse Probleme gestoßen, wenn man den Code im Debugging verwendete. Durch die gehostete Exe, ist der Prozess eventuell schon länger aktiv. Wenn man die Exe allerdings ohne Debugging startet (Strg+F5), klappt alles.

WPF läuft nun

In einer WPF-Umgebung läuft der Code mit der Erweiterungsmethode ohne Probleme.

Die WPF-Anwendung selbst, findest Du natürlich auch in der Projektmappe des Downloads.

Nachdem ich die Anwendung starte und gefühlt 3 Sekunden warte, bekomme ich folgende Ausgabe:

Ausgabe Anwendungsdauer in WPF mit Erweiterungsmethode
Ausgabe Anwendungsdauer in WPF mit Erweiterungsmethode

Winforms-Fix – VB.NET Anwendungsdauer auslesen

Nun bringen wir das Ganze Snippet auch in ähnlicher Form in Winforms-Awendungen zum Laufen.

Dazu lege ich einfach auch ein Modul an, Welches dann geschachtelte Klassen mit der Funktionalität enthält.

Module modExtensions

    Public Class Extensions

        Public Class Application

            Public Shared Function GetTimeRunning() As TimeSpan
                Dim timeDiff = Date.Now - Process.GetCurrentProcess().StartTime
                Return timeDiff
            End Function

        End Class

    End Class

End Module

Dessen Aufruf in einer Windows-Form, bzw. in einem Button Klick-Ereignishandler sieht dann ähnlich einfach aus:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Debug.WriteLine(Extensions.Application.Runtime())
    End Sub

Weiterführende Links

Downloads – VB.NET Anwendungsdauer auslesen

Der Download enthält die Projektmappe für das „VB.NET Anwendungsdauer auslesen“-Projekt, bestehend aus dem Winformsund dem WPF-Projekt.

Das richtige Startprojekt beim Ausprobieren des Codes kannst Du mit einem Rechtsklick auf das Projekt + "Als Startprojekt festlegen" ändern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert