【问题标题】:Unable to call 32-bit unmanaged DLL from 64-bit managed code无法从 64 位托管代码调用 32 位非托管 DLL
【发布时间】:2017-04-01 22:28:32
【问题描述】:

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

以下是我尝试过的事情:

  1. 我创建了一个名为 COM1 的 32 位 vb.net 包装类库,并添加了一个调用 32 位非托管 dll 的公开函数的 VB.Net COM 类。 该项目启用了“注册 COM 互操作”。 当我将 32 位 DLL (COM1.dll) 引用到我的 64 位应用程序并执行该应用程序时,我收到以下异常:

    无法加载文件或程序集“COM1.dll”...试图加载格式不正确的程序。

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

    试图加载格式不正确的程序。

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

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

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


我的部分代码:

  1. 我的 COM 类

    <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
    

【问题讨论】:

    标签: vb.net com ipc


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 感谢您的回答。我能够创建一个 COM+ 服务器。我将 32 位 .NET 包装器导入到组件服务中,在“运行进程”窗格中,我可以看到我的服务(作为服务器安装)。但我不确定如何将它引用到我的 64 位应用程序。
    • 你引用它的方式和以前一样。 COM 负责处理差异。
    • 我添加了 32 位 dll 作为参考。但我仍然得到“BadImageFormat 异常”。看来我正试图以某种方式通过我的应用程序直接调用 dll。我需要设置 COM 服务的任何属性吗?
    • 您确定将其设置为服务器应用程序吗? (转到组件服务\计算机\我的电脑\COM+应用程序,右键单击您应用程序的图标;属性,“激活”选项卡,在“激活类型”下,将其设置为“服务器应用程序”而不是“库应用程序”)。这是在单独的 32 位进程中运行库的关键。
    • 感谢您的耐心,欧元。我仍然无法让我的应用程序运行。以下是我执行的步骤顺序: 1. 创建了一个 x86 类库 - COM_1。 2. 添加了一个 COM 类文件 - “ComClass1”。 3. 将我的 32 位非托管 dll 函数声明为公共的。 4. 编译类库项目。 5.在组件服务>我的电脑>COM+应用程序>新建应用程序>创建一个空应用程序>“PartestCOM”命名服务器应用程序>交互式用户控件>角色为“CreateOwner”>完成。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2011-02-28
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 2011-01-31
      • 2010-11-03
      • 2020-08-30
      • 2011-12-22
      相关资源
      最近更新 更多