对来自同一托管dll的32位和64位dll使用pinvoke

时间:2013-03-04 09:59:59

标签: .net pinvoke

我正在使用来自.NET(C#)dll的pinvoke来调用本机dll。现在我想将我的.NET dll编译为“AnyCPU”但是当“pinvoking”时,我必须知道,我是否必须调用32位或64位dll。我将两个版本的本机dll安装到子文件夹bin32和bin64中。现在,当我的DLL被加载时,我想检查一下,无论我们是32位还是64位模式,并使用适当的路径调用SetDllDirectory。这种方法似乎没有问题,除了从哪里调用SetDllDirectory的良好“入口点”。在本机DLL中有一个DllMain条目,当DLL附加到进程时会被调用。 .NET DLL中是否有类似的入口点? 你认为动态调用SetDllDirectory是个好主意吗?

2 个答案:

答案 0 :(得分:3)

.NET确实具有DllMain()函数的等价物,它被称为module initializer。但是,从C#和VB.NET代码中无法访问,您只能在IL或C ++ / CLI中创建一个。 C ++ / CLI本身具有位依赖性,因此只留下IL。您可以在this answer中找到一个示例代码。将它链接到程序集非常尴尬,构建系统不直接支持运行程序集链接器。

下一个最好的东西是同一篇文章中提到的“类型初始化器”,在C#中称为静态构造函数。你需要在你的代码中使用一些相似的组织来使这些代价得到回报,这个类在你的“数千个方法”之一被调用之前保证会被使用。用这么多方法应该很难。

这不会超出必须由应用程序在其Main()方法中调用的初始化方法。当然还有标准解决方案,两个安装程序,一个用于32位计算机,另一个用于64位计算机。这也确保您的应用程序最终位于“正确”的目录中,c:\ program files vs c:\ program files(x86)。

答案 1 :(得分:1)

基本上你要问的是你是否可以编写首次加载程序集时将执行的代码。这个问题在这里得到解决:.Net: Running code when assembly is loaded

在你的位置,我会把责任放在你图书馆的用户身上。提供初始化库的函数,并要求库的用户在任何其他函数之前调用它。

如果您愿意,可以使用延迟初始化在库中进行初始化。因此,您的所有方法都可能如下所示:

private static void EnsureInitialized()
{
    if (!MyLibraryInitialized)
        InitializeMyLibrary();
}

public static void DoSomething()
{
    EnsureInitialized();
    .... // implementation of DoSomething
}

我还建议不要使用SetDllDirectory。有一种更简单的方法。由于您可以获取需要加载的DLL的完整路径,因此只需通过调用InitializeMyLibrary()将其加载到LoadLibrary()即可。加载DLL后,您的p / invokes将自动绑定到您已加载的DLL。