使用 Environment.Is64BitProcess 从 c# 应用程序动态调用 32 位或 64 位 DLL

本文关键字:位或 DLL 调用 动态 Is64BitProcess Environment 应用程序 使用 | 更新日期: 2023-09-27 18:35:31

我正在为.NET 4.0(通过Visual Studio 2010)编写一个用C#编写的项目。有一个第三方工具需要使用 C/C++ DLL,并且有 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();
}

谢谢!!

使用 Environment.Is64BitProcess 从 c# 应用程序动态调用 32 位或 64 位 DLL

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

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

  • 很少有程序真正需要 64 位代码提供的大量地址空间。 只需将平台目标设置为 x86 即可

  • 使用 [DllImport] 属性的入口点字段。 将其设置为"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);

具有讽刺意味的是,在 64 位系统上,kernel32.dll(驻留在 %windir%'System32' )是 64 位版本,%windir%'SysWOW64'版本是 32 位系统。这里发生了极其不幸的命名...

无论如何,您可以做的是使用我链接它们的路径绑定到两个版本,到两个不同的变量名称(例如,system32 版本为 LoadLibrarysyswow64 版本为 LoadLibrary32)。然后在 32 位系统上,您可以只使用 LoadLibrary ,如果您检测到 64 位系统,LoadLibrary将是 64 位版本,而LoadLibrary32将是 32 位版本。

但是,我质疑这会对您有所帮助,因为我认为您无法动态绑定到不匹配的位(将使其成为这个词!我想会对你的第二个例子有所帮助,你实际上得到了两个不同的库,每种情况一个。

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

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

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

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

Libs64''ABC
.dllLibs32''ABC

.dll