与来自64位.NET的32位访问进行通信

时间:2019-05-10 18:52:58

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

我有一个.NET(C#)应用程序,必须将其编译为64位。它使用ADO.NET与包括OLEDB的Excel&Access在内的各种数据库一起使用(是的,我知道-Excel不喜欢像被当作数据库那样对待,但是客户确实希望这样做,所以我允许它带有很多警告)< / p>

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

现在,使用COM可以进行32位Excel通信。因此,我已经进行了一些测试,并且可以为使用Excel COM的Excel编写替代接口。

因此,我也尝试了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位边界进行通信?

1 个答案:

答案 0 :(得分: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。 )。

并通过创建Access的WHOLE实例,然后所有启动代码以及该Access应用程序的部分将开始运行。最好是简单地创建数据库引擎的实例,这样您就不会启动Access + VBA + WHOLE应用程序。要使用互操作,此代码将起作用:

    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模型进行“更新”。但是,即时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数据库引擎被视为并被视为外部数据库对象,并且互操作编组不支持.net的数据库引擎。

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