3

我正在使用 .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 是个好主意吗?

4

2 回答 2

4

.NET 确实具有等效于 DllMain() 函数,它被称为模块初始化程序。然而,C# 和 VB.NET 代码无法实现它,您只能在 IL 或 C++/CLI 中创建一个。C++/CLI 本身具有位依赖性,因此只留下 IL。您将在此答案中找到其中之一的示例代码。将它链接到您的程序集中非常尴尬,构建系统不直接支持运行程序集链接器。

Next best thing is a "type initializer" as mentioned in the same article, called a static constructor in C#. You do need some semblance of organization in your code to make these pay off, a class that's guaranteed to get used before one of your 'thousands of methods' get called. That ought to be difficult with that many methods.

That doesn't leave much beyond an initialization method that has to be called by the app in its Main() method. And of course the standard solution, two installers, one for 32-bit machines, another for 64-bit machines. Which also ensures your app ends up in the 'right' directory, c:\program files vs c:\program files (x86).

UPDATE: .NET 5 now supports module initializers in C# v9 with the [ModuleInitializer] attribute

于 2013-03-04T13:19:10.173 回答
1

本质上,您要问的是您是否可以编写将在首次加载程序集时执行的代码。这个问题在这里得到解决:.Net:加载程序集时运行代码

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

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

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

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

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

于 2013-03-04T12:04:51.040 回答