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