Laden...

Prüfen, ob das Programm über die Konsole (cmd.exe) gestartet wurde

Erstellt von Mallett vor 9 Jahren Letzter Beitrag vor 9 Jahren 5.038 Views
M
Mallett Themenstarter:in
171 Beiträge seit 2012
vor 9 Jahren
Prüfen, ob das Programm über die Konsole (cmd.exe) gestartet wurde

Hallo,

ich hab ein C# (WinForms) Programm. Dieses kann per Doppelklick gestartet werden -> dann soll eine Winforms Oberfläche angezeigt werden, also ganz normal.

Das Programm soll aber auch über die Console ausgeführt werden können, wobei dann Kommandozeilenparameter übergeben werden müssen. Das Programm läuft dann mit den übergebenen Parametern im "silent" mode, d.h. ohne Oberfläche-

Das funktioniert auch alles so weit.

Ein Problem habe ich jetzt, wenn das Programm über die Konsole aufgerufen wird, aber keine Command Line args übergeben wurden. Dann öffnet sich ebenfalls die Winforms Oberfläche. Es sollte dann aber ebenfalls "silent" laufen, mit default-Parametern.

Die Unterscheidung ist so umgesetzt:


static void Main(string[] args)
{
    if (args == null || args.Length == 0)
    {
        // exe double click -> show gui
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Main(null));
    }
    else
    {
        // command line parameters -> execute in silent mode
        // ...
    }
}


Demnach logisch, dass die Form aufgeht. Die Frage ist, wie könnte ich es anders machen? Meine Idee wäre, irgendwie zu erkennen, dass das Programm von der Console aufgerufen wurde, ich wüsste aber nicht wie. Einfach prüfen, ob cmd.exe läuft, hilft mir nicht, da während das Programm gestartet wird, noch mehrere cmd-Instanzen laufen können.

Hat jemand eine simple Idee ?

Danke...

16.842 Beiträge seit 2008
vor 9 Jahren

Entscheide Dich für eine Variante, die gestartet werden soll, wenn es keine Parameter gibt.
Aber zu erkennen, ob das über die CMD läuft (oder batch, Direktaufruf oder was auch immer) geht so nicht.

Du kannst ja auch -Forms als Parameter fordern und per default es als Console laufen lassen, oder eine Auswahl anbieten wenn es keine Parameter gibt etc etc....

H
523 Beiträge seit 2008
vor 9 Jahren

Du könntest versuchen Deine Applikation mittels der API AttachConsole an eine Console zu binden und zu prüfen, ob das Fenster was gerade den Focus hat eine Console ist. Das ist zwar keine tolle und vollständig sichere Lösung, _könnte _aber funktionieren.

Normalerweise löst man so ein Problem, wie Abt es bereits vorgeschlagen hat, mit Übergabeparametern.

M
Mallett Themenstarter:in
171 Beiträge seit 2012
vor 9 Jahren

Danke für die Antwort, ich werde mir dann wohl irgendwas überlegen müssen.

Noch was Anderes dazu:
Mir ist gerade aufgefallen, dass Console.WriteLine im obigen else-Fall nur dann dann eine Consolen-Ausgabe produziert, wenn cmd.exe als Administrator gestartet wurde. Hat cmd.exe keine Admin-Rechte werden die Konsolenausgaben einfach ignoriert.

Gibt es dafür einen bestimmten Grund und eine Möglichkeit das zu umgehen ?

Über eine manifest-Datei sorge ich zwar schon dafür. dass mein Programm Admin-Rechte fordert, ich habe aber keinen Einfluss darauf, ob cmd.exe als admin ausgeführt wird.

Danke nochmals..

M
Mallett Themenstarter:in
171 Beiträge seit 2012
vor 9 Jahren

Update: mein letzter Post kann ignoriert werden, das Problem gestaltet sich anders:

wenn cmd.exe mit Admin-Rechten läuft, werden die Consolenausgaben in dieser cmd.exe-Instanz ausgegeben.

wenn cmd.exe nicht mit Admin-Rechten läuft, wird beim Aufruf des Programms ein neues consolenfenster geöffnet und die Ausgaben werden darin ausgegeben.

Kann ich irgendwie dafür sorgen, dass die Ausgaben immer in der aufrunden cmd-Instanz ausgegeben werden ?

H
523 Beiträge seit 2008
vor 9 Jahren

Ja, das geht mittels der von mir genannten API-Funktion:

    static class Program
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AttachConsole(int ProcessId);
 
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AllocConsole();
 
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool FreeConsole(); 

        [STAThread]
        static int Main(string[] args)
        {            
            if (args.Length > 0)
            {
                if (!AttachConsole(-1)) AllocConsole();
                Console.WriteLine("test");
                FreeConsole();
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
            return 0;
        }
    }

AttachConsole function

-1 - Use the console of the parent of the current process.

M
Mallett Themenstarter:in
171 Beiträge seit 2012
vor 9 Jahren

Hallo hypersurf,

danke, aber das scheint nicht zu funktionieren, wenn cmd.exe keine Admin-Rechte hat, öffnet die Anwendung weiterhin ein neues Konsolen-Fenster.

H
523 Beiträge seit 2008
vor 9 Jahren

Bei mir funzt das, wobei mein Benutzer lokaler Admin ist. Liegt es vielleicht daran, dass Deine Anwendung Adminrechte anfordert?

1.346 Beiträge seit 2008
vor 9 Jahren

Du könntest versuchen mittels des Parent Prozesses zu entscheiden. Wenn in der Aufrufskette cmd oder powershell auftaucht die Konsolenversion nutzen, und sonst auf Forms zurückweichen

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Mallett,

wie ist deine Anwendung übersetzt, als Windows Forms oder als Konsolenanwendung? Will meinen, /target:winexe oder /target:exe?

So oder so: Bei solchen Hybrid-Anwendungen gibt es immer Probleme. Der einzige saubere Weg wäre wohl zwei EXE-Dateien zu erzeugen. Dazu muss man keinen Code duplizieren, sondern nur die momentane Entscheidung im Main per if dann über zwei Buildkonfigurationen und per #IFDEF zu treffen.

herbivore

1.361 Beiträge seit 2007
vor 9 Jahren

Hi Mallet,

bei Anwendung "klaut" Konsolenfenster? konnten wir zwar nicht alles lösen, aber vielleicht hilft dir auch die Funktion GetConsoleWindow.

beste Grüße
zommi