Как перенаправить исключение exe обратно в приложение VB6?
-
11-09-2019 - |
Вопрос
у меня есть приложения vb6, которые будут вызывать mencoder.exe, который является частью mplayer, для преобразования некоторых файлов в формат flv.Я получаю эту странную проблему с необработанными исключениями от mencoder всякий раз, когда пытаюсь преобразовать этот файл opendivx.
На данный момент мне неясно, является ли этот кодек виновником этого.В любом случае я попытался изменить командную строку и даже загрузил последнюю доступную версию для 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
Обновления:
и если вам интересно, что выдавало приложение при сбое, вот оно:
1 дубликат кадра(ов)!
Позиция:83,2 с 2504f (99%) 112,65 кадров в секунду Трем:0min 6 МБ AV: 0,008 [571: 79]] 1 дубликат рамы (ы)!
Позиция:83,4 с 2510f (102%) 112,74 кадра в секунду Трем:0min 6 МБ AV: 0,006 [571: 79] 1 дубликат рамы (ы)!
Позиция:83,6 с 2516f (102%) 112,84 кадра в секунду Трем:0min 6 МБ AV: 0,004 [571: 79] 1 дубликат рамы (ы)!
[mpeg4 @ 0x1ac53a0]сокрытие 40 ошибок постоянного тока, 40 переменного тока, 40 МВ A-V:0,003 [571:79]
альтернативный текст http://img21.imageshack.us/img21/4539/Exception.png
Спасибо :)
Решение
Вы можете попробовать использовать API SetUnhandledExceptionFilter, чтобы перехватить исключение.Я использовал его раньше, но с ограниченным успехом.Я считаю, что этот код изначально появился, находился под сильным влиянием или был вдохновлен статьей в журнале Visual Basic Programmers Journal за май 99 года под названием «Нет ошибок-исключений, мой дорогой доктор».Уотсон» Джонатана Лунмана.
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
Проверьте Функция SetUnhandledExceptionFilter в MSDN для получения дополнительной информации.
Другие советы
Если это приложение работает под Windows XP или более поздней версии, попробуйте использовать векторную обработку исключений.Вы можете написать простой набор DLL C++ или использовать вызовы API для перехвата различных действий, происходящих в API Win32.