Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将exe异常路由回VB6应用程序?_Vb6_Exception Handling_Mencoder - Fatal编程技术网

如何将exe异常路由回VB6应用程序?

如何将exe异常路由回VB6应用程序?,vb6,exception-handling,mencoder,Vb6,Exception Handling,Mencoder,我有一个vb6应用程序,它将调用mencoder.exe,它是mplayer的一部分,用于将一些文件转换为flv格式。每当我试图转换这个opendivx文件时,我都会从mencoder得到一个奇怪的未处理异常问题 目前,我还不清楚这个编解码器是否是背后的罪魁祸首。无论哪种方式,我都尝试修改命令行,甚至下载了mencoder的最新可用版本 因此,转换工作正常,唯一的问题是mencoder最终会崩溃,因为视频文件不知何故超过了100%到102%。因此,我的问题是如何将此异常路由到我的vb6应用程序来

我有一个vb6应用程序,它将调用mencoder.exe,它是mplayer的一部分,用于将一些文件转换为flv格式。每当我试图转换这个opendivx文件时,我都会从mencoder得到一个奇怪的未处理异常问题

目前,我还不清楚这个编解码器是否是背后的罪魁祸首。无论哪种方式,我都尝试修改命令行,甚至下载了mencoder的最新可用版本

因此,转换工作正常,唯一的问题是mencoder最终会崩溃,因为视频文件不知何故超过了100%到102%。因此,我的问题是如何将此异常路由到我的vb6应用程序来处理,以便不会显示丑陋的错误弹出窗口

我甚至在代码中包含了异常捕获,但它没有捕获该异常

    ' Function GetCommandOutput
