3

I have an application that is both gui and console.

Console: It executes from a windows schedule to do some automated tasks, so its called with an argument

GUI: Used for entering config parameters, a much nicer way for the user to do this than console.

All this works great. its primarily a console app, the console is hidden if its opened with no arguments and the configuration form is shown.

Problem: If I open it FROM the console with NO arguments, the console is hidden and the form is shown. how can i detect what or where i opened the app from, if it was opened from windows then hide the console, if it was opened from console then leave the console shown.

habib
  • 2,366
  • 5
  • 25
  • 41
magiva
  • 45
  • 6
  • Perhaps just have it default to console mode & require an argument to open the GUI, you can create a shortcut for this for the user to use. Failing that see [How to check if the program is run from a console?](https://stackoverflow.com/questions/9009333/how-to-check-if-the-program-is-run-from-a-console) – Alex K. Jun 29 '18 at 11:29
  • You can check your running processes and find you required one and apply operations as you want. – habib Jun 29 '18 at 11:59

4 Answers4

5

If you really want to know "where" your application has been started you have to know what is your parent process. In order to know your parent process you can read the solution of How to get parent process in .NET in managed way

Then you can for example check if your parent process name is explorer(windows) to open your application as a GUI.

sample code based on the solution provided in How to get parent process in .NET in managed way

namespace ConsoleApp1
{
    public static class ProcessExtensions
    {
        private static string FindIndexedProcessName(int pid)
        {
            var processName = Process.GetProcessById(pid).ProcessName;
            var processesByName = Process.GetProcessesByName(processName);
            string processIndexdName = null;

            for (var index = 0; index < processesByName.Length; index++)
            {
                processIndexdName = index == 0 ? processName : processName + "#" + index;
                var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
                if ((int)processId.NextValue() == pid)
                {
                    return processIndexdName;
                }
            }

            return processIndexdName;
        }
        private static Process FindPidFromIndexedProcessName(string indexedProcessName)
        {
            var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
            return Process.GetProcessById((int)parentId.NextValue());
        }

        public static Process Parent(this Process process)
        {
            return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Process.GetCurrentProcess().Parent().ProcessName);
            Console.ReadKey();
        }
    }
}

This code will outputs:

  • debug in visual studio: devenv
  • start from windows: explorer
  • start from cmd: cmd
  • start from powershell console: powershell
  • ...
asidis
  • 1,374
  • 14
  • 24
  • @magiva does it answer your question completely? If not could you please give me what you need or why this answer is not complete and I'll try to make it better. If it does answer your question, can you mark your question as answered ? – asidis Jul 06 '18 at 05:25
  • this is a perfect solution to finish this off very nicely. now, my console app will hide the console if its opened from explorer, console stays open under all other types, perfect. many thanks indeed – magiva Jul 09 '18 at 14:14
1

One way to do this is to separate your cli version and gui version into 2 executable (like 7z do with 7z.exe a command line tool and 7zG the Gui version)

You could have 3 projects in visual studio:

  • MyApp.Console (console app)
  • MyApp.WindowsGui (winform/wpf app)
  • MyApp.Logic (all the logic)

Console and WindowsGui have a reference to your Logic project

This will give you cleaner code as each "Frontend" project will handle only their purpose (handling GUI or console stuff) and your Logic are callable by both frontends

asidis
  • 1,374
  • 14
  • 24
0

I am unclear as to what you're trying to achieve. From my understanding, the application will launch as a console application regardless of having arguments or not. To prevent it from disappearing, you can utilize a Boolean to prevent the window from closing while the user is inputting configuration. For example (syntax may not be 100% at DialogResult):

using System;
using System.Windows.Forms;

// Allows you to access the static objects of Console
//     without having to repeatedly type Console.Something.
using static System.Console;

static bool configured = false;
static bool showForm = false;
static void Main(string[] args) {
    showForm = args.Length < 1;
    if (showForm) {
        WriteLine("The application needs to be configured.");
        using (ConfigForm config = new ConfigForm()) {
            if (config.ShowDialog() == DialogResult.OK) {
                showForm = false;
                configured = true;
                // Set your configured arguments here.
            }
        }
    }

    // Prevents the console from closing.
    while (showForm)
        ReadKey();

    // Do your processing in this condition.
    if (!showForm && configured)
        WriteLine("Thanks for playing. Press any key to exit.");
    else // Retry or exit in this one.
        WriteLine("An error occurred. Press any key to exit.");

    ReadKey();
}

If your application is set as a console application then it will launch the console window by default. Now, if you need to show and hide your console at different times, you can look into this post where the accepted answer provides a proper way to utilize Windows API to achieve this without having to perform some shady logic to find the window by title or identity.

using System.Runtime.InteropServices;

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

const int SW_HIDE = 0;
const int SW_SHOW = 5;

var handle = GetConsoleWindow();

// Hide
ShowWindow(handle, SW_HIDE);

// Show
ShowWindow(handle, SW_SHOW);

If this doesn't solve what you need, feel free to be more thorough in your post and include some code to give more definition to your issue. I am unable to comment and ask questions so I gave a basic solution. If you have any questions, feel free to ask.

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44
  • i can appreciate this question seems odd but it works like this. it can be called from cmd with no parameters, i dont want the console to hidden at that point, or in actual fact i want to re-show it when it closes if i open from windows then it would just hide the console, the console is a by product of how i need it to work in both console and windows. the reason why i need it as a console app is so i can call it with parameters on a server from a windows schedule. im not sure im helping explain it in a better way. – magiva Jul 09 '18 at 13:55
0

This might help:

using System;
using System.Diagnostics;

static class IsRanFromConsole
{
    private static readonly string[] consoleNames = {
        "cmd", "bash", "ash", "dash", "ksh", "zsh", "csh",
        "tcsh", "ch", "eshell", "fish", "psh", "pwsh", "rc",
        "sash", "scsh", "powershell", "tcc"
    };

    private static bool isCache = false;
    private static bool isConsole;

    public static bool IsConsole()
    {
        if (!isCache)
        {
            string parentProc = Process.GetCurrentProcess().Parent().ProcessName;
            isConsole = Array.IndexOf(consoleNames, parentProc) > -1;
        }
        return isConsole;
    }
}

Usage:

Console.WriteLine(IsRanFromConsole.IsConsole());

For the .Parent() function, you need to add this code.

mekb
  • 554
  • 8
  • 22