介绍
公共语言基础设施(CLI)的目的是使它“容易”与现有代码进行互操作。原则上,所有您需要做的就是创建一个函数声明DllImport为现有的代码来调用,运行时将处理其余的。例如:
[DllImport ("libc.so")]
privatestaticexternint getpid ();
请注意,大多数的类和枚举提到在这个文档保存在System.Runtime.InteropServicesnamespace.
上面的c#函数声明将调用POSIX getpid(2)系统调用的平台上有libc.so库
如果libc.so存在但getpid没有输出, 抛出一个EntryPointNotFoundException异常。如果libc.so不能加载, 抛出一个DllNotFoundException异常。简单,直接。有什么能比这更容易?
有三个问题
1在DllImport语句指定库。
2确定实际调用哪个函数。
3传递参数,大多数现有的代码更复杂。字符串需要被传递,结构可能需要被传递,内存管理实践也将参与……
现有的代码是一个复杂的怪兽,和互操作层需要支持这种复杂性。
库处理
如何在运行时发现,并指定在DllImport属性中?这个问题本质上是特定于平台的。
Windows DLL搜索路径
从MSDNLoadLibrary文档,dll程序所需的是按照下面的顺序进行搜索:
1.应用程序加载的目录。
2.当前目录
3.系统目录,使用GetSystemDirectory()函数来获得这个目录的路径。
4.16位系统目录。
5.Windows目录。使用GetWindowsDirectory()函数来获得这个目录的路径。
6.PATH环境变量中列出的目录。
当然,现实并没有那么简单。实际上,“system”目录实际上是%WINDIR%\system32,除了Windows9x平台%WINDIR%\system。16位系统目录通常%WINDIR%\system,但不被视为一个单独的搜索目录在Windows 9 x平台。
此外,在Windows Server 2003和Windows XP SP1, 注册表入口HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\SafeDllSearchMode改变上述命令, 如果这是1(默认),然后搜索当前目录是在系统和Windows目录。这是一个安全特性(它可以防止木马库被载入代替,例如,OLE32.DLL) 但它把上面的列表改为:1、3、4、5、2、6。
Linux共享库搜索路径
从dlopen(3)手册页,必要的程序所需的共享库是按照下面的顺序进行搜索:
1在用户的LD_LIBRARY_PATH环境变量中以冒号分隔的目录列表.这是一个经常使用的方法,允许本地共享库是一个CLI程序发现的。
2库的列表,缓存在/etc/ld.so.cache./etc/ld.so.cache是由编辑/etc/ld.so.conf和运行ldconfig. 编辑/ etc/ld.so.conf首选方法是搜索附加目录,而不是使用LD_LIBRARY_PATH, 因为这是更安全的(很难达到一个木马库到/ etc/ld.s.cache比插入到LD_LIBRARY_PATH)。
3 / lib,紧随其后的是/ usr / lib。
作为一个mono的扩展, 如果一个库正被加载是__Internal,然后主程序是寻找方法符号。这相当于调用dlopen(3)和一个文件名的空。这允许您P / Invoke方法,都在一个应用程序嵌入Mono。
Mac OS X框架和.dylib搜索路径
框架和库搜索路径是:
1在用户的DYLD_FRAMEWORK_PATH环境变量中以冒号分隔的目录列表.
2在用户的DYLD_LIBRARY_PATH环境变量中以冒号分隔的目录列表.
3在用户的DYLD_FALLBACK_FRAMEWORK_PATH环境变量中以冒号分隔的目录列表.它是默认目录:
·~/Library/Frameworks
·/Library/Frameworks
·/Network/Library/Frameworks
·/System/Library/Frameworks
4在用户的DYLD_FALLBACK_LIBRARY_PATH环境变量中以冒号分隔的目录列表, 它是默认目录:
·~/lib
·/usr/local/lib
·/lib
·/usr/lib
注意:使用GLib,Mono加载库, 还有在Mac OS X上GLib有bug不使用,..dylib扩展,而是使用Unix.soextension,虽然这应该最终被修复, 目前的解决方法是写一个.config文件映射到.dylib文件
<configuration>
<dllmapdll="mylib"target="mylib.dylib"/>
</configuration>
TODO:将mono同时支持框架和dylibs吗?
库名:
知道到哪里查找库是只有一半的问题。了解库的加载是另一半。
不同的平台有不同的命名约定。Windows平台上是库名.dll,如OLE32.DLL等。Linux平台使用lib前缀和一个.so后缀。MacOSX平台使用lib前缀和一个.dylib后缀。除非他们是一个框架,在这种情况下,他们是一个目录,事情变得更加复杂。