EDIT#1我正在开发一个VB6 EXE应用程序,目的是向输出一些特殊的图形。
下面的示例代码将中的给定图形绘制为虚线。
' 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 SP3,Adobe CS3)的示例:
EDIT#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总是提出自动化错误440PathItems.Add这样的表达式强项
还有处理自动化错误的其他方法吗?
,对于2)的弱点#1有解决办法吗?
给出的代码可以改进吗?
任何想法都是值得赞赏的!提前感谢!
塞尔日
发布于 2014-12-13 01:00:17
想一想为什么您可能想知道错误是从哪里引发的。原因之一是为了简单的调试目的。另一个更重要的原因是,当错误发生时,您希望做一些特定的事情来处理特定的错误。
正确的调试解决方案实际上取决于您要解决的问题。如果这是一个临时的bug搜索,并且您正在交互地工作,那么简单的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 --它非常适合。)
事实上,取决于您的需要,您可能最终会得到一个完整的类,只是为了“包装”您正在使用的库类的方法。当库由于任何原因有一个不方便的接口时,这类事情实际上是相当常见的。
我不会做的是你的解决方案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我可能不会为了调试的目的而费心使用包装类。同样,任何包装器(如果您使用的话)的目的都是解决库接口的一些问题。但是包装器也使调试更容易。
发布于 2014-12-11 18:19:27
可以在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,但只需选择调试工具。
在C:\中创建一个名为符号的文件夹
启动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符号名设置断点
da显示在该地址找到的ascii数据。 dda显示指针的值 kv 10显示最后10个堆栈帧 lm列表模块 *列出所有模块中的所有函数 P阶 !系统信息机
如果用VB6编程,那么这个环境变量link=/pdb:none将符号存储在dll中,而不是单独保存文件。确保编译程序时没有优化,并勾选创建符号调试信息的框。都在项目的属性的编译选项卡上。
此外,CoClassSyms (microsoft.com/msj/0399/msj/hood0399.aspx)可以从类型库中生成符号。
https://stackoverflow.com/questions/27429431
复制相似问题