6

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

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

4

5 回答 5

5

P/Invoke 使用 LoadLibrary 加载 DLL,如果已经有一个使用给定名称加载的库,LoadLibrary 将返回它。因此,如果您可以为 DLL 的两个版本赋予相同的名称,但将它们放在不同的目录中,您可以在第一次从 scilexer.dll 调用函数之前执行一次类似的操作,而无需复制您的 extern 声明:

    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 + ".");
于 2009-03-17T02:31:56.253 回答
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 在第一次被调用时被延迟加载,这实际上是有效的,尽管每个平台只能加载它的本机版本。有关更详细的说明,请参阅本文。

于 2009-01-31T17:18:00.673 回答
2

我想出的最好的方法如下:

  • 使用两个名为 64 或 32 的 DLL 分发我的应用程序
  • 在主启动代码中包括以下内容:
    
    File.Delete(Application.StartupPath + @"\scilexer.dll");
    {
      // 检查 64 位并复制正确的 scilexer dll
        if (IntPtr.Size == 4)
        {
          File.Copy(Application.StartupPath + @"\scilexer32.dll",
            Application.StartupPath + @"\scilexer.dll");
        }
        别的
        {
          File.Copy(Application.StartupPath + @"\scilexer64.dll",
            Application.StartupPath + @"\scilexer.dll");
        }
    }
于 2008-12-18T11:43:36.910 回答
1

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

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

这是powershell 安装程序所做的。

于 2008-12-18T08:25:25.813 回答
0

非托管 dll 可以与其托管对应项并排安装到 GAC 中。 这篇文章应该解释它是如何工作的。

于 2008-12-18T15:39:15.283 回答