开发环境:

操作系统:windows 7
IDE:Microsoft Visual Studio Professional 2015
SWIG: 3.0.12

swig的介绍

详细介绍可看官网,一下贴出官网上的原话:

SWIG is a software development tool that connects programs written
in C and C++ with a variety of high-level programming languages. SWIG is
used with different types of target languages including common
scripting languages such as Javascript, Perl, PHP, Python, Tcl and Ruby.
The list of supported languages also includes non-scripting languages
such as C#, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), D, Go language,
Java including Android, Lua, Modula-3, OCAML, Octave, Scilab and R.
Also several interpreted and compiled Scheme implementations (Guile,
MzScheme/Racket, Chicken) are supported. SWIG is most commonly used to
create high-level interpreted or compiled programming environments, user
interfaces, and as a tool for testing and prototyping C/C++ software.
SWIG is typically used to parse C/C++ interfaces and generate the ‘glue
code’ required for the above target languages to call into the C/C++
code. SWIG can also export its parse tree in the form of XML and Lisp
s-expressions. SWIG is free software and the code that SWIG generates is
compatible with both commercial and non-commercial projects.

以下是我的理解(注:以下这段话并不是上段话的翻译):
Swig主要是为了将c++/c中的代码所实现的功能移植到别的语言上。一般我们要将c++/c移植到别的语言上,基本操作是将c++中的实现代码转变成dll,然后再供别的语言调用,这样安全性高,且易于调用。但是因为各种语言不相同,如果不借助swig,自己去封装。在调用dll时就会有很多类型(包括基本类型,结构体和类)转换需要注意,比如c#调c++

dll,可能得自己造一个相对应与c++的结构体和类才能成功调用。但是如果我们用了swig,这些我们都不用考虑,我们只需要考虑swig给我们的接口类型是什么,然后我们只要按照swig给的接口类型传入参数,就OK了。说白了就是swig代替了我们利用c#去重新定义dll中所需要传入的参数类型(如结构体或类)这个工作。

swig实现步骤

swig的安装:

进入如下网址:http://www.swig.org/download.html
由于我是windows系统,所以安装如下版本:

下载后,将其解压至制定目录,如:D:\SDK\swigwin-3.0.12

1、建立如下c++项目(应用程序类型选择dll类型)和c#项目,还没实现代码,都是空项目。主要有.h .cpp .idl .cs文件(具体这四个文件怎么创建我就不赘述了,想必能找到这篇博文就说明已具备了创建此文件的能力)。

2、填写代码:
(1) c++_file.idl:
(网上说的都是.i文件,其实就是vs里的.idl文件)

%module cppdll
%{
/* 在包装代码中包含头文件 */
#include "c++_file.h"
%}
/* 解析头文件生成包装代码 */
%include "c++_file.h"

(2) c++_file.cpp

#include "c++_file.h"
int CPlusPlusClass::Add(int a, int b)
{
return a + b;
}

(3)c++_file.h

#pragma once
class CPlusPlusClass
{
public:
// 测试对C++模块中定义的Class的调用
int Add(int a, int b);
};

(4)Program.cs

CPlusPlusClass fromCPlusPlus = new CPlusPlusClass();
Console.WriteLine("1+2=" + fromCPlusPlus.Add(1,2));
Console.ReadKey();

3、build .idl接口文件。在.cpp所在目录下用命令框输入
D:\SDK\swigwin-3.0.12\swig.exe -csharp -c++ c++_file.idl
回车后会发现当前文件夹中出现以下几个文件:

4、分别在c++项目和c#项目中引用各自需要的文件,引用完后,应该和如下图一样。

5、在生成dll之前,先将.idl文件的属性改为如下图所示:

6、生成c++ dll:重新生成 c++项目即可,在debug文件夹中会发现有一个c++_project.dll文件,说明生成成功。
7、运行c#项目,将c#项目设为启动项。将c++_project.dll该名为.idl文件中的module名(cppdll.dll),并放入bin/debug/中.如下图所示:

8、然后直接运行可得如下结果:

swig需要注意的几点:

  • 装swig时需注意:windows安装swigwin版本的,否则会找不到swig命令。
  • “cppPINVOKE”的类型初始值设定项引发异常。原因:未找到所要调用的dll文件,需要手动将dll文件名改为module名。
  • 报错:“cppPINVOKE”的类型初始值设定项引发异常。解决方案:生成dll的工程平台要与c#的活动解决方案平台保持一致,否则就会报此错误。(注:有的时候vs上面显示的并不是你真正的所在平台,你必须在属性页面查看,尤其是csharp项目平台)
  • 报错‘possibly a missing semicolon’,原因:可能由于.h文本里面嵌套着.h文本。解决方案:https://stackoverflow.com/questions/28523496/syntax-error-when-include-opencv-core-hpp-in-swig
  • Error: Syntax error in inputs(3)。解决方案:在.idl文件中还得include本身.h文件里包含的那些.h文件。
  • Syntax error in inputs(3),在引别的.h文件时把__declspec(dllexport)前缀给去了。
  • C++中添加库目录,调用的不一定是库目录里的dll,但是放在工程项目中的release下的dll,一定能被调用。
  • 如果生成dll时调用了别的dll的时候记得把dll一起拷到bin目录下。

难点。

Intptr参数的转换:
Intptr是c#中的句柄,有点类似于c++指针,但又不是一个东西,指针指向的是一个地址,但是Intptr只是某个资源的编号。
这个也是最不可控的一点,我在这上面花费了很大的精力。我准备是利用swig将c++实现的人脸识别代码用c#来调用,因为c#做壳子挺方便的。但是我通过swig调用的时候,他传入的图像参数类型是intptr的,但是我是bitmap类型的。然后我遇到了一下棘手的问题:

  • 我用GetHbitmap()函数将bitmap变为intptr类型,但发现c++不可访问,
    最后我把bitmap先转为byte[]类型,然后再转成inptr类型就成功了。

最后我也把我解决这个问题的代码贴出来吧:
(1)BitmapExtensions.cs:

internal static class BitmapExtensions
{
/// <summary>
/// 将图像转换为RGB图像
/// </summary>
/// <param name="self"></param>
/// <returns></returns>
public static Bitmap ConvertToRgb24(this Bitmap self)
{
if (self.PixelFormat != PixelFormat.Format24bppRgb)
{
var convertImage = new Bitmap(self.Width, self.Height, PixelFormat.Format24bppRgb);
using (var g = Graphics.FromImage(self))
{
g.DrawImage(self, 0, 0);
} return convertImage;
}
return self;
} /// <summary>
/// 获取位图数据的像素数据
/// </summary>
/// <param name="self"></param>
/// <param name="useNativePixelFormat"></param>
/// <param name="pixelSize"></param>
/// <returns></returns>
public static byte[] GetBitmapData(this Bitmap self, out int pixelSize, bool useNativePixelFormat = false)
{
var rect = new Rectangle(0, 0, self.Width, self.Height);
var bmpData = self.LockBits(rect, ImageLockMode.ReadOnly,
useNativePixelFormat ? self.PixelFormat : PixelFormat.Format24bppRgb);
var dataPtr = bmpData.Scan0;
var bytesCount = Math.Abs(bmpData.Stride) * self.Height; var data = new byte[bytesCount];
Marshal.Copy(dataPtr, data, 0, bytesCount); self.UnlockBits(bmpData); pixelSize = bmpData.Stride / bmpData.Width; return data;
}
}

外部实现代码:

Bitmap gray = new Bitmap(image.Width, image.Height, PixelFormat.Format8bppIndexed);
gray = new Grayscale(0.2125, 0.7154, 0.0721).Apply(image);
int pixelSize;
var imageData = BitmapExtensions.GetBitmapData(gray,out pixelSize,true);
var pImageData = Marshal.AllocHGlobal(imageData.Length); //未释放
Marshal.Copy(imageData, 0, pImageData, imageData.Length);

待参考网址:

http://www.swig.org/ (官网)
http://blog.csdn.net/lee353086/article/details/40707305 (建立一个示例)
http://www.technical-recipes.com/2013/getting-started-with-swig-interfacing-between-c-and-c-visual-studio-projects/ (建立一个示例)
http://www.swig.org/Doc1.3/CSharp.html#csharp_directors_example (讲解swig与c#)

良心教程(建议英语好的可以看这个教程,官网教程太含糊了):
http://www.jenkinssoftware.com/raknet/manual/swigtutorial.html

https://blog.csdn.net/liu14lang/article/details/78882539

