启动Windows服务并启动CMD

启动Windows服务并启动CMD

本文介绍了启动Windows服务并启动CMD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是否需要启用交互desktp为它工作的,什么是正确的code启动EXE或cmd窗口?我仍然无法甚至开始服务的时候我不得不使其能够与桌面交互。

我会用聊天引擎,所以它更容易管理作为Windows服务。

有什么毛病我code?

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用System.ServiceProcess;
使用System.Diagnostics程序;
使用System.ComponentModel;
使用的System.Threading;命名空间MyNewService
{
    类节目:ServiceBase
    {
        静态无效的主要(字串[] args)
        {
        }        公共项目()
        {
            this.ServiceName =颤振;
        }        保护覆盖无效的OnStart(字串[] args)
        {
            base.OnStart(参数);            // TODO:在此处放置你的开始code
            首发的ThreadStart =新的ThreadStart(bw_DoWork);
            线程t =新主题(首发);
            t.Start();        }        私人无效bw_DoWork()
        {
            进程p =新的Process();
            p.StartInfo =新的ProcessStartInfo(@C:\\ WINDOWS \\ SYSTEM32 \\ cmd.exe的);
            p.Start();
            p.WaitForExit();
            base.Stop();
        }        保护覆盖无效调用OnStop()
        {
            base.OnStop();            // TODO:清理所有变量和停止任何线程
        }
    }
}


解决方案

我已经经历这样做的所有的疼痛消失了。

在窗口7 / Vista中/ 2008年,它是不可能从服务加载任何互动的过程 - 没有调用了一些API赢的。 = BLACK MAGIC

看一看here和here.

