为什么从Evaluate调用VBA Find循环失败?

当使用Application.Evaluate或ActiveSheet.Evaluate方法调用例程时,我遇到了在子例程内部运行查找循环的问题。 例如,在下面的代码中,我定义了一个子例程FindSub(),它在工作表中searchstring“xxx”。 例程CallSub()使用标准的Call语句和Evaluate调用FindSub()例程。

当我运行Call FindSub时,一切都将按预期工作:每个匹配的地址被打印到即时窗口,当代码完成时,我们会得到一个“完成”的最终消息。 但是,当我做Application.Evaluate“FindSub()”时,只有第一个匹配的地址打印出来,我们永远不会达到“完成”消息。 换句话说,在循环尝试评估它是否应该继续时,在Cells.FindNext行之后遇到一个错误,并且程序执行停止,没有打印任何运行时错误。

我期望既调用FindSub和Application.Evaluate“FindSub()”在这种情况下产生相同的结果。 有人可以解释为什么他们不这样做,如果可能的话,解决这个问题的方法? 谢谢。

注意:在这个例子中,我显然不需要使用Evaluate。 这个版本被简化为专注于我在一个更复杂的情况下遇到的特定问题。

Sub CallSub() Call FindSub Application.Evaluate "FindSub()" End Sub Sub FindSub() Dim rngFoundCell As Range Dim rngFirstCell As Range Set rngFoundCell = Cells.Find(What:="xxx", after:=ActiveCell, LookIn:=xlValues, _ LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ MatchCase:=False, SearchFormat:=False) If Not rngFoundCell Is Nothing Then Set rngFirstCell = rngFoundCell Do Debug.Print rngFoundCell.Address Set rngFoundCell = Cells.FindNext(after:=rngFoundCell) Loop Until (rngFoundCell Is Nothing) Or (rngFoundCell.Address = rngFirstCell.Address) End If Debug.Print "Finished up" End Sub 

原因很可能是Evaluate将您的函数视为UDF,就好像它是从工作表公式中调用一样。 UDF对他们可以做的事情有严格的限制 – 特别是没有设置属性或者调用其他函数 – 我想这里有些事情已经违反了这些限制,尽pipe我无法确切地说明这里做了什么。

在UDF内部,错误被无声地吞噬,因为表单公式不允许抛出VB错误。 (如果公式错误不断抛出VB对话框,会中断Excel用户界面)

有关UDF限制的详细信息,请参阅http://support.microsoft.com/kb/170787

编辑:好的,这里有一些关于你的问题的澄清,我知道你的代码在评估期间默默地错误。 使用这个代码:

 Sub FindSub() Dim rngFoundCell As Range Dim rngFirstCell As Range Set rngFoundCell = Cells.Find(What:="xxx", after:=ActiveCell, LookIn:=xlValues, _ LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ MatchCase:=False, SearchFormat:=False) If Not rngFoundCell Is Nothing Then Set rngFirstCell = rngFoundCell Do Debug.Print "FOUND: " & rngFoundCell.Address Set rngFoundCell = Cells.FindNext(after:=rngFoundCell) Debug.Print "FIND NEXT: " & IIf(rngFoundCell Is Nothing, " NOTHING", " SOMETHING") Loop Until (rngFoundCell Is Nothing) Or (rngFoundCell.Address = rngFirstCell.Address) Debug.Print "ESCAPED LOOP" End If Debug.Print "Finished up" End Sub 

我在即时窗口中得到以下输出:

 findsub FOUND: $G$6 FIND NEXT: SOMETHING FOUND: $D$11 FIND NEXT: SOMETHING ESCAPED LOOP Finished up 

太好了。 但:

 callsub FOUND: $G$6 FIND NEXT: SOMETHING FOUND: $D$11 FIND NEXT: SOMETHING ESCAPED LOOP Finished up FOUND: $G$6 FIND NEXT: NOTHING 

这里有三点值得注意的地方,至less在我运行的时候。

  1. 该函数被调用两次。 这是Evaluate的一个已知问题,就是Excel如何在表单上处理计算。 这就是为什么Evaluate不应该用于logging数据的函数 – 因为可以在一个Evaluate中多次调用它。
  2. 在第二个循环上,“查找下一个”无法find另一个单元格。 这是一个谜,但是不应该使用Evaluate来运行围绕表单运行的函数,所以从某种意义上说,这是未定义的行为,不能被认为是一个错误。 评估是为了运行一个公式,其中所有单元格引用在公式中明确地映射出来。 我自己的理论是“查找下一个”不起作用,因为您正在尝试使用不是活动单元格的单元格引用,并且正在尝试closures这种非法活动。
  3. 你的错误。 在Loop Until行,您处理或testing。 麻烦的是,如果rngFoundCellNothing ,第二个testing会抛出一个错误; VBA正在尝试处理完整expression式,并且在这种情况下无法评估rngFoundCell.Address 。 当作为UDF运行时(即在Evaluate内),代码将立即退出而不会出现错误对话框。 这就是为什么你在“评估”中看不到“完成”的原因。

以下应该工作:

 Call FindSub Call Application.Run("FindSub") 

对我来说, .Evaluate失败并没有做任何事情。

如果我使用Call Application.Run("FindSub()") (与parens)我看到相同的行为,你做(“部分”第二次调用)。

你也可以尝试Application.Evaluate "FindSub"