Unity 与 .so\.a\.dll库文件、 C\C++\OC\Java 交互
来源:互联网 发布:淘宝真丝针织背心 编辑:程序博客网 时间:2024/05/19 23:09
简介
通用语言基础架构(CLI) 的设计思想是 代码间更容易的复用或者相互调用。
我们要使用 其他语言打包成的 库文件时,只需 创建DllImport
的来声明。
需要引入System.Runtime.InteropServices
命名空间。
形如:
[DllImport ("libc.so")] private static extern int getpid ();
- 如果运行平台上有
libc.so
将会调用POSIX getpid(2)
- 如果不存在
getpid ()
方法,将会 抛出EntryPointNotFoundException
异常。- 如果
libc.so
无法被加载,则抛出DllNotFoundException
异常。总结调用有三要点
- 指明要抵用的库文件名称 (如
libc.so
)- 确定要调用的函数名 (如
getpid ()
)- 传递参数
然而参数的传递有很多复杂的情况,如
String\Sturct\IntPtr ...
库文件的加载
库文件的加载是分平台处理的。
Windows DLL Search Path
按照以下顺序搜索
- 被加载的应用程序的目录
- 当前目录
- 系统目录,
GetSystemDirectory()
来获取系统目录16-bit
系统目录Windows
目录,GetWindowsDirectory()
来获取PATH
环境变量中列出的目录。当然,事实上并非这么简单。在实践中,
System
目录实际上是%WINDIR%\system32
,除了在Windows 9 x平台%WINDIR%\system
。16位系统目录通常是%WINDIR%\system
,但不认为是一个单独的搜索目录在Windows 9 x平台。
此外,在Windows Server 2003和Windows XP SP1,注册表键入HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
改变上述排序。如果这个1
(默认),然后搜索当前目录是在System
和Windows
目录。这是一个安全特性(它可以防止木马库被载入代替,例如,OLE32.DLL
),但它上面的列表变成:1,3,4,5,2,6
。See also
Linux Shared Library Search Path
共享库搜索按照以下顺序:
- 以冒号分隔的目录列表在用户的
LD_LIBRARY_PATH
环境变量。这是一个经常使用的方法,允许本地共享库来发现一个CLI
程序。- 在
/etc/ld.so.cache
库缓存列表。/etc/ld.so.cache
通过编辑/etc/ld.so.conf
创建缓存配置和runningldconfig(8)
。编辑/etc/ld.so.conf
额外配置的首选方法是搜索目录,而不是使用LD_LIBRARY_PATH
,因为这是更安全(这是木马库进入/etc/ld.so.cache
比将它插入到LD_LIBRARY_PATH
更加困难)。/lib
、/usr/lib
As a Mono extension, if the library being loaded is __Internal, then the main program is searched for method symbols. This is equivalent to calling dlopen(3) with a filename of NULL. This allows you to P/Invoke methods that are within an application that is embedding Mono.
See also
Mac OS X Framework and .dylib Search Path
顺序如下
- 以冒号分隔的目录列表在用户的
DYLD_FRAMEWORK_PATH
环境变量。- 以冒号分隔的目录列表在用户的
DYLD_LIBRARY_PATH
环境变量。以冒号分隔的目录列表在用户的
DYLD_FALLBACK_FRAMEWORK_PATH
环境变量,默认目录:
~/Library/Frameworks
/Library/Frameworks
/Network/Library/Frameworks
/System/Library/Frameworks
以冒号分隔的目录列表在用户的
DYLD_FALLBACK_LIBRARY_PATH
环境变量,默认目录:
~/lib
/usr/local/lib
/lib
/usr/lib
Note: Mono uses GLib to load libraries, and GLib has a bug on Mac OS X where it doesn’t use a
.dylib
extension, but instead uses the Unix.so
extension. While this should eventually be fixed, the current workaround is to write a.config
file which maps to the.dylib
file, e.g.
<configuration> <dllmap dll="mylib" target="mylib.dylib" /> </configuration>
See also
Library Names
知道从哪去寻找
Library
只是进行到了一半,而另一半是 怎么加载。不同的平台库文件的命名协议不一样。
Window
– 以.dll
结尾。 (eg.OLE32.dll
)Linux
– 以lib
为前缀.so
结尾。Mac OS
– 以lib
为前缀.dylib
结尾。(PS:如果是Framework
的话则是一个目录,这种情况更为复杂。)严格地说,
Unix
的命名通常是.so
后加上版本号。(eg.libfreetype.so.6.3.3
)在声明
DllImport
的时候,使用的名称,需要去掉前缀和后缀。
例如:
[DllImport ("MyLibrary")] private static extern void Frobnicate ();
那么,你只要为
Window
平台 提供MyLibrary.dll
、 为Unix
平台 提供libMyLibrary.so
、为Mac OS X
平台 提供libMyLibrary.dylib
。
调用 非托管代码
首先,加载库
DllImport
属性中指定,如上所述。如果你需要调用c++代码,你有两个选择
- 对 C++ 方法 使用
extern "C"
把它视为 C 方法。并确保它使用一个已知的调用协定(PS.Window
平台可调用winapi
,Unix
平台可调用Cdecl
,以此类推)- 在确保它使用一个已知的调用协定的前提下,不使用
extern "C"
。但需要 在方法前使用DllImport.EntryPoint
我们来分析一段代码。
typedef void (*Handler) (const char *message); void InvokeHandler (Handler handler) { char *message = (char *) malloc (10); strcpy (message, "A Message"); (*handler)(message); free (message); }
如果
handler
是一个托管指针这里可能会抛出一个异常,那么free
就不会被执行,那么结果就是导致内存泄漏。然而在这时,由于 C++的垃圾回收并不会帮助你回收这块内存,而你又没有处理这种异常情况的代码。另一方面,托管代码那边也不知道 C++的异常处理。
这在封装 C++方法中很常见。所以 C++的异常 应该映射在一个
Out
的参数,或者 返回值中。这样,托管代码侧就知道,C++这边是否抛出了异常。当然你也可以抛出一个 托管的异常来“传播”C++的这个异常。
- SeeAlso
- SeeAlso
- SeeAlso
Marshaling
在给定一个托管调用的位置、非托管的调用位置后,他们之间的通信的调用位置被称为
marshaled
的地方。可以理解为一个类型转换。而实际上
marshaled
将数据放在栈上,然后去调用非托管代码。对于简单类型(eg. int \ float)的
Marshaling
是一个bitwise-copy
(“blitting”) 的过程。
有些情况下可以不进行Marshaling
操作。比如 在传递structures
的引用,这时是一个指向结构的指针传递。对于
String
在运行时将以UTF-16-encoded
编码,这些需要我们去marshaled
为更为合适的编码方式。
Memory Boundaries
托管和非托管内存应该认为是完全独立的。
- 托管内存通常是一个垃圾收集堆上分配的内存
- 非托管内存是:ANSI C内存池(通过调用malloc)、自定义内存池和垃圾收集堆外CLI的控制实现(如LISP或Scheme内存堆)。
使用C#固定语句可以锁定一个托管堆的一块内存。这一段托管堆可以传递给非托管代码操作而不用担心未来的GC回收。
然而,这完全是受控于编程人员,而不是平台调用是如何工作的。在P/Invoke调用运行时不模仿c#固定的语句。相反,类和结构的内存排列通过以下伪流程:
- 非托管内存的运行时分配一块内存。
- 管理类数据复制到非托管内存。
- 非托管函数被调用时,通过它管理的非托管内存信息而不是托管内存。这必须这样做,如果发生
GC
,非托管函数不需要担心。(是的,我们需要担心GC,
作为非托管函数可以调用回运行时,最终导致GC
。多线程代码也会导致一个GC
而非托管代码执行)。- 非托管内存复制回托管内存。
要记住有一个关键问题:
在上面指定的内存管理过程是隐式的,并没有办法控制运行时如何管理、分配、排列内存或持续多长时间。如果运行时
marshals
一个字符串Ansi
转化(如utf - 16
),marshals
字符串只要调用就会存在。 非托管代码不能保持这个内存引用,因为它将调用结束后释放。 这适用于任何marshal
过程运行时分配内存的marshal
的过程。委托管理的非托管函数指针表示持续只要委托管理。
委托收集的GC时,非托管函数指针也会收集。这也是很重要的:如果委托收集和非托管内存调用函数指针,就发生了“踩内存空间”了(不再属于期望的那个内存内容了,已是物是人非了)。任何事情都有可能发生,其中包括程序报错。因此,必须确保非托管函数指针的生命周期是一个适当的子集的生命周期管理委托实例。
Blittable Types
- Unity 与 .so\.a\.dll库文件、 C\C++\OC\Java 交互
- Java框架JNA调用C方法(windows链接库dll文件、linux链接库so文件)
- C与Java 文件数据交互
- (英文)关于Unity3d c#和.a\.o\.so等native库文件的交互,库文件可以由c\c++\object-c等编译
- c/C++中后缀obj/o lib/a dll/so bin文件意义
- unity 与objective-c交互
- unity 中 c# 与 object-c 交互
- JNA调用C动态库dll、so
- 移动项目中JAVA与C/C++编解码相关的JNI动态库问题(.dll vs .so)
- JNI 使用总结 (JAVA 调用C语言编写的DLL/SO/SL文件)
- java与c的交互
- C/Java/Unity(C#)三者间大数据交互简析
- linux C 生成与使用 so 文件
- swift与oc的互用--c语言API交互
- windows/linux + java + jna + dll/so 调用C/C++
- java通过jni调用c编译的dll或so
- Golang与C互用以及调用C的so动态库和a静态库
- C#应用程序与DLL交互中使用消息
- 道德经
- CC2530与tinyos
- 方格填数
- Method的invoke()方法的使用
- 抽象类和接口联系与区别
- Unity 与 .so\.a\.dll库文件、 C\C++\OC\Java 交互
- 一些自己用到的学习网站
- 坐在马桶上看算法:只有五行的Floyd最短路算法
- Spring与SpringMVC的关系
- 从零移植uboot 2017 到nuc970(第十五天)
- 算法训练 未名湖边的烦恼
- java实现DFS求路径是否有解问题
- 自然语言处理中CNN模型几种常见的Max Pooling操作
- 关于归并排序的思考