VBA错误91:工作表保护场景下Intersect返回Nothing问题求助
VBA 错误91(Intersect返回Nothing)问题修复
问题现象
- 代码绑定在
Worksheet_Change(ByVal Target As Range)事件下执行,运行时同步打开2个用户窗体,全程未使用ActiveSheet类易产生歧义的相对引用语句。 - 触发规律:工作表初始为未保护状态时代码运行完全正常;一旦通过宏代码或手动开启工作表保护,即使后续执行取消保护操作,代码自动运行时就会抛出错误91;逐行按F8调试模式下代码可正常运行,添加
Wait等待语句无法解决问题。 - 报错定位:报错行是
Intersect(targetRow, rgRecName) = foundName,经确认三个关联变量均能正常读取有效值:targetRow为整行范围对象、rgRecName为列范围对象、foundName为字符串类型,但Intersect(targetRow, rgRecName)返回值始终为Nothing。
关联代码片段
主执行逻辑
....... Application.EnableEvents = False PrUpr.UJournal '工作表保护相关逻辑存放在PrUpr模块 Intersect(targetRow, rgRecName) = foundName '!! 报错触发位置 !! ....... PrUpr.PJournal .......
工作表取消保护逻辑(PrUpr模块内)
Sub UJournal() ThisWorkbook.Worksheets("Journal").Unprotect "123" End Sub
工作表加保护逻辑(PrUpr模块内)
Sub PJournal() With ThisWorkbook.Worksheets("Journal") .Protect Password:="123", UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, AllowSorting:=False, AllowFiltering:=True, AllowDeletingRows:=True .EnableSelection = xlNoRestrictions End With End Sub
已排查无效的方案
- 切换
UserInterfaceOnly:=True / False参数 - 确认
Workbook_Open事件中无保护相关逻辑 - 调整全表单元格的锁定/解锁状态
根因说明
这类「逐行调试正常、全速运行报错,加Wait也无效」的Intersect返回Nothing问题,核心原因是传入Intersect的两个Range对象内部父句柄不一致:
工作表执行保护/取消保护操作时,会刷新自身的Range对象实例索引。全速运行时VBA不会等待实例索引刷新完成,之前定义的targetRow、rgRecName还保留着操作前的旧实例句柄,Intersect判定二者不属于同一个工作表实例,直接返回Nothing;逐行调试时每步操作都会触发VBA环境的消息循环,等待工作表实例刷新完成,所以不会触发问题。Wait语句是阻塞式等待,不会触发消息循环处理对象实例刷新,因此无法解决问题。
另外如果定义Range变量时没有显式绑定父工作表,用户窗体切换焦点时产生的隐式活动表变更,也会导致两个Range实际归属不同工作表,触发同样问题。
修复步骤
- 所有Range变量强制显式绑定父工作表:定义
targetRow、rgRecName时,必须显式指定父对象为ThisWorkbook.Worksheets("Journal"),禁止省略父对象隐式调用活动表,从根源避免父表引用不一致。示例:Dim wsJournal As Worksheet Set wsJournal = ThisWorkbook.Worksheets("Journal") ' 定义范围时强制绑定wsJournal Set targetRow = wsJournal.Rows(Target.Row) Set rgRecName = wsJournal.Columns("B") ' 替换为实际的记录名列 - 保护状态切换后重新获取Range引用:不要在加/取消保护操作前定义Range然后跨操作使用,在调用
PrUpr.UJournal完成取消保护后,重新执行一次targetRow、rgRecName的赋值操作,拿到刷新后的新实例句柄再执行Intersect。 - Intersect返回值强制校验:禁止直接对Intersect返回结果赋值,先判断返回值是否为Nothing再操作,避免错误91:
Dim writeRng As Range Set writeRng = Intersect(targetRow, rgRecName) If Not writeRng Is Nothing Then writeRng.Value = foundName End If - 补全UserInterfaceOnly参数初始化:
UserInterfaceOnly:=True参数仅在单次设置保护的会话周期内生效,工作簿关闭重开后会自动重置为False,需要把PrUpr.PJournal的调用放到Workbook_Open事件中,每次打开工作簿自动重新设置保护,避免参数失效带来的异常。
内容的提问来源于stack exchange,提问作者Arno Z
相关产品推荐
相关产品推荐

