Autor Beitrag
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: So 25.12.05 16:14 
Wichtig: Dieser Beitrag basiert auf diesem Artikel: dotnetaddict.dotnetd...al_world_example.htm

Diesen Beitrag gibt es auch als Artikel auf meiner Seite.

Einleitung
Es kommen immer wieder Anwendungen vor, bei denen man erreichen möchte, dass nur eine Anwendungs-Instanz von ihnen existiert. Sowohl unter Win32 als auch unter .NET kann man dies mit einem Mutex erreichen, in beiden Welten geht es gleich einfach. Vor einem Problem steht man unter .NET, wenn man Daten von der neuen Anwendungs-Instanz an die bestehende Instanz übergeben möchte, z.B. Aufrufparameter.

Unter Win32 konnte dies z.B. relativ einfach mittels WM_COPYDATA erreicht werden. Diese Möglichkeit bleibt einem unter .NET verschlossen. Unter .NET 1.1 war es nötig, mittels TCP einen Server und einen Client aufzumachen, welche sich dann Daten schickten. .NET 2.0 bietet für die Kommunikation auf einem einzelnen Rechner entsprechende IPC-Klassen, welche deutlich schneller als TCP arbeiten.

Wie man dies nutzt, um Aufrufparameter von einer Anwendungs-Instanz zur anderen zu schaufeln, sei im folgenden gezeigt. Ich werde hierbei auf die im Anhang zu findende Anwendung eingehen.

Trockenübung
Zur Kommunikation zwischen den beiden Anwendungs-Instanzen wird ein spezielle Klasse verwendet. An diese Klasse werden kaum Anforderungen gestellt, einzig von MarshalByRefObject muss sie abgeleitet sein. Kurz gesagt kann man dadurch über Applikations-Grenzen hinweg auf ein und dasselbe Objekt zugreifen! Ein wichtiger Baustein also bei der Kommunikation zwischen zwei Anwendungs-Instanzen.

Man kann sich dieses Objekt nun als Vermittler zwischen den beiden Anwendungs-Instanzen vorstellen. Intern arbeiten dabei sogenannte "Marshaler", die das Objekte serialisieren bzw. deserialisieren. Beim Serialisieren werden einfach alle Eigenschaften des Objektes in einen Speicherblock "gestopft", welcher somit den Zustand des Objektes zum aktuellen Zeitpunkt repräsentiert. Dieser Speicherblock wird nun einfach in den anderen Prozess kopiert und deserialisiert, womit man ein Objekt erhält, dessen Zustand dem aus dem anderen Prozess entspricht.

Erstellt wird dieses Objekt von der ersten Instanz. Dabei soll dem Objekt ein Delegat übergeben werden (eine Methode in der ersten Instanz), welcher (via Objekt) von der zweiten Instanz aufgerufen werden kann.

Die zweite Anwendungs-Instanz stelllt also erst einmal mittels Mutex fest, dass sie nicht die erste ihrer Art ist. Dann holt sie sich das (durch die erste Anwendungs-Instanz erstellte und mit Delegat bestückte) Objekt und ruft den Delegaten auf. Der Delegat erhält dabei als Parameter die Aufrufparameter, welche an die erste Anwendungs-Instanz übergeben werden sollen.

Der Aufruf des Delegaten ist die Brücke in die erste Anwendungs-Instanz. Sie kann nun den Parameter verarbeiten.


Wie es geht ...

Der erste Start
Beim Programmstart wird in der Datei "program.cs", bevor überhaupt eine Form erstellt wurde, mittels eines Mutex überprüft, ob bereits eine Anwendungs-Instanz dieser Anwendung existiert. Als Name des Mutex verwende ich die GUID aus der Datei "AssemblyInfo.cs". Wurde ein neuer Mutex erzeugt, existierte noch keine Anwendungs-Instanz und die Anwendung darf normal weitermachen.

Die erste Instanz
Ist die Anwendung also vorschriftsmäßig gestartet, muss sie nun (in "Form_Load" in der Datei "Form1.cs") das "Vermittlungsobjekt" (kein Fachbegriff ;-)) erstellen. Dazu würde man normalerweise einen so genannten IpcChannel erstellen (zur Datenübertragung) und dann den Typen des Vermittlungsobjektes als Dienst dieses Channels registrieren.

