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

使用Environment.Is64BitProcess从c#应用程序动态调用32位或64位DLL,c#,.net-4.0,C#,.net 4.0,我正在从事一个用C#for.NET4.0编写的项目(通过VisualStudio2010)。有一个第三方工具需要使用C/C++DLL,并且在C#中有32位应用程序和64位应用程序的示例 问题是32位演示静态链接到32位DLL,而64位演示静态链接到64位DLL。作为一个.NET应用程序,它可以在客户端PC上作为32位或64位进程运行 .NET 4.0 framework提供Environment.Is64BitProcess属性,如果应用程序作为64位进程运行,该属性将返回true 我想做的是在

我正在从事一个用C#for.NET4.0编写的项目(通过VisualStudio2010)。有一个第三方工具需要使用C/C++DLL,并且在C#中有32位应用程序和64位应用程序的示例

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

.NET 4.0 framework提供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() ...
    }
}


谢谢

讽刺的是,在64位系统上,
kernel32.dll(位于
%windir%\System32\
中)是64位版本,
%windir%\SysWOW64\
版本是32位系统。这里发生了非常不幸的事情

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


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

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

  • 这是一个部署问题,只需让安装程序复制正确的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);

<> P>而不是这么低级别的互操作,我会考虑多走.NET路由-使用插件类程序集来处理它。
  • 创建2个程序集,链接到x86和x64版本的DLL(并针对正确的平台进行编译)
  • 使此程序集公开实现相同接口的类(或使它们相同的其他方法)。确保其余的代码可以使用这两个库中的任何一个,可能需要具有基本类型/接口的第三个程序集
  • 在运行时手动加载所需的程序集。确保它不在搜索路径中,以避免错误地自动加载

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

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

Libs64\ABC.dll
Libs32\ABC.dll

[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);