【问题标题】:Dynamically calling 32-bit or 64-bit DLL from c# application using Environment.Is64BitProcess使用 Environment.Is64BitProcess 从 c# 应用程序动态调用 32 位或 64 位 DLL
【发布时间】:2017-09-11 23:27:51
【问题描述】:

我正在开发一个用 C# 为 .NET 4.0 编写的项目(通过 Visual Studio 2010)。有一个需要使用 C/C++ DLL 的第 3 方工具,并且有 C# 中 32 位应用程序和 64 位应用程序的示例。

问题在于 32 位演示静态链接到 32 位 DLL,而 64 位演示静态链接到 64 位 DLL。作为一个 .NET 应用程序,它可以在客户端 PC 上作为 32 位或 64 位进程运行。

.NET 4.0 框架提供 Environment.Is64BitProcess 属性,如果应用程序作为 64 位进程运行,则返回 true。

我想做的是在检查 Is64BitProcess 属性后动态加载正确的 DLL。但是,当我研究动态加载库时,我总是会想到以下内容:

[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);

[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);

这些方法似乎专门针对 32 位操作系统。是否有 64 位等效项?

只要基于 Is64BitProcess 检查调用适当的方法,静态链接 32 位和 64 位库是否会导致问题?

public class key32
{
    [DllImport("KEYDLL32.DLL", CharSet = CharSet.Auto)]
    private static extern uint KFUNC(int arg1, int arg2, int arg3, int arg4);

    public static bool IsValid()
    {
       ... calls KFUNC() ...
    }
}

public class key64
{
    [DllImport("KEYDLL64.DLL", CharSet = CharSet.Auto)]
    private static extern uint KFUNC(int arg1, int arg2, int arg3, int arg4);

    public static bool IsValid()
    {
       ... calls KFUNC() ...
    }
}

...

if (Environment.Is64BitProcess)
{
    Key64.IsValid();
}
else
{
    Key32.IsValid();
}

谢谢!!

【问题讨论】:

    标签: c# .net-4.0


    【解决方案1】:

    有很多方法可以做到这一点:

    • 这是一个部署问题,只需获取安装程序复制的正确DLL,给它们起相同的名称

    • 实际上很少有程序需要 64 位代码提供的海量地址空间。只需将平台目标设置为 x86

    • 使用 [DllImport] 属性的 EntryPoint 字段。将其设置为“KFUNC”。并给方法不同的名称。现在您可以根据 IntPtr.Size 的值调用其中一个或另一个

    演示最后的解决方案:

    [DllImport("KEYDLL32.DLL", EntryPoint = "KFUNC")]
    private static extern uint KFUNC32(int arg1, int arg2, int arg3, int arg4);
    
    [DllImport("KEYDLL64.DLL", EntryPoint = "KFUNC")]
    private static extern uint KFUNC64(int arg1, int arg2, int arg3, int arg4);
    
    ...
    
    if (IntPtr.Size == 8) KFUNC64(1, 2, 3, 4);
    else                  KFUNC32(1, 2, 3, 4);
    

    【讨论】:

      【解决方案2】:

      讽刺的是,在 64 位系统上,kernel32.dll(驻留在%windir%\System32\)是 64 位版本,%windir%\SysWOW64\ 版本是 32 位系统。非常不幸的命名在这里发生......

      无论如何,你可以做的是绑定到 both 版本,使用我链接它们的路径,绑定到两个不同的变量名(例如,LoadLibrary 用于 system32 版本和 @987654326 @ 为syswow64 版本)。那么在 32 位系统上你可以只使用LoadLibrary,如果你检测到 64 位系统,LoadLibrary 将是 64 位版本,而LoadLibrary32 将是 32 位版本。

      但是我怀疑这会对您有所帮助,因为我认为您不能动态绑定到不匹配的位数(要使这个 字!)动态库...会帮助您的第二个示例我猜,你实际上确实得到了两个不同的库,每个案例一个。

      【讨论】:

        【解决方案3】:

        我会考虑采用更多的 .Net 路由,而不是这样做低级互操作 - 使用类似插件的程序集来处理它。

        • 创建 2 个程序集,它们链接到 DLL 的 x86 和 x64 版本(并针对正确的平台进行编译)。
        • 使这些程序集公开实现相同接口的类(或使它们相同的其他方式)。确保其余代码可以使用任何一个库,可能需要使用基本类型/接口的第三个程序集。
        • 在运行时手动加载您需要的程序集。确保它不会在搜索路径中,以避免错误地自动加载。

        请注意,您的第二种方法(基于位数选择方法)应该可以正常工作。我仍然会将对每个 DLL 的所有访问封装在具有相同接口的类中,并确保在运行时只能实例化正确的一个。

        【讨论】:

          【解决方案4】:

          将 dll 保存在两个不同的目录中并动态调用它们。

          Libs64\ABC.dll
          Libs32\ABC.dll

          【讨论】:

            猜你喜欢
            • 2019-03-07
            • 1970-01-01
            • 1970-01-01
            • 2013-04-11
            • 1970-01-01
            • 1970-01-01
            • 2017-09-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多