2008-12-18 82 views
6

我有一个非托管DLL(Scintilla代码编辑器的scilexer.dll,由CodePlex使用,由Scintilla.Net使用)通过Scintilla.Net组件从托管应用程序加载。在32位和64位环境下,Windows托管应用程序运行没有问题,但我需要创建使用64或32 scilexer.dll的不同安装。32位或64位DLL从.net托管代码加载

有没有办法将32位和64位格式的这两个DLL分发,以便.Net框架的DLL加载程序根据某些.config选项或某些“路径名称加载32或64位格式的非托管DLL魔术“的东西?

+0

我会说,大部分时间不打扰 - 除非你希望你的应用程序使用接近2GB的RAM只是让你的项目目标仅适用于x86,它只会在32位版本的scilexer.dll中运行。 – 2009-11-15 11:07:09

回答

5

P/Invoke使用LoadLibrary加载DLL,如果已经有一个加载了给定名称的库,LoadLibrary将返回它。所以,如果你可以给这两个版本的DLL使用相同的名字,但是把它们放在不同的目录中,你可以在第一次从scilexer调用函数之前做一次这样的事情。DLL,而无需复制你的外部声明:

string platform = IntPtr.Size == 4 ? "x86" : "x64"; 
    string dll = installDir + @"\lib-" + platform + @"\scilexer.dll"; 
    if (LoadLibrary(dll) == IntPtr.Zero) 
     throw new IOException("Unable to load " + dll + "."); 
1

你可以把dll放在system32中。 syswow64中的32位和真正的system32中的64位。对于32位应用程序,当访问system32时,它们被重定向到Syswow64。

您可以在注册表中创建一个条目。软件密钥有一个名为Wow6432Node的子项,32位应用程序将其视为软件密钥。

这是什么powershell installer does

2

我想出的最好的是以下几点:

  • 分发我的应用程序名为64或32
  • 在主启动代码的两个DLL包括以下内容:
  
    File.Delete(Application.StartupPath + @"\scilexer.dll"); 
    { 
     // Check for 64 bit and copy the proper scilexer dll 
     if (IntPtr.Size == 4) 
     { 
      File.Copy(Application.StartupPath + @"\scilexer32.dll", 
      Application.StartupPath + @"\scilexer.dll"); 
     } 
     else 
     { 
      File.Copy(Application.StartupPath + @"\scilexer64.dll", 
      Application.StartupPath + @"\scilexer.dll"); 
     } 
    } 
0

非托管dll可以与其管理的对应方一起安装到GAC中。 This article应该解释它是如何工作的。

4

不幸的是,我不知道任何关于这个特定的DLL。但是,当您自己进行P/Invoke时,您可以应付一点重复,可以为每个平台创建一个代理。

例如,假设您有以下界面,应该由这两个一个32位或64位DLL中实现:

public interface ICodec { 
    int Decode(IntPtr input, IntPtr output, long inputLength); 
} 

您创建代理:

public class CodecX86 : ICodec { 
    private const string dllFileName = @"Codec.x86.dll"; 

    [DllImport(dllFileName)] 
    static extern int decode(IntPtr input, IntPtr output, long inputLength); 

    public int Decode(IntPtr input, IntPtr output, long inputLength) { 
     return decode(input, output, inputLength); 
    } 
} 

public class CodecX64 : ICodec { 
    private const string dllFileName = @"Codec.x64.dll"; 

    [DllImport(dllFileName)] 
    static extern int decode(IntPtr input, IntPtr output, long inputLength); 

    public int Decode(IntPtr input, IntPtr output, long inputLength) { 
     return decode(input, output, inputLength); 
    } 
} 

最后让一个工厂为你挑选合适的工厂:

public class CodecFactory { 
    ICodec instance = null; 

    public ICodec GetCodec() { 
     if (instance == null) { 
      if (IntPtr.Size == 4) { 
       instance = new CodecX86(); 
      } else if (IntPtr.Size == 8) { 
       instance = new CodecX64(); 
      } else { 
       throw new NotSupportedException("Unknown platform"); 
      } 
     } 
     return instance; 
    } 
} 

由于第一次调用DLL时懒惰地加载了DLL,尽管每个平台都只能加载原生版本,但实际上它仍然有效。有关更详细的解释,请参阅this article

+1

小心!我已经对我的应用程序做了完全相同的事情,而且我仍然不时地在32位系统上遇到问题。由于无法控制JIT的工作方式,因此无法确定应用程序不会尝试在32位系统上加载64位DLL,反之亦然。 – 2009-03-17 03:31:12

+0

我一直在生产中使用这个为期一年半,迄今为止它对我来说效果很好。 – SteinNorheim 2010-10-08 19:10:27