如何在Windows和Linux上进行跨平台P/Invoke

 我来答
飞得更高200309
高粉答主

推荐于2016-04-17 · 说的都是干货,快来关注
知道顶级答主
回答量:4.6万
采纳率:93%
帮助的人:9661万
展开全部
  NET的程序是和Java一样的托管代码,在底层操作上,具有很大的局限性,像Java的JNI一样,.NET具有Platform Invoke(平台调用,通常叫P/Invoke)。本文中,Linux下的.NET托管代码运行在Mono CLR上。之所以做跨平台的P/Invoke,是因为考虑到有些客户在Win32/WinCE等系统中开发的.NET程序,需要换到Linux平台运行。嵌入式开发中,经常需要操作IO,.NET程序就通过P/Invoke来调用一些用比如c/c++一类语言开发的native代码完成IO操作。这时候针对windows编写的native代码,就不能不加修改的移植到Linux上,要完成这个移植工作就需要编写Linux下的native代码。但如何做到不修改.NET程序呢,下面就让笔者以实例讲述。
  要保证.NET程序不加修改,不许重新编译,需要做到native代码具有一致的接口。比如我们有native.dll何libnative.so两个不同系统下的动态链接库,在.NET程序中,调用动态库中的getSum(int a,int b)函数,则需要在native.dll和libnative.so中都存在getSum(int a, int b)函数,而且导出的名字要一致,都是getSum。编译时要注意编译器对符号名称的修饰,vc编译器中,可以用Module-Defination File(.def)文件来规范到处的函数名称。
  在.NET的代码中,透过DllImport引入外部函数时,指定的链接库模块不要加扩展名。比如native.dll,只要写native就好。windows中,会自动寻找native.dll,Linux下对应的是libnative.so。
  以下是实例代码:
  using System;
  using System.Runtime.InteropServices;
  namespace Managed
  {
  class Program
  {
  [DllImport("native")]
  public static extern int getSum(int a, intb);
  
  static void Main(string[] args)
  {
  System.Console.WriteLine("Managed code out.");
  System.Console.WriteLine("1+2=" + getSum(1, 2));
  }
  }
  }
  上边的代码演示了从外部动态链接库引入函数的方式,注意没有加扩展名。接下来在看看windows下的c代码是如何编写的:
  /**
  * native.h 头文件,声明函数原型
  */
  #ifndef NATIVE_H
  #define NATIVE_H
  #ifdef __cplusplus
  extern "C" {
  #endif
  int __stdcall getSum(const int a, const intb); // 原型
  #ifdef __cplusplus
  }
  #endif
  #endif
  
  /*
  * native.cpp
  * 2013-03-05 实现功能的代码
  */
  #include "native.h"
  #include <stdio.h>
  
  int __stdcall getSum(const int a, const intb)
  {
  printf("WindowsNative code.\n");
  returna+b;
  }
  以上是具体的代码,另外需要模块定义文件(.def)来指定导出的函数表。如下:
  LIBRARY "native"
  
  EXPORTS
  getSum
  在VC中,编译,以上代码,可以生成dll文件。用dumpbin工具可以看到导出的函数名为getSum。
  Linux下的共享库(Shared Object,简称so)的实现比上边更简单,编译时gcc加上-shared参数即可,这方面网上很多。我直接采用了code block的IDE,建立shared library工程。编译时IDE就会把这些处理好。编写的代码如下:
  #include <stdio.h>
  
  int getSum(int a, int b)
  {
  printf("Linux Natie code\n");
  return a+b;
  }
  编译生成libnative.so。
  我们在native的代码中插入了输出语句,用来显示调用了哪个库。将这些native.dll, libnative.so, 还有C#程序managed.exe拷贝到一个文件夹,在Windows上运行managed.exe结果如下:
  
  
  可以看出,在Windows和Linux下的P/Invoke调用都很成功。差不多到这里就该结束了,但是还有一点需要提醒,不论哪个平台,如果提示找不到库的问题,请将库放在一个程序能够找到的地方。
  以上只是简单的演示了P/Invoke,实际上更复杂的情况,我们可以在.NET程序中,判断当前运行的操作系统,然后采用LoadLibrary或者dlopen等,动态加载共享库,这样更灵活,不再有上边提到的“不加扩展名”,路径找不到的要求或者问题。感兴趣的读者可以自行了解这方面的内容。
快又稳
2024-10-28 广告
在Linux环境下配置基于域名的虚拟主机,需安装Apache或Nginx等Web服务器,并编辑配置文件。以Apache为例,需创建虚拟主机配置文件,指定域名、文档根目录等,然后启用该配置文件并重启Apache服务。同样,Nginx也需在相应... 点击进入详情页
本回答由快又稳提供
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式