'
' sCommandLine:  [in] Command line to launch
' blnStdOut        [in,opt] True (defualt) to capture output to STDOUT
' blnStdErr        [in,opt] True to capture output to STDERR. False is default.
' blnOEMConvert:   [in,opt] True (default) to convert DOS characters to Windows, False to skip conversion
'
' Returns:       String with STDOUT and/or STDERR output
'
Public Function GetCommandOutput(sCommandLine As String, _
                                 Optional blnStdOut As Boolean = True, _
                                 Optional blnStdErr As Boolean = False, _
                                 Optional blnOEMConvert As Boolean = True, _
                                 Optional encoderType As String) As String

    Dim hPipeRead   As Long, hPipeWrite1 As Long, hPipeWrite2 As Long
    Dim hCurProcess As Long
    Dim sa          As SECURITY_ATTRIBUTES
    Dim si          As STARTUPINFO
    Dim pi          As PROCESS_INFORMATION
    Dim baOutput()  As Byte
    Dim sNewOutPut  As String
    Dim lBytesRead  As Long
    Dim fTwoHandles As Boolean
    Dim lRet        As Long

    Const BUFSIZE = 1024      ' pipe buffer size

    On Error GoTo ErrorHandler

    ' At least one of them should be True, otherwise there's no point in calling the function
    If (Not blnStdOut) And (Not blnStdErr) Then
        Err.Raise 5         ' Invalid Procedure call or Argument
    End If

    ' If both are true, we need two write handles. If not, one is enough.
    fTwoHandles = blnStdOut And blnStdErr
    ReDim baOutput(BUFSIZE - 1) As Byte

    With sa
        .nLength = Len(sa)
        .bInheritHandle = 1    ' get inheritable pipe handles
    End With

    If CreatePipe(hPipeRead, hPipeWrite1, sa, BUFSIZE) = 0 Then

        Exit Function

    End If

    hCurProcess = GetCurrentProcess()
    ' Replace our inheritable read handle with an non-inheritable. Not that it
    ' seems to be necessary in this case, but the docs say we should.
    Call DuplicateHandle(hCurProcess, hPipeRead, hCurProcess, hPipeRead, 0&, 0&, DUPLICATE_SAME_ACCESS Or DUPLICATE_CLOSE_SOURCE)

    ' If both STDOUT and STDERR should be redirected, get an extra handle.
    If fTwoHandles Then
        Call DuplicateHandle(hCurProcess, hPipeWrite1, hCurProcess, hPipeWrite2, 0&, 1&, DUPLICATE_SAME_ACCESS)
    End If

    With si
        .cb = Len(si)
        .dwFlags = STARTF_USESHOWWINDOW Or STARTF_USESTDHANDLES
        .wShowWindow = SW_HIDE          ' hide the window

        If fTwoHandles Then
            .hStdOutput = hPipeWrite1
            .hStdError = hPipeWrite2
        ElseIf blnStdOut Then
            .hStdOutput = hPipeWrite1
        Else
            .hStdError = hPipeWrite1
        End If

    End With

    Dim totalSeconds As Double

    If CreateProcess(vbNullString, sCommandLine, ByVal 0&, ByVal 0&, 1, 0&, ByVal 0&, vbNullString, si, pi) Then
        ' Close thread handle - we don't need it
        Call CloseHandle(pi.hThread)
        ' Also close our handle(s) to the write end of the pipe. This is important, since
        ' ReadFile will *not* return until all write handles are closed or the buffer is full.
        Call CloseHandle(hPipeWrite1)
        hPipeWrite1 = 0

        If hPipeWrite2 Then
            Call CloseHandle(hPipeWrite2)
            hPipeWrite2 = 0
        End If

        Do

            ' Add a DoEvents to allow more data to be written to the buffer for each call.
            ' This results in fewer, larger chunks to be read.
            'DoEvents
            If ReadFile(hPipeRead, baOutput(0), BUFSIZE, lBytesRead, ByVal 0&) = 0 Then

                Exit Do

            End If

            If blnOEMConvert Then
                ' convert from "DOS" to "Windows" characters
                sNewOutPut = String$(lBytesRead, 0)
                Call OemToCharBuff(baOutput(0), sNewOutPut, lBytesRead)
            Else
                ' perform no conversion (except to Unicode)
                sNewOutPut = Left$(StrConv(baOutput(), vbUnicode), lBytesRead)
            End If

            GetCommandOutput = GetCommandOutput & sNewOutPut
            ' If you are executing an application that outputs data during a long time,
            ' and don't want to lock up your application, it might be a better idea to
            ' wrap this code in a class module in an ActiveX EXE and execute it asynchronously.
            ' Then you can raise an event here each time more data is available.
            'Debug.Print sNewOutPut + vbNewLine

            If encoderType = "ffmpeg" Then
                If totalSeconds < 1 Then
                    totalSeconds = GetFFmpegFileTotalSeconds(sNewOutPut)
                End If

                Call CalculateFFMpegProgress(sNewOutPut, totalSeconds)
            Else
                Call CalculateMencoderProgress(sNewOutPut)
            End If

            'RaiseEvent OutputAvailable(sNewOutput)
        Loop

        ' When the process terminates successfully, Err.LastDllError will be
        ' ERROR_BROKEN_PIPE (109). Other values indicates an error.
        Call CloseHandle(pi.hProcess)
    Else
        GetCommandOutput = "Failed to create process, check the path of the command line."
    End If

    ' clean up
    Call CloseHandle(hPipeRead)

    If hPipeWrite1 Then
        Call CloseHandle(hPipeWrite1)
    End If

    If hPipeWrite2 Then
        Call CloseHandle(hPipeWrite2)
    End If
    Exit Function

ErrorHandler:
    Call WriteErrorLog(Err, "Class clsThread : Sub GetCommandOutput")
