Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 对来自同一托管dll的32位和64位dll使用pinvoke_.net_Pinvoke - Fatal编程技术网

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

.net 对来自同一托管dll的32位和64位dll使用pinvoke,.net,pinvoke,.net,Pinvoke,我正在使用.NET(C#)dll中的pinvoke调用本机dll。现在我想将我的.NET dll编译为“AnyCPU”,但当“pinvoking”时,我必须知道,我是否必须调用32位或64位dll。我将两个版本的本机DLL安装到子文件夹bin32和bin64中。现在,当我的DLL被加载时,我想检查我们是在32位还是64位模式下,并使用适当的路径调用SetDllDirectory。这种方法似乎没有问题,除了从哪里调用SetDllDirectory有一个很好的“入口点”。在本机DLL中,有一个Dll

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

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

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

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

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

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

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

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

其次是同一篇文章中提到的“类型初始值设定项”,在C#中称为静态构造函数。您的代码中确实需要一些组织的外表来实现这些功能,这个类保证在调用“数千个方法”之一之前得到使用。用这么多的方法应该很难做到

除了必须由应用程序在其Main()方法中调用的初始化方法外,这并没有留下太多内容。当然,标准的解决方案是两个安装程序,一个用于32位机器,另一个用于64位机器。这也确保了你的应用程序最终位于“正确”目录中,即c:\program files vs c:\program files(x86)


更新:.NET 5现在支持C#v9中的模块初始化器,使用

谢谢,LoadLibrary在许多情况下肯定比SetDllDirectory好,但不幸的是,在我的情况下不是这样,根据用户调用的方法,可能会加载几十个DLL。如果不需要的话,我不想占用这些内存空间。@Gerhard我不建议在启动时加载它们。只是加载所需的内容。但是,如果这些DLL彼此有依赖关系,则需要修改DLL搜索路径,以便适当地解决依赖关系。您的答案并没有明确说明托管DLL中没有“DllMain”,而是提供了一个很好的解决方法。不幸的是,我的DLL中有数千个方法,所以我不能使用“初始化”预检查。如果没有人提出托管代码中的DllMain,我将检查您的答案是否为已接受答案。再次感谢。如果你不能使用延迟初始化,那么你可以要求用户调用你的初始化函数。然而,我不相信你的库中真的有成千上万的pinvoke调用。我认为这对你来说是一个很好的解决方案,至少在Windows上是这样。我不得不用注册表来解决我的问题,所以我使用了模块初始化器。如果您将托管对象创建封装在类似工厂的类中进行初始化,或者尝试将其放在保存pinvoke定义的静态类(构造函数)中,也可以避免这种情况。