平台互操作性和不安全的代码

168 篇文章 171 订阅

1、平台调用(P/Invoke)实现c#调用c++
1)创建一个c++的dll(vs2019),如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里注意不要把头文件给删了!
在这里插入图片描述
c++工程中的代码如下:

extern "C" __declspec(dllexport)
int add1(int a, int b)
{
	return a + b;
}

清理解决方案-》重新生成解决方案,生成Main.dll
2)新建一个c#的winform工程,将Main.dll放到winform工程debug目录(程序运行目录)下,新建一个MonitorSample的类,并在类中添加如下代码,并调用

 class MonitorSample
    {
       [DllImport("Main.dll", CallingConvention =CallingConvention.Cdecl)]
        internal   static extern int add1(int a,int b);
    }

调用:

  int num = MonitorSample.add1(12, 13);
            Console.WriteLine (num);

输出

25

2、利用ref和Out参数实现引用的传递
c++代码

extern "C" __declspec(dllexport)
int add1(int a, int* b)
{
	/**b =*b +100;
	int c = *b;*/
	return  a+1;
	
}

c#代码:

 [DllImport("Main.dll", CallingConvention =CallingConvention.Cdecl)]
    internal   static extern int add1(int a,out int b);

调用:

  int ini;
  int num = MonitorSample.add1(int.MaxValue , out ini);

3、对于c++中存在的一些没有对应托管类型,使用自定义托管类型实现
c++代码

struct ddd
{
	int s;
	double b;
};
extern "C" __declspec(dllexport)
int add2(ddd a)
{
	
	int c = a.s;
	return c;
}

c#代码

public   struct ddd
    {
       public  int s;
        public double b;
    };
 [DllImport("Main.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int add2(ddd dd);

调用:

 ddd dd;
 dd.b = 200;
 dd.s = 300;
 int nums = MonitorSample.add2(dd);
 Console.WriteLine(num);

4、异常捕获
可以对于使用extern声明的函数,外加一个包装的函数,函数中加入异常的抛出与处理

  [DllImport("Main.dll", CallingConvention =CallingConvention.Cdecl)]
    internal   static extern int add1(int a,out int b);
    
  internal static int add(int a,int b)
        {
            int result;
            result= add1(a,out b);
            if(result <100)
            {

            }
            else
            {
                throw new Exception("错误");
            }
            return result;
        }

2、指针和地址
1)在c#中直接访问和操纵内存(访问值类型变量的地址)

  private void Test()
        {
            int a = 100;
            int value;
            unsafe
            {
                int* aAddress = &a;
                 value = *aAddress;
               
            }
            Console.WriteLine(value);
        }

1、使用unsafe提醒编译器支持不安全的代码;
2、将项目-属性-生成-允许不安全的代码选上;
3、不能访问引用类型,例如string,泛型类型的地址;
2)访问数组的地址(在堆上分配内存)
数组的值在内存中存在移动,所以需要将地址固定;

private void Test()
        {
            byte value;
            unsafe
            {
                byte[] a = new byte[5] { 1,2,3,4,5};
               
                fixed (byte* aAddress = &a[0])
                {
                    value = *aAddress;
                }


            }
            Console.WriteLine(value);
        }

3)访问数组的地址(在栈上分配内存)

private void Test()
        {
            byte value;
            unsafe
            {
                byte* a = stackalloc  byte[5] { 1,2,3,4,5};
                byte* aAddress = &a[0];
                    value = *aAddress;
            }
            Console.WriteLine(value);
        }

4)访问被引用变量的成员

 struct Postion
    {
        public double x;
        public double y;
    }
   private void Test()
        {
            Postion pos;
            pos.x = 100;
            pos.y = 200;
            double value;
            double value2;
            unsafe
            {
                Postion* posAdd = &pos;
                value = posAdd->x;//一种调用成员的方法
                value2 = (*posAdd).y;//另一种调用成员的方法
            }
            Console.WriteLine(value);
            Console.WriteLine(value2);
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c#上位机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值