无法从 64 位托管代码调用 32 位非托管 DLL

Unable to call 32-bit unmanaged DLL from 64-bit managed code

我有一个 64 位 VB.Net 应用程序需要使用第 3 方 32 位非托管 DLL。

以下是我尝试过的方法:

  1. 我创建了一个 32 位 vb.net 包装器 class 库,称为 COM1,并添加了一个 VB.Net COM class 来调用 32 -bit 非托管 dll 的公开函数。 该项目启用了 "Register for COM interop"。 当我将 32 位 DLL (COM1.dll) 引用到我的 64 位应用程序并执行该应用程序时,我收到以下异常:

    Could not load file or assembly 'COM1.dll'...An attempt was made to load a program with an incorrect format.

  2. 我创建了一个 64 位 vb.net 包装器 class 库,称为 COM2,并添加了一个 VB.Net COM class 来调用 32位非托管 dll。 该项目启用了 "Register for COM interop"。 当我在我的 64 位应用程序中引用 64 位 DLL (COM2.dll) 并执行该应用程序时,我能够加载 64 位 dll,但是当我调用其中一个公开的函数时收到以下异常在非托管 dll 中(通过 64 位包装器 dll):

    An attempt was made to load a program with an incorrect format.

  3. 我也使用 WCF 应用程序尝试了上述步骤,其中我用 WCF 服务替换了 COM 包装器,但我得到了相同的结果。

我知道我不能直接从我的 64 位应用程序调用 32 位 dll。我想要做的是通过 IPC 机制调用 32 位 dll——在本例中是 COM 或 WCF。显然,我在这里犯了一些错误。

谁能给我一个工作代码或者告诉我在上述步骤中我做错了什么?


我的部分代码:

  1. 我的COMclass

    <ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
    Public Class ComClass1
        Public Declare Sub InitializePort Lib "I2CDrvrs" (ByVal I2cAddr As Byte, ByVal evalBoardUsed As Byte)
    
    #Region "COM GUIDs"
        ' These  GUIDs provide the COM identity for this class 
        ' and its COM interfaces. If you change them, existing 
        ' clients will no longer be able to access the class.
        Public Const ClassId As String = "5da6d3a4-848c-42b1-bc7c-4079ec5457b1"
        Public Const InterfaceId As String = "8de9508b-fda6-496e-bb29-a90dc5282d2c"
        Public Const EventsId As String = "cfec40ff-fec0-4250-9d72-9d63f1e37d21"
    #End Region
    
        ' A creatable COM class must have a Public Sub New() 
        ' with no parameters, otherwise, the class will not be 
        ' registered in the COM registry and cannot be created 
        ' via CreateObject.
        Public Sub New()
            MyBase.New()
        End Sub
    End Class
    
  2. 我的 64 位应用程序

    Public Function foo() As Boolean
        Try
            COM1.ComClass1.InitializePort(2, 2)
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
        Return True
    End Function
    

引入 COM DLL 作为中介(无论是 32 位还是 64 位)并不能解决问题。您仍在尝试将该 32 位库加载到您的 64 位进程中。再多的 COM 技巧也无法解决这个问题。

32 位库必须 运行 来自 32 位进程,并通过[在此处插入您选择的进程间方法[=]与您的 64 位程序通信23=]]。

您当然可以使用 COM 作为中介;这不是一个坏主意。但是 COM 中介必须是进程外服务器(EXE),而不是 DLL。

实现此目的的一种快速方法是将 COM 助手安装为 COM+(组件服务)应用程序。将其编译为“32 位”,而不是 "AnyCPU"。确保它安装为 "Server" 而不是 "Library"。 COM+会为其提供一个32位的主机进程。

我不知道您是否能负担得起 运行 通过进程外主机 运行 进程内的库的开销。这将取决于图书馆的作用。在某些情况下,这可能根本不可能(例如,在进程仿射资源上运行的库)。

如果 DLL 必须 运行 在您的程序中进行,那么您只有两个选择:a) 您的程序必须编译为 32 位。或者,b) 您必须购买 64 位版本的库。

我找到了一个相当简单的方法来解决我的问题。 我使用 Socket Class' 方法和属性实现了客户端-服务器模型。 我启动了一个作为服务器工作的 32 位托管服务代码。服务器调用 32 位非托管 dll 的函数。所以在某种程度上,服务器充当非托管 dll 的包装器。 我使用我的 64 位应用程序作为客户端。 我从客户端向服务器传递一个字符串。 该字符串包含有关要调用的函数及其参数的信息。 我在服务器中解析字符串并在非托管 dll 中调用适当的函数。