mupan7
Goto Top

Start mehrerer Instanzen eines Programms verhindern

Ich hab nur aufwändige Programmierungen mit Windows-Titel-Abfrage usw. gesehen. Und meist testen dann die Anwendungen selbst und müssen sich erst wieder schließen.

Meine Lösung ist eine Batch. Wo die Execution-Policy es erlaubt, kann auch der Command in " " als .ps1 gespeichert werden. In dieser auf eine Zeile reduzierten Fassung und mit powershell -Command statt powershell -File läuft die Batch auch, wenn die Execution-Policy unklar oder Restricted ist.
%windir%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{ if ( (Get-Process | Where-Object {$_.ProcessName -eq 'calc'} | Measure-Object).Count -eq 0 ) { Start-Process 'calc' } else { add-type -AssemblyName microsoft.VisualBasic ; [Microsoft.VisualBasic.Interaction]::AppActivate('calc') } }"  
Warum eine Batch, warum nicht die Zeile direkt in das Target-Feld eines .lnk-Files schreiben? Auch mit Kommandozeilen-Parameter-Abkürzung (-c statt -Command), Powershell-Aliasen (gps, ?, measure, start), Umgebungsvariablen und 8.3-Pfaden und -Namen ließ sich die Zeile nicht weit genug kürzen, dass sie mit dem langen Pfad und Namen "meiner" Anwendung in das Target-Feld einer .lnk passt. (Übrigens: .NET-Programme finden ihre .config nicht, wenn sie mit execu~1.exe aufgerufen werden, da muss man wenigstens den Namen ausschreiben.)

Diese Batch ist als Target eines .lnk gedacht. Andere .lnk kann man löschen. Direktes mehrfaches Starten einer .exe fängt es nicht ab. Das war auch nicht meine Anforderung.

Content-ID: 247816

Url: https://administrator.de/contentid/247816

Ausgedruckt am: 25.11.2024 um 22:11 Uhr

Lochkartenstanzer
Lochkartenstanzer 30.08.2014 um 11:54:11 Uhr
Goto Top
Moin,

warum machst Du nicht einfach ein lockfile:

  • beim Start wird geprüft, ob ein Lockfile (kann irgendwo, aber an einem fest definierten Ort sein) existiert.
  • Wenn das lockfile existiert, darf das programm nicht starten.
  • wenn es nicht existiert, legt die batchdatei ein lockfile an udn startet das Programm udn wartet dann, bis es beendet wird.
  • Wenn das programm beendet wird, löscht die batchdatei das lockfile.

Standardverfahren seit Jahrzehnten (mindestens seit fast einem halben Jahrhundert).


Und wenn das Programm/das batchfile mal abstürzt, ohne das Lockfile zu löschen, kann man es manuell löschen.

lks

PS: man kanmn das ganz natürlich noch ausgefeilter machen und in das lockfile die prozess-identifikation des Programms schreiben, so das das Lockfile nur dann als gültig erkannt wird, wenn der dazugehörige prozess noch läuft.
mupan7
mupan7 30.08.2014, aktualisiert am 03.09.2014 um 10:04:39 Uhr
Goto Top
Hallo Lochkartenstanzer,

meine Lösung deckt meine Anforderung am besten ab. Ein Standardverfahren, das an der konkreten Anforderung vorbeigeht, bleibt gut, aber eben nicht hier.

Als Grund für die lockfile-Lösung kann ich mir z.B. vorstellen, wenn jede Startvariante des Programms abgefangen werden soll. Das brauche ich hier nicht.

Access arbeitet mit lockfiles (.ldb und aktuell glaube .laccdb?). Dieses Standardverfahren ist ein Standard-Supportfall, wenn du Access-Anwendungen betreuen musst face-wink
Sheogorath
Sheogorath 31.08.2014 um 05:18:14 Uhr
Goto Top
Moin,

also ich habe das bei mir wirklich sehr simple gelöst...

Einfach in der Aufgabenplanung den Task erstellt und gesagt, dass er nur einmal aufgerufen werden darf. der Rest ist dann ein Aufruf des Tasks. Ob direkt per Link oder mit Batch ist dann egal.

Allerdings ist deine Lösung auch nicht gerade unelegant.

Gruß
Chris
70866
70866 31.08.2014 um 14:47:13 Uhr
Goto Top
also was wirklcih sicher ist:
man holt sich die Liste der laufenden Prozesse ab
entdeckt die Applikation dabei daß eine .exe mit demselben Namen schon in der Liste auftaucht dann startet sie nicht.

LCK Dateien haben halt den Nachteil daß sie liegenbleiben wenn die Applikation aus irgendeinem Grunde abstürzen sollte.

Im Dot net Framework ist die Prozeßliste hier untergebracht:

system.diagnostics.process.GetProcesses
rubberman
rubberman 31.08.2014 aktualisiert um 15:39:27 Uhr
Goto Top
@70866

Genau das passiert doch in dem Einzeiler.

Der Weg dahin ist nur etwas kompliziert. Eine Batchdatei, die die PowerShell aufruft, die dann ggf. eine VB Methode aufruft.
Übrigens funktioniert das Beispiel bei mir nicht. AppActivate möchte gern den Fenstertitel übergeben bekommen, und der ist (auf meinem deutschen Win7 x86) nicht, auch nicht teilweise, "calc" sondern "Rechner".
Der Anspruch, es anders zu machen als ...
Ich hab nur aufwändige Programmierungen mit Windows-Titel-Abfrage usw. gesehen.
... wird so leider teilweise ad absurdum geführt.