Leider soll das Vermittlungsobjekt ja einen Delegaten erhalten, was die Sache etwas komplizierter macht. Bei einer "normalen" Erstellung eines Channels, bei der einfach nur ein Name festgelegt wird, kann ein solcher Delegat nicht korrekt serialisiert werden, was eine Voraussetzung dafür ist, dass die ganze Sache funktioniert.

An dieser Stelle war der ganz oben verlinkte Artikel eine gigantische Hilfe, im Prinzip der Schlüssel zum Ganzen. In ihm wird demonstriert, dass man dem Channel ein Objekt zur Verfügung stellen kann, welches für die korrekte Serialisierung sorgt. Es hat den handlichen Namen "BinaryServerFormatterSinkProvider".

Über MessageSinks kann man sich hier informieren. Um eine kurze Vorstellung hier eine recht unfachliche Beschreibung: Eine Nachricht, welche sich durch einen Channel vom Client zum Server bewegt, passiert dabei MessageSinks. Diese verarbeiten diese Nachricht und verändern diese dabei. Jeder Sink tut dabei andere Dinge. Der hier vorliege Sink sorgt halt für eine korrekte Serialisierung.

Mittels dieses Objektes kann man nun einen Channel erstellen, der auch Delegaten korrekt verwenden kann. Dieser muss dann noch registriert werden. Nun kommt das "Vermittlungsobjekt" zum Einsatz. Es muss als Service registriert werden. Dabei ist wichtig, es im Modus "WellKnownObjectMode.Singleton" zu registrieren, damit immer nur eine einzige Instanz davon verwendet wird.

Der Rest ist einfach: Das Objekt der Activator-Klasse besorgen (an dieser Stelle wird es erzeugt, weil noch keine Instanz vorhanden ist) und den Delegaten zuweisen.

Die zweite Anwendungs-Instanz
Beim Start der zweiten Anwendungs-Instanz wird in der "program.cs" kein neuer Mutex erzeugt, da er ja schon existiert. Anstatt die Anwendung zu Starten, wird nun erneut ein IpcChannel erstellt, dieses Mal jedoch ohne das Objekt zu Serialisierung. Das wird hier nicht benötigt, da kein Delegat gesetzt wird.

Stattdessen holt man sich erneut das Vermittlungsobjekt mittels der Activator-Klasse. Dieses Mal wird der Aufruf von GetObject keine neue Instanz erzeugen, sondern die von der ersten Anwendungs-Instanz erstellte zurückgeben. Man greift also auf dasselbe Objekt wie die erste Anwendungs-Instanz zu!

Nun braucht man nur noch den Delegaten mit dem passenden Parameter aufrufen und ist in der zweiten Anwendungs-Instanz fertig.

Eine kleine Tücke ...
... gibt es aber noch: der Delegat wird in einem anderen Thread aufgerufen, was den Zugriff auf Elemente des Formulars erschwert. Daher habe ich als Delegaten auch nicht direkt die verarbeitende Methode zugewiesen, sondern noch eine Methode drum herum gebaut: Diese sorgt mittels Invoke dafür, dass die eigentliche Methode im richtigen Thread ausgeführt wird und es zu keinen "Unfällen" kommt.


Der Test
Das angehängt Projekt sollte problemlos kompilieren. Die Anwendung, die dabei herauskommt, braucht man einfach nur zweimal zu starten. Beim zweiten Start sollte keine zweite Anwendungs-Instanz erscheinen, sondern in der Listbox der ersten Anwendungs-Instanz der Programmname eingefügt werden, der ja immer in der Parameterliste steht.


Dank an user profile iconManuel, welcher diesen Artikel Korrektur gelesen hat, Anregungen zur Verbesserung des Quellcodes gab und den Teil der Serialisierung des Objektes beitrug! Danke!

Aktualisierte und verbesserte Version

Weiter unten gibt es eine für VS 2015 (und höher) aktualisierte und verbesserte Version, da es bei diesem Code Probleme mit der "Lebenszeit" des IPC-Objektes gibt (wenn er länger als ein paar Minuten läuft), so daß dann ein leeres Objekt übertragen wird und es zu einer Exception kommt!

Moderiert von user profile iconTh69: "Aktualisierte und verbesserte Version" hinzugefügt.
Moderiert von user profile iconTh69: Weitere Rechtschreibfehler korrigiert.
Einloggen, um Attachments anzusehen!
_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
alexpj
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Mi 10.02.16 14:49 
Ich habe das Beispiel übernommen aber ein kleines Problem. Die zweite Instanz kann keine args übergeben, da vorher eine Exception kommt.
Zitat:
Ein Ausnahmefehler des Typs "System.NullReferenceException" ist in MSGBox2.exe aufgetreten. Zusätzliche Informationen: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.