End Function
函数GetCommandOutput ' 'sCommandLine:[in]要启动的命令行 'blnStdOut[in,opt]True(default)以捕获到STDOUT的输出 'blnStdErr[in,opt]True以捕获到STDERR的输出。默认为False。 'blnOEMConvert:[in,opt]True(默认)将DOS字符转换为Windows,False将跳过转换 ' '返回:带有STDOUT和/或STDERR输出的字符串 ' 公共函数GetCommandOutput(sCommandLine作为字符串_ 可选blnStdOut为布尔值=真_ 可选的blnStdErr作为布尔值=False_ 可选blnOEMConvert为布尔值=真_ 可选编码器类型(作为字符串)作为字符串 将hPipeRead变长,HPIPERWRITE1变长,HPIPERWRITE2变长 Dim HCUR进程尽可能长 将sa设置为安全属性 将si设置为STARTUPINFO 作为过程信息的Dim pi Dim baOutput()作为字节 暗sNewOutPut作为字符串 变暗的字节数等于长的字节数 将句柄设置为布尔值 暗淡的lRet尽可能长 Const BUFSIZE=1024'管道缓冲区大小 关于错误转到错误处理程序 至少其中一个应该为True,否则调用该函数没有意义 如果(非blnStdOut)和(非blnStdErr),则 错误。引发5'无效的过程调用或参数 如果结束 '如果两者都为真,则需要两个写入句柄。如果没有,一个就足够了。 fTwoHandles=blnStdOut和blnStdErr ReDim输出(BUFSIZE-1)作为字节 与sa .nLength=Len(sa) .bInheritHandle=1'获取可继承的管道句柄 以 如果CreatePipe(hPipeRead、HPIPERWRITE1、sa、BUFSIZE)=0,则 退出功能 如果结束 hCurProcess=GetCurrentProcess() '将可继承的读取句柄替换为不可继承的。并非如此 在这种情况下,这似乎是必要的,但医生说我们应该这样做。 调用DuplicateHandle(hCurProcess、hPipeRead、hCurProcess、hPipeRead、0&、DUPLICATE\u SAME\u ACCESS或DUPLICATE\u CLOSE\u SOURCE) '如果STDOUT和STDERR都应该重定向,则获取一个额外的句柄。 如果是这样的话 调用DuplicateHandle(hCurProcess、hPipeWrite1、hCurProcess、hPipeWrite2、0&、1&、DUPLICATE\u SAME\u访问) 如果结束 与si .cb=Len(si) .dwFlags=STARTF_USESHOWWINDOW或STARTF_USESTDHANDLES .wShowWindow=SW_HIDE'隐藏窗口 如果是这样的话 .hStdOutput=hpipebrite1 .hStdError=hPipeWrite2 那么艾尔塞夫·布朗斯杜特呢 .hStdOutput=hpipebrite1 其他的 .hStdError=hpipebrite1 如果结束 以 将总秒数设置为双精度 如果CreateProcess(vbNullString、sCommandLine、ByVal 0&、ByVal 0&、1、0&、ByVal 0&、vbNullString、si、pi),则 '关闭线程句柄-我们不需要它 调用CloseHandle(pi.hThread) '同时关闭管道写入端的句柄。这很重要,因为 在关闭所有写入句柄或缓冲区已满之前,'ReadFile将*不*返回。 调用CloseHandle(hPipeWrite1) hPipeWrite1=0 如果是hPipeWrite2,那么 调用CloseHandle(hPipeWrite2) hPipeWrite2=0 如果结束 做 '添加DoEvents以允许为每个调用将更多数据写入缓冲区。 这会导致要读取的块更少、更大。 ”“是吗 如果ReadFile(hPipeRead、baOutput(0)、BUFSIZE、lBytesRead、ByVal 0&)=0,则 退出Do 如果结束 如果blnOEMConvert那么 '从“DOS”字符转换为“Windows”字符 sNewOutPut=String$(lBytesRead,0) 调用OemToCharBuff(输出(0)、输出sNewOutPut、字节读取) 其他的 '不执行任何转换(到Unicode除外) sNewOutPut=Left$(StrConv(baOutput(),vbUnicode),lBytesRead) 如果结束 GetCommandOutput=GetCommandOutput&sNewOutPut '如果您正在执行一个长时间输出数据的应用程序, 如果你不想锁定你的应用程序,最好是 '将此代码包装在ActiveX EXE的类模块中,并异步执行。 '然后,每次有更多数据可用时,您都可以在此处引发一个事件。 'Debug.Print sNewOutPut+vbNewLine 如果encoderType=“ffmpeg”,则 如果总秒数小于1,则 totalSeconds=GetFFmpegFileTotalSeconds(sNewOutPut) 如果结束 调用CalculateFmpegProgress(sNewOutPut,总秒数) 其他的 调用CalculationCoderProgress(sNewOutPut) 如果结束 'RaiseEvent OutputAvailable(sNewOutput) 环 '当进程成功终止时,将返回Err.LastDllError '错误\断开\管道(109)。其他值表示错误。 调用CloseHandle(pi.hProcess) 其他的 GetCommandOutput=“未能执行此操作。”
Public Const SYSEXC_MAXIMUM_PARAMETERS = 15
'Not exactly as in API, shorter declaration, but internally the same
Type CONTEXT
  Dbls(0 To 66) As Double
  Longs(0 To 6) As Long
End Type

Type SYSEXC_RECORD
    ExceptionCode As Long
    ExceptionFlags As Long
    pExceptionRecord As Long
    ExceptionAddress As Long
    NumberParameters As Long
    ExceptionInformation(SYSEXC_MAXIMUM_PARAMETERS) As Long
End Type    
Type SYSEXC_POINTERS
    pExceptionRecord As SYSEXC_RECORD
    ContextRecord As CONTEXT
End Type

Private Declare Function SetUnhandledExceptionFilter Lib "kernel32" _
    (ByVal lpTopLevelExceptionFilter As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Sub CopyExceptionRecord Lib "kernel32" Alias "RtlMoveMemory" (pDest As SYSEXC_RECORD, ByVal LPSYSEXC_RECORD As Long, ByVal lngBytes As Long)


Public Property Get ErrSysHandlerWasSet() As Boolean
    ErrSysHandlerWasSet = mSysHandlerWasSet
End Property


Public Sub ErrSysHandlerSet()
    If mSysHandlerWasSet Then ErrSysHandlerRelease
    Call SetUnhandledExceptionFilter(AddressOf SysExcHandler)
    mSysHandlerWasSet = True
End Sub

Public Sub ErrSysHandlerRelease()
    ErrPreserve 'This Sub may be called from error handler, so preserve errors
    On Error Resume Next
    If mSysHandlerWasSet Then Call SetUnhandledExceptionFilter(0)
    mSysHandlerWasSet = False
    ErrRestore
End Sub

'========================== Private stuff ===========================================
Private Function SysExcHandler(ByRef ExcPtrs As SYSEXC_POINTERS) As Long
  Dim ExcRec As SYSEXC_RECORD, strExc As String
  ExcRec = ExcPtrs.pExceptionRecord
  Do Until ExcRec.pExceptionRecord = 0
    CopyExceptionRecord ExcRec, ExcRec.pExceptionRecord, Len(ExcRec)
  Loop
  strExc = GetExcAsText(ExcRec.ExceptionCode)
  Err.Raise ERR_SYSEXCEPTION, SRC_SYSHANDLER, _
    "(&H" & Hex$(ExcRec.ExceptionCode) & ") " & strExc
End Function

Private Function GetExcAsText(ByVal ExcNum As Long) As String
    Select Case ExcNum
        Case SYSEXC_ACCESS_VIOLATION:          GetExcAsText = "Access violation"
        Case SYSEXC_DATATYPE_MISALIGNMENT:     GetExcAsText = "Datatype misalignment"
        Case SYSEXC_BREAKPOINT:                GetExcAsText = "Breakpoint"
        Case SYSEXC_SINGLE_STEP:               GetExcAsText = "Single step"
        Case SYSEXC_ARRAY_BOUNDS_EXCEEDED:     GetExcAsText = "Array bounds exceeded"
        Case SYSEXC_FLT_DENORMAL_OPERAND:      GetExcAsText = "Float Denormal Operand"
        Case SYSEXC_FLT_DIVIDE_BY_ZERO:        GetExcAsText = "Divide By Zero"
        Case SYSEXC_FLT_INEXACT_RESULT:        GetExcAsText = "Floating Point Inexact Result"
        Case SYSEXC_FLT_INVALID_OPERATION:     GetExcAsText = "Invalid Operation"
        Case SYSEXC_FLT_OVERFLOW:              GetExcAsText = "Float Overflow"
        Case SYSEXC_FLT_STACK_CHECK:           GetExcAsText = "Float Stack Check"
        Case SYSEXC_FLT_UNDERFLOW:             GetExcAsText = "Float Underflow"
        Case SYSEXC_INT_DIVIDE_BY_ZERO:        GetExcAsText = "Integer Divide By Zero"
        Case SYSEXC_INT_OVERFLOW:              GetExcAsText = "Integer Overflow"
        Case SYSEXC_PRIVILEGED_INSTRUCTION:    GetExcAsText = "Privileged Instruction"
        Case SYSEXC_IN_PAGE_ERROR:             GetExcAsText = "In Page Error"
        Case SYSEXC_ILLEGAL_INSTRUCTION:       GetExcAsText = "Illegal Instruction"
        Case SYSEXC_NONCONTINUABLE_EXCEPTION:  GetExcAsText = "Non Continuable Exception"
        Case SYSEXC_STACK_OVERFLOW:            GetExcAsText = "Stack Overflow"
        Case SYSEXC_INVALID_DISPOSITION:       GetExcAsText = "Invalid Disposition"
        Case SYSEXC_GUARD_PAGE_VIOLATION:      GetExcAsText = "Guard Page Violation"
        Case SYSEXC_INVALID_HANDLE:            GetExcAsText = "Invalid Handle"
        Case SYSEXC_CONTROL_C_EXIT:            GetExcAsText = "Control-C Exit"
    End Select
End Function