EDIT#1 我正在开发一个VB6 EXE应用程序,旨在将一些特殊图形输出到Adobe Illustrator。
下面的示例代码将Adobe Illustrator中的给定图形绘制为虚线折线。
' Proconditions:
' ai_Doc As Illustrator.Document is an open AI document
' Point_Array represented as "array of array (0 to 1)" contains point coordinates
'
Private Sub Draw_AI_Path0(ByRef Point_Array As Variant)
Dim New_Path As Illustrator.PathItem
Set New_Path = ai_Doc.PathItems.Add
New_Path.SetEntirePath Point_Array
New_Path.Stroked = True
New_Path.StrokeDashes = Array(2, 1)
End Sub
但是,这个简单的代码会引发由以下原因引起的各种运行时自动化错误:
New_Path.StrokeDashes
)Point_Array
传递给New_Path.SetEntirePath
)EDIT#2
不幸的是,由于服务器应用程序(AI,在我们的例子中)引发了这样的错误,因此它们的描述通常不充分,不足和误导。错误情况可能取决于AI版本,安装的应用程序,系统资源等。单个问题可能导致不同的错误。将Point_Array
传递给New_Path.SetEntirePath
的示例(Windows XP SP3,Adobe Illustrator CS3):
编辑结束#2
传统的错误处理可用于防止客户端崩溃并显示错误详细信息,如下所示:
Private Sub Draw_AI_Path1(ByRef Point_Array As Variant)
Dim New_Path As Illustrator.PathItem
On Error GoTo PROCESS_ERROR
Set New_Path = ai_Doc.PathItems.Add
New_Path.SetEntirePath Point_Array
New_Path.Stroked = True
New_Path.StrokeDashes = Array(2, 1)
Exit Sub
PROCESS_ERROR:
MsgBox "Failed somewhere in Draw_AI_Path1 (" & Format(Err.Number) & ")" _
& vbCrLf & Err.Description
End Sub
如您所见,可以轻松访问错误编号和错误说明。但是,我还需要知道哪个调用会导致错误。这对于包含许多自动化接口调用的大型复杂过程非常有用。所以,我需要知道:
目标#3可以通过here描述的技术来满足。所以,让我们关注目标#1和2.现在,我可以看到两种方法来检测失败的呼叫:
1)通过对描述进行硬编码来“检测”对自动化接口的每次调用:
Private Sub Draw_AI_Path2(ByRef Point_Array As Variant)
Dim New_Path As Illustrator.PathItem
Dim Proc As String
On Error GoTo PROCESS_ERROR
Proc = "PathItems.Add"
Set New_Path = ai_Doc.PathItems.Add
Proc = "SetEntirePath"
New_Path.SetEntirePath Point_Array
Proc = "Stroked"
New_Path.Stroked = True
Proc = "StrokeDashes"
New_Path.StrokeDashes = Array(2, 1)
Exit Sub
PROCESS_ERROR:
MsgBox "Failed " & Proc & " in Draw_AI_Path2 (" & Format(Err.Number) & ")" _
& vbCrLf & Err.Description
End Sub
弱点:
优点
2)通过设计调用任何自动化接口调用的函数来“检测”所有调用:
Private Function Invoke( _
ByRef Obj As Object, ByVal Proc As String, ByVal CallType As VbCallType, _
ByVal Needs_Object_Return As Boolean, Optional ByRef Arg As Variant) _
As Variant
On Error GoTo PROCESS_ERROR
If (Needs_Object_Return) Then
If (Not IsMissing(Arg)) Then
Set Invoke = CallByName(Obj, Proc, CallType, Arg)
Else
Set Invoke = CallByName(Obj, Proc, CallType)
End If
Else
If (Not IsMissing(Arg)) Then
Invoke = CallByName(Obj, Proc, CallType, Arg)
Else
Invoke = CallByName(Obj, Proc, CallType)
End If
End If
Exit Function
PROCESS_ERROR:
MsgBox "Failed " & Proc & " in Draw_AI_Path3 (" & Format(Err.Number) & ")" _
& vbCrLf & Err.Description
If (Needs_Object_Return) Then
Set Invoke = Nothing
Else
Invoke = Empty
End If
End Function
Private Sub Draw_AI_Path3(ByRef Point_Array As Variant)
Dim Path_Items As Illustrator.PathItems
Dim New_Path As Illustrator.PathItem
Set Path_Items = Invoke(ai_Doc, "PathItems", VbGet, True)
Set New_Path = Invoke(Path_Items, "Add", VbMethod, True)
Call Invoke(New_Path, "SetEntirePath", VbMethod, False, Point_Array)
Call Invoke(New_Path, "Stroked", VbSet, False, True)
Call Invoke(New_Path, "StrokeDashes", VbSet, False, Array(2, 1))
End Sub
弱点:
CallByName
PathItems.Add
优点
还有其他处理自动化错误的方法吗?
针对2的弱点#1是否有解决方法?
可以改进给定的代码吗?
任何想法都表示赞赏!提前谢谢!
塞尔
答案 0 :(得分:2)
想想为什么你可能想知道从哪里产生错误。一个原因是简单的调试目的。另一个更重要的原因是,您希望在发生特定错误时执行特定于处理的错误。
正确的调试解决方案实际上取决于您尝试解决的问题。如果这是一个临时的错误搜索并且您正在以交互方式工作,那么简单的Debug.Print
语句可能就是您所需要的。如果您只有几个例程需要进行粒度错误识别,那么您的解决方案#1就可以了,并且您可以容忍弹出消息框。但是,就像你说的那样,它有点乏味且容易出错,所以把它变成样板或某种标准做法是个不错的主意。
但这里真正的红旗是你的声明,你有大量复杂的程序包含对自动化界面的多次调用,以及需要处理或至少以细粒度方式跟踪错误。解决方案就是它始终如一 - 将大而复杂的程序分解为一组更简单的程序!
例如,您可能有一个例行程序:
Sub SetEntirePath(New_Path As Illustrator.PathItem, ByRef Point_Array As Variant)
On Error Goto EH
New_Path.SetEntirePath Point_Array
Exit Sub
EH:
'whatever you need to deal with "set entire path" errors
End Sub
您基本上将大型过程中的逐行错误处理拉到更小,更集中的例程并调用它们。而且你有能力追踪"你的错误是免费的。 (如果你有某种系统的跟踪系统,比如我在这里描述的系统 - https://stackoverflow.com/a/3792280/58845 - 它恰好适合。)
事实上,根据您的需要,您最终可能会选择全班,以及#34; wrap"您正在使用的库类的方法。当图书馆出于某种原因有一个不方便的界面时,这种事情实际上很常见。
我不做的是你的解决方案#2。这只是为了找出错误发生的地方,基本上扭曲了你的整个程序。我保证"通用目的" Invoke
稍后会导致您遇到问题。你可以通过以下方式获得更好的效果:
Private Sub Draw_AI_Path4(ByRef Point_Array As Variant)
...
path_wrapper.SetEntirePath Point_Array
path_wrapper.Stroked = True
path_wrapper.StrokeDashes = Array(2, 1)
...
End Sub
我可能不会为了调试目的而烦恼包装类。同样,任何包装器(如果使用包装器)的要点是解决库接口的一些问题。但是包装器也使调试更容易。
答案 1 :(得分:1)
可以在VB6调试器中运行它。如果在没有优化的情况下进行编译(如果优化,您将无法识别代码),您还可以从WinDbg或WER获取堆栈跟踪(使用GFlags进行设置)。 HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ AeDebug是存储设置的地方。
您也可以从调试器开始。
windbg或ntsd(ntsd是一个控制台程序,可能已安装)。两者都来自Windows调试工具。
下载并安装适用于Windows的调试工具
http://msdn.microsoft.com/en-us/windows/hardware/hh852363
安装Windows SDK,但只需选择调试工具。
在C:\
中创建名为Symbols的文件夹启动Windbg。文件菜单 - 符号文件路径并输入
srv*C:\symbols*http://msdl.microsoft.com/download/symbols
然后
windbg -o -g -G c:\windows\system32\cmd.exe /k batfile.bat
您可以按F12停止它,kb将显示调用堆栈(g继续程序)。如果出现错误,它也会停止并显示它们。
输入lm列出已加载的模块,输入x *!*列出符号,使用bp symbolname设置断点
da显示在该地址找到的ascii数据
dda显示指针的值
kv 10显示最后10个堆栈帧
lm list modules
x *!*列出所有模块中的所有功能
p步骤
!sysinfo machineid
如果在VB6中编程,则此环境变量link = / pdb:none将符号存储在dll中而不是单独的文件中。确保使用No Optimisations编译程序并勾选Create Symbolic Debug Info框。两者都在项目属性的“编译”选项卡上。
CoClassSyms(microsoft.com/msj/0399/hood/hood0399.aspx)也可以从类型库中创建符号。