Kann ich mir nicht erklären, da args definitiv nicht leer ist....
Einloggen, um Attachments anzusehen!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 10.02.16 15:24 
Hallo und :welcome:

da wird wohl eher die Variable ac den Wert null haben, d.h. das Objekt konnte nicht instanziiert werden.
alexpj
Hält's aus hier
Beiträge: 15



BeitragVerfasst: Fr 11.03.16 09:59 
ich begreife das nicht:

ich hab ein Tool gemacht, das sich 100% an dem Beispiel orientiert. Als Args werden Pfade und Dateinamen von Outlook attachments übergeben. Das funktioniert soweit perfekt.

Aber:

vergehen ein paar Minuten im Leerlauf passiert garnichts mehr. Es werden weder die alte noch eine neue Instanz aufgerufen. Mit Debug komme ich nicht weiter.
Wie gehe ich da an eine Fehlersuche bzw. ist in dem Beispiel möglicherweise so eine Zeitbombe verborgen?
King2k7
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Sa 31.12.16 13:56 
Ich habe da eine Frage:

In welcher Zeile befindet sich der Code das der Pfad der Exe gespeichert wird. Also ich meine ich sehe nicht wo genau definiert ist das das Programm den Pfad nehmen soll?
Christian S. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 31.12.16 14:06 
Der Pfad zur Anwendung wird nicht benötigt, die erste und zweite Instanz finden sich über den IPC-Channel.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
King2k7
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Sa 31.12.16 14:20 
Ja, das habe ich gesehn.
Was ich meine ist: Es wird ja der Pfad der Exe in die Listbox geschrieben von jeder Exe außer der ersten. Ich sehe aber nicht wo dieser hergenommen wird um die Listbox zu füllen.

ausblenden Quelltext
1:
listBox1.Items.AddRange(filesOrFolders);					


Wo wird festgelegt das filesorFolder der Pfad ist? Ich würde den Code gerne umschreiben das nur der Dateiname Verwender wird. ICh nutzt für das Verzeichnis z.B. immer Path.GetDirectoryName aber nichts der gleichen ist im Code zu finden.
Christian S. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 31.12.16 14:29 
Ach so, das meinst Du. :think:

Die zweite Instanz ruft in der program.cs den Delegaten
ausblenden C#-Quelltext
1:
ac.OnAddArgs(System.Environment.GetCommandLineArgs());					

auf, welcher dann in der ersten Instanz ausgeführt wird. Und da kommt der Pfad her, der ist Teil der CommandLineArgs.

In der ersten Instanz wurde für den OnAddArgs-Delegaten die Methode InvokeAddFilesOrFolders registriert und diese ruft (im richtigen Thread) AddFilesOrFolders auf.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
King2k7
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Sa 31.12.16 15:35 
Danke, jetzt hab ich es verstanden.

Kann es sein das nicht mehrere Instanzen gleichzeitig versuchen dürfen an die 1. Instanz über IPC Parameter zu senden. Wenn ich mehrere Dateien auswähle und mittels einen "Rechtsklick Menü" versuche an meine 1. Instanz denn Dateipfad zu senden kommt eine Fehler Meldung das das Programm nicht funktioniert und nur eine Datei wird der Listbox hinzugefügt.
Christian S. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 31.12.16 15:44 
Das kann ich bei mir nicht reproduzieren, bei mir klappt das.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
King2k7
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Sa 31.12.16 17:49 
Man kann es mit dem Beispielprojekt nachstellen indem man die Exe 3x erstellt. 1. Exe wird einfach ausgeführt und Exe 2 und 3 zusammen mankiert und über einen Rechtsklick geöffnet.

Siehe Bild im Anhang.
Einloggen, um Attachments anzusehen!
Christian S. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 31.12.16 17:57 
Dann ist jetzt wohl der Programmierer in Dir an der Reihe, das zu debuggen ;)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
King2k7
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Sa 31.12.16 18:06 
:D Ja, das werde ich wohl tun müssen. Dachte nur es sei ein bekanntes Problem oder vllt ist IPC nicht für sowas ausgelegt.
Christian S. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 31.12.16 18:15 
Es hat mich jetzt doch interessiert. Das Problem ist, dass die "späteren" Clients (in der program.cs) alle einen Channel mit Port "IPCDemoClient" aufmachen. Das geht aber nur einmal.

