供将来参考:这里有 2 种新的创新产品可帮助您解决确切的问题:
1) https://HiveLink.io: - 使用 HiveLink,您可以创建电子表格的“轻量级”版本,将其提供给您的用户,但它不包含任何敏感的 VBA 或计算公式。您从轻量级电子表格中剔除知识产权,并向您的用户发送下载此电子表格的邀请。当您的用户输入他们的输入数据时,HiveLink 会将数据传送到您的原始电子表格以处理数据,然后自动将结果返回给用户。
这种方法的好处是不可能使用 .NET 反射甚至汇编代码进行逆向工程 - 因为您完全从他们的计算机中删除了代码。这是最安全的选择,如果您的模型适合输入/输出往返设计,那就太好了——如果您需要即时发生的客户端交互式代码,那就不是很好了。如果您确实需要快速的客户端交互代码,通常这不太敏感,您可以使用工作簿保护,甚至可以使用 DoneEx Excel Compiler 之类的东西编译基本代码,并使用 Excel 编译器和 HiveLink 的组合进行保护。
2) http://FCell.io:这允许您将 .NET 代码直接构建到电子表格中。它甚至在电子表格中带有一个代码编辑器窗口,有点像用 .NET 代码编辑器替换现有的 VBA 代码编辑器。代码编辑器中的对象模型比普通的对象模型稍微不全面,但您也可以创建任务窗格并将它们嵌入到工作簿中进行分发,这样您的用户甚至不需要安装任何东西!我不确定您的代码嵌入到工作簿中的安全性如何,但我 100% 确信如果您的代码对他们来说足够重要,人们可以访问您的代码。
关于 Re Mat's Mug 的进一步回复:
Re: 性能成本 - 实际上,您可能会注意到通过在 .NET 中实现的东西可以显着提高性能,尤其是在您利用多线程时,Excel 根本不会使用 UDF 或宏。我已经看到在 .NET 库中重写我的一些客户代码(用于繁重的处理计算)获得了 100 倍的收益。您可能还会发现 .NET 代码比 VBA 更容易维护和改进。我已经将 VBA 代码和功能转换为 .NET 代码进行了大量转换,并且在正确完成时从未遇到过明显的性能问题。
Re:用户值得通过反射 .NET 库获得访问权限?? - 我完全不同意这一点。 非常很容易使用反射访问 .NET 代码,甚至可能比 cracking Excel's weak passwords 更容易。如果您确实有想要保护的敏感计算,那么最好使用HiveLink 之类的东西来完全消除逆向工程的可能性,或者使用混淆来使其更难/非常烦人。对于混淆,我使用 CryptoObfuscator($) 和 Dotfuscator($$$)。如果没有这个,我不会在 .NET 库中为 excel 共享我客户的敏感模型 VBA 代码。我有时也使用 CryptoLicensing 让他们通过为每个用户创建许可证来控制谁可以访问他们的 DLL 功能。
Re:让 VBA 代码负责向/从工作表写入/读取 - 我也强烈反对这一点。我建议在 VBA 中保留尽可能少的代码并对 .NET 进行高级调用,将读/写留给 .NET 插件。在工作表中使用命名范围来识别输入/输出和数据位置,然后将这些命名范围定义为 .NET 库中的常量。在您的库中,您可以非常轻松地读取范围并写入范围。以这种方式维护起来更清洁、更容易。
在为 Excel 构建任何您想从 VBA 调用外部功能的扩展库时 - 您必须使您的库 COM 可见。有几种方法可以做到这一点:我强烈建议避免使用 regsvr32 在 Windows COM 列表中注册您的库 - 不惜一切代价避免它!
注册库的最佳方法是使用ExcelDna 加载它,这允许您在每次启动 Excel 时动态加载 DLL,而不必在注册表中使用 COM 接口永久定义每个类(当你更新版本)。您最终会创建一个 XLL 文件,该文件可以将 DLL 打包在其中 - 您可以告诉 Excel 在每次启动时加载 XLL,方法是在注册表中放置一个键。这样做的好处是不需要您将整个 COM 接口存储在注册表中,因此管理新版本非常容易。
因此,您的 VBA 代码可能类似于:
Sub Button_Click()
Call ThisWorkbook.EnsureLibraryInitialized
Call ThisWorkbook.MyLibrary.ReadRangesAndWriteResults(someInputParam)
End Sub
请注意,VBA 会在运行时查找此方法 ReadRangesAndWriteResults。如果您在 VBA 中公开编译时方法,那么您必须在注册表中注册其 COM 接口签名 - 值得不惜一切代价避免!!!
ThisWorkbook 模块:
Public MyLibrary as Object
public sub Workbook_Open()
EnsureLibraryInitialized
End Sub
public Sub EnsureLibraryInitialized()
Dim addin As COMAddIn
If MyLibrary is Nothing Then
For Each addin In Application.COMAddIns
If InStr(addin.Description, "MyLibrary.COMHelper") Then
If addin.object Is Nothing Then
'complain it can't connect to library, tell user to reinstall it
Else
Set MyLibrary = addin.object
Exit For
End If
Next
End if
End Sub
Re:Excel 互操作和 .NET 库 - 好点 Mat's Mug,当使用普通的 Microsoft.Office.Interop.Excel 时,这可能是一场噩梦。因为您正在从托管 .NET 环境访问本机代码,所以您必须确保正确清理您的 .NET COM 包装器对象,否则即使您关闭 Excel 并且看起来它已经消失了,您也会获得 Excel 的挂起/僵尸进程/已关闭(查看任务管理器,它们可能还在!)
我发现处理此问题的最佳方法是使用 NetOffice,它基本上是 Excel 互操作模型的克隆,但创建它是为了安全地为您管理所有这些问题。最好同时注意 COM 对象的良好安全处理,例如here 和here。
祝你好运!