【问题标题】:Ways to access a 32bit DLL from a 64bit exe从 64 位 exe 访问 32 位 DLL 的方法
【发布时间】:2010-05-10 17:20:29
【问题描述】:

我有一个必须在 64 位模式下编译和运行的项目。不幸的是,我需要调用仅在 32 位模式下可用的 DLL,因此我无法将所有内容都包含在 1 Visual Studio 项目中。我正在努力寻找将 32 位 DLL 包装在其自己的 exe/服务中并从我的 64 位应用程序远程(尽管在同一台机器上)调用该 exe/服务的最佳方法。我的操作系统是 Win7 Pro 64 位。

对这个 32 位进程所需的调用是每秒几十次,但数据量很小。这是一个实时图像分析应用程序,因此尽管容量很小,但响应时间很关键。大量发送/接收单个原语。

理想情况下,我会托管一个 WCF 服务来容纳这个 DLL,但在 64 位操作系统中,不能强制该服务以 x86 方式运行! Source。这真的很不幸,因为我对 WCF 服务的函数调用定时在我的机器上只有 4 毫秒。

我已经尝试过命名管道是.net。我发现它们比 WCF 慢 40-50 倍(我无法使用)。

对于解决我的难题的最佳方式还有其他选择或建议吗?

【问题讨论】:

  • 有关从 64 位应用程序访问 32 位 DLL 的更全面的技术列表,请参阅 this answer

标签: c# .net visual-studio-2010


【解决方案1】:

正如您正确指出的那样,无法在同一过程中混合位数。您的 32 位部分需要一个单独的进程。

我认为托管 WCF 服务是正确的方法。您的链接仅谈论 wcfsvchost。我很确定您可以创建自己的 Windows 服务,并在其中托管 32 位的 WCF 服务。

查看此链接:How to host a WCF service in a managed application。您可以在任何托管应用程序(包括 Windows 服务)中托管您的服务,并在您喜欢的位数下运行它。

这是在您的应用程序中自托管 WCF 服务所需的代码量,假设您刚刚创建了一个名为 MyService 的新服务,并且适当的配置已添加到 app.config:

class Program
{
    static void Main(string[] args)
    {
        using(ServiceHost host = new ServiceHost(typeof(MyService), new Uri[0]))
        {
            host.Open();
            Console.ReadKey();    
        }
    }
}

上面的程序也可以运行,如果你将它显式编译为 32 位或 64 位。

【讨论】:

  • 您能详细说明一下吗?我知道我可以创建一个 32 位 Windows 服务,我将如何创建一个 WCF 服务来为我的 32 位 Windows 服务执行 I/O?
  • 谢谢德里斯!我不知道您可以从应用程序手动托管 WCF 服务。这是一个比我认为我最终会使用的解决方案更好的解决方案。 举起拳头
  • 哦,如果您遇到安全问题,这里有一个链接:blogs.msdn.com/amitlale/archive/2007/01/29/…
【解决方案2】:

没有。观点。 64 位进程中的 32 位 dll = 不行。

我所做的是运行一个 32 位包装进程并使用 WCF 与它进行通信——就像你做的那样。我可以强制操作系统运行 32 位。

我有一个核心库 (Tradex.Connectivity.Core),带有独立于平台的 .NET 代码。我有两个包装器(Wrapper32.exe、Wapper64.exe),它们启动并加载独立代码,然后加载类(托管 C++)。像魅力一样工作。

这对我来说几乎是唯一的方法 - 你不能 crss 加载 32 位和 64 位元素。

【讨论】:

  • “我所做的是运行一个 32 位包装进程并使用 WCF 与其通信 - 就像你一样。我可以强制操作系统运行 32 位。”您是如何设法让您的 WCF 服务在 64 位操作系统上以 32 位模式运行的?将平台目标设置为 x86 会引发 BadImageFormatException,我无法研究解决此问题的方法。
  • 我为什么要关心?我的意思是,WCF 无论如何都是基于网络的。一旦这些东西被序列化,就不再有 32 位或 64 位模式了。哦,我自己托管 - 没有 wcfsvdhost,我在我的 exe 中开始自己的托管。只有几行代码。
  • 感谢 TomTom,我不知道您可以在 WCF 模板项目之外自行托管 WCF 元素。既然你问“我为什么在乎?”我必须指出,我实际上无法编译包含 32 位 DLL 的 32 位 WCF 模板项目。只是模板,自托管工作。再次感谢。
【解决方案3】:

我知道这个答案可能有点晚了,但前段时间我遇到了完全相同的问题(将 32 位 dll 加载到 64 位机器上的 AnyCPU 程序集中)。

作为解决方案,我写了LegacyWrapper。它基本上由一个 32 位包装器 exe 组成,加载所需的 dll,通过命名管道与您的应用程序通信。

调用如下所示:

// Define delegate matching api function
private delegate int GetSystemMetrics(int index);

// Create new WrapperClient
// Remember to ensure a call to the Dispose()-Method!
using (var client = new WrapperClient())
{
    // Make calls providing library name, function name, and parameters
    int x = (int)client.Invoke<GetSystemMetrics>("User32.dll", "GetSystemMetrics", new object[] { 0 });
    int y = (int)client.Invoke<GetSystemMetrics>("User32.dll", "GetSystemMetrics", new object[] { 1 });
}

一些细节可以参考这个blog post

编辑: Since Version 2.1, LegacyWrapper also supports loading 64bit DLLs from a 32bit process.

【讨论】:

  • 一个很好的解决方案,但遗憾的是它不适用于 .NET 类库 DLL
  • .NET 类库不能以这种方式工作,因为它们不能通过 P/Invoke 加载。最好的解决方案是始终使用 AnyCPU 配置文件编译类库。
  • 是的,但不幸的是,我有某些古老的专有类库作为无法重新编译为 x64 或 AnyCPU 的参考。
猜你喜欢
  • 2011-04-16
  • 2022-01-20
  • 2016-08-28
  • 2017-02-18
  • 1970-01-01
  • 2014-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多