【问题标题】:Communicating with 32 bit Access from 64 bit .NET从 64 位 .NET 与 32 位访问进行通信
【发布时间】:2019-05-10 18:52:58
【问题描述】:

我有一个必须编译为 64 位的 .NET (C#) 应用程序。这使用 ADO.NET 来处理各种数据库,包括 Excel 和 OLEDB 访问(是的,我知道 - Excel 不喜欢被视为数据库,但客户真的想这样做,所以我允许它有很多警告)

在我们遇到 32 位 Office 系统之前,一切都很好。 64 位应用程序无法使用 32 位 OLEDB 驱动程序。

现在,32 位 Excel 通信确实可以使用 COM。所以我已经运行了一些测试,我可以为 Excel 编写一个使用 Excel COM 的替代接口。

所以,我也尝试了 Access。此在线的一些描述暗示 DAO 将起作用。然而,深入挖掘这似乎并不正确。 DAO 遇到了同样的 32 位/64 位问题。

使用 Access COM 接口,我可以查询表名列表,但仅此而已。例如。

  Access.Application accessApp = new Access.Application();
  accessApp.Visible = false;
  accessApp.OpenCurrentDatabase("mydb.accdb", false, "");

  Access._CurrentData dt = accessApp.CurrentData;
  foreach ( dynamic tbl in dt.AllTables )
  {
      string name = tbl.Name;
      if (! name.StartsWith("MSys"))
          Console.WriteLine(">" + tbl.Name+"< ");
  }
  accessApp.Quit();

这是我能做的极限吗?我希望能够查询表列及其类型。查询数据行(简单的“获取所有内容”就足够了),并更新行(简单的 UPDATE WHERE 就足够了)。

我不需要支持 JET。

如何在不使用 DAO 或 OLEDB 的情况下使用 Access COM 接口读取数据行并更新它们,这两者都不会跨 32 位/64 位边界进行通信?

【问题讨论】:

标签: .net ms-access com ado.net dao


【解决方案1】:

很遗憾,您不能这样做。

虽然互操作确实有很多技巧,并使用一种“编组”形式来允许进程内 x64 启动 + 自动化 32 位版本的 word,或者在本例中是 Access,但互操作编组系统确实不支持数据库引擎。

所以,下面是“如果”这可行的话,你可以如何编写代码:

    Dim accessApp As New Access.Application
    accessApp.OpenCurrentDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")
    Dim strSQL As String
    accessApp.Visible = True
    Application.DoEvents()

    strSQL = "select * from tblHotels3"
    Dim rst As Access.Dao.Recordset

    Dim strBuf As String = ""
    rst = accessApp.CurrentDb.OpenRecordset(strSQL)
    Do While rst.EOF = False
        strBuf += vbCrLf & rst("ID").Value & "," & rst("HotelName").Value
        rst.MoveNext()
    Loop
    Me.TextBox1.Text = strBuf
    accessApp.Quit()

所以,如果可能的话,上面的代码就是你如何使用互操作。

但是,请记住,您需要完整版的 Access 才能使用“createObject()”或创建 Access 的实例。运行时版本不支持此功能(因此,请记住,虽然您已成功创建 Access 实例,但您无法使用运行时执行此操作。(现在,您显然确实安装了完整版的访问权限)。

通过创建一个完整的访问实例,所有的启动代码和该访问应用程序的一部分都将开始运行。更好的是简单地创建数据库引擎的一个实例,因此您无需启动 Access + VBA + 整个应用程序。要使用互操作,此代码将起作用:

    Dim db As New Access.Dao.DBEngine
    Dim MyDatabase As Access.Dao.Database

    db.OpenDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")
    Dim rst As Access.Dao.Recordset
    Dim strSQL As String = "select * from tblHotels3"
    Dim strBuf As String = ""
    rst = db.Workspaces(0)(0).OpenRecordset(strSQL)
    Do While rst.EOF = False
        strBuf += vbCrLf & rst("ID").Value & "," & rst("HotelName").Value
        rst.MoveNext()
    Loop
    rst.Close()
    db.Workspaces(0)(0).Close() 
    Me.TextBox1.Text = strBuf

然而,再一次,当您尝试使用 .net 本地的数据引擎时,您正在跨进程内 (x64) 进行编组,因此上述再次不起作用。

然而,如果你想修改一个文本文件,你可以让word打开文本文件,执行word命令来修改文档,然后保存。这在理论上应该并且应该在 x32/x64 桥上工作。

事实上,以下 Access 互操作代码应该可以工作,但不能:

    Dim accessApp As New Access.Application
    accessApp.OpenCurrentDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")

    Dim strSQL As String

    strSQL = "update tblHotels3 set City = 'zoo' "

    accessApp.DoCmd.RunSQL(strSQL)
    accessApp.Quit()

请注意,在上面,我们尝试使用 Access 模型进行“更新”。但是,即时访问尝试运行+使用数据库引擎,它失败了。上面的例子应该可以工作,但是如果上面的 .net (vb.net) 代码是作为 x64 运行的,那么会发现:

代码确实创建了一个正确运行的 Access 实例(.net = x64,Access = x32)。

但是,似乎在我们尝试尝试运行 + 使用 Access 数据引擎的那一刻,然后 .net 就会抛出一条错误消息 (所以上面失败了 accessApp.DoCmd.RunSQL(strSQL) - 那是我们尝试使用数据引擎的时候。

因此,虽然 inter-op 可以启动 + 为您提供 Access 的运行副本,但尝试使用数据引擎会失败。

我确实发现您可以告诉 MSAccess 运行一些 VBA 代码。所以这会起作用:

    Dim accessApp As New Access.Application
    accessApp.OpenCurrentDatabase("\\ALBERTKALLAL-PC\test\vbtest\test44.accdb")

    accessApp.Visible = True
    Application.DoEvents()
    MsgBox("access open = ok - show access ok")
    accessApp.Run("MyUpdate")
    accessApp.Quit()

还有,上面的 VBA 代码?

VBA 代码 - 不是 vb.net:

  Public Sub MyUpdate()

     MsgBox "about to update"
     CurrentDb.Execute "update tblHotels3 set city = 'zoozoo'"

     MsgBox "upate ok"


  End Sub

我可以确认上述方法有效:

所以,这里的问题是 Access 数据库引擎被视为外部数据库对象,而 inter-op marshalling 不支持来自 .net 的数据库引擎。

解决此问题的唯一方法是安装 Access 数据引擎的 x64 位版本。您可以单独安装引擎,而不必安装 Access,但据我所知,在 .net 中,除非您拥有 x64 位版本的数据引擎,否则无法执行此操作。

【讨论】:

  • 因此调用 VBA 可能是一种方法。这里的缺点是我必须返回值,并且还要处理仅在运行时确定的字段名称。使事情复杂化。可能很慢!另一种方法是 32 位 COM 服务器,然后使用 COM 通过 32 bti / 64 位线路进行通信。同样,可能会很慢。
  • 安装 64 位数据引擎:是的,到目前为止,我的建议是“安装 64 位 Office”。但这通常是不可能的或太难了。例如,由于加载项和宏兼容性,Microsoft 自己推荐 32 位 Office。并且仅安装驱动程序/引擎意味着必须卸载 Office x32。
  • 我可能会玩弄宏或 COM 服务器的想法,但我认为事情的发展方式是,我将实现 Excel COM 接口并跳过 Access 32 位。我收到的大多数查询都来自想要使用 Excel 的人。编写自己的 Excel 界面的优点是可以平滑一些“将 excel 用作 RDBMS”的粗糙边缘!
  • 嗯,可以让access/vba代码调用.net代码吗?这当然是可能的。但是,您最终会使用进程内 x32 代码 - 您的 .net 项目将需要“任何”,并且如前所述,这将不允许 .net 项目(如果从 Access/VBA 调用)使用和使用 x64 位代码。我不关心 Access 的互操作,因为总是只在 .net 中构建一个 com 对象(类),而且它的代码很少。但是您对 x64 in-process 的要求意味着这不起作用。另一种可能是从 .net 中取出一个 x32 位 .net 进程,并让它与 Access 一起使用。
  • 但是,如果您不需要 Access(应用程序),并且只需要使用数据,那么实际上,您需要在该机器上获得 x64 数据引擎。您可以静默安装 2010 运行时,它应该与所有最新版本的 office 一起工作。
猜你喜欢
  • 2012-06-05
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 2022-01-20
  • 2018-02-06
  • 2014-07-18
  • 2017-02-18
  • 2017-03-15
相关资源
最近更新 更多