Imports System.ComponentModel
Imports System.IO

Namespace UTSModule.Test.Command.ProcessCommand
    Public Class ProcessCommandManager

        Const ERROR_FILE_NOT_FOUND As Integer = 2
        Const ERROR_ACCESS_DENIED As Integer = 5

        Public Shared Function CreateExecutor(command As TestCommand) As TestCommandExecutor
            Dim executor As TestCommandExecutor
            Select Case command.Name
                Case "Proc_Execute"
                    executor = New ProcessExecuteExecutor(command)
                Case Else
                    Throw New Exception($"Process集,未知命令 ：{command.Name}")
            End Select

            Return executor
        End Function


        '''' <summary>
        '''' 运行CMD命令并获取返回值
        '''' </summary>
        '''' <param name="filePath"></param>
        '''' <param name="arguments"></param>
        '''' <returns></returns>
        'Public Shared Function RunCmdGetReturn(filePath As String, arguments As String, ByRef result As String) As Boolean
        '    Dim proc As New Process
        '    With proc.StartInfo
        '        .FileName = filePath
        '        .Arguments = arguments
        '        .UseShellExecute = False
        '        .RedirectStandardInput = True
        '        .RedirectStandardOutput = True
        '        .RedirectStandardError = True
        '        .CreateNoWindow = True
        '    End With

        '    Dim errorMsg As String

        '    Try
        '        proc.Start()
        '        proc.WaitForExit()
        '        result = proc.StandardOutput.ReadToEnd()
        '        errorMsg = proc.StandardError.ReadToEnd()

        '        proc.Close()

        '        If errorMsg.Length > 0 Then
        '            result = errorMsg
        '            Return False
        '        End If
        '    Catch ex As Exception
        '        result = ex.Message
        '        Return False
        '    End Try

        '    Return True
        'End Function

        '''' <summary>
        '''' 运行CMD命令并获取返回值
        '''' </summary>
        '''' <param name="filePath"></param>
        '''' <param name="arguments"></param>
        '''' <returns></returns>
        'Public Shared Function RunCmdGetReturn(filePath As String, arguments As String, timeout As Integer, ByRef result As String) As Boolean
        '    Dim proc As New Process
        '    With proc.StartInfo
        '        .FileName = filePath
        '        .Arguments = arguments
        '        .UseShellExecute = False
        '        .RedirectStandardInput = True
        '        .RedirectStandardOutput = True
        '        .RedirectStandardError = True
        '        .CreateNoWindow = True
        '    End With

        '    Dim errorMsg As String

        '    Try
        '        proc.Start()
        '        proc.WaitForExit(timeout)
        '        result = proc.StandardOutput.ReadToEnd()
        '        errorMsg = proc.StandardError.ReadToEnd()

        '        proc.Close()

        '        If errorMsg.Length > 0 Then
        '            result = errorMsg
        '            Return False
        '        End If
        '    Catch ex As Exception
        '        result = ex.Message
        '        Return False
        '    End Try

        '    Return True
        'End Function

        '''' <summary>
        '''' 运行CMD命令并获取返回值 2022-10-25 1.6.1 版本,有时会出现外部程序已关闭后调用，结果弹出错误框
        '''' </summary>
        '''' <param name="filePath">执行文件路径</param>
        '''' <param name="arguments">执行参数</param>
        '''' <param name="timeout">超时时间</param>
        '''' <param name="sr">获取输出流内容</param>
        '''' <param name="destStr">目标字符串，为空则错误输出流有内容则判定失败</param>
        '''' <param name="result"></param>
        '''' <returns></returns>
        'Public Shared Function RunCmdGetReturn(filePath As String, arguments As String, timeout As Integer, sr As Integer, destStr As String, ByRef result As String) As Boolean

        '    'Process used tips
        '    'Dim Process As Process = New Process()
        '    'Process.StartInfo.UseShellExecute = False '// 是否使用外壳程序
        '    'Process.StartInfo.CreateNoWindow = True '// 是否在新窗口中启动该进程的值
        '    'Process.StartInfo.RedirectStandardInput = True '// 重定向输入流
        '    'Process.StartInfo.RedirectStandardOutput = True '// 重定向输出流
        '    'Process.StartInfo.RedirectStandardError = True '// 重定向错误流

        '    '需要注意的是：     若要使用 StandardOutput， 必须将 
        '    'Process.StartInfo.UseShellExecute = False
        '    'Process.StartInfo.RedirectStandardOutput = True
        '    '否则， 读取StandardOutput 流时将引发异常；
        '    'https://blog.csdn.net/e295166319/article/details/77932082?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-77932082-blog-6859166.pc_relevant_vip_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-77932082-blog-6859166.pc_relevant_vip_default&utm_relevant_index=1

        '    Dim proc As New Process
        '    With proc.StartInfo
        '        .FileName = filePath '//待输入的执行文件路径
        '        .Arguments = arguments
        '        .UseShellExecute = False
        '        ' .RedirectStandardInput = True

        '        If sr = 1 Then '标准错误流
        '            .RedirectStandardError = True
        '        Else
        '            .RedirectStandardOutput = True
        '        End If

        '        .CreateNoWindow = True
        '    End With

        '    Dim pid As Integer
        '    Try
        '        proc.Start()

        '        pid = proc.Id
        '        If timeout = 0 Then
        '            proc.WaitForExit() '无限期等待进程结束
        '        Else
        '            If proc.WaitForExit(timeout) = False Then
        '                result = "进程超时退出"
        '                proc.Close()

        '                Try
        '                    Dim p As Process = Process.GetProcessById(pid)
        '                    If p IsNot Nothing Then p.Kill()
        '                Catch ex As Exception
        '                    result &= $",{ex.Message}"
        '                End Try

        '                Return False
        '            End If
        '        End If

        '        Select Case sr
        '            Case 0 '标准输出流
        '                result = proc.StandardOutput.ReadToEnd()
        '            Case 1 '标准错误流
        '                result = proc.StandardError.ReadToEnd()
        '            Case Else '默认标准输出流
        '                result = proc.StandardOutput.ReadToEnd()
        '        End Select

        '        proc.Close()

        '        If String.IsNullOrEmpty(destStr) Then
        '            Return True
        '        Else
        '            Return result.Contains(destStr)
        '        End If
        '    Catch ex As Exception
        '        result = ex.Message
        '        proc.Close()
        '        Return False
        '    End Try

        '    Return True
        'End Function

        ''' <summary>
        ''' 运行CMD命令并获取返回值 2022-10-25 1.6.2 版本
        ''' </summary>
        ''' <param name="filePath">执行文件路径</param>
        ''' <param name="arguments">执行参数</param>
        ''' <param name="timeout">超时时间</param>
        ''' <param name="sr">获取输出流内容</param>
        ''' <param name="destStr">目标字符串，为空则错误输出流有内容则判定失败</param>
        ''' <param name="result"></param>
        ''' <returns></returns>
        Public Shared Function RunCmdGetReturn(filePath As String, arguments As String, timeout As Integer, sr As Integer, destStr As String, ByRef result As String) As Boolean

            'Process used tips
            'Dim Process As Process = New Process()
            'Process.StartInfo.UseShellExecute = False '// 是否使用外壳程序
            'Process.StartInfo.CreateNoWindow = True '// 是否在新窗口中启动该进程的值
            'Process.StartInfo.RedirectStandardInput = True '// 重定向输入流
            'Process.StartInfo.RedirectStandardOutput = True '// 重定向输出流
            'Process.StartInfo.RedirectStandardError = True '// 重定向错误流

            '需要注意的是：     若要使用 StandardOutput， 必须将 
            'Process.StartInfo.UseShellExecute = False
            'Process.StartInfo.RedirectStandardOutput = True
            '否则， 读取StandardOutput 流时将引发异常；
            'https://blog.csdn.net/e295166319/article/details/77932082?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-77932082-blog-6859166.pc_relevant_vip_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-77932082-blog-6859166.pc_relevant_vip_default&utm_relevant_index=1

            Dim proc As New Process
            With proc.StartInfo
                .FileName = filePath '//待输入的执行文件路径
                .Arguments = arguments
                .UseShellExecute = False
                ' .RedirectStandardInput = True

                If sr = 1 Then '标准错误流
                    .RedirectStandardError = True
                Else
                    .RedirectStandardOutput = True
                End If

                .CreateNoWindow = True
            End With

            Dim pid As Integer
            Try
                proc.Start() '启动程序
                pid = proc.Id

                '把读取返回的代码放到进程结束之前
                Select Case sr
                    Case 0 '标准输出流
                        result = proc.StandardOutput.ReadToEnd()
                    Case 1 '标准错误流
                        result = proc.StandardError.ReadToEnd()
                    Case Else '默认标准输出流
                        result = proc.StandardOutput.ReadToEnd()
                End Select

                '等待程序执行完退出进
                If timeout = 0 Then
                    proc.WaitForExit() '无限期等待进程结束
                Else
                    If proc.WaitForExit(timeout) = False Then
                        result = "进程超时退出"
                        proc.Close()

                        Try
                            Dim p As Process = Process.GetProcessById(pid)
                            If p IsNot Nothing Then p.Kill()
                        Catch ex As Exception
                            result &= $",{ex.Message}"
                        End Try

                        Return False
                    End If
                End If

                proc.Close()

                If String.IsNullOrEmpty(destStr) Then
                    Return True
                Else
                    Return result.Contains(destStr)
                End If

            Catch e As Win32Exception
                If e.NativeErrorCode = ERROR_FILE_NOT_FOUND Then result = e.Message & ",检查文件路径."
                If e.NativeErrorCode = ERROR_ACCESS_DENIED Then result = e.Message & ",没有权限操作文件."

            Catch ex As Exception
                result = ex.Message
                proc.Close()
                Return False
            End Try

            Return True
        End Function

    End Class
End Namespace