0

I have a .NET (C#) application that has to be compiled 64 bit. This uses ADO.NET to work with various databases including Excel & Access with OLEDB (yes, I know - Excel doesn't like being treated like a database but customers really want to do it, so I allow it with lots of warnings)

All is fine until we come across a system with 32 bit Office. A 64 bit app cannot use the 32 bit OLEDB drivers.

Now, 32 bit Excel communication does work using COM. So I've run some tests, and I can write an alternative interface for Excel that uses Excel COM.

So, I also tried Access. Some descriptions of this online hint that DAO will work. However, digging deeper this does not appear to be true. DAO hits the same 32 bit /64 bit problems.

Using the Access COM interface, I can query a list of table names but that is about it. Eg.

  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();

Is this the limit of what I can do? I would like to be able to query the table columns and their types. Query data rows (simple "fetch everything" would be sufficient), and to update rows (simple UPDATE WHERE would be sufficient).

I don't need to support JET.

How can I read data rows and update them using Access COM interface without using DAO or OLEDB, both of which will not communicate across the 32 bit / 64 bit boundary?

winwaed
  • 7,645
  • 6
  • 36
  • 81
  • It will be very slow, but it is possible to create a proxy application with self-hosted WCF. [Self-Hosted WCF Service for 32 bit dll access](https://stackoverflow.com/q/16508638/9014308), [is it a good practise to self host wcf service in production](https://stackoverflow.com/q/26710909/9014308), [Automation Error when invoking method on WCF mex Moniker with Excel](https://stackoverflow.com/q/25744843/9014308), [Configure your report server to host Excel workbooks using Office Online Server (OOS)](https://learn.microsoft.com/en-us/power-bi/report-server/excel-oos) – kunif May 10 '19 at 23:03
  • Thanks - I'll look into WCF. Another approach in a similar vein, would be to create a 32 bit COM server which talked to Access directly. It would also be slow. – winwaed May 11 '19 at 15:09

1 Answers1

1

Unfortunately, you can’t do this.

While the interop DOES have a bag of tricks, and uses a form of “marshalling” to allow the in-process x64 to launch + automate a 32 bit version of word, or in this case Access, the interop marshalling system does not support the database engine.

So, here is how you could code things “if” this would work:

    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()

So, the above code is how you could use interop if this was possible.

However, keep in mind that you require the full version of Access to use "createObject()" or create a instance of Access. The runtime version does not support this (so, just keep in mind that while you HAVE success in creating a instance of Access, you can't do this with the runtime. (now in your case you obviously do have full edition of access installed).

And by creating a WHOLE instance of access, then all of the startup code, and parts of that Access application will start to run. MUCH better would be to simply create a instance of the database engine, and thus you not launching Access + VBA + the WHOLE application. To use inter-op, this code would work:

    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

Once again, however, the instant you attempt to use the data engine local to .net, then you are marshalling across the in-process (x64), and thus once again the above will not work.

However, if you wanted to modify a text file, you could have word open the text document, execute word commands to modify the doc, and save it. This would and should in theory work over the x32/x64 bridge.

In fact, the following code for Access inter-op SHOULD work, but it does not:

    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()

Note in above, we attempt to use the Access model to do the "update". However, the instant Access attempts to run + use the database engine, it fails. The above example SHOULD work, but if the above .net (vb.net) code is run as x64, then find that:

The code does create a correct running instance of Access (.net = x64, Access = x32).

However, it seems the instant we attempt to try run + use the Access dataengine, then then a error message is tossed up by .net (so above fails on accessApp.DoCmd.RunSQL(strSQL) - that's when we try to use the data engine).

So, while inter-op can launch + get a you a running copy of Access, attempts to use the data engine fail.

I do find that you CAN tell MSAccess to run some VBA code. So this will work:

    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()

And, the VBA code for above?

VBA code - not vb.net:

  Public Sub MyUpdate()

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

     MsgBox "upate ok"


  End Sub

I can confirm that the above DOES work:

So, the problem here is that the Access database engine is deemed and seen as a external database object, and the inter-op marshalling does not support the data base engine from .net.

You only way around this is to install an x64 bit version of the Access data engine. You can install the engine separate and NOT have to install Access, but to my knowledge, from .net, you can't do this unless you have a x64 bit version of the data engine.

Albert D. Kallal
  • 42,205
  • 3
  • 34
  • 51
  • So calling VBA could be a way to do it. The downside here is that I would have to return values, and also handle field names that are only determined at run times. Complicates things. Could be slow! Another approach would be a 32 bit COM server and then use COM to communicate across the 32 bti / 64 bit line. Again, could be slow. – winwaed May 11 '19 at 15:05
  • Installing the 64 bit data engine: Yes my advice so far has been "install 64 bit Office". But that often isn't possible or is too difficult. For example Microsoft themselves recommend 32 bit Office due to add-in & macro compatibility. And to install just the drivers/engine, means Office x32 has to be uninstalled. – winwaed May 11 '19 at 15:06
  • I might play around witht h e macro or COM server ideas, but I think the way things are looking, I'll implement an Excel COM interface and just skip Access 32 bit. Most of the queries I do get are from people who want to use Excel. Writing my own Excel interface has the advantage that I can smooth some of the rough "using excel as a RDBMS" edges! – winwaed May 11 '19 at 15:08
  • Well, can you have the access/vba code call the .net code? That certainly is possible. But, you wind up with in-process x32 code - your .net project will require "any", and that as noted will not allow the .net project (if called from Access/VBA) to use and consume x64 bit code. I don't bother with interop for Access, since always just build a com object (class) in .net, and its very little code. But your requirement of x64 in-process means this will not work. Another possible is to shell out from .net a x32 bit .net process, and have it work with Access. – Albert D. Kallal May 11 '19 at 18:38
  • However, if you not needing Access (the application), and ONLY need use of the data, then really, you need to get a x64 data engine on that machine. You can do a silent install of the 2010 runtime, and that should work side by side with all recent versions of office. – Albert D. Kallal May 11 '19 at 18:39
  • No I don't need the application just the data. But to install the 64 bit runtime, I'm fairly you have to uninstall the 32 bit version first. (having VBA calling my .NET code isn't possible. I actually have two programs - one runs as an add-in in a 3rd party 64 bit app; the other is my own 64 bit app) – winwaed May 11 '19 at 20:21
  • You can't mix/match the bit size of office. However, you can say install 2010 runtime x64 if user has 2013, or 2016. So as long as you install a version that is NOT the same as current office, the runtime will work. However, you well note that you don't need access but really just the data engine (a LOT more light weight approach anyway). In this case, I believe you can force and get the x64 bit version of the data engine (ACE) to install. I would start a new question - since if possible, the data engine only is far less of a huge install compared to Access which you don't need. – Albert D. Kallal May 11 '19 at 22:07
  • Hmm, could be difficult to impose unless the requirements were something like "Office 2013 and later". could be an option although I tend to be conservative with keeping support for old versions (dropping support for JET is fine, but it would be nice to keep 2010 for at least a bit longer) – winwaed May 12 '19 at 15:22
  • You can't install two versions of the same office,but you CAN install two versions of ACE. We quite much determined that you not really needing Access, but only the ACE data engine. Side by side installs of the data engine are permitted - you just have to do a "passive" install. this is outlined here: https://datasavvy.me/2017/07/20/installing-the-microsoft-ace-oledb-12-0-provider-for-both-64-bit-and-32-bit-processing/ – Albert D. Kallal May 12 '19 at 23:16