编辑注:感谢Mathieu Guindon使我意识到TempVars系列!在那和数组的本地表之间,我将能够跳过appdomain的使用。
我正在使用所附的代码将全局变量保留在MS-Access中。但是,在Access关闭后,由于它从未完全离开任务管理器,因此无法正确重新打开。
在VBA中是否可以做一些事情以确保其正常关闭?我将MS Access 2010用作SQL Server 2012后端的前端。
我得出的结论是,仅当我添加了代码以使用DefaultAppDomain存储脚本字典时才出现此问题,并希望可以在域侧执行一些清理代码以允许App完全关闭。
Private Function GetDomainDict() As Object
Const vName = "dict-data"
Static vDict As Object
If vDict Is Nothing Then
Dim vDomain As mscorlib.AppDomain
Dim vHost As New mscoree.CorRuntimeHost
'get the vDomain from .net
vHost.Start
vHost.GetDefaultDomain vDomain
'Get the Disctionary for this app from .net or create it
If IsObject(vDomain.GetData(vName)) Then
Set vDict = vDomain.GetData(vName)
Else
Set vDict = CreateObject("Scripting.Dictionary")
vDomain.SetData vName, vDict
End If
End If
Set GetDomainDict = vDict
End Function
Public Sub StGV(vVarName As String, vVar As Variant)
'Set Global Variable Dictionary to the dictionary saved in .net for this Application
Set pGlobals = GetDomainDict()
'Check if variable exists and set value either way
If pGlobals.Exists(vVarName) Then
pGlobals(vVarName) = vVar
Else
pGlobals.Add vVarName, vVar
End If
End Sub
Public Function GtGv(vVarName As String)
'Set Global Variable Dictionary to the dictionary saved in .net for this Application
Set pGlobals = GetDomainDict()
'Check if variable exists return its value or null if nonexistant
If pGlobals.Exists(vVarName) Then
GtGv = pGlobals(vVarName)
Else
GtGv = Null
End If
End Function
评论之前
我设计了一个taskkill,以确保访问权限关闭。那就是关闭应用程序的原因。我宁愿不依靠它。
评论后...
如果我不使用“ as new”,则变量似乎不会加载,并且出现带有或变量未设置错误的对象,但是我确实添加了set = none。 我实现了.stop,并尝试在退出前端时进行卸载,但出现了自动化错误-2146234347。之后,我通过单击数据库窗口关闭按钮来强制关闭,但是访问仍然无法关闭。 新密码
Dim vDomain As mscorlib.AppDomain
Dim vHost As New mscoree.CorRuntimeHost
'get the vDomain from .net
vHost.Start
vHost.GetDefaultDomain vDomain
'folowing line errors out automation error
vHost.UnloadDomain vDomain
vHost.Stop
Set vDomain = Nothing
Set vHost = Nothing
DoCmd.Quit
End Sub
Private Function GetDomainDict() As Object
Const vName = "dict-data"
Static vDict As Object
If vDict Is Nothing Then
Dim vDomain As mscorlib.AppDomain
Dim vHost As New mscoree.CorRuntimeHost
'get the vDomain from .net
vHost.Start
vHost.GetDefaultDomain vDomain
'Get the Disctionary for this app from .net or create it
If IsObject(vDomain.GetData(vName)) Then
Set vDict = vDomain.GetData(vName)
Else
Set vDict = CreateObject("Scripting.Dictionary")
vDomain.SetData vName, vDict
End If
vHost.Stop
Set vDomain = Nothing
Set vHost = Nothing
End If
Set GetDomainDict = vDict
End Function
Public Sub StGV(vVarName As String, vVar As Variant)
'Set Global Variable Dictionary to the dictionary saved in .net for this Application
Set pGlobals = GetDomainDict()
'Check if variable exists and set value either way
If pGlobals.Exists(vVarName) Then
pGlobals(vVarName) = vVar
Else
pGlobals.Add vVarName, vVar
End If
End Sub
Public Function GtGv(vVarName As String)
'Set Global Variable Dictionary to the dictionary saved in .net for this Application
Set pGlobals = GetDomainDict()
'Check if variable exists return its value or null if nonexistant
If pGlobals.Exists(vVarName) Then
GtGv = pGlobals(vVarName)
Else
GtGv = Null
End If
End Function `
答案 0 :(得分:1)
据我所知,这可能是GetDomainDict
的实现(尽管名称令人困惑):
Public Function GetDomainDict() As Object
Static dict As Object
If dict Is Nothing Then Set dict = CreateObject("Scripting.Dictionary")
Set GetDomainDict = dict
End Function
启动.NET应用程序域是完全不必要的步骤-尤其是考虑到Scripting.Dictionary
是 Microsoft Scripting Runtime COM类型库中定义的数据类型时……首先与.NET有关。
这里不需要涉及任何.NET。即使您想使用System.Collections.IDictionary
,也不需要创建一个AppDomain即可使用它。
说...
Dim vHost As New mscoree.CorRuntimeHost
这将创建一个自动实例化的对象,这意味着如果您这样做:
Set vHost = Nothing
对象引用将设置为Nothing
,应用程序应该正确关闭。除非您再次引用它,否则:
Debug.Print vHost Is Nothing ' will always be False
避免使用As New
,尤其是对于您不拥有的对象,尤其是。
也就是说,ICorRuntimeHost
接口有一个Stop
方法,应该在某个时候调用它,还有一个UnloadDomain
方法应该用于卸载AppDomain对象-假设首先有一个真正的原因产生并Start
。
答案 1 :(得分:1)
仅提供一种替代方法,使其保持纯VBA格式,并避免对.NET的新依赖性,您可以考虑使用Access 2007中引入的TempVars
集合。这将在VBIDE重置后继续有效。请注意,它只能存储原始数据类型(例如字符串,数字,日期,但不能存储对象),并且它在全球范围内可用。
您还可以考虑将本地Access表用作数据存储并对其进行读/写操作,这也将在重置后仍然存在,并且在重启后也可能存在,这取决于是否需要变量,这可能是合乎需要的对于。如果您希望它在重新启动后无法幸免,那么只需清除表就足够了。
我喜欢使用AppDomain提供内存中的数据存储的想法,该存储将无法在重新启动后继续运行,但会在重置后出现,但是确实感觉很费力,特别是如果那是您唯一使用的.NET CLR。我对评论也有些担心:
我使用此命令的原因是,任何未捕获的错误都会导致在Access vba中清除所有全局变量。
那不是正常的婚外情。通常,未捕获的错误将显示VBIDE错误消息,您可以在其中调试或结束。应该注意的是,单击End
按钮将重置状态,就像单击“停止”按钮或执行Stop
语句一样。为了进行开发,使用“调试”按钮并正常退出过程(例如,通过将黄色箭头移至出口)将避免重置状态。根据用户的经验,除非使用ACCDE或在运行时模式下运行Access,否则他们永远不会看到这种“重置”,这意味着没有可用的VBIDE进行调试,因此唯一有意义的事情就是做好一切然后退出。在这种情况下,这意味着错误应该首先被捕获。
如果错误处理是一个足够大的问题,则您可能需要考虑使用诸如vbWatchDog之类的商业第三方加载项,这对改善错误UX有很大帮助,尤其是对于ACCDE或运行时环境。
IOW,我有点担心AppDomain的想法正在解决开发人员专用的问题。