在Excel VBA中,如何将关键variables保存在“状态丢失”(不写入单元格或文件)?
Excel VBA是一个灵活的开发环境。 这是编译。 但是,有时在开发过程中会出现“国家损失”。 所有variables都被拆除时,“状态损失”就是这样。 事实上,VBA有一个选项“状态丢失前通知”选项进行分类。 在所有情况下都不能编辑和继续编码,这并不奇怪。 然而,有时在生产中运行状态损失,因为打开一些其他的工作簿可能会导致您的应用程序会话的创伤(相信我,它发生!)
我知道可以将数据保存到工作表单元格甚至文件中,但是这对于保留类的实例是不合适的,特别是如果这是整个对象图的锚。
所以在坚持记忆variables的情况下,如何坚持状态过失?
在Excel生命周期中保持数据持久性的一种方法是将它们存储在附加到实例的默认.Net域中:
Sub Usage() Dim dict As Object Set dict = GetPersistentDictionary() End Sub
Public Function GetPersistentDictionary() As Object ' References: ' mscorlib.dll ' Common Language Runtime Execution Engine Const name = "weak-data" Static dict As Object If dict Is Nothing Then Dim host As New mscoree.CorRuntimeHost Dim domain As mscorlib.AppDomain host.Start host.GetDefaultDomain domain If IsObject(domain.GetData(name)) Then Set dict = domain.GetData(name) Else Set dict = CreateObject("Scripting.Dictionary") domain.SetData name, dict End If End If Set GetPersistentDictionary = dict End Function
试图回答我自己的问题
解决scheme是有一个简单的容器,我selectScripting.Dictionary,编译成一个DLL,并使用COM访问VBA。 在过去,人们可以使用VB6。
现在,也可以使用C ++,但是在这里我介绍了一个C#解决scheme(使用COM互操作)。
using System.Runtime.InteropServices; namespace VBAStateLossProofStorageLib { // Code curated by S Meaden from Microsoft documentation // 1. C# Shared Class library // 2. In AssemblyInfo.cs set ComVisible(true) // 3. In Project Properties->Build check 'Register for Interop' // 4. Add Com reference to Microsoft Scripting Runtime public interface IVBAStateLossProofStorage { Scripting.Dictionary getGlobalDictionary(); } [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(IVBAStateLossProofStorage))] public class VBAStateLossProofStorage : IVBAStateLossProofStorage { public Scripting.Dictionary getGlobalDictionary() { return CVBAStateLossProofStorage.m_dictionary; } } // https://msdn.microsoft.com/en-gb/library/79b3xss3.aspx // "a static class remains in memory for the lifetime of the application domain in which your program resides. " [ComVisible(false)] static class CVBAStateLossProofStorage { public static Scripting.Dictionary m_dictionary; static CVBAStateLossProofStorage() { m_dictionary = new Scripting.Dictionary(); } } }
这里有一些客户VBA代码来演示。 需要一个工具 – >引用到在Dll旁边创build的types库(.tlb文件)。
Option Explicit Public gdicLossy As New Scripting.Dictionary Public gdicPermanent As Scripting.Dictionary Sub RunFirst() Set gdicLossy = New Scripting.Dictionary gdicLossy.add "Greeting", "Hello world!" Dim o As VBAStateLossProofStorageLib.VBAStateLossProofStorage Set o = New VBAStateLossProofStorageLib.VBAStateLossProofStorage Set gdicPermanent = o.getGlobalDictionary gdicPermanent.RemoveAll '* clears it down gdicPermanent.add "Greeting", "Bonjour!" End '* THIS PROVOKES A STATE LOSS - ALL VARIABLES ARE TORN DOWN - EVENT HANDLERS DISAPPEAR End Sub Sub RunSecond() Debug.Assert gdicLossy.Count = 0 '* sadly we have lost "Hello world!" forever Dim o As VBAStateLossProofStorageLib.VBAStateLossProofStorage Set o = New VBAStateLossProofStorageLib.VBAStateLossProofStorage Set gdicPermanent = o.getGlobalDictionary Debug.Assert gdicPermanent.Count = 1 '* Happily we have retained "Bonjour!" as it was safe in its compiled Dll Debug.Assert gdicPermanent.Item("Greeting") = "Bonjour!" End Sub