c#利用SWIG调用c++dll学习总结【转】的更多相关文章

  1. 利用OllyDebug查看程序调用的dll模块

    最近在做一个Qt项目,在产品发布的时候一直为找不到程序到底缺少了哪些dll组件而困扰.具体问题是,在我的项目中使用到了QMediaPlayer播放一段音频文件,我使用的开发环境的Win7 32位,而在 ...

  2. 利用Swig转换C++代码为C#可用的代码

    详细的文件路径为:http://user.qzone.qq.com/1259374136/blog/1432887689 Swig学习教程 1.Swig的基本介绍 SWIG(Simplified Wr ...

  3. Native Application 开发详解(直接在程序中调用 ntdll.dll 中的 Native API,有内存小、速度快、安全、API丰富等8大优点)

    文章目录:                   1. 引子: 2. Native Application Demo 展示: 3. Native Application 简介: 4. Native Ap ...

  4. c#利用IronPython调用python的过程种种问题

    c#利用IronPython调用python的过程种种问题 小菜鸟一枚,最新学习了Python,感觉语言各种简短,各种第三方类库爽歪歪,毕竟之前是从c#转来的,看到Python的request类各种爽 ...

  5. dll学习

    Dll:动态链接库 动态链接库(dll)是包含共享函数库的二进制文件,可以被多个应用程序同时使用.建立应用程序的可执行文件时,不必将DLL连接到应用程序中,而是在运行时动态装载DLL,装载时DLL被映 ...

  6. C#调用C++ DLL类方法

    C++的优势在于高效灵活,C#的优势在于简单易用,两者结合起来对项目开发来说是件好事,而且C++不容易反编译,也保障了代码的安全性,如果一些核心算法使用C#编写,那么保密就是一个问题. C++生成的D ...

  7. paip.java 调用c++ dll so总结

    paip.java 调用c++ dll so总结 ///////JNA (这个ms sun 的) 我目前正做着一个相关的项目,说白了JNA就是JNI的替代品,以前用JNI需要编译一层中间库,现在JNA ...

  8. C#调用C++ DLL 文件

    说来惭愧,都注册一年多了,却没有发表过一篇正式的博文,中间很多学习的过程也没有记录下来.如今到了一个新的环境,也有了学习的机会,一定要把每天的收获记录一下. 要做的东西需要引用C++编写的DLL,刚开 ...

  9. 【JNI】OPUS压缩与解压的JNI调用(.DLL版本)

    OPUS压缩与解压的JNI调用(.DLL版本) 一.写在开头: 理论上讲,这是我在博客园的第一篇原创的博客,之前也一直想找个地方写点东西,把最近做的一些东西归纳总结下,但是一般工程做完了一高兴就把东西 ...

随机推荐

  1. Redis高可用之集群配置(六)

    0.Redis目录结构 1)Redis介绍及部署在CentOS7上(一) 2)Redis指令与数据结构(二) 3)Redis客户端连接以及持久化数据(三) 4)Redis高可用之主从复制实践(四) 5 ...

  2. 使用Metasploit工作区

    使用Metasploit工作区   Metasploit将所有数据都存储在PostgeSQL服务器中的msf数据库.渗透测试人员经常要使用Metasploit同时执行多个任务.为了避免数据混杂,Met ...

  3. DrawFrameControl 绘制标准控件

    BOOL DrawFrameControl( HDC hDC,        // 设备环境句柄    LPRECT lpRect,  // 矩形区域    UINT nType,     // 控件 ...

  4. 微信小程序自定义组件封装及父子间组件传值

    首先在我们可以直接写到需要的 page 中,然后再进行抽取组件,自定义组件建议 wxzx-xxx 命名 官网地址:https://developers.weixin.qq.com/miniprogra ...

  5. [Go] 子类 调用 父类 的 属性、方法

    package main import ( "fmt" ) type A struct { Text string Name string } func (a *A) Say() ...

  6. Java学习笔记八(反射)

    1.介绍 反射为Java程序在执行时提供了动态的能力.利用反射能够在执行时对程序进行动态的控制.本篇博客着重解说一下Java中的反射. 2.Class类的使用 在Java执行过程中,每一个类被载入后都 ...

  7. 采用模拟账号读取Exchange server未读邮件的注意事项(链接邮箱问题)【转】

    最近做项目碰到Exchange中,用EWS API方法读取的未读邮箱(ConnectingIdType.PrincipalName设置该属性的方法)附带代码部分: 核心代码 using Microso ...

  8. 使用EF Code First搭建一个简易ASP.NET MVC网站,允许数据库迁移

    本篇使用EF Code First搭建一个简易ASP.NET MVC 4网站,并允许数据库迁移. 创建一个ASP.NET MVC 4 网站. 在Models文件夹内创建Person类. public ...

  9. DotNetty 学习

    [转载]http://www.cnblogs.com/littlegod/p/7699482.html DotNetty的学习是带着如下这些问题展开: 1. Socket基础框架方案: 通信模式:异步 ...

  10. mysql between and 遇到日期查询边界问题

    最近实现一个按日期范围查询列表,例如输入的是日期 2015-11-01到2015-11-03,想得到1号到3号的数据, 执行 select * from table where create_date ...