Autor |
Beitrag |
_mk_
Beiträge: 23
|
Verfasst: Mo 22.08.22 15:51
Hallo zusammen.
Folgende Code funktioniert bereits, aber ich empfinde meine Lösung sehr plump und unschön. Besonders die letzte Endlosschleife gefällt mir nicht. Das muss doch irgendwie schöner gehen? Für einen Denkanstoß wäre ich Euch sehr dankbar.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
| public static void ShadowRemoteSession(string remoteServer, int sessionID) { Process process = new Process(); process.StartInfo.FileName = "mstsc"; process.StartInfo.Arguments = $"/v:{remoteServer} /shadow:{sessionID} /multimon /control"; process.Start(); process.WaitForInputIdle();
int processID = 0; do { Process[] processes = Process.GetProcessesByName("mstsc"); foreach (Process p in processes) { string mainTitle = p.MainWindowTitle.ToLower();
if (mainTitle.Contains($"(sitzungs-id {sessionID}) auf \"{remoteServer}\"")) { processID = p.Id; break; } } } while (true);
do { try { Process processByID = Process.GetProcessById(processID);
Thread.Sleep(10); } catch (Exception ex) { SendRemoteMessage(remoteServer, sessionID, "Ihre Sitzung wird nicht mehr gespiegelt."); break; } } while (true); } |
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 22.08.22 16:16
Die Process Klasse hat einen Exited Event der entsprechend gefeuert wird. Aber je nach Anwendung mußt du auch irgendwie warten bis der gefeuert wird.
Process.Exited
Moderiert von Th69: URL-Titel hinzugefügt
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Di 23.08.22 08:51
Vielen Dank. Mit Ereignissen habe ich noch keinerlei Erfahrung gemacht. Da ich ein Process-Objekt habe, kann ich so lange warten, bis dieser beendet wird. Zeitgleich wird nur eine Sitzung gespiegelt. Das sollte so reichen.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| public static void ShadowRemoteSession(string remoteServer, int sessionID) { using (Process process = new Process()) { process.StartInfo.FileName = "mstsc"; process.StartInfo.Arguments = $"/v:{remoteServer} /shadow:{sessionID} /multimon /control";
process.Start(); process.WaitForInputIdle(); }
Process mirrorProcess = new Process(); bool detected = false; do { Process[] processes = Process.GetProcessesByName("mstsc"); foreach (Process p in processes) { string mainTitle = p.MainWindowTitle.ToLower(); if (mainTitle.Contains($"(sitzungs-id {sessionID}) auf \"{remoteServer}\"") || mainTitle.Contains($"(sessionid {sessionID}) on {remoteServer}")) { mirrorProcess = p; detected = true; }
} } while (detected == false);
mirrorProcess.WaitForExit(); SendRemoteMessage(remoteServer, sessionID, "Ihre Sitzung wird nicht mehr gespiegelt."); } |
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Di 23.08.22 09:35
_mk_ hat folgendes geschrieben : | Mit Ereignissen habe ich noch keinerlei Erfahrung gemacht. |
Dann solltest du dich mal damit beschäftigen!
Dein Schleife erzeugt 100% Kernauslastung (nicht gut für den Rechner und die Umwelt)!!!
PS: Außerdem ist da noch ein möglicher Fehler in deinem Code bzgl. der Contains-Abfrage.
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Di 23.08.22 10:06
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Di 23.08.22 10:30
Manchmal ist schlafen ganz gut, um einer Ermüdung vorzubeugen.
Was passiert, wenn remoteSever Großbuchstaben enthält?
Aber ich verstehe den Sinn deiner Schleife sowieso nicht, denn mit mirrorProcess.WaitForExit() wartest du doch auf das Ende dieses Prozesses - warum nicht gleich process.WaitForExit() verwenden? Oder sind process und mirrorProcess zwei verschiedene Prozesse?
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Di 23.08.22 11:01
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 23.08.22 11:21
Zitat: | Mir fällt keine einfachere und sinnvollere Lösung ein, um an das Process-Object zu kommen. |
In Windows kennt eigentlich jeder Prozess den Prozess der ihn gestartet hat. Darüber wäre es relativ leicht den zusammenhang festzustellen ohne auf Fenstertitles zu prüfen.
Auf solchen Text zu testen ist natürlich immer ein Problem. Niemand garantiert das jede Remote Desktop Version genau diesen Text als Titel benutzt und wenn verschiedene Clientsprachen ins Spiel kommen wirds erst recht schwierig. Du versuchst ja schon deutsch und englisch abzudecken.
Leider ist das in der Process Klasse nicht veröffentlicht(warum auch immer). Per WMI kann man an die ProcessId des Parents kommen um rauszufinden ob die zusammengehören.
Ist aber möglicherweise zuviel komplexität für zu wenig gewinn.
Kannst du in der Schleife mal prüfen ob du an die StartInfo des Prozesses kommst und ob da was hilfreiches drin ist? Die enthält vermutlich die Parameter mit dem der SubProzess gestartet wurde. Diese Info ist dann eventuell eindeutiger als der Fenstertitel. Zumindest ist eine Kommandozeile nie lokalisiert
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Di 23.08.22 13:02
Ralf Jansen hat folgendes geschrieben : | Kannst du in der Schleife mal prüfen ob du an die StartInfo des Prozesses kommst und ob da was hilfreiches drin ist? Die enthält vermutlich die Parameter mit dem der SubProzess gestartet wurde. Diese Info ist dann eventuell eindeutiger als der Fenstertitel. Zumindest ist eine Kommandozeile nie lokalisiert |
Leider liefert die StartInfo-Klasse nichts brauchbares.
Ralf Jansen hat folgendes geschrieben : | Per WMI kann man an die ProcessId des Parents kommen um rauszufinden ob die zusammengehören.
Ist aber möglicherweise zuviel komplexität für zu wenig gewinn. |
In der Tat hat die WMI-Klasse Win32_Process eine Eigenschaft namens ParentProcessID.
Moderiert von Th69: C#-Tags hinzugefügt
|
|
_mk_
Beiträge: 23
|
Verfasst: Di 23.08.22 15:12
Meine Methode habe überarbeitet. Es kann ja sein, dass die Spiegelung bereits gestartet ist. Da bekomme ich den PID von ParentProcess nicht mehr raus. Deshalb bleibe erst einmal beim Fenstertitel bis ich etwas besseres gefunden habe.
Meine kleine Funktion innerhalb meiner Methode liefert mir ein Process-Object. Kann ich schon bereits beim Rückgabewert zwischen angenommener und abgelehnter Sitzungsspiegelung unterscheiden. Ich möchte nicht noch mal außerhalb der Funktion auf den Fenstertitel prüfen. Ich würde eine boolsche Variable außerhalb meiner Funktion definieren und entsprechend in meiner Funktion setzen. Ich weiß nicht, ob das ein schöner Programmierstil ist. Nach Möglichkeit möchte ich mir gerne gleich einen guten Programmierstil angewöhnen.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
| public static void ShadowRemoteSession(string remoteServer, int sessionID) { Process mirrorProcess = GetMirrorProcess();
if (mirrorProcess == null) { using (Process process = new Process()) { process.StartInfo.FileName = "mstsc"; process.StartInfo.Arguments = $"/v:{remoteServer} /shadow:{sessionID} /multimon /control"; process.Start(); process.WaitForInputIdle(); } }
do { mirrorProcess = GetMirrorProcess(); System.Threading.Thread.Sleep(50); } while (mirrorProcess == null);
mirrorProcess.WaitForExit(); SendRemoteMessage(remoteServer, sessionID, "Ihre Sitzung wird nicht mehr gespiegelt."); Process GetMirrorProcess() { Process[] processes = Process.GetProcessesByName("mstsc");
foreach (Process process in processes) { string mainTitle = process.MainWindowTitle.ToLower();
if (mainTitle.Contains($"(sitzungs-id {sessionID}) auf \"{remoteServer.ToLower()}\"") || mainTitle.Contains($"(sessionid {sessionID}) on {remoteServer.ToLower()}") || mainTitle.Contains("spiegelungsfehler") || mainTitle.Contains("shadow error"))
return process; }
return null; } } |
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Mi 24.08.22 11:32
_mk_ hat folgendes geschrieben : | Kann ich schon bereits beim Rückgabewert zwischen angenommener und abgelehnter Sitzungsspiegelung unterscheiden. |
Soll das ein Frage sein?
Gib deiner Methode doch einen bool-Wert als Rückgabe.
PS: Persönlich halte ich lokale Methoden für nicht so toll, da sie m.E. den Lesefluß beeinträchtigen.
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Do 25.08.22 11:04
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 25.08.22 11:48
_mk_ hat folgendes geschrieben : | Ja. Eigentlich war es als Frage formuliert. |
Dafür gibt es aber dann ein bestimmtes Satzeichen.
Und wegen der bool-Rückgabe: ich dachte, du meinst die Hauptmethode ShadowRemoteSession.
Bei der lokalen Methode kannst du entweder ein Tupel zurückgeben oder aber einen out-Parameter hinzufügen.
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Do 25.08.22 12:59
Th69 hat folgendes geschrieben : | Bei der lokalen Methode kannst du entweder ein Tupel zurückgeben oder aber einen out-Parameter hinzufügen. |
Ich hatte gelesen, dass man die Verwendung des out-Parameters vermeiden sollte. Tupel hatte ich nicht wirklich auf dem Schirm, weil ich auch nicht wußte, wofür ich sie einsetzen soll.
Jetzt sollten wir es endlich haben.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46:
| public static void ShadowRemoteSession(string remoteServer, int sessionID) { (Process mirrorProcess, bool isAborted)result = GetMirrorProcess();
if (result.mirrorProcess == null) { using (Process process = new Process()) { process.StartInfo.FileName = "mstsc"; process.StartInfo.Arguments = $"/v:{remoteServer} /shadow:{sessionID} /multimon /control"; process.Start(); process.WaitForInputIdle(); } }
do { result = GetMirrorProcess(); System.Threading.Thread.Sleep(50); } while (result.mirrorProcess == null);
result.mirrorProcess.WaitForExit(); if (result.isAborted == false) SendRemoteMessage(remoteServer, sessionID, "Ihre Sitzung wird nicht mehr gespiegelt.");
(Process, bool)GetMirrorProcess() { Process[] processes = Process.GetProcessesByName("mstsc");
foreach (Process process in processes) { string mainTitle = process.MainWindowTitle.ToLower();
if (mainTitle.Contains($"(sitzungs-id {sessionID}) auf \"{remoteServer.ToLower()}\"") || mainTitle.Contains($"(sessionid {sessionID}) on {remoteServer.ToLower()}")) { return (process, false); } else if (mainTitle.Contains("spiegelungsfehler") || mainTitle.Contains("shadow error")) { return (process, true); } }
return (null, true); } } |
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 25.08.22 13:24
Zitat: | Ich hatte gelesen, dass man die Verwendung des out-Parameters vermeiden sollte. |
Wir leben in Zeiten von asynchronem Code also das Ding mit Task(s) und async/ await Schlüsselwörtern.
Da funktioniert out nicht. Das hast du vermutlich gelesen. In klassischem Code ist das völlig ok.
Moderiert von Th69: C#- durch Quote-Tags ersetzt
Moderiert von Th69: C#-Tags hinzugefügt
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Do 25.08.22 13:43
Danke für den Hinweis. In dem Zusammenhang mit Tasks hatte ich es nicht gelesen. Mit den Klassen der Task Parallel Library muss ich mich sowieso noch tiefergehender beschäftigen.
Moderiert von Th69: Voll-Zitat entfernt
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 25.08.22 19:45
Wo ich da gerade nochmal auf deinen Code gucke.
C#-Quelltext 1:
| (Process mirrorProcess, bool isAborted)result = GetMirrorProcess(); |
Du brauchst hier result nicht.
C#-Quelltext 1:
| (Process mirrorProcess, bool isAborted) = GetMirrorProcess(); |
reicht. Bei Tuplen gibt es eine sogenannte Deconstruction. Das Tuple wird aufgelöst und einfach lokalen Variablen zugeordnet. In ShadowRemoteSession gibts den Tuple dann also nicht sondern einfach 2 lokale Variablen die genauso benutzt werden können wie lokale Variablen.
Der nächste Aufruf von GetMirrorProcess wäre dann auch einfach
C#-Quelltext 1:
| (mirrorProcess, isAborted) = GetMirrorProcess(); |
denn die beiden lokalen Variablen gibts dann ja schon.
Für diesen Beitrag haben gedankt: _mk_
|
|
_mk_
Beiträge: 23
|
Verfasst: Fr 26.08.22 08:32
Ralf Jansen Vielen Dank, dass Du Dir meinen Code noch einmal angeschaut und vereinfach hast. Tuple gefallen mir immer mehr. Jetzt, wo ich einen konkreten Anwendungsfall, kenne.
|
|