.NetCore下使用DllImport 加载动态链接库

.NetCore下DllImport 

环境Mac

C++代码,注意一定要使用extern “C”,不然由于Cpp文件是要使用C++编译器的,这样导出函是数加一些后缀的,造成C# 找不到Entry Point出错。

#ifndef Test_h
#define Test_h

#include <stdio.h>

class TestC{
public:
    int i;
    TestC();
};

extern "C" {
    void Hello();
    TestC* GetC();
}

#endif /* Test_h */
#include <stdio.h>
#include "Test.h"

TestC* GetC(){
    return new TestC();
}

TestC::TestC(){
    i = 99;
}

void Hello()
{
    printf("hello");
}

C#代码

Then, you just need to provide MyLibrary.dll for Windows platforms, libMyLibrary.so for Unix platforms, and libMyLibrary.dylib for macOS platforms.

各平台有不同的前缀和后缀,如以上的形式,为了支持不同的平台,可以直接写Lib的名字,即Mac不到其前缀lib和dylib,它会自动找到对应的名字。本例的Lib是放在代码目录下的。

    [StructLayout(LayoutKind.Sequential)]
    public class TestC
    {
        public int i = 100;

        [DllImport("TestLib")]
        public static extern TestC GetC();

        [DllImport("TestLib", EntryPoint ="Hello")]
        public static extern void Hello();
    }

访问成功:

确认一下一些问题:

1. C#类中的名字不一致:这个与名字没有关系,只与内存的排列位置有关系。

2. 属性是否对C#的内存排列有影响?属性如何Marshaling呢?

        public int i { get; set; }

通过以上定义会引入默认的成员变量定义,这会占用内存的,所以也会支持Marshaling导入。

        public int i { get => ii; set => ii = value; }
        public int ii = 100;

如上定义就不会占用内存的,而使用也是ii的内存,结果也是输出99

        extern public int ei {
            [MethodImpl(MethodImplOptions.InternalCall)]
            get;
            [MethodImpl(MethodImplOptions.InternalCall)]
            set; 
        }

这种外部的属性定义也不会占用内存的,很好理解,因为它的实现在外部。

3. Enum支持

        [DllImport("TestLib")]
        public static extern void TestFuncWithParm(TestEnum test);

C++使用int就可以接收了。

对于类的Marshaling需要以下设置

There are two other issues with classes. First of all, classes by default use LayoutKind.Auto layout. This means that the ordering of class data members is unknown, and won’t be determined until runtime. The runtime can rearrange the order of members in any way it chooses, to optimize for access time or data layout space. As such, you MUST use the StructLayout attribute and specify a LayoutKindvalue of LayoutKind.Sequential or LayoutKind.Explicit.

字符串Marshaling

C++中:

    char name[32];

C#定义如下:

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string test;

以上参考,这里的很详细的介绍了Marshal的原理,其本质还是内存的处理,

https://www.mono-project.com/docs/advanced/pinvoke/

 基类Marshaling

如果派生类进行Marshaling,基类也需要定义

[StructLayout(LayoutKind.Sequential)]

基类成员的顺序是要排列在派生类的成员的前面。

C++中可以不定义基类,所有的成员定义完整就可以了。

由此也可以看出这种静态注入对源Dll版本更新变化,非常敏感。

IntPtr成员Marshaling

它对应的就是指针,比如Void*

比如Unity Object类其定义如下:

可以看其也加了StructLayout的定义,就是为其它派生类,对C++ Marshaling的支持。

发布了51 篇原创文章 · 获赞 10 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/FeiBin2013/article/details/86749210
今日推荐