在code以下开了窍,用你自己的风险使用它:

 公共静态类ProcessAsCurrentUser
{    ///<总结>
    ///会话的连接状态。
    ///< /总结>
    公共枚举ConnectionState
    {
        ///<总结>
        ///一个用户登录到会话中。
        ///< /总结>
        活性,
        ///<总结>
        ///一个客户端连接到会话。
        ///< /总结>
        连接的,
        ///<总结>
        ///会话是在连接到客户端的过程。
        ///< /总结>
        ConnectQuery,
        ///<总结>
        ///本届会议是阴影另一个会话。
        ///< /总结>
        阴影,
        ///<总结>
        ///会话处于活动状态,但客户端已经从中断开。
        ///< /总结>
        断开,
        ///<总结>
        ///会话正在等待客户端连接。
        ///< /总结>
        闲,
        ///<总结>
        ///会话侦听连接。
        ///< /总结>
        听,
        ///<总结>
        ///会话处于复位状态。
        ///< /总结>
        重启,
        ///<总结>
        ///会话是下降,原因是一个错误。
        ///< /总结>
        下,
        ///<总结>
        ///会话初始化。
        ///< /总结>
        初始化
    }
    [StructLayout(LayoutKind.Sequential)]
    类SECURITY_ATTRIBUTES
    {
        公众诠释nLength;
        公众的IntPtr lpSecurityDescriptor;
        公众诠释bInheritHandle;
    }
    [StructLayout(LayoutKind.Sequential,字符集= CharSet.Uni code)条]
    STARTUPINFO结构
    {
        公众的Int32 CB;
        公共字符串升preserved;
        公共字符串lpDesktop;
        公共字符串lpTitle;
        公众的Int32 DWX;
        公众的Int32 DWY;
        公众的Int32 dwXSize;
        公众的Int32 dwYSize;
        公众的Int32 dwXCountChars;
        公众的Int32 dwYCountChars;
        公众的Int32 dwFillAttribute;
        公众的Int32 dwFlags中;
        公众的Int16 wS​​howWindow;
        公众的Int16 cbReserved2;
        公众的IntPtr升preserved2;
        公众的IntPtr hStdInput;
        公众的IntPtr hStdOutput;
        公众的IntPtr hStdError;
    }    [StructLayout(LayoutKind.Sequential)]
    内部结构PROCESS_INFORMATION
    {
        公众的IntPtr hProcess;
        公众的IntPtr hThread;
        公众诠释dwProcessId;
        公众诠释dwThreadId;
    }    枚举LOGON_TYPE
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK,
        LOGON32_LOGON_BATCH,
        LOGON32_LOGON_SERVICE,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT,
        LOGON32_LOGON_NEW_CREDENTIALS
    }    枚举LOGON_PROVIDER
    {
        LOGON32_PROVIDER_DEFAULT,
        LOGON32_PROVIDER_WINNT35,
        LOGON32_PROVIDER_WINNT40,
        LOGON32_PROVIDER_WINNT50
    }    [国旗]
    枚举CreateProcessFlags:UINT
    {
        CREATE_BREAKAWAY_FROM_JOB =为0x01000000,
        CREATE_DEFAULT_ERROR_MODE = 0x04000000,
        CREATE_NEW_CONSOLE = 0x00000010,
        CREATE_NEW_PROCESS_GROUP = 0x00000200,
        CREATE_NO_WINDOW = 0x08000000,
        CREATE_PROTECTED_PROCESS = 0x00040000,
        CREATE_ preSERVE_ code_AUTHZ_LEVEL = 0x02000000,
        CREATE_SEPARATE_WOW_VDM = 0x00000800,
        CREATE_SHARED_WOW_VDM = 0x00001000,
        CREATE_SUSPENDED = 0x00000004,
        CREATE_UNI code_ENVIRONMENT = 0x00000400时,
        DEBUG_ONLY_THIS_PROCESS = 0x00000002,
        DEBUG_PROCESS = 00000001,
        DETACHED_PROCESS = 0x00000008,
        EXTENDED_STARTUPINFO_ preSENT = 0x00080000,
        INHERIT_PARENT_AFFINITY = 0x00010000在
    }    [StructLayout(LayoutKind.Sequential)]
    公共结构WTS_SESSION_INFO
    {
        公众诠释的SessionID;
        [的MarshalAs(UnmanagedType.LPTStr)
        公共字符串WinStationName;
        公共ConnectionState国家;
    }    函数[DllImport(wtsapi32.dll,字符集= CharSet.Auto,SetLastError = TRUE)]
    公共静态外部的Int32 WTSEnumerateSessions(IntPtr的hServer,INT保留,诠释的版本,
                                                    裁判的IntPtr sessionInfo,裁判诠释计数);
    函数[DllImport(advapi32.dll的入口点=CreateProcessAsUserW,SetLastError = true时,字符集= CharSet.Auto)
    静态外部布尔CreateProcessAsUser(
        IntPtr的hToken,
        串lpApplicationName,
        串lpCommandLine,
        IntPtr的lpProcessAttributes,
        IntPtr的lpThreadAttributes,
        BOOL bInheritHandles,
        UInt32的dwCreationFlags,
        IntPtr的lpEnvironment,
        串lpCurrentDirectory,
        REF STARTUPINFO lpStartupInfo,
        出PROCESS_INFORMATION lpProcessInformation);    函数[DllImport(wtsapi32.dll)]
    公共静态外部无效WTSFreeMemory(IntPtr的内存);    函数[DllImport(KERNEL32.DLL)]
    私人静态外部UInt32的WTSGetActiveConsoleSessionId();    函数[DllImport(wtsapi32.dll,SetLastError = TRUE)]
    静态外部INT WTSQueryUserToken(UInt32的的sessionId,出的IntPtr令牌);    函数[DllImport(advapi32.dll的,字符集= CharSet.Auto,SetLastError = TRUE)]
    公众的extern静态布尔DuplicateTokenEx(
        IntPtr的hExistingToken,
        UINT dwDesiredAccess,
        IntPtr的lpTokenAttributes,
        INT ImpersonationLevel,
        INT TokenType,
        出的IntPtr phNewToken);    私人const int的TokenImpersonation = 2;
    私人const int的SecurityIdentification = 1;
    私人const int的MAXIMUM_ALLOWED = 0x2000000;
    私人const int的TOKEN_DUPLICATE = 0X2;
    私人const int的TOKEN_QUERY = 0x00000008;    ///<总结>
    ///推出用于登录的用户是否有任何当前的处理。
    ///如果没有,在以下情况下返回false以及
    ///
    /// ##### !!!谨防 !!! #### ------------------------------------------
    ///在Windows服务运行时该code只会工作(它真正需要的)
    ///这样的情况下,你需要对其进行测试,它需要在服务运行。原因
    ///是一个安全PRIVILEG只服务有(SE _ ???什么,记不起)!
    ///< /总结>
    ///< PARAM NAME =processExe>< /参数>
    ///<&回报GT;< /回报>
    公共静态布尔CreateProcessAsCurrentUser(字符串processExe)
    {        IntPtr的重复=新的IntPtr();
        STARTUPINFO信息=新STA​​RTUPINFO();
        PROCESS_INFORMATION procInfo =新PROCESS_INFORMATION();        的Debug.WriteLine(的String.Format(。CreateProcessAsCurrentUser processExe:+ processExe));        IntPtr的P = GetCurrentUserToken();        布尔结果= DuplicateTokenEx(P,MAXIMUM_ALLOWED | TOKEN_QUERY | TOKEN_DUPLICATE,IntPtr.Zero,SecurityIdentification,SecurityIdentification,出副本);
        的Debug.WriteLine(的String.Format(DuplicateTokenEx结果:{0},结果));
        的Debug.WriteLine(的String.Format(重复:{0},重复));
        如果(结果)
        {
            结果= CreateProcessAsUser(一式两份,processExe,空,
                IntPtr.Zero,IntPtr.Zero,假的,(UInt32的)CreateProcessFlags.CREATE_NEW_CONSOLE,IntPtr.Zero,空,
                参考信息,出procInfo);
            的Debug.WriteLine(的String.Format(CreateProcessAsUser结果:{0},结果));        }
        如果(p.ToInt32()!= 0)
        {
            Marshal.Release(P);
            的Debug.WriteLine(的String.Format(发布手柄号码:{0},P));
        }
        如果(duplicate.ToInt32()!= 0)
        {
            Marshal.Release(一式两份);
            的Debug.WriteLine(的String.Format(发布处理重复:{0},重复));
        }        返回结果;
    }    公共静态INT GetCurrentSessionId()
    {
        UINT的sessionId = WTSGetActiveConsoleSessionId();
        的Debug.WriteLine(的String.Format(的sessionId:{0}的sessionId));        如果(==的sessionId 0xFFFFFFFF的)
            返回-1;
        其他
            返回(INT)的sessionId;
    }    公共静态布尔IsUserLoggedOn()
    {
        清单< WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
        的Debug.WriteLine(的String.Format(会话数:{0},wtsSessionInfos.Count));
        返回wtsSessionInfos.Where(X => x.State == ConnectionState.Active).Count之间的()> 0;
    }    私有静态的IntPtr GetCurrentUserToken()
    {
        清单< WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
        INT的sessionId = wtsSessionInfos.Where(X => x.State == ConnectionState.Active).FirstOrDefault()的SessionID。
        // INT的sessionId = GetCurrentSessionId();        的Debug.WriteLine(的String.Format(的sessionId:{0}的sessionId));
        如果(==的sessionId int.MaxValue)
        {
            返回IntPtr.Zero;
        }
        其他
        {
            IntPtr的P =新的IntPtr();
            INT结果= WTSQueryUserToken((UInt32的)的sessionId,出P);
            的Debug.WriteLine(的String.Format(WTSQueryUserToken结果:{0},结果));
            的Debug.WriteLine(的String.Format(WTSQueryUserToken号码:{0},P));            回磷;
        }
    }    公共静态列表< WTS_SESSION_INFO> ListSessions()
    {
        IntPtr的服务器= IntPtr.Zero;
        清单< WTS_SESSION_INFO> RET =新的List< WTS_SESSION_INFO>();        尝试
        {
            IntPtr的ppSessionInfo = IntPtr.Zero;            INT32计数= 0;
            INT32 RETVAL = WTSEnumerateSessions(IntPtr.Zero,0,1,参考ppSessionInfo,引用计数);
            INT32数据大小= Marshal.SizeOf(typeof运算(WTS_SESSION_INFO));            Int64的电流=(INT)ppSessionInfo;            如果(RETVAL!= 0)
            {
                的for(int i = 0; I<计数;我++)
                {
                    WTS_SESSION_INFO SI =(WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)当前的typeof(WTS_SESSION_INFO));
                    当前+ =数据大小;                    ret.Add(SI);
                }                WTSFreeMemory(ppSessionInfo);
            }
        }
        赶上(例外的例外)
        {
            的Debug.WriteLine(exception.ToString());
        }        返回RET;
    }}

