4

I'm writing some executables that use the Windows console, in C and C++.

I'm trying to get the console to not close after the logic of my program finishes... But not just merely pause or wait, I'd like it to become a cmd.exe command line console itself, ready to accept new prompts.

Essentially I'd like the behavior of running my program via double-clicking or drag-and-dropping to be equivalent to hitting winkey + r and running :

cmd /k "program.exe [list of drag+drop files if any]"

(While not opening a new console if run from a command-line itself.)

Is this possible at all?

Edit


I've been tinkering with this and arrived to a solution that seems to work:

std::getenv("PROMPT") will return 0 when not run from the commandline (I think anyway, not sure if that holds in all cases), and so that can be used to fork the logic depending on how the executable is run.

The following code works for me at least, in my limited experimentation with it. If it's run from the explorer, it uses it's first instance to invoke cmd.exe with parameters that lets THAT instance invoke our program again, with the original parameters.

int main(int argc, char * argv[]) {
    // checks if we're in the explorer window, if so delegates to a new instance
    if (std::getenv("PROMPT") == NULL) {
        printf("Starting from explorer...\n");
        std::string str("cmd /Q /k \"");
        for (uint32 n = 0; n < argc; ++n) {
            str.append("\"");
            str.append(argv[n]);
            str.append("\"");
            if(n < argc-1)
                str.append(" ");
        }
        str.append("\"\n");
        system(str.c_str());
        return 0;
    }

    // actual code we want to run 
    uint32 fileCount = 0;
    for (uint32 n = 0; n < argc - 1; ++n) {
        fileCount++;
        printf("file %02u >> %s\n", n, argv[n+1]);
    }
    if (fileCount == 0) {
        printf("No inputs...\n");
    }
    return 0;
}

So I guess conceptually, it looks like this.

____stays open_______________________   __closes when finished___
program.exe [paramList] ---> cmd.exe -+-> program.exe [paramList]
                                      |
                                      +-> any subsequent commands
                                      |
                                     etc
Anne Quinn
  • 12,609
  • 8
  • 54
  • 101
  • 1
    I'm curious to know if anyone has a proper answer to this. I would suspect the answer would actually be _no_ -- and that the intended way to accomplish this would be a wrapper application that performs the `cmd /k` logic. – Human-Compiler Jun 29 '21 at 21:09
  • 1
    You could have something along the lines of your "program" being actually a batch script that invokes the actual `.exe`. And use something like https://stackoverflow.com/a/36663349/4442671 to behave correctly depending on where it's invoked from. –  Jun 29 '21 at 21:09
  • sorry, `std::getenv()` is not C, but C++. If you are writing C++ code, you had better not to use discouraged C functions like `printf()`, and if your problem is C language related, then you had better not to use namespaces at all (they don't exist in C) Please, clarify and don't mix both languages, or you finally end with a non-portable, non-maintainable program. And of course, tag adequately your question, as it is tagged C and C++ (but your code is C++ only, as you use namespaces in your program) – Luis Colorado Jul 01 '21 at 11:06

2 Answers2

0

You could simply insert the line

system( "cmd" );

at the end of your program, which will call the command prompt after your program finished executing.

However, this may not fulfil your following requirement:

(While not opening a new console if run from a command-line itself.)

Although using system( "cmd" ); will not open a new console window (it will use the existing one), it will create a new process cmd.exe, which means that you will now have 2 cmd.exe processes if your program was invoked by cmd.exe. Also, if the original cmd.exe process was invoked by your own program, then you will now have 2 processes running your program. If you now call your program again from this new command prompt, you will now have 3 cmd.exe processes and 3 processes running your program. This could get ugly very quickly, especially if you are repeatedly calling your program from a batch file.

In order to prevent this, then your program could try to somehow detect whether its parent process already is cmd.exe, and if it was, it should exit normally instead of invoking cmd.exe again.

Unfortunately, the Windows API does not seem to offer any official way for a child process to obtain the process ID of its parent process. However, according to this page, it is possible to accomplish this using undocumented functions.

Using undocumented functions is generally not advisable, though. Therefore, it would probably be better if you always called your program from a command prompt, so that it could simply exit normally.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

In my opinion, you have linked your program as a Windows console program, so it will always open a console terminal when you run it. In that case, your program is presenting the information it outputs in the console (as if the standard output had been redirected to the opened window) this means you cannot use it as a UNIX filter like dir or copy commands. (indeed, you are not in a unix system, so the console is emulated with a special windows library that is linked to your program).

To be able to run your program inside a cmd.exe invocation in a normal window terminal (as you do with the dir command --well, dir is internal to cmd.exe, but others, like xcopy.exe aren't), you need to build your program as a different program type (a unix filter command or a windowless console program, I don't remember the program type name as I'm not a frequent windows developer) so the standard input and the standard output (these are things that Windows hinerits from MS-DOS) are preserved on the program that started it, and you program is capable of running with no window at all.

Windows console program is a different thing that a windows filter program that doesn't require a console to run. The later is like any other ms-dos like command (like dir or copy) and they have an interface more similar to the unix like counterparts.

If you do this, you will be able to run your program from cmd in another window, and it will not create a Windows terminal console to show your program output.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31