在C#中以编程方式设置dllimport

Mat*_*att 9 .net c# 64-bit interop dllimport

DllImport在我的解决方案中使用.
我的问题是我有两个版本的相同的DLL一个为32位而另一个为64位.

它们都使用相同的名称和相同的签名来公开相同的功能.我的问题是我必须使用两个静态方法来暴露这些,然后在运行时使用IntPtr大小来确定要调用的正确方法.

private static class Ccf_32
{
    [DllImport(myDllName32)]
    public static extern int func1();
}

private static class Ccf_64
{
    [DllImport(myDllName64)]
    public static extern int func1();
}
Run Code Online (Sandbox Code Playgroud)

我必须这样做,因为myDllName32并且myDllName64必须保持不变,我还没有找到在运行时设置它的方法.

有没有人有一个优雅的解决方案,所以我可以摆脱代码重复和不断的IntPtr大小检查.

如果我可以设置文件名,我只需要检查一次,我就可以摆脱大量重复的代码.

Jos*_*are 18

我更喜欢通过使用来自kernel32.dll 的LoadLibrary调用来强制从特定路径加载特定DLL.

如果您将32位和64位DLL命名为相同但将它们放在不同的路径中,则可以使用以下代码根据您运行的Windows版本加载正确的代码.您需要做的就是在引用任何引用ccf类的代码之前调用ExampleDllLoader.LoadDll():

private static class ccf
{
    [DllImport("myDllName")]
    public static extern int func1();
}

public static class ExampleDllLoader
{
    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    private extern static IntPtr LoadLibrary(string librayName);

    public static void LoadDll()
    {
        String path;

        //IntPtr.Size will be 4 in 32-bit processes, 8 in 64-bit processes 
        if (IntPtr.Size == 4)
            path = "c:/example32bitpath/myDllName.dll";
        else
            path = "c:/example64bitpath/myDllName.dll";

        LoadLibrary(path);
    }
}
Run Code Online (Sandbox Code Playgroud)


Fre*_*örk 12

您可以使用#if关键字实现此目的.如果定义一个被调用的条件编译器符号win32,下面的代码将使用win32-block,如果你删除它将使用另一个块:

#if win32
    private static class ccf_32
    {
        [DllImport(myDllName32)]
        public static extern int func1();
    }
#else    
    private static class ccf_64
    {
        [DllImport(myDllName64)]
        public static extern int func1();
    }
#endif
Run Code Online (Sandbox Code Playgroud)

这可能意味着您可以删除现在拥有的类包装:

    private static class ccf
    {
#if win32
        [DllImport(myDllName32)]
        public static extern int func1();
#else    
        [DllImport(myDllName64)]
        public static extern int func1();
#endif
    }
Run Code Online (Sandbox Code Playgroud)

为方便起见,我猜你可以创建用于控制编译符号的构建配置.

  • 是的,但我想保留'Any CPU'选项而不是32位和64位版本. (3认同)

dea*_*nis 10

我知道这是一个非常古老的问题(我是新问题 - 回答一个老问题是不是很糟糕?),但我只需要解决同样的问题.我必须动态引用基于操作系统的32位或64位DLL,而我的.EXE是针对任何CPU编译的.

您可以使用DLLImport,而不需要使用LoadLibrary().

我是通过使用SetDLLDirectory完成的.与名称相反,SetDLLDirectory添加到DLL搜索路径,并不替换整个路径.这允许我在Win32和Win64子目录中有一个具有相同名称的DLL(用于此讨论的"TestDLL.dll"),并进行适当调用.

public partial class frmTest : Form
{
    static bool Win32 = Marshal.SizeOf(typeof(IntPtr)) == 4;
    private string DLLPath = Win32 ? @"\Win32" : @"\Win64";

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool SetDllDirectory(string lpPathName);
    [DllImport("TestDLL.dll", SetLastError = true)]
    static extern IntPtr CreateTestWindow();

    private void btnTest_Click(object sender, EventArgs e)
    {
        string dllDir = String.Concat(Directory.GetCurrentDirectory(), DLLPath);
        SetDllDirectory(dllDir);

        IntPtr newWindow = CreateTestWindow();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的方法,特别是如果你有多个需要32位和64位版本的DLL.我相信我比使用我在答案中解释的LoadDll方法更喜欢SetDllDirectory方法.与包装器方法相比,它的代码也少得多,让我们编译任何CPU. (2认同)