<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>programmieren Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/programmieren/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Thu, 18 Jan 2024 00:52:44 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://robbelroot.de/wp-content/uploads/2020/12/cropped-favicon-32x32.png</url>
	<title>programmieren Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>VB.NET Autostart für Dein eigenes Programm erstellen – 2024 Version</title>
		<link>https://robbelroot.de/blog/vb-net-autostart-fuer-dein-eigenes-programm-erstellen/</link>
					<comments>https://robbelroot.de/blog/vb-net-autostart-fuer-dein-eigenes-programm-erstellen/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Tue, 27 Dec 2022 05:40:27 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[automatisch]]></category>
		<category><![CDATA[autostart]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[erstellen]]></category>
		<category><![CDATA[programm]]></category>
		<category><![CDATA[programmieren]]></category>
		<category><![CDATA[programmierung]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[shortcut]]></category>
		<category><![CDATA[start]]></category>
		<category><![CDATA[starten]]></category>
		<category><![CDATA[startup]]></category>
		<category><![CDATA[systemstart]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[verknüpfung]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=13290</guid>

					<description><![CDATA[<p>Dein VB.NET Programm automatisch bei Systemstart starten Hast Du Deine nächste tolle Anwendung entwickelt, Welche Du nun via VB.NET in den Autostart packen möchtest? Im heutigen Beitrag schauen wir uns genau das und mehr, wie z. B. das Erstellen von Verknüpfungen via der &#8222;WshShell&#8220; an. Bleib also dran, es wird &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vb-net-autostart-fuer-dein-eigenes-programm-erstellen/">VB.NET Autostart für Dein eigenes Programm erstellen – 2024 Version</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Autostart-fuer-Dein-eigenes-Programm-erstellen-Programm-mit-Windows-starten-–-2023-Remake-Beitrags-Header.png"><img fetchpriority="high" decoding="async" width="1280" height="720" src="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Autostart-fuer-Dein-eigenes-Programm-erstellen-Programm-mit-Windows-starten-–-2023-Remake-Beitrags-Header.png" alt="VB.NET Autostart für Dein eigenes Programm erstellen - Programm mit Windows starten" class="wp-image-13329" title="VB.NET Autostart für Dein eigenes Programm erstellen - Programm mit Windows starten"/></a><figcaption class="wp-element-caption">VB.NET Autostart für Dein eigenes Programm erstellen &#8211; Programm mit Windows starten</figcaption></figure>






<h2 class="wp-block-heading">Dein VB.NET Programm automatisch bei Systemstart starten</h2>



<p>Hast Du Deine nächste tolle Anwendung entwickelt, Welche Du nun via VB.NET in den Autostart packen möchtest? Im heutigen Beitrag schauen wir uns genau das und mehr, wie z. B. das Erstellen von Verknüpfungen via der &#8222;WshShell&#8220; an. Bleib also dran, es wird ziemlich interessant &#x1f609;!</p>



<p class="info-banner">&#x1f4a1; <strong>Hinweis</strong>: Wenn Du es eilig hast, kannst Du auch direkt zum Code weiter unten scrollen, bzw. das <strong><a href="#toc_container">Inhaltsverzeichnis</a></strong> für das Springen zu verschiedenen Eckpunkten verwenden. Auch wenn der Beitrag seinen Fokus auf VB.NET hat, sind alle Code-Beispiele natürlich auch für C# verfügbar! Springe für den <strong><a href="#kompletter-code">kompletten Code</a></strong>, oder für dessen <strong><a href="#verwendungsbeispiele">Verwendungsbeispiele</a></strong> nach unten.</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<p>Wie Du vielleicht weißt hatte ich auch schonmal ein Video zum Thema gemacht &#8211; vor unfassbaren 11 Jahren, oh man, ich werde alt.. Ein Abonnent hatte mich darauf aufmerksam gemacht, dass es in die Jahre gekommen ist und er sich ein Update wünscht. Dies war mir Befehl und nun sind wir hier &#x1f913;!</p>



<p>Wenn Du moderne Anwendungen entwickeln möchtest – Welche dann passenderweise in den Autostart können –, solltest Du Dir unbedingt diese beiden Beiträge anschauen:</p>



<ul class="wp-block-list">
<li><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener"><strong>Der ultimative INotifyPropertyChanged Guide – für C# &amp; VB.NET</strong></a></li>



<li><strong><a href="https://robbelroot.de/blog/der-ultimative-wpf-datagrid-mvvm-guide-csharp-und-vb-net/" target="_blank" rel="noreferrer noopener">Der ultimative WPF DataGrid MVVM Guide – C# &amp; VB.NET</a></strong></li>
</ul>



<h2 class="wp-block-heading">Als Video ansehen – &#8222;VB.NET Autostart von Programmen&#8220;</h2>



<p>Wenn Du es eiliger, bzw. eventuell keine Lust auf Text hast, kannst Du natürlich auch gerne zum Videoformat greifen und Dich berieseln lassen. Nutze auch im Video gerne die Kapitel, um zu den Stellen von besonderem Interesse zu springen.</p>


<div class="async-youtube" data-embed="ESRgqNvvfKg" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading">Wie startet man Software überhaupt via Autostart?</h2>



<p>Bevor wir uns an die VB.NET-spezifische Thematik wagen, ist es ggf. vorerst ganz sinnvoll, sich mit dieser Frage auseinanderzusetzen: Wie starte ich ein Programm überhaupt bei Systemstart? Grundsätzlich ist die Antwort darauf ziemlich einfach, denn Windows bietet eigentlich alle Bordmittel, Die man als Administrator oder auch Entwickler, braucht.</p>



<p>Dazu gibt es den sogenannten Autostart-Ordner, Welcher ungefähr so wie gleich folgend aussieht. Bei mir ist – zugegebenermaßen – nicht viel dort zu sehen, denn ich versuche den immer &#8222;clean&#8220; zu halten.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Autostart-fuer-das-eigene-Programm-erstellen.png"><img decoding="async" width="851" height="505" src="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Autostart-fuer-das-eigene-Programm-erstellen.png" alt="VB.NET Autostart für das eigene Programm erstellen" class="wp-image-13305" title="VB.NET Autostart für das eigene Programm erstellen"/></a><figcaption class="wp-element-caption">VB.NET Autostart für das eigene Programm erstellen</figcaption></figure>



<h3 class="wp-block-heading">Vorgehensweise</h3>



<p>Um ein Programm beim Start des Windows-Systems automatisch mit-starten zu lassen, muss man Dieses, bzw. eine Verknüpfung dazu in den Autostart-Ordner ablegen. Das Schöne ist hier wirklich die Möglichkeit der Verknüpfung, denn wer hat Lust, jedes Mal x Megabyte zu kopieren und eventuell dann doppelt zu haben. Ich persönlich hatte bei dieser Vorgehensweise auch nie Probleme, im Gegensatz zu einigen recherchierten Suchergebnissen auf Google. Kommentiere gerne, wenn auch Du auf derartige Probleme stößt, würde mich interessieren!</p>



<h3 class="wp-block-heading">Vorsicht geboten</h3>



<p>Wie erwähnt wird jedes Programm, bzw. jede Verknüpfung im genannten Ordner automatisch bei Systemstart gestartet. Das stattet uns Entwickler &amp; Administratoren natürlich auch mit einer großen Bürde aus. Erstens – so finde ich – sollte man dem Nutzer bei Systemstart nicht direkt 20 GUIs an den Kopf schmeißen und zweitens sollte man ja auch noch an die Startzeit denken. Wer hat schon Lust, 5 Minuten länger zu warten, nur weil ein Programm bei Start schon viel Auslastung zieht!?</p>



<h2 class="wp-block-heading">Welche Möglichkeiten habe ich beim Autostart?</h2>



<p>Egal ob mit VB.NET (oder C#..), oder ohne, wir haben verschiedene Möglichkeiten, den Autostart zu verwenden. Einerseits können wir benutzerspezifische Startmöglichkeiten verwenden, oder auch global, also für alle Nutzer einen automatischen Programmstart anlegen. In diesem Beitrag gehe ich jedoch in erster Linie auf den benutzerspezifischen Autostart ein.</p>



<h2 class="wp-block-heading">Wo, bzw. wie finde ich die Autostart-Ordner?</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/75jxwu.jpg"><img decoding="async" width="888" height="499" src="https://robbelroot.de/wp-content/uploads/2022/12/75jxwu.jpg" alt="Wo, bzw. wie finde ich die Autostart-Ordner? VB.NET Autostart erstellen" class="wp-image-13331" title="Wo, bzw. wie finde ich die Autostart-Ordner? VB.NET Autostart erstellen"/></a><figcaption class="wp-element-caption">Wo, bzw. wie finde ich die Autostart-Ordner? VB.NET Autostart erstellen</figcaption></figure>



<p>In erster Linie kommt das natürlich darauf an, für wen Du einen Autostart erstellen möchtest. Möchtest Du Dein Programm z. B. für den aktuellen Nutzer in den Autostart legen, dann kommt folgendes Verzeichnis in Frage. Beachte hierbei, dass Du den Platzhalter natürlich durch den jeweiligen Nutzernamen ersetzen müsstest:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">C:\Users\&lt;DeinNutzername>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup</pre>



<p>Du kannst den Ordner auch vereinfacht finden, indem Du die Windows-Taste+R drückst, was den &#8222;Ausführen&#8220;-Dialog startet. Und im nächsten Schritt dann:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">shell:startup</pre>



<p>eingeben, was Dich dann in dem für Dich passenden Autostart-Ordner auskommen lässt. Cool, oder?</p>



<h3 class="wp-block-heading">Globaler Autostart-Ordner</h3>



<p>Möchtest Du hingegen den &#8222;globalen&#8220; Ordner finden, kannst Du stattdessen in folgendem Verzeichnis</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp</pre>



<p>und mit diesem Befehl hier fündig werden (denke an Windows-Taste+R):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">shell:common startup</pre>



<p>Hier findest Du dann die Programme, Welche für alle Nutzer automatisch bei Systemstart gestartet werden sollen.</p>



<h2 class="wp-block-heading">Wie sieht der VB.NET Autostart nun aus?</h2>



<p>Um nun die oben erklärte Logik, bzw. Vorgehensweise mit VB.NET nachzubilden, müssen wir ja praktisch nichts Anderes tun. Wir müssen (via Code) eine Verknüpfung unserer Anwendung erschaffen und Diese nach Möglichkeit im Autostart-Ordner unserer Wahl unterbringen. Besonders die Erstellung einer Verknüpfung kann aber tricky sein, wenn man nicht weiß, wie.</p>



<p>Zusätzlich könnte man weitere Hilfsmittel schreiben, um z. B. überprüfen zu können, ob sich unsere Anwendung aktuell schon im Autostart befindet. Dies alles werden wir selbstverständlich nach Regeln der OOP (Objektorientierten Programmierung) in eine Klasse auslagern. So bleibt alles schön wiederverwendbar und portierbar.</p>



<p>Lege also im nächsten Schritt einen Ordner namens &#8222;Utils&#8220; in Deinem Projekt an und erstelle dort drin eine &#8222;Autostart&#8220;-Klasse.</p>



<h2 class="wp-block-heading">Mit VB.NET den Autostart-Ordner ermitteln</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/Autostart-Ordner-mit-VB.NET-ermitteln.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/12/Autostart-Ordner-mit-VB.NET-ermitteln.png" alt="Autostart-Ordner mit VB.NET ermitteln" class="wp-image-13386" title="Autostart-Ordner-mit-VB.NET-ermitteln"/></a><figcaption class="wp-element-caption">Autostart-Ordner mit VB.NET ermitteln</figcaption></figure>



<p>Bevor wir uns jedoch Gedanken über Dinge wie &#8222;Wie kann ich die Verknüpfung erstellen&#8220;, usw. machen, starten wir easy. Zuerst einmal müssen wir wissen, wie wir an den Autostart-Ordner kommen, ist ja schließlich Betriebssystem-Sache. Zufälligerweise benutzen wir eine optimale Sprache für dieses Betriebssystem vom selben Hersteller – kann ja dann nicht so schwer sein, richtig? Richtig!</p>



<p>Um an den Pfad zum Autostart-Ordner (auch Startup-Folder genannt) zu kommen, können wir vorgefertigte Funktionen nutzen. Die Methode unseres Vertrauens befindet sich in der <strong><a href="https://learn.microsoft.com/en-us/dotnet/api/system.environment?view=net-7.0" target="_blank" rel="noreferrer noopener">&#8222;Environment&#8220;-Klasse</a></strong> und heißt <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.environment.getfolderpath?view=net-7.0" target="_blank" rel="noreferrer noopener">&#8222;GetFolderPath&#8220;</a></strong>. Diese erwartet einen Wert der <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.environment.specialfolder?view=net-7.0" target="_blank" rel="noreferrer noopener">&#8222;SpecialFolder&#8220;-Enumeration</a></strong> aus selbiger Klasse.</p>



<p>Implementieren wir nun eine Art &#8222;Singleton&#8220;-, bzw. eine &#8222;Lazy&#8220;-Property (Eigenschaft), Welche uns den Autostart-Ordner serviert. So müssen wir der Environment nicht öfter als nötig auf die Nerven gehen &#8211; ergo, die Funktion nur einmalig aufrufen und den Rückgabewert zwischenspeichern:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="startup-directory-property">        Private Shared _startupDirectory As String

        Public Shared ReadOnly Property StartupDirectory As String
            Get
                If String.IsNullOrWhiteSpace(_startupDirectory) Then
                    _startupDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Startup)
                End If
                Return _startupDirectory
            End Get
        End Property</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="startup-directory-property">    private static string _startupDirectory;

    public static string StartupDirectory
    {
        get
        {
            if (string.IsNullOrWhiteSpace(_startupDirectory))
                _startupDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
            return _startupDirectory;
        }
    }</pre>



<h2 class="wp-block-heading">Einen Eintrag in den Autostart mit VB.NET hinzufügen</h2>



<p>Im nächsten Schritt schauen wir uns an, wie wir unsere VB.NET-Anwendung, bzw. eine Verknüpfung davon in den Autostart-Ordner gelegt bekommen. Dazu bauen wir uns eine kleine &#8222;AddEntry&#8220; Methode, Welcher es egal ist, ob ein Pfad zu unserer Anwendung mitkommt, denn Diesen, kann Sie auch selbst ermitteln. So bleibt uns die Möglichkeit übrig, fremde Anwendungen, sowie die Eigene gemütlich hinzuzufügen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="add-entry-method">        ''' &lt;summary>
        ''' Adds an entry to the autostart folder for the given Application
        ''' &lt;/summary>
        ''' &lt;param name="applicationFilePath">The given application filepath, or empty to create an autostart for the current executing .exe&lt;/param>
        Public Shared Sub AddEntry(Optional applicationFilePath As String = "")
            Dim noAppPathProvided = applicationFilePath = ""
            If noAppPathProvided Then
                DefaultToExecutingExe(applicationFilePath)
            End If
            CreateShortcut(applicationFilePath)
        End Sub</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="add-entry-method">/// &lt;summary>
/// Adds an entry to the autostart folder for the given Application
/// &lt;/summary>
/// &lt;param name="applicationFilePath">The given application filepath, or empty to create an autostart for the currently executing .exe&lt;/param>
public static void AddEntry(string applicationFilePath = "")
{
    var noAppPathProvided = applicationFilePath == "";
    if (noAppPathProvided)
        DefaultToExecutingExe(applicationFilePath);
    CreateShortcut(applicationFilePath);
}</pre>



<p>Wie Du hier schon sehen kannst, schauen wir (wie erwähnt), ob ein passender &#8222;applicationFilePath&#8220; mitgeliefert wurde. Wenn nicht &#8222;Defaulten&#8220; wir zur ausführenden Exe-Datei, also dem aktuellen Programm. So oder so erstellen wir am Ende der Methode eine Verknüpfung, was wir im nächsten Schritt besprechen werden.</p>



<h2 class="wp-block-heading">Die ausgeführte .Exe-Datei erkennen</h2>



<p>Nachdem wir die eigentliche Methode schon einmal im letzten Schritt vorbereitet haben, fehlen nun noch die 2 Sub-Routinen. In erster Linie schauen wir hier uns hier schnell die &#8222;DefaultToExecutingExe&#8220;-Methode an. Diese bekommt einen &#8222;ByRef&#8220;-Parameter übergeben &#8211; empfand ich hier irgendwie leichter lesbar &#8211; aber ist nur meine Meinung. Diese setzt dann den &#8222;applicationFilePath&#8220; via &#8222;Process&#8220;-Klasse, bzw. mittels einer verschachtelten Sub-Eigenschaft des Prozesses. Diesen ermitteln wir mit der statischen &#8222;GetCurrentProcess&#8220;-Funktion der &#8222;Process&#8220;-Klasse. Hier gibt es ab .NET 6 auch eine neue Variante, allerdings habe ich hier Die genommen, Welche vermutlich am geläufigsten ist.</p>



<h2 class="wp-block-heading">Unsere VB.NET Anwendung als Verknüpfung in den Autostart legen</h2>



<p>Nun fehlt nur noch ein letztes Werkzeug, die Funktionalität, für unsere (und auch andere Anwendungen) eine Verknüpfung erzeugen zu können. Dies kann – wie oben bereits erwähnt – ein wenig tricky werden, wenn man nicht weiß, wie. Wir verwenden dazu das &#8222;WshShell&#8220;-Interface, Welches komischerweise instanziiert werden kann, Du glaubst mir nicht? Guck in den Code!</p>



<h3 class="wp-block-heading">COM-Verweis hinzufügen</h3>



<p>Bevor wir damit jedoch starten können, müssen wir zuerst noch den benötigten COM-Verweis auf das &#8222;Windows Script Host Object Model&#8220; hinzufügen. Das kannst Du ganz einfach machen, indem Du einen Rechtsklick auf Dein Projekt durchführst und anschließend &#8222;Hinzufügen-&gt;COM-Verweis&#8220; auswählst.</p>



<p>Danach erscheint dieses folgende Fenster, wo Du dann oben rechts dementsprechend z. B. nach &#8222;host&#8220; suchen kannst, dann dürftest Du – siehe Bild – schnell fündig werden:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Windows-Script-Object-Model-COM-Verweis.png"><img loading="lazy" decoding="async" width="789" height="506" src="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Windows-Script-Object-Model-COM-Verweis.png" alt="VB.NET Windows Script Object Model COM-Verweis" class="wp-image-13370" title="VB.NET Windows Script Object Model COM-Verweis"/></a><figcaption class="wp-element-caption">VB.NET Windows Script Object Model COM-Verweis</figcaption></figure>



<h3 class="wp-block-heading">Ein instanziierbares Interface – what the f**?</h3>



<p>Um ehrlich zu sein – wie ich nunmal bin.. – habe ich mich selbst damit auch nicht auseinandergesetzt, warum man diese Schnittstelle instanziieren kann (auch in C#). Und da ich COM-Dinge eigentlich nie benötige, ist mir das hier auch relativ egal, solange es funktioniert. Ich gehe mal ohne Recherche davon aus, dass das an der Deklaration des Interfaces liegt, dort sehen wir ein &#8222;CoClass&#8220;-Attribut.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Verknuepfung-erstellen-WshShell-Interface.png"><img loading="lazy" decoding="async" width="444" height="194" src="https://robbelroot.de/wp-content/uploads/2022/12/VB.NET-Verknuepfung-erstellen-WshShell-Interface.png" alt="VB.NET Verknüpfung erstellen WshShell-Interface" class="wp-image-13364" title="VB.NET Verknüpfung erstellen WshShell-Interface"/></a><figcaption class="wp-element-caption">VB.NET Verknüpfung erstellen WshShell-Interface</figcaption></figure>



<p>Vermutlich wird &#8222;der Code&#8220; dann sehen: &#8222;Ah, da ist ein CoClass Ding, also muss ich das wohl instaziieren&#8220; – oder so ähnlich. EDIT: Habe kurz nachgeguckt, liegt wie vermutet an dem &#8222;CoClass&#8220;-Attribut – Erfahrung &#8222;strikes again&#8220; &#x1f609;!</p>



<h3 class="wp-block-heading">Eine Verknüpfung erstellen</h3>



<p>Nachdem wir das Interface nun instanziieren können – ew, klingt immer noch ekelig, na egal – tun wir gleich genau das. Vorher erstellen wir noch ein &#8222;FileInfo&#8220;-Objekt, Welches uns bei der Arbeit mit Datei-Infos wie den Namen der Datei, usw. unterstützen wird. Und dann gehen wir schonmal hin und erstellen den letztendlichen Pfad der Verknüpfung mit String-Interpolation.</p>



<p>Hier verwenden wir ein weiteres kleines Helferlein, was – wie der Name schon sagt – den Dateinamen ohne Dateiendung für uns herausfiltert. Dazu übergeben wir der statischen &#8222;Path&#8220;-Klassen-Funktion &#8222;GetFileNameWithoutExtension&#8220;, den Namen des &#8222;FileInfo&#8220;-Objektes.</p>



<p>Im letzten Schritt erzeugen wir die Verknüpfung auf Objekt-Ebene und casten Sie in ein für unsere Zwecke passendes Interface – &#8222;IWshShortcut&#8220;. Anschließend kannst Du weitere Eigenschaften wie z. B. die Beschreibung und den Icon-Pfad angeben, dies lasse ich hier aber aus. Zuletzt kommen die beiden wichtigsten Schritte: Den Ziel-Pfad, also den Pfad zur eigentlichen Anwendung festzulegen und dann final auch &#8222;Save&#8220; aufzurufen, damit die Verknüpfung tatsächlich erstellt wird.</p>



<h2 class="wp-block-heading">Prüfen ob ein Autostart-Eintrag existiert</h2>



<p>Nun haben wir die Funktionalität von oben vorliegen und würden direkt mit der Nächsten starten. Es wäre schließlich ganz nützlich, wenn man auch prüfen könnte, ob bereits eine Verknüpfung im Autostart ist. Dazu erstellen wir im nächsten Schritt eine &#8222;EntryExists&#8220;-Funktion, Welche dies über einen Boolean kommuniziert.</p>



<p>In den ersten Zeilen verfahren wir hier wir in der &#8222;AddEntry&#8220;-Methode, also bezogen auf die Pfad-Sache. Wenn kein Pfad angegeben wurde, nehmen wir den Pfad der aktuellen Exe-Datei, usw. Danach bauen wir uns den Pfad zur Verknüpfung (im Autostart-Ordner!) zusammen. Wenn eine derartige Datei (dort) existiert, dann haben wir das Programm bereits im Autostart – yay!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="entry-exists-method">        Public Shared Function EntryExists(Optional applicationFilePath As String = "") As Boolean
            Dim noAppPathProvided = applicationFilePath = ""
            If noAppPathProvided Then
                DefaultToExecutingExe(applicationFilePath)
            End If
            Dim applicationFile = New FileInfo(applicationFilePath)
            Dim shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk")
            Return IO.File.Exists(shortcutPath)
        End Function</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="entry-exists-method">public static bool EntryExists(string applicationFilePath = "")
{
    var noAppPathProvided = applicationFilePath == "";
    if (noAppPathProvided)
        DefaultToExecutingExe(applicationFilePath);
    var applicationFile = new FileInfo(applicationFilePath);
    var shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk");
    return System.IO.File.Exists(shortcutPath);
}</pre>



<h2 class="wp-block-heading">Mit VB.NET den Autostart wieder entfernen</h2>



<p>Im letzten Abschnitt dieses Beitrages werden wir uns ansehen, wie wir erzeugte Einträge auch wieder entfernen können. Dies kennt man natürlich bereits aus größeren Tools. Wir schreiben also eine &#8222;RemoveEntry&#8220;-Methode, Welche sehr ähnlich zu den Vorherigen funktioniert. Zuerst prüfen wir wieder die Pfad-Übergabe, danach erstellen wir der Einfachheit halber eine &#8222;FileInfo&#8220; und danach generieren wir den Verknüpfungs-Pfad.</p>



<p>Wenn Dieser Pfad existent ist, wird er gelöscht, somit wird auch unser VB.NET Autostart entfernt. Beachte hierbei, dass ich bewusst kein Try-Catch drum gemacht habe. Ich möchte aktiv auf Fehler reagieren und diese separat und sauber verarbeiten können.</p>



<h2 class="wp-block-heading" id="kompletter-code">Kompletter Code</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/Kompletter-Code-VB.NET-Autostart.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/12/Kompletter-Code-VB.NET-Autostart.png" alt="Kompletter Code - VB.NET Autostart" class="wp-image-13384" title="Kompletter Code - VB.NET Autostart"/></a><figcaption class="wp-element-caption">Kompletter Code &#8211; VB.NET Autostart</figcaption></figure>



<p>Hier findest Du den wichtigsten Code für diesen Beitrag. In diesem Beispiel handelt es sich um die kleine von mir gebaute Hilfs-Klasse. Diese vereinfacht Dir die Erstellung der Programm-Verknüpfung innerhalb des Autostart-Ordners via VB.NET (und C#!):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="Autostart.vb" data-enlighter-group="complete-code">Imports System.IO
Imports IWshRuntimeLibrary

Namespace Utils

    Public Class Autostart

        Private Shared _startupDirectory As String

        Public Shared ReadOnly Property StartupDirectory As String
            Get
                If String.IsNullOrWhiteSpace(_startupDirectory) Then
                    _startupDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Startup)
                End If
                Return _startupDirectory
            End Get
        End Property

        ''' &lt;summary>
        ''' Adds an entry to the autostart folder for the given Application
        ''' &lt;/summary>
        ''' &lt;param name="applicationFilePath">The given application filepath, or empty to create an autostart for the current executing .exe&lt;/param>
        Public Shared Sub AddEntry(Optional applicationFilePath As String = "")
            Dim noAppPathProvided = applicationFilePath = ""
            If noAppPathProvided Then
                DefaultToExecutingExe(applicationFilePath)
            End If
            CreateShortcut(applicationFilePath)
        End Sub

        Private Shared Sub DefaultToExecutingExe(ByRef applicationFilePath As String)
            applicationFilePath = Process.GetCurrentProcess().MainModule.FileName
        End Sub

        Private Shared Sub CreateShortcut(applicationFilePath As String)
            Dim applicationFile = New FileInfo(applicationFilePath)
            Dim shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk")
            Dim shell = New WshShell()
            Dim shortcut = CType(shell.CreateShortcut(shortcutPath), IWshShortcut)
            With shortcut
                ' .Description = ""
                ' .IconLocation = ""
                .TargetPath = applicationFile.FullName
                .Save()
            End With
        End Sub

        Public Shared Function EntryExists(Optional applicationFilePath As String = "") As Boolean
            Dim noAppPathProvided = applicationFilePath = ""
            If noAppPathProvided Then
                DefaultToExecutingExe(applicationFilePath)
            End If
            Dim applicationFile = New FileInfo(applicationFilePath)
            Dim shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk")
            Return IO.File.Exists(shortcutPath)
        End Function

        Public Shared Sub RemoveEntry(Optional applicationFilePath As String = "")
            Dim noAppPathProvided = applicationFilePath = ""
            If noAppPathProvided Then
                DefaultToExecutingExe(applicationFilePath)
            End If
            Dim applicationFile = New FileInfo(applicationFilePath)
            Dim shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk")
            IO.File.Delete(shortcutPath)
        End Sub

    End Class

End Namespace
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="Autostart.cs" data-enlighter-group="complete-code">using System.IO;
using IWshRuntimeLibrary;

namespace Utils
{
    public class Autostart
    {
        private static string _startupDirectory;

        public static string StartupDirectory
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_startupDirectory))
                    _startupDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
                return _startupDirectory;
            }
        }

        /// &lt;summary>
        ///         ''' Adds an entry to the autostart folder for the given Application
        ///         ''' &lt;/summary>
        ///         ''' &lt;param name="applicationFilePath">The given application filepath, or empty to create an autostart for the current executing .exe&lt;/param>
        public static void AddEntry(string applicationFilePath = "")
        {
            var noAppPathProvided = applicationFilePath == "";
            if (noAppPathProvided)
                DefaultToExecutingExe(ref applicationFilePath);
            CreateShortcut(applicationFilePath);
        }

        private static void DefaultToExecutingExe(ref string applicationFilePath)
        {
            applicationFilePath = Process.GetCurrentProcess().MainModule.FileName;
        }

        private static void CreateShortcut(string applicationFilePath)
        {
            var applicationFile = new FileInfo(applicationFilePath);
            var shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk");
            var shell = new WshShell();
            var shortcut = (IWshShortcut)shell.CreateShortcut(shortcutPath);
            {
                var withBlock = shortcut;
                // .Description = ""
                // .IconLocation = ""
                withBlock.TargetPath = applicationFile.FullName;
                withBlock.Save();
            }
        }

        public static bool EntryExists(string applicationFilePath = "")
        {
            var noAppPathProvided = applicationFilePath == "";
            if (noAppPathProvided)
                DefaultToExecutingExe(ref applicationFilePath);
            var applicationFile = new FileInfo(applicationFilePath);
            var shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk");
            return System.IO.File.Exists(shortcutPath);
        }

        public static void RemoveEntry(string applicationFilePath = "")
        {
            var noAppPathProvided = applicationFilePath == "";
            if (noAppPathProvided)
                DefaultToExecutingExe(ref applicationFilePath);
            var applicationFile = new FileInfo(applicationFilePath);
            var shortcutPath = Path.Combine(StartupDirectory, $"{Path.GetFileNameWithoutExtension(applicationFile.Name)}.lnk");
            System.IO.File.Delete(shortcutPath);
        }
    }
}</pre>



<h2 class="wp-block-heading" id="verwendungsbeispiele">Verwendung des Codes</h2>



<p>Um den obigen Code verwenden zu können, kannst Du z. B. 2 Knöpfe und eine CheckBox in Deine Form setzen. Beim Start des Formulares wird die Checkbox je nachdem ob das VB.NET Programm im Autostart liegt gefüllt. Wenn Du dann auf die jeweiligen Buttons drückst, kannst Du das Programm wieder aus dem Autostart entfernen, bzw. natürlich auch hinzufügen. Die Namen sind denke ich selbsterklärend..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="Form1.vb" data-enlighter-group="form-example">Imports AutoStartExampleVb.Utils

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        chbAutostartActivated.Checked = Autostart.EntryExists()
    End Sub

    Private Sub btnActivateAutostart_Click(sender As Object, e As EventArgs) Handles btnActivateAutostart.Click
        Autostart.AddEntry()
        chbAutostartActivated.Checked = True
    End Sub

    Private Sub btnDeactivateAutostart_Click(sender As Object, e As EventArgs) Handles btnDeactivateAutostart.Click
        Autostart.RemoveEntry()
        chbAutostartActivated.Checked = False
    End Sub

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="Form1.cs" data-enlighter-group="form-example">using System;
using AutoStartExampleVb.Utils;

public class Form1
{
    private void Form1_Load(object sender, EventArgs e)
    {
        chbAutostartActivated.Checked = Autostart.EntryExists();
    }

    private void btnActivateAutostart_Click(object sender, EventArgs e)
    {
        Autostart.AddEntry();
        chbAutostartActivated.Checked = true;
    }

    private void btnDeactivateAutostart_Click(object sender, EventArgs e)
    {
        Autostart.RemoveEntry();
        chbAutostartActivated.Checked = false;
    }
}</pre>



<h2 class="wp-block-heading">Downloads</h2>



<p>Keine Lust alles zu kopieren und es manuell zusammen zu frickeln? Dann lade Dir hier einfach den Beispielcode herunter, Dieser beinhaltet die komplette und fertig testbare Projektmappe.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=676ab19b-1548-4e62-891b-5a79d57bcf7f" target="_blank" rel="noreferrer noopener">AutoStartExampleVb.zip</a></div>


</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vb-net-autostart-fuer-dein-eigenes-programm-erstellen/">VB.NET Autostart für Dein eigenes Programm erstellen – 2024 Version</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vb-net-autostart-fuer-dein-eigenes-programm-erstellen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Was ist ConfigureAwait und warum sollte &#8222;False&#8220; der Standard sein?</title>
		<link>https://robbelroot.de/blog/was-ist-configureawait-false-und-warum-sollte-es-der-standard-sein/</link>
					<comments>https://robbelroot.de/blog/was-ist-configureawait-false-und-warum-sollte-es-der-standard-sein/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 10 Dec 2022 02:27:47 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[C# Problemlösungen]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[await]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[configure]]></category>
		<category><![CDATA[configureawait]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[effizient]]></category>
		<category><![CDATA[kontext]]></category>
		<category><![CDATA[optimieren]]></category>
		<category><![CDATA[programmieren]]></category>
		<category><![CDATA[prozess]]></category>
		<category><![CDATA[sauber]]></category>
		<category><![CDATA[standard]]></category>
		<category><![CDATA[synchronisationskontext]]></category>
		<category><![CDATA[task]]></category>
		<category><![CDATA[thread]]></category>
		<category><![CDATA[threading]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[verbessern]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=12547</guid>

					<description><![CDATA[<p>ConfigureAwait(False) als Standard für erfahrene Entwickler Erfahre im heutigen Beitrag, warum &#8222;ConfigureAwait&#8220; der Standard für fortgeschrittene Entwickler sein sollte. Hierzu schauen wir uns natürlich auch Beispiele ohne die benannte – ich nenne Sie mal – &#8222;Konfigurations&#8220;-Methode an. Insbesondere fällt hier auch ins Gewicht, welche Hürden man als Anfänger dabei bewältigen &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/was-ist-configureawait-false-und-warum-sollte-es-der-standard-sein/">Was ist ConfigureAwait und warum sollte &#8222;False&#8220; der Standard sein?</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/12/async-await-besser-nutzen.png"><img loading="lazy" decoding="async" width="1920" height="1080" src="https://robbelroot.de/wp-content/uploads/2022/12/async-await-besser-nutzen.png" alt="" class="wp-image-12584"/></a><figcaption class="wp-element-caption">ConfigureAwait für besseres Handling von Tasks – ein Standard für erfahrene .NET-Entwickler</figcaption></figure>






<h2 class="wp-block-heading">ConfigureAwait(False) als Standard für erfahrene Entwickler</h2>



<p>Erfahre im heutigen Beitrag, warum &#8222;<strong>ConfigureAwait</strong>&#8220; der Standard für fortgeschrittene Entwickler sein sollte. Hierzu schauen wir uns natürlich auch Beispiele ohne die benannte – ich nenne Sie mal – <strong>&#8222;Konfigurations&#8220;-Methode</strong> an. Insbesondere fällt hier auch ins Gewicht, welche Hürden man als Anfänger dabei bewältigen muss. Schaue Dir hierzu auch gerne die Beispiele in VB.NET und C# an!</p>



<h2 class="wp-block-heading">Was ist, bzw. wofür ist ConfigureAwait?</h2>



<p>Ganz plump übersetzt und zusammengefasst: Die &#8222;ConfigureAwait&#8220;-Methode konfiguriert eine Task so, dass dessen Folgeanweisungen auf dem Thread des Synchronisations-Kontextes ausgeführt (oder nicht ausgeführt) werden. Für gewöhnlich steht diese Konfiguration auf &#8222;True&#8220;, daher &#8222;springt&#8220; die Ausführung nach einer erwarteten Task immer wieder auf den Thread des Synchronisations-Kontextes zurück.</p>



<h2 class="wp-block-heading">Als Video auf YouTube ansehen</h2>



<p>Hast Du keine Lust auf Text? Dann besuche einfach mein passendes Video auf YouTube dazu. Ich habe mir größte Mühe gegeben, es einfach und verständlich zu erklären.</p>


<div class="async-youtube" data-embed="YKzkM7Pz3aM" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading">Wieso sollte ich nach Möglichkeit ConfigureAwait(False) verwenden?</h2>



<p>Man sollte ConfigureAwait(False) nach Möglichkeit verwenden, damit man eventuellem, permanentem ContextSwitching aus dem Weg geht. Das sähe dann vereinfacht gesagt so aus: Hintergrund, Vordergrund, Hintergrund, Vordergrund,&#8230; Es wäre hingegen doch wesentlich schöner, wenn wir erst alles im Hintergrund erledigen und dann final im Vordergrund bleiben, oder?</p>



<p>Nun hast Du bereits erfahren, dass bei entsprechender Konfiguration (<strong>standardmäßig True</strong>) ein eventuelles, ständiges Hopping zwischen den Threads stattfindet. Stell Dir vor, Du würdest eine Web-Schnittstelle aufrufen, oder eine Datei einlesen. Dies machst Du für gewöhnlich am besten asynchron, damit die grafische Oberfläche dabei nicht hängt. Stell Dir nun 5 Aufgaben vor, Welche dieses &#8222;in den Hintergrund auslagern&#8220; verwenden.</p>



<p>Es wäre doch blöd, wenn man nach jeder ausgeführten Aufgabe erst wieder zurückkommt, nur um dann wieder unnötig hin und her zu hüpfen.</p>



<p>Das ist ungefähr so, als würde ich Dir abwechselnd sagen &#8222;Geh&#8216; weg, komm&#8216; zurück, geh&#8216; weg&#8230;&#8220;. Spätestens nach dem zweiten Mal würdest Du mir vermutlich einen Vogel zeigen. Dies solltest Du bei der Konzeption / der Architektur Deiner Anwendungen auch im Kopf behalten. Leider kann der Computer uns hier nicht ebenfalls einen Vogel zeigen, denn Der macht letztendlich nur das, was Du Ihm durch Code sagst – KI und Co. jetzt mal weggelassen &#x1f609;.</p>



<h2 class="wp-block-heading">Wie sieht der Code ohne ConfigureAwait-Konfiguration aus?</h2>



<p>Damit wir die Vorgehensweise und den positiven Effekt hinter &#8222;ConfigureAwait&#8220; noch besser verstehen können, schauen wir es uns Schritt für Schritt an. Im ersten Schritt, bauen wir einfach mal ein wenig Code, ohne großartig darüber nachzudenken (wie leider viele Anfänger/Junior-Developer). Bei diesem Code ist dies auch nicht weiter &#8222;problematisch&#8220; &#8211; bis auf das ggf. fehlende Wissen dahinter.</p>



<p>Wirf also nun einen Blick auf folgenden, simplen Code, Welcher die statische <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.threading.tasks.task.delay?view=net-7.0" target="_blank" rel="noreferrer noopener">&#8222;Delay&#8220;-Methode der Task-Klasse verwende</a></strong>. Packe einen Knopf und ein Label auf Deine Form und generiere den Klick-Handler für den Button. Da wir uns hier nur auf das Wesentliche konzentrieren gehe ich an dieser Stelle davon aus, dass Du Dich mit dem erstellen eines Button-Klick-Handlers auskennst.</p>



<h3 class="wp-block-heading">Ein wenig mit Hilfe der Task warten</h3>



<p>Hierbei ist es auch relativ egal, ob Du nun Winforms oder WPF verwendest. Achte nur darauf, dass Du die Methode mit &#8222;Async&#8220; (VB.NET) / &#8222;async&#8220; (C#) markierst. Schreibe nun folgenden Code hinein und schaue, wie sich die Anwendung bei einem Klick verhält:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="normaler-task-delay-klick-handler">Private Async Sub Button1_Click(sender As Object, e As EventArgs)
  ' vor dem Delay (der "erwarteten" Task)
  Await Task.Delay(1000)
  ' nach dem Delay (nach der "erwarteten" Task)
  Label1.Text = "Mein neuer Text!"
End Sub</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="normaler-task-delay-klick-handler">private async void Button1_Click(object sender, EventArgs e)
{
  ' vor dem Delay (der "erwarteten" Task)
  await Task.Delay(1000)
  ' nach dem Delay (nach der "erwarteten" Task)
  Label1.Text = "Mein neuer Text!";
}</pre>



<p>Erstmal alles in Ordnung, oder? Die Anwendung startet und wartet darauf, dass Du etwas machst. Wenn Du auf den Button klickst, wartet &#8222;die Anwendung&#8220; eine Sekunde und der Text wird erfolgreich gesetzt. Hier ist wichtig zu verstehen, dass die Anwendung tatsächlich im Hintergrund wartet, ansonsten wäre Deine grafische Oberfläche währenddessen eingefroren.</p>



<h3 class="wp-block-heading">Wie das Ganze non-async aussieht</h3>



<p>Hierzu kannst Du auch einmal die &#8222;Thread.Sleep&#8220;-Variante nehmen, also ohne async und await, dann weißt Du was ich meine &#x1f913;! Du startest die Anwendung wie vorher, klickst auf den Button und merkst dann ups, ich kann das Fenster weder bewegen, noch vergrößern/verkleinern und auch der Text ändert sich nicht? Die Wartezeit habe ich bewusst hochgestellt &#8211; damit es noch klarer sichtbar ist, denn z. B. das Label ändert sich erst nachdem die Zeit abgelaufen ist.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="normaler-thread-sleep-klick-handler">Private Sub Button1_Click(sender As Object, e As EventArgs)
  ' vor dem Sleep
  System.Threading.Thread.Sleep(5000)
  ' nach dem Sleep
  Label1.Text = "Mein neuer Text!"
End Sub</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="normaler-thread-sleep-klick-handler">private void Button1_Click(object sender, EventArgs e)
{
  ' vor dem Sleep
  System.Threading.Thread.Sleep(5000)
  ' nach dem Sleep
  Label1.Text = "Mein neuer Text!";
}</pre>



<p>Nun hast Du gesehen und ggf. verstanden, was es zumindest für Auswirkungen hat, wenn der Thread der grafischen Oberfläche &#8222;zu&#8220; beschäftigt ist.</p>



<h2 class="wp-block-heading">Ein Beispiel mit ConfigureAwait(False)</h2>



<p>Ich kann Dich schon grummeln hören: &#8222;Ja wenn das so wichtig ist, wie sieht denn dann ein konfiguriertes Beispiel aus? Wenn True der Standardwert ist, wie sieht es dann beim – Deiner Meinung nach – richtigen False aus?&#8220;. Das ist eine gute Frage und Dieser widmen wir uns jetzt &#8211; schaue Dir den vorherigen Code nochmal, aber nun wie folgt an. Bedenke dabei, dass der Wert &#8222;True&#8220; standardmäßig voreingestellt ist, wir aber nun explizit &#8222;False&#8220; angeben:<br></p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="normaler-thread-sleep-klick-handler-gg">Private Async Sub Button1_Click(sender As Object, e As EventArgs)
  ' vor dem Delay (der "erwarteten" Task)
  Await Task.Delay(1000) _ ' wegen der Leserlichkeit umgebrochen
    ConfigureAwait(False)
  ' nach dem Delay (nach der "erwarteten" Task)
  Label1.Text = "Mein neuer Text!"
End Sub</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="normaler-thread-sleep-klick-handler-gg">private async void Button1_Click(object sender, EventArgs e)
{
  // vor dem Delay (der "erwarteten" Task)
  await Task.Delay(1000) // wegen der Leserlichkeit umgebrochen
    .ConfigureAwait(false);
  // nach dem Delay (nach der "erwarteten" Task)
  Label1.Text = "Mein neuer Text!";
}</pre>



<h3 class="wp-block-heading">Huch, jetzt gibt es einen Fehler?</h3>



<p>Nachdem Du den obigen Code ausgeführt hast, fragst Du Dich nun bestimmt: &#8222;Toll, jetzt habe ich&#8217;s genauso gemacht, wie Du sagtest, aber jetzt gibt es einen Fehler, warum? Wie soll mir das helfen?&#8220;. Ich kann Deine Aufregung als vermutlicher Anfänger (ggf. sogar Fortgeschrittener) erstmal verstehen. Ich erkläre Dir erstmal was passiert ist und warum wir diesen Fehler bekommen.</p>



<p>Wie oben bereits erwähnt, steht &#8222;ConfigureAwait&#8220; praktisch standardmäßig auf &#8222;True&#8220;, also wenn wir es gar nicht angeben. Dies bewirkt, dass wir uns so gesehen vor der Ausführung der &#8222;Await&#8220;-beinhaltenden Zeile (im obigen Beispiel) auf dem Thread der grafischen Oberfläche befinden. Dies ist der &#8222;captured context&#8220;, also der abgefangene/gefangene Thread a la &#8222;Ah okay, also auf diesem Thread soll ich laufen?&#8220;.</p>



<p>Solange wir Änderungen an der grafischen Oberfläche vornehmen wollen, ist dies auch super, aber warum der Fehler kommt, hörst Du nun. Wenn wir nach dem &#8222;Await&#8220; durch &#8222;ConfigureAwait(False)&#8220; eben NICHT mehr auf den &#8222;captured context&#8220; zurückkommen, dann können wir darin auch nicht arbeiten. Wir können die grafische Oberfläche also nun nicht mehr ändern. Wann und warum das sinnvoll sein kann, bzw. wie das genau aussieht, schauen wir uns im nächsten Abschnitt an.</p>



<h2 class="wp-block-heading">Wann ist &#8222;False&#8220; für ConfigureAwait sinnvoll?</h2>



<p>Nachdem unser letzter Code-Umbau für Dich vermutlich eher etwas Negatives erzeugt hat, bringen wir nun Licht ins Dunkel, wann die Verwendung von &#8222;False&#8220; sinnvoll ist. Eigentlich könnte man sagen, dass die Verwendung von &#8222;False&#8220; als Default-Wert, seine starke Daseinsberechtigung hat, allerdings in manchen Fällen wie oben zu Problemen führt.</p>



<p>Schaue Dir für das nähere Verständnis einmal den folgenden Service isoliert an. Dieser macht Gebrauch von einer kostenlosen Web-Schnittstelle, Welche uns eine zufällige Aktivität für den Alltag vorschlägt &#8211; einen simplen String.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="activity-service">Imports System.Net.Http
Imports System.Text.Json

Public Class ActivityService

    Private _httpClient As HttpClient

    Private Const API_URL As String = "https://www.boredapi.com/api/activity"

    Sub New(httpClient As HttpClient)
        _httpClient = httpClient
    End Sub

    Public Async Function GetRandomActivityAsync() As Task(Of String)
        Dim response = Await _httpClient _
            .GetAsync(API_URL) _
            .ConfigureAwait(False)
        Dim contentStream = Await response.Content _
            .ReadAsStreamAsync() _
            .ConfigureAwait(False)
        Dim options = New JsonSerializerOptions() With {
            .PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        }
        Dim jsonObject = Await JsonSerializer _
            .DeserializeAsync(Of ActivityResponse)(contentStream, options) _
            .ConfigureAwait(False)
        Return jsonObject.Activity
    End Function

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="activity-service">using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Net.Http;
using System.Text.Json;

public class ActivityService
{
    private HttpClient _httpClient;

    private const string API_URL = "https://www.boredapi.com/api/activity";

    public ActivityService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task&lt;string> GetRandomActivityAsync()
    {
        var response = await _httpClient
           .GetAsync(API_URL)
           .ConfigureAwait(false);
        var contentStream = await response.Content
            .ReadAsStreamAsync()
            .ConfigureAwait(false);
        var options = new JsonSerializerOptions()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };
        var jsonObject = await JsonSerializer
            .DeserializeAsync&lt;ActivityResponse>(contentStream, options)
            .ConfigureAwait(false);
        return jsonObject.Activity;
    }
}
</pre>



<p>In der Funktion (Welche eine Task zurückgibt!) &#8222;GetRandomActivityAsync&#8220; siehst Du einige Verwendungen mit dem übergebenen Parameter-Wert &#8222;False&#8220;. Diese bewirken, dass wir nicht nach jedem &#8222;Await&#8220; wieder zurück in den ursprünglich &#8222;gefangenen&#8220; Kontext hüpfen. Dies ist natürlich wesentlich sauberer und vor allem effizienter!</p>



<p>Der Aufruf aus der Form aus könnte daher nun wie gleich folgend aussehen. Wir verwenden unseren Service und lassen die Ausführung anschließend wieder durch &#8222;ConfigureAwait(True)&#8220; – was ja der Standardwert ist – zurück in den alten Thread hüpfen. Dabei handelt es sich um den Thread, in Welchem wir die grafische Oberfläche verändern können, nice!</p>



<p>Nun haben wir also den Service durch die Verwendung von &#8222;ConfigureAwait(False)&#8220; an den entsprechenden Stellen effizienter und sauberer gestaltet. Trotzdem können wir den Form-Code nach wie vor so benutzen, wie wir es gewohnt sind.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="final-example">' irgendwo weiter oben in der Klasse
Private _activityService As ActivityService

Sub New(activityService As ActivityService)
  ' per Dependency Injection injiziert..
   _activityService = activityService
End Sub

Private Async Sub Button1_Click(sender As Object, e As EventArgs)
  ' vor dem Delay (der "erwarteten" Task)
  Dim response = Await _activityService.GetRandomActivityAsync()
  ' nach dem Delay (nach der "erwarteten" Task)
  Label1.Text = "Mein neuer Text!"
End Sub</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="final-example">    // irgendwo weiter oben in der Klasse
    private ActivityService _activityService;

    public ActivityService(ActivityService activityService)
    {
        // per Dependency Injection injiziert..
        _activityService = activityService;
    }

    private async void Button1_Click(object sender, EventArgs e)
    {
        // vor dem Delay (der "erwarteten" Task)
        var response = await _activityService.GetRandomActivityAsync();
        // nach dem Delay (nach der "erwarteten" Task)
        Label1.Text = "Mein neuer Text!";
    }</pre>



<h2 class="wp-block-heading">Fazit</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/02/VB-NET-Tutorial-1-Fazit.jpg"><img loading="lazy" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2022/02/VB-NET-Tutorial-1-Fazit.jpg" alt="Fazit: ConfigureAwait(False) als Standard für erfahrene Entwickler" class="wp-image-8236" title="Fazit: ConfigureAwait(False) als Standard für erfahrene Entwickler"/></a><figcaption class="wp-element-caption">Fazit: ConfigureAwait(False) als Standard für erfahrene Entwickler</figcaption></figure>



<p>Wer als .NET-Entwickler einen saubereren und effizienteren Programmierstil im Bezug auf Tasks und Co. an den Tag legen möchte, sollte unbedingt &#8222;ConfigureAwait(False)&#8220; an passenden Stellen nutzen. Da man vermutlich wesentlich häufiger eben nicht in den alten Synchronisations-Kontext wechseln muss, empfiehlt sich daher eher das Paradigma &#8222;False-first&#8220;. Dies kann jedoch besonders bei Anfängern zu Verwirrung führen &#8211; aber wie heißt es so schön: &#8222;Learning by doing&#8220;, gell!?</p>



<h2 class="wp-block-heading">Weiterführende Links</h2>



<ul class="wp-block-list">
<li><strong><a href="https://robbelroot.de/blog/vb-net-dictionary-ein-kompletter-guide" target="_blank" rel="noreferrer noopener">Dictionaries – ein kompletter VB.NET Guide mit Messungen</a></strong></li>



<li><strong><a href="https://robbelroot.de/blog/eine-csv-preisliste-mit-vb-net-einlesen" target="_blank" rel="noreferrer noopener">Eine CSV-Preisliste mit VB.NET einlesen</a></strong></li>



<li><strong><a href="https://robbelroot.de/blog/csharp-bluetooth-example-searching-listing-devices/" target="_blank" rel="noreferrer noopener">Bluetooth-Geräte mit C# auflisten (English)</a></strong></li>
</ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/was-ist-configureawait-false-und-warum-sollte-es-der-standard-sein/">Was ist ConfigureAwait und warum sollte &#8222;False&#8220; der Standard sein?</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/was-ist-configureawait-false-und-warum-sollte-es-der-standard-sein/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
	</channel>
</rss>
