当模块被修改时,您不可能知道。 VBIDE API甚至不告诉你是否模块被修改,所以你必须自己弄清楚。
VBIDE API令人难以忍受 - 正如您已经注意到的那样。
Rubberduck尚未处理特定于主机的组件(例如表,查询等),但其解析器在自上一次解析后判断模块是否被修改方面做了很好的工作。
“自上次检查后修改”实际上是您所需要知道的。你不能靠行虽然统计,因为这个:
Option Explicit
Sub DoSomething
'todo: implement
End Sub
将与此相同:
Option Explicit
Sub DoSomething
DoSomethingElse 42
End Sub
而且很明显,你会希望这种改变被拾起和跟踪。比较每一行代码中的每个字符都可以工作,但速度要快得多。
总体思路是获取CodeModule
的内容,对其进行散列,然后与之前的内容散列进行比较 - 如果有任何修改,我们正在查看“脏”模块。它是C#,我不知道是否有一个COM库可以容易地从VBA中散列字符串,但最糟糕的情况是,您可以在.NET中编译一个小型实用程序DLL,公开一个需要String
并返回的COM可见函数一个散列,不应该太复杂。
下面是Rubberduck.VBEditor.SafeComWrappers.VBA.CodeModule相关的代码,如果它的任何帮助:
private string _previousContentHash;
public string ContentHash()
{
using (var hash = new SHA256Managed())
using (var stream = Content().ToStream())
{
return _previousContentHash = new string(Encoding.Unicode.GetChars(hash.ComputeHash(stream)));
}
}
public string Content()
{
return Target.CountOfLines == 0 ? string.Empty : GetLines(1, CountOfLines);
}
public string GetLines(Selection selection)
{
return GetLines(selection.StartLine, selection.LineCount);
}
public string GetLines(int startLine, int count)
{
return Target.get_Lines(startLine, count);
}
这里Target
是Microsoft.Vbe.Interop.CodeModule
对象 - 如果你在VBA的土地是那么这只是一个CodeModule
,从VBA扩展性库;这样的事情:
Public Function IsModified(ByVal target As CodeModule, ByVal previousHash As String) As Boolean
Dim content As String
If target.CountOfLines = 0 Then
content = vbNullString
Else
content = target.GetLines(1, target.CountOfLines)
End If
Dim hash As String
hash = MyHashingLibrary.MyHashingFunction(content)
IsModified = (hash <> previousHash)
End Function
所以是的,你的“激烈”的解决方案几乎是唯一可靠的方法去实现它。几件事情要记住:
- “保持所有模块的列表”,将工作,但如果你只储存模块名称和模块改名,缓存是陈旧的,你需要一种方法来使它无效。
- 如果你存储每个模块对象的
ObjPtr
而不是他们的名字,我不确定它在VBA中是否可靠,但我可以告诉你,通过COM互操作,COM对象的哈希码不会始终一致在调用之间 - 所以你会有一个陈旧的缓存和一种方法来使它失效,也是如此。尽管如此,可能不是100%VBA解决方案的问题。
我会去Dictionary
存储模块的对象指针作为一个关键,他们的内容哈希作为一个值。
这就是说作为Rubberduck项目的管理员,我宁愿看到你加入我们,帮助我们整合全功能的源代码控制(即特定主机的功能)直接进入VBE =)
将模块导出为文本文件非常简单,那么您可以比较全文。我不会建议只检查行数,因为有人可以在一行中更改代码,并且不会被检测到。几年前,我喜欢'WinDiff.exe',它会显示两个文件的差异(我发现它仍然可以下载)。我建立了一个具有所有对象,控件,属性和值的'数据字典'数据库,然后可以比较旧的和新的来显示更改。此外,如果您使用SourceSafe(或现代版本),可以跟踪更改。 –
无耻的插件,但[Rubberduck加载项](https://github.com/rubberduck-vba/Rubberduck)具有源代码管理功能。 – Comintern
@Comintern当然,但它不处理任何Access特定的组件。 –