Die Lösung ist einfach: man lässt den Port-Namen weg, wir brauchen hier nur einen Client-Channel und der braucht keinen Port-Namen. Aus
ausblenden C#-Quelltext
1:
IpcChannel ipc = new IpcChannel("IPCDemoClient");					

wird
ausblenden C#-Quelltext
1:
IpcChannel ipc = new IpcChannel();					

und es sollte funktionieren :)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
King2k7
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Di 03.01.17 16:48 
:D Danke dir für die Info :)
Leitstelle_V
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 30.03.20 11:27 
Hallo Christian,

danke für dein Programm. Es ist das beste, was ich zu dieser Thematik (nur eine Instanz pro Anwendung) im Netz gefunden habe.

Ich bin Neueinsteiger in Sachen Programmierung und ich bin ehrlich: Für mich ist das Programm zu komplex, um es komplett zu verstehen oder gar zu debuggen. Ich habe mein eigenes kleines Programm geschrieben, mit dem ich meine Vorgänge abarbeite, brauche aber DEIN Programm als Basis und bitte dich, mir zu helfen.

Ich habe dein Projekt in VB 2017 geöffnet und es wird dabei, weil es schon etwas älter ist, von VB in das passende Format konvertiert. Das Programm läuft auch. ABER: Wenn zwischen den einzelnen Aufrufen der EXE über zwei Minuten liegen (so meine Erfahrung auf 2 Rechnern), funktioniert das Programm nicht mehr (Windows-7-Dialog: "Das Programm funktioniert nicht mehr", die erste Instanz bleibt dann zwar geöffnet, aber es wird nichts mehr hinzugefügt).

Ich kann den Fehler in VB reproduzieren, in dem ich zunächst außerhalb von VB die EXE starte, ne Zeit lang warte und dann dein Projekt in zweiter Instanz aus VB heraus starte. Den erzeugten Fehler findest du als Bild im Anhang (Fehler liegt in Program.cs).

Es wäre cool, wenn du hierfür eine Lösung hättest.


Zur zweiten Sache. Was will ich tun: Ich möchte an die ListBox mit Hilfe deiner EXE Elemente übergeben (Durch Aufruf von z. B. IPCDemo.exe "Listeneintrag A"). In der ListBox erscheinen dann aber zwei Einträge:

- Der Pfad zu IPCDemo.exe
- "Listeneintrag A"

Wie kann ich erreichen, dass der Pfad NICHT erscheint, sondern rein mein Argument "Listeneintrag A"?

Wie kann ich es weiterhin erreichen, dass dem Eintrag noch ein Zeitstempel des Eingangs angefügt wird? Einfach nen String mit DateTime.Now dahinterhängen geht nicht an der Stelle, an der ich es probiert hab. Ich bin dafür aber auch noch zu sehr Noob.


Als letztes noch, was ich mit den Einträgen vorhabe: Ich möchte drei weitere ListBoxen in dem Formular erstellen, und je nach Inhalt der Einträge in der ersten Liste (=der deines Programms) werden diese auf die verschiedenen ListBoxen verteilt und dort weiter bearbeitet (da kommt dann mein Programm ins Spiel...). Sprich: "Deine" Liste wird von oben nach unten abgearbeitet: Der erste Eintrag wird genommen und in eine meiner Liste verschoben, dann wird dieser erste Eintrag aus deiner Liste gelöscht und der nächste Eintrag rutscht nach oben an Position 1 und das Prozedere geht von vorn los, bis deine Liste leer ist. Dieser Vorgang soll "instant" gestartet werden, also sobald neue Einträge in deiner Liste erscheinen, erfolgt immer sofort die Aufteilung auf meine Listen... Ich bin mir nicht ganz sicher, ob ich meine Anweisungen dazu, den ersten Listeneintrag in meine Listen zu kopieren und dann zu löschen einfach an folgende Stelle in Form1.cs z. B. als for-Schleife (die läuft, bis die Liste leer ist) anfügen könnte:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
public void AddFilesOrFolders(string[] filesOrFolders)
{
  listBox1.Items.AddRange(filesOrFolders);
  -> hier anfügen???
}


Oder liegt hier dann ein Fehlerpotential, wenn die EXE mehrfach gleichzeitig aufgerufen wird, sprich, könnte da was verloren gehen oder meine for-Schleife irgendwie "durcheinander kommen"?

Ich kämpfe derzeit wie gesagt noch mit einfachen Mitteln und bitte ich daher um deine Hilfe, dann könnte ich mein eigenes, erstes Programm bald an den Start bringen :-).

