views:

121

answers:

3

Question: I have a console program that shouldn't be seen. (It resets IIS and deletes temp files.)

Right now I can manage to hide the window right after start like this:

static void Main(string[] args)
{
    var currentProcess = System.Diagnostics.Process.GetCurrentProcess();
    Console.WriteLine(currentProcess.MainWindowTitle);

    IntPtr hWnd = currentProcess.MainWindowHandle;//FindWindow(null, "Your console windows caption"); //put your console window caption here
    if (hWnd != IntPtr.Zero)
    {
        //Hide the window
        ShowWindow(hWnd, 0); // 0 = SW_HIDE
    }

The problem is this shows the window for a blink of a second. Is there any constructor for a console program, where I can hide the window before it is shown?

And second:

I use

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

and I don't like the 32 in it. Is there any way to do this without DllImport ?
A .NET way ?

+11  A: 

If you don't need the console (e.g. for Console.WriteLine) then change the applications build options to be a Windows application.

This changes a flag in the .exe header so Windows doesn't allocate a console session when the application starts.

Richard
Or make it a windows service, although that will have a different lifecycle
Grant Crofton
Create a Windows app and don't create a Windows form
abatishchev
@Grand Crofton: Services are for a long-running or repeating background tasks, not for user-triggered actions like an IIS reset. So a service doesn't seem appropriate here. Unless you want to reset IIS every 5 minutes or so, of course ;-)
0xA3
@0xA3: repeating background tasks should not be implemented as a service but as a scheduled task. Having a service running forever when it only actually does something every few mins is a waste of memory, cpu time, coding time (writing a service is a lot more complicated than a console application) and maintainence. Also if you have a memory leak, it'll grow over time in a service, in a scheduled task once the task is finished the process is killed, so it has little effect.
clocKwize
lol, works. Just out of interest, if I would want to show the console again [when it is a window application], how would I do that ? ( I mean apart from switching back to console application)
Quandary
@Quandary: The Win32 API `AllocConsole` will create a console window for a process without one. But it isn't clear if `Console.Out` etc. would be hooked up automatically or you would need to use `Console.OpenStandardOutput` etc.
Richard
+2  A: 

If I understand your question, just create the console process manually and hide the console window:

Process process = new Process();
process.StartInfo.FileName = "Bogus.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;

I do this for an WPF app which executes a console app (in a background worker) and redirects standard output so you can display the result in a window if needed. Works a treat so let me know if you need to see more code (worker code, redirection, argument passing, etc.)

Si
@Si: I think that the OP want to be able to start the "no-window console program" by double-clicking it, for example, not necessarily programmatically from another program.
Andreas Rejbrand
True, I wasn't sure and have had the same need before. One thing I haven't be able to capture is coloured ANSI console output into WPF. See http://stackoverflow.com/questions/1529254/capture-coloured-console-output-into-wpf-application
Si
A: 
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();

void HideConsole()
{
    var ptr = GetStdHandle(-11);
    if (!CloseHandle(ptr))
        throw new Win32Exception();

    ptr = IntPtr.Zero;

    if (!FreeConsole())
        throw new Win32Exception();
}

See more console-related API calls here

abatishchev
Note that instead of `throw new PInvokeExcpetion()` normally `throw new Win32Exception()` or `throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());` is sufficient. With `Win32Exception()` you don't have to bother calling `GetLastError` yourself and then mapping the error code to a meaningful message. Everything is already done for you.
0xA3
@0xA3: Thanks for the tip!
abatishchev