3

I'd like to create a C# application that behaves like a console application when you run it from a console window (and can output text to the console) but that does not create a console window when run externally. I've done a bit of research and the usual suggestion is to create a C# console application, then change its project type to a Windows Application. However that stops the Console.WriteLine messages from being written when run from a console.

Is there any way to run a program like this? I don't need it to take any console input. Perhaps there's some other method I can use to get text to display when run from the console?

4

3 回答 3

3

so all the console output shows up oddly after the prompt

Using AttachConsole() just doesn't work that well in practice. The command processor looks at your .exe file and does two different things, depending if it is a console mode app or a GUI app. If it is console mode app then it waits for the program to exit, then displays the prompt. If it is a GUI app then it doesn't wait, it assumes that the program will display its own window.

Which is what happened, it displayed the prompt after starting your program and waits for input. Your Console.Write() output now intermingles with the command processor output. You'll also have a problem with Console.ReadLine(), the first line that the user types goes to the command processor, not to you. Greatly confuzzling the user.

The workaround is to start your program differently. You have type

  start /wait yourapp.exe args...

Which makes the command processor wait for your program to exit, just like it would for a console mode app.

This is not very practical, the user of your app just won't think to use start /wait. No simple fix for this, you'll need to use AllocConsole(). If that's a deal breaker then you'll just need to create another little EXE project that's a console app. Which starts your GUI app, passing the command line. If you give it the same name as your GUI exe but give the .com filename extension then it will always be found first. It can look like this, works for any gui app:

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

class Program {
    static void Main(string[] args) {
        try {
            var path = Assembly.GetExecutingAssembly().Location;
            var dir = Path.GetDirectoryName(path);
            var file = Path.GetFileNameWithoutExtension(path);
            path = Path.Combine(dir, file + ".exe");

            var prc = Process.Start(path, Environment.CommandLine);
            if (args.Length > 0) prc.WaitForExit();
        }
        catch (Exception ex) {
            Console.WriteLine(ex.Message);
            Environment.Exit(1);
        }
    }
}
于 2013-10-20T00:53:06.160 回答
0

Honestly I needed this too and was looking for an answer and found this in

Show Console in Windows Application?

public static void ShowConsoleWindow()
{
    var handle = GetConsoleWindow();

    if (handle == IntPtr.Zero)
    {
        AllocConsole();
    }
    else
    {
        ShowWindow(handle, SW_SHOW);
    }
}

public static void HideConsoleWindow()
{
    var handle = GetConsoleWindow();

    ShowWindow(handle, SW_HIDE);
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();

[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;

This looks like a nice solution to all the others that have been suggested in this thread.

于 2013-10-19T22:11:52.140 回答
0

For reference, here's what I did. I made a simple "Windowless CLI" executable. I created a new console application, changed it to a Windows Application and passed through the arguments:

static void Main(string[] args)
{
    string programFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    string passArguments = string.Join(" ", args.Select(WrapArgument));

    Process.Start(new ProcessStartInfo(Path.Combine(programFolder, "VidCoderCLI.exe"))
    {
        Arguments = passArguments,
        WindowStyle = ProcessWindowStyle.Hidden
    });
}

private static string WrapArgument(string arg)
{
    if (arg.EndsWith(@"\"))
    {
        return "\"" + arg + "\\\"";
    }

    return "\"" + arg + "\"";
}

Anything that needs to make a call without a window showing up goes through there. It's nice because I avoid dealing with output redirection and console shenanigans.

Though it's not technically what I asked so I won't accept this answer.

于 2013-10-20T16:55:51.090 回答