to 超级绿豆,这段代码就是我上次写的那个,里面有一个很奇怪的问题,在调试期间按第一个按钮不会出问题,按第二个按钮就会出问题,但是在编译成可执行文件后按第一个按钮会出问题,按第二个按钮就不会出问题,里面有一个API我把参数改了一下,帮忙看看最终原因在哪里,谢谢了。' 以下是模块里的内容 basEx.basOption ExplicitPublic Const EXCEPTION_MAXIMUM_PARAMETERS = 15
Public Type EXCEPTION_RECORD
ExceptionCode As Long
ExceptionFlags As Long
pExceptionRecord As Long ' Pointer to an EXCEPTION_RECORD structure
ExceptionAddress As Long
NumberParameters As Long
ExceptionInformation(EXCEPTION_MAXIMUM_PARAMETERS) As Long
End TypePublic Type CONTEXT
FltF0 As Double
FltF1 As Double
FltF2 As Double
FltF3 As Double
FltF4 As Double
FltF5 As Double
FltF6 As Double
FltF7 As Double
FltF8 As Double
FltF9 As Double
FltF10 As Double
FltF11 As Double
FltF12 As Double
FltF13 As Double
FltF14 As Double
FltF15 As Double
FltF16 As Double
FltF17 As Double
FltF18 As Double
FltF19 As Double
FltF20 As Double
FltF21 As Double
FltF22 As Double
FltF23 As Double
FltF24 As Double
FltF25 As Double
FltF26 As Double
FltF27 As Double
FltF28 As Double
FltF29 As Double
FltF30 As Double
FltF31 As Double
IntV0 As Double
IntT0 As Double
IntT1 As Double
IntT2 As Double
IntT3 As Double
IntT4 As Double
IntT5 As Double
IntT6 As Double
IntT7 As Double
IntS0 As Double
IntS1 As Double
IntS2 As Double
IntS3 As Double
IntS4 As Double
IntS5 As Double
IntFp As Double
IntA0 As Double
IntA1 As Double
IntA2 As Double
IntA3 As Double
IntA4 As Double
IntA5 As Double
IntT8 As Double
IntT9 As Double
IntT10 As Double
IntT11 As Double
IntRa As Double
IntT12 As Double
IntAt As Double
IntGp As Double
IntSp As Double
IntZero As Double
Fpcr As Double
SoftFpcr As Double
Fir As Double
Psr As Long
ContextFlags As Long
Fill(4) As Long
End TypePublic Type EXCEPTION_POINTERS
pExceptionRecord As EXCEPTION_RECORD
ContextRecord As CONTEXT
End TypePublic Const EXCEPTION_EXECUTE_HANDLER = 1
Public Const EXCEPTION_CONTINUE_EXECUTION = -1
Public Const EXCEPTION_CONTINUE_SEARCH = 0Public Const EXCEPTION_DEBUG_EVENT = 1Public Const EXCEPTION_ACCESS_VIOLATION = &HC0000005Public Declare Function SetUnhandledExceptionFilter Lib "kernel32" ( _
ByVal lpTopLevelExceptionFilter As Long) As Long'Public Declare Function UnhandledExceptionFilter Lib "kernel32" ( _
ExceptionInfo As EXCEPTION_POINTERS) As Long' 原来的这个声明我把参数改了,上面那个是原型
Public Declare Function UnhandledExceptionFilter Lib "kernel32" ( _
ExceptionInfo As Any) As LongPublic hException As LongPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Public Function MyExceptionProc(ByVal ExceptionInfo As Long) As Long
On Error Resume Next
Static s_SigCount As Long
Dim dwExceptCode As Long
Dim lResult As Long
Dim lpExceptionInfo As EXCEPTION_POINTERS
CopyMemory ByVal lpExceptionInfo, ExceptionInfo, Len(lpExceptionInfo)
dwExceptCode = lpExceptionInfo.pExceptionRecord.ExceptionCode
If dwExceptCode = EXCEPTION_ACCESS_VIOLATION Then
Debug.Print "Access violation caught by MyUnFilter"
s_SigCount = s_SigCount + 1
If s_SigCount < 5 Then
lResult = EXCEPTION_CONTINUE_EXECUTION
Else
lResult = EXCEPTION_EXECUTE_HANDLER
End If
Else
lResult = EXCEPTION_CONTINUE_SEARCH
End If
MyExceptionProc = lResult
End Function' 以下是窗体里的内容 frmMain.frmOption ExplicitPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
Destination As Any, Source As Any, ByVal Length As Long)Dim lpExceptionInfo As EXCEPTION_POINTERSPrivate Sub Command1_Click()
On Error GoTo errFinish
UnhandledExceptionFilter hException
Exit Sub
errFinish:
MsgBox Err.Description
End SubPrivate Sub Command2_Click()
On Error GoTo errFinish
CopyMemory ByVal 1, ByVal 2, 3
Exit Sub
errFinish:
MsgBox Err.Description
End SubPrivate Sub Form_Load()
hException = SetUnhandledExceptionFilter(AddressOf MyExceptionProc)
End Sub
Public Type EXCEPTION_RECORD
ExceptionCode As Long
ExceptionFlags As Long
pExceptionRecord As Long ' Pointer to an EXCEPTION_RECORD structure
ExceptionAddress As Long
NumberParameters As Long
ExceptionInformation(EXCEPTION_MAXIMUM_PARAMETERS) As Long
End TypePublic Type CONTEXT
FltF0 As Double
FltF1 As Double
FltF2 As Double
FltF3 As Double
FltF4 As Double
FltF5 As Double
FltF6 As Double
FltF7 As Double
FltF8 As Double
FltF9 As Double
FltF10 As Double
FltF11 As Double
FltF12 As Double
FltF13 As Double
FltF14 As Double
FltF15 As Double
FltF16 As Double
FltF17 As Double
FltF18 As Double
FltF19 As Double
FltF20 As Double
FltF21 As Double
FltF22 As Double
FltF23 As Double
FltF24 As Double
FltF25 As Double
FltF26 As Double
FltF27 As Double
FltF28 As Double
FltF29 As Double
FltF30 As Double
FltF31 As Double
IntV0 As Double
IntT0 As Double
IntT1 As Double
IntT2 As Double
IntT3 As Double
IntT4 As Double
IntT5 As Double
IntT6 As Double
IntT7 As Double
IntS0 As Double
IntS1 As Double
IntS2 As Double
IntS3 As Double
IntS4 As Double
IntS5 As Double
IntFp As Double
IntA0 As Double
IntA1 As Double
IntA2 As Double
IntA3 As Double
IntA4 As Double
IntA5 As Double
IntT8 As Double
IntT9 As Double
IntT10 As Double
IntT11 As Double
IntRa As Double
IntT12 As Double
IntAt As Double
IntGp As Double
IntSp As Double
IntZero As Double
Fpcr As Double
SoftFpcr As Double
Fir As Double
Psr As Long
ContextFlags As Long
Fill(4) As Long
End TypePublic Type EXCEPTION_POINTERS
pExceptionRecord As EXCEPTION_RECORD
ContextRecord As CONTEXT
End TypePublic Const EXCEPTION_EXECUTE_HANDLER = 1
Public Const EXCEPTION_CONTINUE_EXECUTION = -1
Public Const EXCEPTION_CONTINUE_SEARCH = 0Public Const EXCEPTION_DEBUG_EVENT = 1Public Const EXCEPTION_ACCESS_VIOLATION = &HC0000005Public Declare Function SetUnhandledExceptionFilter Lib "kernel32" ( _
ByVal lpTopLevelExceptionFilter As Long) As Long'Public Declare Function UnhandledExceptionFilter Lib "kernel32" ( _
ExceptionInfo As EXCEPTION_POINTERS) As Long' 原来的这个声明我把参数改了,上面那个是原型
Public Declare Function UnhandledExceptionFilter Lib "kernel32" ( _
ExceptionInfo As Any) As LongPublic hException As LongPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Public Function MyExceptionProc(ByVal ExceptionInfo As Long) As Long
On Error Resume Next
Static s_SigCount As Long
Dim dwExceptCode As Long
Dim lResult As Long
Dim lpExceptionInfo As EXCEPTION_POINTERS
CopyMemory ByVal lpExceptionInfo, ExceptionInfo, Len(lpExceptionInfo)
dwExceptCode = lpExceptionInfo.pExceptionRecord.ExceptionCode
If dwExceptCode = EXCEPTION_ACCESS_VIOLATION Then
Debug.Print "Access violation caught by MyUnFilter"
s_SigCount = s_SigCount + 1
If s_SigCount < 5 Then
lResult = EXCEPTION_CONTINUE_EXECUTION
Else
lResult = EXCEPTION_EXECUTE_HANDLER
End If
Else
lResult = EXCEPTION_CONTINUE_SEARCH
End If
MyExceptionProc = lResult
End Function' 以下是窗体里的内容 frmMain.frmOption ExplicitPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
Destination As Any, Source As Any, ByVal Length As Long)Dim lpExceptionInfo As EXCEPTION_POINTERSPrivate Sub Command1_Click()
On Error GoTo errFinish
UnhandledExceptionFilter hException
Exit Sub
errFinish:
MsgBox Err.Description
End SubPrivate Sub Command2_Click()
On Error GoTo errFinish
CopyMemory ByVal 1, ByVal 2, 3
Exit Sub
errFinish:
MsgBox Err.Description
End SubPrivate Sub Form_Load()
hException = SetUnhandledExceptionFilter(AddressOf MyExceptionProc)
End Sub
首先,
UnhandledExceptionFilter的参数类型是EXCEPTION_POINTERS,也就是异常的信息结构,而不是函数地址。
SetUnhandledExceptionFilter返回的是前一次用SetUnhandledExceptionFilter设定的异常处理函数的地址。
所以,你在UnhandledExceptionFilter参数里使用SetUnhandledExceptionFilter返回的函数地址肯定是错了。
其次,
EXCEPTION_EXECUTE_HANDLER的意思是,告诉系统从UnhandledExceptionFilter函数返回,然后执行相应的异常处理程序,再然后基本上就是程序结束了。
EXCEPTION_CONTINUE_EXECUTION意思是,同样从UnhandledExceptionFilter函数返回,然后重新从发生异常的地方开始执行。或者可以通过修改作为参数传入的lpEXCEPTION_POINTERS结构的内容来修改重新开始地址。
EXCEPTION_CONTINUE_SEARCH意思是,继续执行UnhandledExceptionFilter,也就是遵照函数SetErrorMode设定的标志(例如,不显示系统默认的应用程序出错提示框等),或者调用应用程序错误提示框。再说说你的异常处理函数,你出错首先是因为你没有捕捉到内存存取异常(&HC00005)这个错误,你之所以没有捕捉到这个错误是因为你的EXCEPTION_POINTERS结构写错了。记得我说过VB自带的Win32 API文件有很多翻译错误的地方,在这里就是一个很典型的例子。
MSDN里EXCEPTION_POINTERS的声明是这样的:
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
也就是说它里面的ExceptionRecord和ContextRecord应该分别是*EXCEPTION_RECORD和*CONTEXT类型,说白了就是两个结构的地址指针,而不是像API文件中写那样是两个结构。
所以,在VB里应该声明为
Public Type EXCEPTION_POINTERS
pExceptionRecord As Long
ContextRecord As Long
End Type
而不是
Public Type EXCEPTION_POINTERS
pExceptionRecord As EXCEPTION_RECORD
ContextRecord As CONTEXT
End Type
,所以我写的那段异常处理里面用copymemory获得pExceptionRecord结构的内容。
错误既然捕捉不到,那自然就执行到lResult = EXCEPTION_CONTINUE_SEARCH这一句了,这句啥意思呢?看看上面就知道了,所以你就觉得自己莫名其妙错了。
还有啥问题吗?