我的任务是将旧版 VB6 应用程序(使用 MS Access 作为数据库,不要问)增量移植到 .NET。
这将是一篇很长的文章,但我认为最好提供一些背景信息。
此应用程序有一个带菜单的主 MDI 窗体,该菜单是根据应用程序文件夹中找到的 DLL 动态创建的。它本质上是一种插件类型的东西:每个 DLL 都由一个菜单项表示,单击该菜单项时,将打开 DLL 中包含的主窗体,根据需要调用
SetParent()
。
MDI 表单是我的起点。我想重写足够的内容(当然,重新设计和单元测试)以便能够打开所述表单。一旦我解决了这个问题,我就会开始一次重写一个 DLL。
每个 DLL 都需要一个 ADO 连接,我已经能够从 C# 传递该连接。
问题是,这些插件之一(至少,但可能还有许多其他插件)使用 ADOX 在数据库上执行操作,这就是问题所在:当我尝试将 ADOX.Catalog 的 ActiveConnection 属性设置为 ADO 连接时,我得到的只是运行时错误 3001:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
我一生都无法弄清楚我做错了什么。
VB6 代码非常简单:
Dim c As New ADOX.Catalog
Set c.ActiveConnection = theAdoConnectionComingFromDotNet ' error!
创建 ADO 连接的 C# 代码与 VB 代码一样简单:
var conn = new ADODB.Connection();
conn.Open("Provider=Microsoft.JET.Oledb;[...]");
并且对
Open()
的调用成功。
如果我尝试在 C# 端设置 ActiveConnection
,如下所示:
var catalog = new ADOX.Catalog();
catalog.ActiveConnection = conn;
一切正常。
现在,我可以通过简单地在 C# 端实例化 ADOX 并将其传递给 VB6 来解决该问题,但是调整 VB6 代码(当然没有单个单元测试)可能会被证明是 PITA,而且我甚至不确定这是否容易做到(因为应用程序可以同时使用多个 Access DB,根据需要打开和关闭与每个数据库的连接)。
那么,有人知道我做错了什么吗?在 C# 中,我尝试从 .NET 选项卡和 COM 选项卡引用 ADODB(我从 COM 选项卡中选择的 ADO 版本是正确的:2.5...再次,不要问),但仍然没有喜悦。
编辑
当我尝试将 RecordSet 的 ActiveConnection 属性分配给来自 C# 的连接时,会发生完全相同的事情,如下所示:
Dim rs As New ADODB.Recordset
Set rs.ActiveConnection = theAdoConnectionComingFromDotNet
我能想到的另一个解决方法是,由于 ActiveConnection 是一个变体,因此将其设置为连接的 ConnectionString 属性。这可行,但它每次都会创建并打开一个新连接,坦率地说,我不喜欢它。
这似乎是错误的方式,但这与我遇到的问题非常相似——ADO 在 Win7 机器上重新编译然后在 XP 机器上使用的 COM 对象中停止工作——我认为这可能是相同的事物。也就是说,灾难性的 Windows 更新破坏了 COM 对象中的 MDAC ADO(线程很长,预计加载速度很慢)。如果是这样,可以在这里找到官方修复程序。
如果不是这样并且您找不到解决方案,我认为您最好的做法是仅使用您在编辑中提到的连接字符串解决方法。这并不理想,但你说无论如何你都会开始重写 DLL,所以这只是一个临时安排。
Public Function DbConnection(dbPath As String, dbName As String) As ADODB.Connection
Dim cnn As New ADODB.Connection
cnn.Open("Provider='Microsoft.ACE.OLEDB.12.0';Data Source= '" & dbPath & dbName & ".mdb';")
Return cnn
End Function
然后像这样使用
Dim ADOXcatalog As New ADOX.Catalog
ADOXcatalog.ActiveConnection = DbConnection(dbPath, dbName)