从64位exe访问32位DLL的方法

16

我有一个项目必须以64位模式编译和运行。不幸的是,我需要调用一个只能在32位模式下使用的DLL,因此无法将所有内容放在一个Visual Studio项目中。我正在寻找将32位DLL包装在自己的exe / service中并从我的64位应用程序发出远程(尽管在同一台计算机上)调用的最佳方法。我的操作系统是Win7 Pro 64位。

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

理想情况下,我会托管一个WCF服务来容纳这个DLL,但在64位操作系统中,无法强制该服务运行为x86!来源。这真的很不幸,因为我在我的机器上计时了WCF服务的函数调用仅需4ms。

我已经在.NET中尝试过命名管道。我发现它们比WCF慢40-50倍(对我来说无法使用)。

还有其他选项或建议,以最佳方式解决我的难题吗?


请参考此答案,获取更全面的访问32位DLL文件的技术列表,以供64位应用程序使用。 - cdiggins
3个回答

9
正如您所指出的,没有办法在同一进程中混合使用不同位数。您需要为32位部分创建一个单独的进程。
我认为托管WCF服务是正确的选择。您提供的链接只谈到了wcfsvchost。我非常确定您可以创建自己的Windows服务,并在32位上托管WCF服务。
请参阅此链接:如何在托管应用程序中托管WCF服务。您可以在任何托管应用程序中托管您的服务,包括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服务的输入/输出? - bufferz
谢谢driis!我不知道你可以从应用程序手动托管WCF服务。这比我原本想要使用的解决方案好多了。举拳庆祝 - bufferz
哦,如果你遇到安全问题,这里有一个链接:http://blogs.msdn.com/amitlale/archive/2007/01/29/addressaccessdeniedexception-cause-and-solution.aspx - driis

4

没有办法。32位dll在64位进程中无法运行。

我的做法是运行一个32位包装器进程,并使用WCF进行通信-就像你一样。我可以强制操作系统运行32位。

我有一个核心库(Tradex.Connectivity.Core),其中包含平台无关的.NET代码。我有两个包装器(Wrapper32.exe,Wapper64.exe),它们启动并加载独立的代码,然后加载类(managed C++)。效果很好。

那基本上是我唯一的选择-你不能混合加载32位和64位元素。


我所做的是运行一个32位包装器进程,并使用WCF进行通信 - 就像您所做的那样。我可以强制操作系统运行32位。你是如何让你的WCF服务在64位操作系统上以32位模式运行的?将平台目标设置为x86会引发BadImageFormatException异常,我还没有找到解决方法。 - bufferz
为什么我要在意呢?我的意思是,WCF本来就是基于网络的。一旦东西被序列化,就不再有32位或64位模式了。噢,还有,我是自托管的-没有wcfsvdhost,我在我的exe中启动自己的托管。只需要几行代码。 - TomTom
谢谢TomTom,我不知道您可以在WCF模板项目之外自行托管WCF元素。既然您问了“为什么我会在意?”,我必须指出,我简直无法编译32位WCF模板项目,该项目包装了32位DLL。只有模板不能编译,自主托管正常工作。再次感谢。 - bufferz

3

我知道这个答案可能有点晚了,但是一段时间以前我也遇到了完全相同的问题(在64位机器上将32位dll加载到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 });
}

关于详情,您可以参考这篇博客文章

编辑:自版本2.1起,LegacyWrapper还支持从32位进程加载64位DLL。


一个相当不错的解决方案,但遗憾的是它不能用于.NET类库DLL。 - Burhan
.NET类库不会以这种方式工作,因为它们无法通过P/Invoke加载。最好的解决方案是始终使用AnyCPU配置文件编译类库。 - Franz Wimmer
是的,但不幸的是我有一些古老的专有类库作为参考,它们无法重新编译为x64或AnyCPU。 - Burhan

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