Excel 2016锁定了在以前版本的Excel中工作的VBA函数

时间:2015-12-25 19:31:14

标签: excel vba excel-vba crash

以下是VBA代码的简化版本:

Option Explicit

Function LooBac(RawRan)

'   This VBA function locks up in Excel 2016.  It worked in previous
'   versions of Excel.

Dim oRawRanObj                  'The Raw Range
Dim iRawRanObjRow As Integer    'Number of Rows
Dim iRawRanObjCol As Integer    'Number of Columns
Dim Tem As Double               'Temp value

Dim i As Integer                'Counter
Dim j As Integer                'Counter

Application.Volatile

If TypeName(RawRan) <> "Range" Then

'       The Raw Range is not a range.

    LooBac = "*** An invalid RawRan range has been provided. ***"
    Exit Function

End If

'   Build an object using the structure of the Raw Range.

Set oRawRanObj = RawRan
iRawRanObjRow = oRawRanObj.Rows.Count
iRawRanObjCol = oRawRanObj.Columns.Count

'   This section seems to be the problem.
'   It appears to be related to the term oRawRanObj.Cells(j).Value

For i = 1 To 200
    For j = 1 To iRawRanObjRow
        Tem = oRawRanObj.Cells(j).Value
    Next j
Next i

LooBac = Tem

End Function

使用以下内容设置电子表格:

  1. 打开一个新的空白Excel 2016文件。
  2. 将计算模式设置为手动。
  3. 转到VBA并将VBA代码添加到VBA模块。
  4. 转到空白电子表格并在单元格A1中放入1。
  5. 将公式= A1 + 1放入单元格A2中。
  6. 将单元格A2复制到A2到A2400
  7. 的所有单元格中
  8. 在单元格B25中,将公式= LooBac(A1:A25)
  9. 将细胞B25复制到B25至B2400
  10. 的所有细胞中
  11. 点击F9(重新计算)按钮。
  12. 我的机器将达到61%并挂起,或者将达到85%然后Excel崩溃。以下是我机器上的规格:

    1. Excel 2016(32位)
    2. 戴尔Inspiron 3847
    3. Windows 10 Pro(64位)
    4. Intel i7 3.6 GHz
    5. 16 GB内存
    6. 我读过其他一些用户认为Excel 2016有内存泄漏的帖子。其他线程认为可能正在发生其他事情。有没有人知道这类问题的解决方案?

      编辑(2015年12月29日)======================================= ======================

      我收到了几封有类似问题的人发来的电子邮件。他们问我是如何解决这个问题的。所以,就是这样。

      在上面的代码(原始方案)中,我替换了行:

      Dim oRawRanObj                  'The Raw Range
      Dim iRawRanObjRow As Integer    'Number of Rows
      Dim iRawRanObjCol As Integer    'Number of Columns
      
      Set oRawRanObj = RawRan
      iRawRanObjRow = Int(oRawRanObj.Rows.Count)
      iRawRanObjCol = Int(oRawRanObj.Columns.Count)
      
      Tem = oRawRanObj.Cells(j).Value
      

      使用以下行:

      Dim RawRanVal As Variant        'This was added to replace the Raw Range Object
      Dim iRawRanValRow As Integer    'This was added to store the number of rows that are in RawRanVal
      
      RawRanVal = RawRan.Cells.Value2
      iRawRanValRow = UBound(RawRanVal, 1)
      
      Tem = RawRanVal(j, 1)
      

      新方案与原始方案的主要区别在于新RawRanVal需要的内存少于原始oRawRanObj。将UDF复制到许多单元格(示例中为2375个单元格)时,新方案浪费的内存量要少得多。因为这不是以前版本的Excel的问题,我的猜测是Excel 2016的垃圾收集方案与以前版本的Excel不同。

      此外,使用原始方案,Excel的图形通常被搞砸了。 Excel的一些百分比单元格将显示为灰色,不显示任何数字/字符。我仍然可以按向下箭头移动到那些单元格(我可以告诉我在哪里,因为公式栏会显示每个单元格的内容),但无论我尝试什么,单元格都不会正常显示。因此,我的猜测是Excel 2016有内部内存泄漏。

      最后一个问题是即使新方案允许我继续使用我的UDF,问题也没有真正解决。使用新方案,如果我只做15次recalc(F9),Excel 2016将始终给我一条错误消息,说我记忆不足。

      最重要的是,当我运行原始方案时,Excel向Microsoft发回了大约一半的消息。我假设他们会把它放在他们的错误修复列表中。

1 个答案:

答案 0 :(得分:0)

您使用了太多variant变量声明。

如果单元格是#ERR,空或非数字,会发生什么?

Option Explicit

Function LooBac(byval RawRan AS RANGE) AS DOUBLE 'declare return value type too

Dim oRawRanObj AS RANGE                 'The Raw Range
Dim iRawRanObjRow As LONG       'Number of Rows
Dim iRawRanObjCol As LONG       'Number of Columns
Dim Tem As Double               'Temp value

Dim i As LONG                'Counter
Dim j As LONG                'Counter

Application.Volatile

If RawRan is nothing  Then 'i deleted this part if not change the condition


    'LooBac = "*** An invalid RawRan range has been provided. ***" 'really? at the end of the function it is a double and here a string !
Exit Function

End If

'   Build an object using the structure of the Raw Range.

Set oRawRanObj = RawRan
iRawRanObjRow = oRawRanObj.Rows.Count
iRawRanObjCol = oRawRanObj.Columns.Count

'   This section seems to be the problem.
'   It appears to be related to the term oRawRanObj.Cells(j).Value
dim h$
For i = 1 To iRawRanObjCol '@=200 (makes no sense else)
    For j = 1 To iRawRanObjRow
       h= oRawRanObj.Cells(j,I).Value '(just j makes no sense)
       IF ISNUMERIC(H) THEN 
          Tem = CDBL(H) 'change value to double
          'obviously some big part of the code is missing here, just looping and doing nothing with 'tem' is useless
           IF some condition is met THEN
              LooBac = Tem 
              EXIT FUNCTION
           END IF
       END IF
    Next j
Next i

'LooBac = Tem

End Function