LG
Max

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 30.03.20 11:53 
Hallo und :welcome:

du hast vergessen, den Anhang hochzuladen.

Christian ist hier nur noch selten im Forum, aber ich versuche dir dann zu helfen.

PS: Meinst du wirklich VB (Visual Basic) oder doch eher VS (Visual Studio)?

Für diesen Beitrag haben gedankt: Leitstelle_V
Leitstelle_V
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Mo 30.03.20 16:26 
Hallo Th69,

dank für deine Hilfe :-). Natürlich meine ich VS, sorry :-D. So, nun noch der Anhang, keine Ahnung, eigentlich hatte ich den beigepackt.

LG
Max
Einloggen, um Attachments anzusehen!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 30.03.20 17:29 
Die Fehlermeldung bedeutet ja, daß eines der Objekte null ist. Überprüfe doch dann im Debugger die Variablenwerte (nach dem Bild tippe ich darauf, daß der Delegat OnAddArgs nicht gesetzt ist -> dann läuft etwas bei der IPC-Datenübertragung falsch).

Und bzgl. der ListBox: wie fügst du denn die Elemente hinzu (passiert das mit der Methode AddFilesOrFolders)?
Du müßtest dann selber eine Schleife von 1 bis < filesOrFolders.Length schreiben, welche dann die Strings einzeln per Add hinzufügt (so kannst du dann auch noch jeweils die Zeit zu dem String hinzufügen), s. Gewusst wie: Hinzufügen und Entfernen von Elementen in bzw. aus ComboBox-, ListBox- oder CheckedListBox-Steuerelementen in Windows Forms.

Und zu deiner letzten Frage: wenn du doch gleich nach dem Eintragen in die erste ListBox die Einträge automatisch auf die anderen ListBoxen verteilen willst, dann kannst du das doch sofort in der Methode AddFilesOrFolders machen (ohne den Umweg über die erste ListBox).

Für diesen Beitrag haben gedankt: Leitstelle_V
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 31.03.20 11:03 
Hallo,

hier nun die Antwort auf deine PM.

Ändere mal den Code in der Main-Methode so ab:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
//Delegaten mit korrektem Parameter aufrufen
var onAddArgs = ac.OnAddArgs;
if (onAddArgs != null)
  onAddArgs(System.Environment.GetCommandLineArgs());
else
  MessageBox.Show("Fehler: Delegate 'OnAddArgs' ist null!");

So sollte die Exception nicht mehr auftreten, stattdessen die Fehlermeldung.

Warum der Fehler auftritt ist jedoch (aus der Ferne) schwer zu sagen.

Edit:
Ich habe es selber mal unter Win10, VS 2015 ausprobiert und konnte den Fehler - nach ein paar Minuten - nachvollziehen (es wird ein leeres ArgContainer-Objekt zurückgeliefert).
In All you need to know about .NET Remoting habe ich dann den entscheidenden Hinweis darauf gefunden (unter "4.1. Server Side Object Activation. Singleton"):
Zitat:
If Lease Time is expired, Singleton might be destroyed on Server. In this case with new request from Client application new Singleton is created and is used in the same way – e.g. Single object for all Clients requests.

In "5. What is Lease Time? How to control it?" steht dann die Lösung: LifetimeServices.LeaseTime passend setzen.
Diese Zeile also in Form_Load (z.B. nach "Channel registrieren", aber noch vor "Vermittlungsobjekt als Dienst registrieren") einfügen:
ausblenden C#-Quelltext
1:
2:
// LeaseTime auf 1 Jahr setzen
LifetimeServices.LeaseTime = TimeSpan.FromDays(365); // TimeSpan.MaxValue creates ArgumentOutOfRangeException

(und noch passendes using System.Runtime.Remoting.Lifetime; oben in der Datei einfügen)

Bei mir klappt es nun - auch nach mehr als 10 Minuten funktioniert die Datenübertragung und das Eintragen in die ListBox!

Viel Erfolg!

PS:
Und die Schleife sieht einfach so aus:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
public void AddFilesOrFolders(string[] filesOrFolders)
{
  // Programmpfad auslassen
  for (int i = 1; i < filesOrFolders.Length; i++)
    listBox1.Items.Add(filesOrFolders[i] + " " + DateTime.Now);
}

(auch diesen Code habe ich bei mir erfolgreich getestet ;- )

Für diesen Beitrag haben gedankt: Leitstelle_V