Do I need to enable Interactive desktp for it to work and what is the correct code to start an EXE or cmd window? I'm still unable to start the service even when I had enable it to interact with desktop.

I would be using an chat engine so it is easier to manage as a windows service.

What wrong with my code?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading;

namespace MyNewService
{
    class Program : ServiceBase
    {
        static void Main(string[] args)
        {
        }

        public Program()
        {
            this.ServiceName = "Chatter";
        }

        protected override void OnStart(string[] args)
        {
            base.OnStart(args);

            //TODO: place your start code here
            ThreadStart starter = new ThreadStart(bw_DoWork);
            Thread t = new Thread(starter);
            t.Start();

        }

        private void bw_DoWork()
        {
            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(@"C:\Windows\system32\cmd.exe");
            p.Start();
            p.WaitForExit();
            base.Stop();
        }

        protected override void OnStop()
        {
            base.OnStop();

            //TODO: clean up any variables and stop any threads
        }
    }
}
解决方案

I have gone through all the pain of doing this.

Under windows 7/Vista/2008 it is not possible to load any interactive process from a service - without calling a number of Win API. = BLACK MAGIC

Have a look here and here.

The code below does the trick, use it with your own risk:

public static class ProcessAsCurrentUser
{

    /// <summary>
    /// Connection state of a session.
    /// </summary>
    public enum ConnectionState
    {
        /// <summary>
        /// A user is logged on to the session.
        /// </summary>
        Active,
        /// <summary>
        /// A client is connected to the session.
        /// </summary>
        Connected,
        /// <summary>
        /// The session is in the process of connecting to a client.
        /// </summary>
        ConnectQuery,
        /// <summary>
        /// This session is shadowing another session.
        /// </summary>
        Shadowing,
        /// <summary>
        /// The session is active, but the client has disconnected from it.
        /// </summary>
        Disconnected,
        /// <summary>
        /// The session is waiting for a client to connect.
        /// </summary>
        Idle,
        /// <summary>
        /// The session is listening for connections.
        /// </summary>
        Listening,
        /// <summary>
        /// The session is being reset.
        /// </summary>
        Reset,
        /// <summary>
        /// The session is down due to an error.
        /// </summary>
        Down,
        /// <summary>
        /// The session is initializing.
        /// </summary>
        Initializing
    }


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


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

