以编程方式运行控制台应用程序作为前台或后台进程c#

时间:2016-03-31 16:00:14

标签: c# .net console-application

我有一个控制台应用程序,我将安排通过Windows任务计划程序运行。现在我的一个要求是让它作为基于app.config设置的前台或后台进程运行。有可能实现吗?

3 个答案:

答案 0 :(得分:1)

您可以使用此代码

通过代码在后台中运行控制台应用程序
string path = "C:\\myfile.bat";
string args = "";
ProcessStartInfo procInfo = new ProcessStartInfo(path, args);
procInfo.CreateNoWindow = false;
procInfo.UseShellExecute = true;
procInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process procRun = Process.Start(procInfo);
procRun.WaitForExit();

要在前台运行此项,请将WindowStyle行更改为

procInfo.WindowStyle = ProcessWindowStyle.Normal;

答案 1 :(得分:0)

这不是一个“任务”,但可以作为一个参考。右键单击您的项目并转到属性。在属性内部,应用程序选项卡中应该有一个选项 - >输出类型 - > [将其切换为“Windows应用程序”]:

using System;
using System.Windows.Forms;

namespace TestConsoleApp
{
    public class Program
    {
        private const string GuiWinForm = "gui";
        private const string GuiConsole = "console";
        private const string BackgroundProcess = "bgp";
        private const string Cmd = "cmd";

        [DllImport("kernel32", SetLastError = true)]
        private static extern bool AttachConsole(int dwProcessId);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", SetLastError = true)]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        private static void LoadForm()
        {
            Application.EnableVisualStyles();

            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new Form1());
        }

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

        private static void CreateNewConsole()
        {
            AllocConsole();
            Console.WriteLine("New Console App");
            Console.ReadLine();
        }

        private static void LoadConsole()
        {
            // *** Gets Command Window if it is already open ***
            var ptr = GetForegroundWindow();
            int u;

            GetWindowThreadProcessId(ptr, out u);

            var process = Process.GetProcessById(u);

            if (process.ProcessName == Cmd)
                AttachConsole(process.Id);
            // *** Creates a new Command Prompt if the foreground is not a console ***
            else
                CreateNewConsole();
        }

        // Get the args from either command line or from config file
        [STAThread]
        private static void Main(string[] args)
        {
            var mode = args.Length > 0 ? args[0] : Gui;

            switch (mode)
            {
                case Gui:
                    LoadForm();
                    break;
                /* If for some reason you just cannot stand the 
                idea of using a winform for this task/process */
                case GuiConsole:
                     LoadConsole();
                     break;
                case BackgroundProcess:
                    // Code that will perform task
                    break;
            }
        }
    }
}

答案 2 :(得分:0)

---编辑---

我记得,你可以使用Windows API来隐藏窗口。

您将需要这些名称空间:

using System.Linq;
using System.Runtime.InteropServices;

然后你可以导入这两个函数:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);

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

GetConsoleWindow()将获得当前控制台窗口的窗口句柄。

ShowWindow()是一个WinAPI函数,可让您显示/隐藏/最小化/最大化/等。窗口通过发送窗口句柄。

Main()方法中,只要传递-silent参数,您就可以这样做:

static void Main(string[] args)
{
    if (args.Length >= 1 && args.Any(s => s.Equals("-silent", StringComparison.OrdinalIgnoreCase))) //Case-insensitively iterate through all arguments and look for the arg "-silent".
    {
        ShowWindow(GetConsoleWindow(), 0); //0 is equal to SW_HIDE, which means hide the window.
    }
}

因此,在任务计划程序中,只需使用参数-silent启动应用程序,它就不应显示窗口。

希望这有帮助!

---老答案---

为了能够在没有第二个应用程序的帮助下将您的应用程序作为前台/后台应用程序启动,您必须有一些方法向您的应用程序指示您希望它在没有窗口的情况下启动。

一旦您的应用程序启动,您可以检查某个参数,告诉您是否希望它在后台。然后,您可以让应用程序在没有窗口的情况下启动自身的新实例,然后自动关闭当前实例。

使用System.Reflection.Assembly.GetExecutingAssembly(),您可以通过CodeBase属性获取当前可执行文件的名称和完整路径。然后,您可以使用适当的设置将其传递给ProcessStartInfo类的实例,以便不创建窗口。

这是Main()方法的一个示例:

static void Main(string[] args)
{
    if (args.Length >= 1 && args.Any(s => s.Equals("-silent", StringComparison.OrdinalIgnoreCase))) //Case-insensitively iterate through all arguments and look for the arg "-silent".
    {
        ProcessStartInfo psi = new ProcessStartInfo(System.Reflection.Assembly.GetExecutingAssembly().CodeBase); //Start this application again.
        psi.CreateNoWindow = true; //Create no window (make it run in the background).
        psi.WindowStyle = ProcessWindowStyle.Hidden; //Create no window (make it run in the background).
        psi.WorkingDirectory = Process.GetCurrentProcess().StartInfo.WorkingDirectory; //Use the same working directory as this process.

        Process.Start(psi); //Start the process.
        return; //Stop execution, thus stopping the current process.
    }

//...your normal code here...
}

请注意,此代码必须位于Main()方法的 非常顶级

此代码的唯一问题是,为了关闭应用程序(如果它不自行关闭),您必须通过任务管理器或第二个应用程序强行终止进程(是的,遗憾的是)。

foreach (Process myApp in Process.GetProcessesByName("myApplication")) //Your executable's name, without the ".exe" part.
{
    myApp.Kill();
}

任务计划程序也无法控制新实例,这意味着你无法从那里阻止它。