AppActivate aktiviert ein minimiertes Programm übrigens nur in der Taskleiste und holt nicht das Fenster zurück auf den Bildschirm. (Anders bei Fenstern im Hintergrund. Diese werden in den Vordergrund gebracht und erhalten den Fokus.)

Grüße
rubberman
Endoro
Endoro 31.08.2014 aktualisiert um 16:05:27 Uhr
Goto Top
Hey,
warum nicht eine Batch mit tasklist?
tasklist |findstr "\<calc.exe\>" >nul && echo Läuft schon.|| calc.exe  
Gruss Endoro
An-dir
An-dir 31.08.2014 aktualisiert um 16:55:26 Uhr
Goto Top
Hallo,
so hätte ich das auch gemacht Endoro face-smile

Kleiner Hinweis für mupan7:
Verwende find mit dem Parameter "/i" damit die Prozessprüfung nicht casesensitive ist oder beachte einfach die Schreibweise.

Gruß
Andi
mupan7
mupan7 03.09.2014 aktualisiert um 09:41:23 Uhr
Goto Top
@Endoro:

Danke. Für mich würde das völlig reichen. Ob es sicher ist, kommt auf den Einzelfall an, bekanntlich pipet cmd Strings, PowerShell dagegen Objekte, was tendenziell sicherer ist, aber bei eindeutigen Strings keinen Unterschied machen sollte.

Wesentlicher ist:

  • In einem PowerShell-Skript kann ich ohne Verrenkungen (nämlich ohne die Abhängigkeit von nicht zu den Bordmitteln gehörenden.exe's) Dialoge ausgeben. Welcher Enduser beim Kunden akzeptiert schon Befehlszeilenausgaben?

  • Die Ausgabe ist per Batch nur sehr schwer zu regionalisieren, also, in der Sprache des Anwenders oder ersatzweise Englisch zu halten, wo die Übersetzung nicht vorliegt.
mupan7
mupan7 03.09.2014 um 09:55:38 Uhr
Goto Top
@rubberman

Für meine Anforderung reicht der Versuch, die App zu aktivieren, wenn das nicht geht, dann halt nicht. Vielleicht gibt es als Nachbarn auch eine AppMaximize-Methode, die implizit das Fenster fokussiert? Ich hätte auch ohne den ganzen else-Block leben können, wichtig ist bei uns hier, dass die Anwendung nur einmal gestartet wird.

Dass der Admin testet und anpasst, bevor er so etwas auf sein User-Volk loslässt, davon geh ich aus.

Dass so eine Funktion auf jedem System andere Parameter-Werte verlangt, ist mal wieder typisch. Vielleicht lässt sich der Wert irgendwie ermitteln, mit sowas wie

FOR /F "usebackq tokens=2* delims==" %%g IN (`wmic group where sid^="S-1-5-32-544" get name /Value^`) do set admgrpname=%%g

(legt den lokalen, regionalisierten Namen der Administratoren-Usergroup in die Umgebungsvariable admgrpname), aber das macht es dann noch komplizierter und anfälliger. Also eher gar nichts, wenn es schon läuft.

Die Kompliziertheit kommt daher, dass ich der Batch-Pipe nicht traue, PowerShell-Zeilen aber nicht per Doppelklick ausführbar sind, PowerShell-Skripte von der ExecutionPolicy sehr wahrscheinlich abgefangen werden, ich nicht skrupellos genug bin, mir die Erlaubnis einfach per powershell -ExecutionPolicy zu holen, und dass es in v4 m.W. für das Aktivieren / Fokussieren eines Fenster kein Cmdlet gibt, ich außerdem beim Kunden von v2 ausgehen muss.
mupan7
mupan7 03.09.2014 um 10:08:10 Uhr
Goto Top
Moin Chris,

das behalte ich auf jeden Fall im Hinterkopf. Beim Deployen auf Clients beim Kunden, die ich nicht selbst administriere, müsste ich doch ein wenig Sorgfalt auf die Einstellungen zum User verwenden, und ein paar Testreihen in VMs hier starten. Es muss halt immer alles vorzugsweise auf Doppelklick laufen, oder von einem automatischen Setup eingerichtet werden.

Grüßle,

mupan
mupan7
mupan7 03.09.2014 um 10:10:10 Uhr
Goto Top
Stimmt, unbekannter Mod, das passt besser in Tipps. face-wink
rubberman
rubberman 03.09.2014 um 23:59:30 Uhr
Goto Top
Hallo mupan7.

Vielleicht gibt es als Nachbarn auch eine AppMaximize-Methode, die implizit das Fenster fokussiert?
Nein, gibt es nicht. Und ein Cmdlet gibt es imho tatsächlich auch nicht. Einzige Möglichkeit ist soweit ich weiß die Verwendung der WinAPI ShowWindow() oder ShowWindowAsync() aus der user32.dll. Damit ließe sich sicher ein benutzerdefiniertes Cmdlet erstellen, einfacher wird es damit aber wiederum nicht und kommt vermutlich für dich auch nicht infrage...

Grüße
rubberman
mupan7
mupan7 04.09.2014 aktualisiert um 08:58:44 Uhr
Goto Top
Hi rubberman,

ich stelle mir grade vor, wie ich mein benutzerdefiniertes Cmdlet genervten Admins erkläre face-wink Nö, einfach muss es sein.

Im Fall des Falles könnte ich nircmd (nirsoft.net) mit ausrollen, dann heißt der Aufruf so:

"<Pfad>\nircmd.exe" win activate process calc.exe

Man muss ja nicht immer das Rad neu erfinden, und Aufwand und Nutzen müssen zur Anforderung passen.

Danke für's Zusammendenken, hat Spaß gemacht.