    enum LOGON_TYPE
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK,
        LOGON32_LOGON_BATCH,
        LOGON32_LOGON_SERVICE,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT,
        LOGON32_LOGON_NEW_CREDENTIALS
    }

    enum LOGON_PROVIDER
    {
        LOGON32_PROVIDER_DEFAULT,
        LOGON32_PROVIDER_WINNT35,
        LOGON32_PROVIDER_WINNT40,
        LOGON32_PROVIDER_WINNT50
    }

    [Flags]
    enum CreateProcessFlags : uint
    {
        CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
        CREATE_DEFAULT_ERROR_MODE = 0x04000000,
        CREATE_NEW_CONSOLE = 0x00000010,
        CREATE_NEW_PROCESS_GROUP = 0x00000200,
        CREATE_NO_WINDOW = 0x08000000,
        CREATE_PROTECTED_PROCESS = 0x00040000,
        CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
        CREATE_SEPARATE_WOW_VDM = 0x00000800,
        CREATE_SHARED_WOW_VDM = 0x00001000,
        CREATE_SUSPENDED = 0x00000004,
        CREATE_UNICODE_ENVIRONMENT = 0x00000400,
        DEBUG_ONLY_THIS_PROCESS = 0x00000002,
        DEBUG_PROCESS = 0x00000001,
        DETACHED_PROCESS = 0x00000008,
        EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
        INHERIT_PARENT_AFFINITY = 0x00010000
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct WTS_SESSION_INFO
    {
        public int SessionID;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string WinStationName;
        public ConnectionState State;
    }

    [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Int32 WTSEnumerateSessions(IntPtr hServer, int reserved, int version,
                                                    ref IntPtr sessionInfo, ref int count);


    [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUserW", SetLastError = true, CharSet = CharSet.Auto)]
    static extern bool CreateProcessAsUser(
        IntPtr hToken,
        string lpApplicationName,
        string lpCommandLine,
        IntPtr lpProcessAttributes,
        IntPtr lpThreadAttributes,
        bool bInheritHandles,
        UInt32 dwCreationFlags,
        IntPtr lpEnvironment,
        string lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);

    [DllImport("wtsapi32.dll")]
    public static extern void WTSFreeMemory(IntPtr memory);

    [DllImport("kernel32.dll")]
    private static extern UInt32 WTSGetActiveConsoleSessionId();

    [DllImport("wtsapi32.dll", SetLastError = true)]
    static extern int WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateTokenEx(
        IntPtr hExistingToken,
        uint dwDesiredAccess,
        IntPtr lpTokenAttributes,
        int ImpersonationLevel,
        int TokenType,
        out IntPtr phNewToken);

    private const int TokenImpersonation = 2;
    private const int SecurityIdentification = 1;
    private const int MAXIMUM_ALLOWED = 0x2000000;
    private const int TOKEN_DUPLICATE = 0x2;
    private const int TOKEN_QUERY = 0x00000008;

    /// <summary>
    /// Launches a process for the current logged on user if there are any.
    /// If none, return false as well as in case of
    ///
    /// ##### !!! BEWARE !!! ####  ------------------------------------------
    /// This code will only work when running in a windows service (where it is really needed)
    /// so in case you need to test it, it needs to run in the service. Reason
    /// is a security privileg which only services have (SE_??? something, cant remember)!
    /// </summary>
    /// <param name="processExe"></param>
    /// <returns></returns>
    public static bool CreateProcessAsCurrentUser(string processExe)
    {

        IntPtr duplicate = new IntPtr();
        STARTUPINFO info = new STARTUPINFO();
        PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION();

        Debug.WriteLine(string.Format("CreateProcessAsCurrentUser. processExe: " + processExe));

        IntPtr p = GetCurrentUserToken();

        bool result = DuplicateTokenEx(p, MAXIMUM_ALLOWED | TOKEN_QUERY | TOKEN_DUPLICATE, IntPtr.Zero, SecurityIdentification, SecurityIdentification, out duplicate);
        Debug.WriteLine(string.Format("DuplicateTokenEx result: {0}", result));
        Debug.WriteLine(string.Format("duplicate: {0}", duplicate));


        if (result)
        {
            result = CreateProcessAsUser(duplicate, processExe, null,
                IntPtr.Zero, IntPtr.Zero, false, (UInt32)CreateProcessFlags.CREATE_NEW_CONSOLE, IntPtr.Zero, null,
                ref info, out procInfo);
            Debug.WriteLine(string.Format("CreateProcessAsUser result: {0}", result));

        }


        if (p.ToInt32() != 0)
        {
            Marshal.Release(p);
            Debug.WriteLine(string.Format("Released handle p: {0}", p));
        }


        if (duplicate.ToInt32() != 0)
        {
            Marshal.Release(duplicate);
            Debug.WriteLine(string.Format("Released handle duplicate: {0}", duplicate));
        }



        return result;
    }

    public static int GetCurrentSessionId()
    {
        uint sessionId = WTSGetActiveConsoleSessionId();
        Debug.WriteLine(string.Format("sessionId: {0}", sessionId));

        if (sessionId == 0xFFFFFFFF)
            return -1;
        else
            return (int)sessionId;
    }

    public static bool IsUserLoggedOn()
    {
        List<WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
        Debug.WriteLine(string.Format("Number of sessions: {0}", wtsSessionInfos.Count));
        return wtsSessionInfos.Where(x => x.State == ConnectionState.Active).Count() > 0;
    }

    private static IntPtr GetCurrentUserToken()
    {
        List<WTS_SESSION_INFO> wtsSessionInfos = ListSessions();
        int sessionId = wtsSessionInfos.Where(x => x.State == ConnectionState.Active).FirstOrDefault().SessionID;
        //int sessionId = GetCurrentSessionId();

        Debug.WriteLine(string.Format("sessionId: {0}", sessionId));
        if (sessionId == int.MaxValue)
        {
            return IntPtr.Zero;
        }
        else
        {
            IntPtr p = new IntPtr();
            int result = WTSQueryUserToken((UInt32)sessionId, out p);
            Debug.WriteLine(string.Format("WTSQueryUserToken result: {0}", result));
            Debug.WriteLine(string.Format("WTSQueryUserToken p: {0}", p));

            return p;
        }
    }

    public static List<WTS_SESSION_INFO> ListSessions()
    {
        IntPtr server = IntPtr.Zero;
        List<WTS_SESSION_INFO> ret = new List<WTS_SESSION_INFO>();

        try
        {
            IntPtr ppSessionInfo = IntPtr.Zero;

            Int32 count = 0;
            Int32 retval = WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref ppSessionInfo, ref count);
            Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));

            Int64 current = (int)ppSessionInfo;

            if (retval != 0)
            {
                for (int i = 0; i < count; i++)
                {
                    WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
                    current += dataSize;

                    ret.Add(si);
                }

                WTSFreeMemory(ppSessionInfo);
            }
        }
        catch (Exception exception)
        {
            Debug.WriteLine(exception.ToString());
        }

        return ret;
    }

}

这篇关于启动Windows服务并启动CMD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 04:07