将.Net dll嵌入Microsoft Access数据库

3

1) 是否可以将 .net dll 嵌入到 Microsoft Access 数据库中?理想情况下,我希望该 dll 实际上被嵌入到访问数据库中,以便它不会丢失。我需要从我的访问数据库中访问一些 API。

2) 如果可能的话,有哪些限制?我假设访问数据库必须在已安装 .net 的计算机上使用。还有其他问题需要考虑吗?


2
那似乎是一个异常糟糕的解决方案,无论您面临的问题是什么。为什么不直接询问您实际的问题呢? - nvoigt
你可以将一个单词、.exe或.dll存储在Access中。因此,在Access启动时,您可以检查.dll文件的存在性,如果未找到,则从Access中的本地表中提取它们,并将.dll文件放置在应用程序的相同目录中。但是请注意,在提取.net(COM)文件之前,它们无法被Access使用。在大多数情况下,您还必须注册此类COM对象,然后才能使用它们 - 这意味着用户需要足够的权限来注册COM对象,除非可以使用并行的.net方法。 - Albert D. Kallal
1个回答

6
实际上,如果我理解正确,这似乎是两个略微不同于所提问的问题:(1)您能否将二进制文件嵌入JET / ACE数据库中?(2)您能否从MS-Access调用.NET DLL中的方法?
  1. 是的,您可以将二进制文件嵌入JET/ACE数据库。我的首选方法是以二进制形式读取并在Memo字段中编码为Base64。

首先,您需要将二进制文件读入一个字节数组中。这可以使用 Open 或使用 ADODB.Stream 对象来完成。然后,您将字节数组编码为Base64字符串,最后将该字符串写入表格。要导出二进制文件,则执行相反操作。

以下是将字节数组转换为Base 64的函数:

(源代码):

'Requires reference to Microsoft XML v3.0
Private Function EncodeBase64(ByRef arrData() As Byte) As String

    Dim objXML As MSXML2.DOMDocument
    Dim objNode As MSXML2.IXMLDOMElement

    ' help from MSXML
    Set objXML = New MSXML2.DOMDocument

    ' byte array to base64
    Set objNode = objXML.createElement("b64")
    objNode.dataType = "bin.base64"
    objNode.nodeTypedValue = arrData
    EncodeBase64 = objNode.Text

    ' thanks, bye
    Set objNode = Nothing
    Set objXML = Nothing

End Function

Private Function DecodeBase64(ByVal strData As String) As Byte()

    Dim objXML As MSXML2.DOMDocument
    Dim objNode As MSXML2.IXMLDOMElement

    ' help from MSXML
    Set objXML = New MSXML2.DOMDocument
    Set objNode = objXML.createElement("b64")
    objNode.dataType = "bin.base64"
    objNode.Text = strData
    DecodeBase64 = objNode.nodeTypedValue

    ' thanks, bye
    Set objNode = Nothing
    Set objXML = Nothing

End Function

以下是如何使用Base64函数将二进制文件导入和导出到Memo字段中,使用ADODB.Stream对象的示例:

Function ImportBinary()
    'Requires a reference to ActiveX Data Objects 2.8 or higher
    Dim InputStream As ADODB.stream
    Dim FileBytes() As Byte

    Set InputStream = New ADODB.stream
    InputStream.Type = adTypeBinary
    InputStream.Open
    InputStream.LoadFromFile ("A:\Binary\File\To\Import.dll")
    FileBytes = InputStream.Read()

    With CurrentDb().TableDefs("TableWithMemoField").OpenRecordset
        .AddNew
        !MemoField.Value = EncodeBase64(FileBytes)
        .Update
        .Close
    End With

    InputStream.Close
End Function

Function ExportBinary()
    Dim OutputStream As ADODB.stream

    Set OutputStream = New ADODB.stream
    OutputStream.Type = adTypeBinary
    OutputStream.Open

    With CurrentDb().TableDefs("TableWithMemoField").OpenRecordset
        OutputStream.Write DecodeBase64(!MemoField.Value)
        .Close
    End With

    OutputStream.SaveToFile "A:\Binary\File\To\Export.dll"

    OutputStream.Close
End Function

另外,您也可以将文件嵌入到OLE字段中,或者最近版本的Access还有一个“附件”字段。我相信这是可行的。

  1. 是的,可以从.NET DLL调用方法-请参见此处。您所做的基本上是在Access中托管.NET运行时。

局限性在于,您只能托管.NET 2.0或3.5运行时-尽管链接页面说您可以使用4.0。据我所知,在VBA中没有简单的方法来托管.NET 4.0+运行时。如果尝试调用4.0+ DLL,则会出现“程序集比运行时新”的错误。

是的,您还需要在安装了2.0和/或3.5运行时的计算机上使用它。

此外,它不会直接从网络共享加载DLL。这是.NET框架的限制,可以克服(link),但我不确定在Access中托管DLL时是否可以这样做。

为了使用“嵌入式”DLL,在使用之前需要从数据库中导出它;一个好地方是用户的临时文件夹。

编辑:关于第(2)点-我之前写过您不需要将C#类公开为COM,但是在测试后,我意识到这是不正确的。您需要使用[COMVisible(true)]属性(或实现IDispatch接口)声明类,以便VBA正确实例化您的类-否则CreateInstanceFrom将返回Nothing。


访问应该可以很好地使用.net 4.5。如果您只是创建一个vb.net类对象,并选中注册COM互操作,则该类将出现在Windows“标准”引用列表中,从VBA编辑器(工具->引用)中选择。我使用了.net 4.5,这在Access中运行良好。唯一的建议是限制(强制).net应用程序以x86(强制32位)运行/编译。不仅需要导出.dll文件,还需要进行regasm以注册和公开.net作为标准COM对象。您无法使用.net创建标准的Windows .dll文件-只能创建COM对象。 - Albert D. Kallal
@AlbertD.Kallal,我认为你说的是稍微有些不同的事情。使用COM方法,你是绝对正确的——可以使用更高版本的.NET框架。但是——正如你所说,除非实际可以使用SxS reg,否则需要注册。这里链接的答案实际上在Access中_托管_.NET框架,这有点不同——它不需要注册。然而,在我写那篇答案的时候,我有点混淆了我的概念,认为我正在使用SxS。 - transistor1
据我所知,链接的答案只是允许您使用 .NET COM 对象而无需注册它。因此,与允许使用普通的 .NET COM 对象相比,并没有“更多”或“更少”地将应用程序托管在 Access 中。然而,不必注册 .NET 对象肯定是一个“大”的优势。因此,我将研究这个问题,因为通常用户没有权限注册 .com 对象(它们需要注册表更改)。因此,这仍然是您提出的一个“很棒”的观点,如果我能使其正常工作,我将采用它来处理我的使用 .NET 对象的 Access 应用程序。 - Albert D. Kallal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接