Vba 从另一个workwook或加载项卸载Userform

Vba 从另一个workwook或加载项卸载Userform,vba,excel,Vba,Excel,我正在尝试运行一些通用代码来从外接程序卸载UserForm。下面的代码存储在已添加的中。如何检查用户的特定工作簿 我一直在玩VBProject.VBComponents,但毫无乐趣 Function CheckUnloadForm(ByVal UserFormName As String) As Boolean Dim objUserForm As Object CheckUnloadForm = False For Each objUserForm In VBA.UserForms I

我正在尝试运行一些通用代码来从外接程序卸载UserForm。下面的代码存储在已添加的中。如何检查用户的特定工作簿

我一直在玩
VBProject.VBComponents
,但毫无乐趣

Function CheckUnloadForm(ByVal UserFormName As String) As Boolean
Dim objUserForm As Object

CheckUnloadForm = False

For Each objUserForm In VBA.UserForms
  If objUserForm.Name = UserFormName Then
    CheckUnloadForm = True
    Exit For
  End If
Next objUserForm

End Function

这可以使用您暗示的Visual Basic扩展性库来完成。在
Test
过程中,我们循环打开的
工作簿
集合,对于每个工作簿,我们循环
VBComponents
。如果有一个组件与
formName
参数匹配,那么我们将向工作簿中注入一些代码,该工作簿将
卸载
。隐藏该表单,最后我们删除注入的代码模块

NB只有在窗体显示为
vbModeless
时才能执行此操作

在外接程序中,使用以下代码创建标准模块:

Option Explicit
Public compName As String
Public procName As String

Sub Test()
Dim wb As Workbook
Dim formName As String
Dim f As Object
formName = "UserForm1"
Dim VBC As Object ' UserForm VBComponent

For Each wb In Workbooks
    For Each VBC In wb.VBProject.VBComponents
        '## If any component matches this name: 
        If VBC.Name = formName Then
            '## Inject some code into wb that will hide/unload the form
            AddCodeToHideUserForm wb, formName
            DoEvents
            '## Call on the Sub that we just injected
            Run procName
            '## Finally, remove the module that we injected into wb.
            RemoveInjectedCode wb, formName
        End If
    Next
Next

End Sub
Sub RemoveInjectedCode(wb As Workbook, formName As String)
Dim cm As VBComponent
On Error Resume Next
Set cm = wb.VBProject.VBComponents(compName)
wb.VBProject.VBComponents.Remove cm

End Sub
Sub AddCodeToHideUserForm(wb As Workbook, formName As String, Optional hideInsteadOfUnload As Boolean = False)
Dim code As String
Dim cm As VBComponent
code = "Public Sub hide" & formName & "()" & vbNewLine
code = code & " On Error Resume Next" & vbNewLine
If hideInsteadOfUnload Then
    code = code & formName & ".Hide" & vbNewLine
Else
    code = code & " Unload " & formName & vbNewLine
End If
code = code & "End Sub"
Set cm = wb.VBProject.VBComponents.Add(vbext_ct_StdModule)
DoEvents
cm.CodeModule.AddFromString (code)
cm.Name = "Hide" & formName
DoEvents
compName = cm.Name
procName = "'" & wb.Name & "'!" & compName & ".hide" & formName

End Sub

这里的用例是什么?换句话说,为什么不从表单所在的某个模块/类中卸载
呢?您没有提供足够的信息。您需要向我们展示加载UserForm的代码。另外:用户表单是模态的还是非模态的?如果是模态的,那么当Excel应用程序被阻止时,您如何期望任何其他代码能够执行?为什么您首先需要
卸载
表单?请参阅,以从代码中删除有害的默认实例全局状态管理。对问题的更新:“加载项”用作VBA代码和其他一些东西(包括一些用户表单)的通用错误代码处理程序。因此,在“外接程序”中处理Userform卸载似乎更容易。我不理解“Load”命令的问题,代码是在每个工作簿中执行的,具体取决于Userform所在的位置。最后,用户表单是模态的。我认为可能有任何简单的方法可以卸载用户表单而不必加载编码,但似乎没有。谢谢你的评论,我可能会坚持在每个工作簿中添加卸载代码。如果表单是模态的,那么在任何情况下都不可能这样做,因为当表单以这种方式显示时,线程正在等待用户输入,并且由于Visual Basic不是多线程的,因此当表单处于模态时,无法拦截正在运行的线程显示