C#使用ctrl-c终止进程

时间:2016-06-10 11:31:04

标签: c#

我必须在我们的系统中使用ffmpeg,但我们的系统不支持多任务处理。我可以使用batchfile或exe启动外部程序。我使用ffmpeg记录testrun后,我的系统启动我的exceutable,然后ffmpeg将被终止。我使用了process.kill(),但是认识到该文件似乎没有正确关闭,因为videofile以暂停结束,而不是停止。我找到了解决方案http://stanislavs.org/stopping-command-line-applications-programatically-with-ctrl-c-events-from-net/。我在我的代码中使用了解决方案4,但似乎无法工作。

我的程序是ffmpeg启动和停止的切换开关,意思是 1.执行我的程序ffmpeg启动 2.执行我的程序ffmpeg将停止

如果我调试,则执行该方法,但在Taskmanager中仍然打开ffmpeg。如果我使用p.kill(),那么进程将很难终止。

Process p = Process.GetProcessById(Int32.Parse(appsettings.getAppSetting("ProcID")));
                if (p.ProcessName == "ffmpeg")
                {
                    //p.Kill(); //works 
                    StopProgramByAttachingToItsConsoleAndIssuingCtrlCEvent(p); // doesnt work
                    Console.WriteLine("Recording stopped");

修改 似乎我没有附加到控制台,但proc.Id是正确的。

if (AttachConsole((uint)proc.Id))

不是,但proc.ID似乎是正确的。

完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
using BizArk.Core;
using BizArk.Core.CmdLine;
using System.Runtime.InteropServices;
using System.Collections;


namespace Recorder
{
    class Program
    {
        #region pinvoke

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

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

        [DllImport("kernel32.dll")]
        static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
        // Delegate type to be used as the Handler Routine for SCCH
        delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);

        // Enumerated type for the control messages sent to the handler routine
        enum CtrlTypes : uint
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT,
            CTRL_CLOSE_EVENT,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT
        }

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);

        private enum ShowCommands
        {
            SW_HIDE = 0,
            SW_SHOWNORMAL = 1,
            SW_NORMAL = 1,
            SW_SHOWMINIMIZED = 2,
            SW_SHOWMAXIMIZED = 3,
            SW_MAXIMIZE = 3,
            SW_SHOWNOACTIVATE = 4,
            SW_SHOW = 5,
            SW_MINIMIZE = 6,
            SW_SHOWMINNOACTIVE = 7,
            SW_SHOWNA = 8,
            SW_RESTORE = 9,
            SW_SHOWDEFAULT = 10,
            SW_FORCEMINIMIZE = 11,
            SW_MAX = 11
        }
        [DllImport("shell32.dll")]
        static extern IntPtr ShellExecute(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, ShowCommands nShowCmd);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public int dwProcessId;
            public int dwThreadId;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }

        [DllImport("kernel32.dll")]
        static extern bool CreateProcess(string lpApplicationName,
           string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
           ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles,
           uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
           [In] ref STARTUPINFO lpStartupInfo,
           out PROCESS_INFORMATION lpProcessInformation);

        private const int WM_VSCROLL = 277;
        private const int SB_BOTTOM = 7;

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, uint nSize);

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

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

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

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        public delegate bool EnumedWindow(IntPtr handleWindow, ArrayList handles);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ArrayList lParam);

        [DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private const int VK_CONTROL = 0x11;
        private const int WM_KEYDOWN = 0x100;
        private const int WM_CHAR = 0x102;
        private const int WM_KEYUP = 0x101;
        private const int VK_CANCEL = 0x03;
        private const int VK_C = 0x0043;
        #endregion pinvoke
        static Process proc = null;
        static ProcessStartInfo psi = null;
        static AppSettings appsettings = new AppSettings();


        static void Main(string[] args)
        {
            ConsoleApplication.RunProgram<Arguments>(RunMain);
        }

        static void RunMain(Arguments args)
        {
            bool state = bool.Parse(appsettings.getAppSetting("State"));
            state = !state;
            appsettings.setAppSetting("State", state.ToString());
            if (state)
            {
                Run(args.OFileName);
                appsettings.setAppSetting("ProcID", proc.Id.ToString());
                appsettings.setAppSetting("ProcName", proc.ProcessName);
                Console.WriteLine("Recording started");
            }else{
                Process p = Process.GetProcessById(Int32.Parse(appsettings.getAppSetting("ProcID")));
                if (p.ProcessName == "ffmpeg")
                {
                    //p.Kill(); //works 
                    StopProgramByAttachingToItsConsoleAndIssuingCtrlCEvent(p); // doesnt work
                    Console.WriteLine("Recording stopped");

                }
            }
        }

        public static void StopProgramByAttachingToItsConsoleAndIssuingCtrlCEvent(Process proc)
        {
            //This does not require the console window to be visible.
            if (AttachConsole((uint)proc.Id))
            {
                //Disable Ctrl-C handling for our program
                SetConsoleCtrlHandler(null, true);
                GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);

                //Must wait here. If we don't and re-enable Ctrl-C handling below too fast, we might terminate ourselves.
                proc.WaitForExit();

                FreeConsole();

                //Re-enable Ctrl-C handling or any subsequently started programs will inherit the disabled state.
                SetConsoleCtrlHandler(null, false);
            }
        }

        static void Run(string OutputFileName)
        {

            try
            {
                psi = new ProcessStartInfo(appsettings.getAppSetting("ffmpegpath"));
                psi.Arguments = "-r 25 -i " + appsettings.getAppSetting("CameraURL") + " -y -c:v copy -vcodec libx264 -pix_fmt yuv420p -f h264 -b:v 128k -bufsize 128k -r 25 " + OutputFileName;
                psi.WorkingDirectory = appsettings.getAppSetting("Workingpath");
                psi.CreateNoWindow = false;
                psi.RedirectStandardInput = false;
                psi.RedirectStandardOutput = false;
                psi.RedirectStandardError = false;
                psi.WindowStyle = ProcessWindowStyle.Normal;
                psi.UseShellExecute = false;
                proc = Process.Start(psi);
            }
            catch(Exception)
            {

            }
        }

    }
}

0 个答案:

没有答案