c#利用SWIG調用c++dll學習總結【轉】

開發環境:

操做系統:windows 7
IDE:Microsoft Visual Studio Professional 2015
SWIG: 3.0.12html

swig的介紹

詳細介紹可看官網,一下貼出官網上的原話:c++

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.express

如下是個人理解(注:如下這段話並非上段話的翻譯):
Swig主要是爲了將c++/c中的代碼所實現的功能移植到別的語言上。通常咱們要將c++/c移植到別的語言上,基本操做是將c++中的實現代碼轉變成dll,而後再供別的語言調用,這樣安全性高,且易於調用。可是由於各類語言不相同,若是不借助swig,本身去封裝。在調用dll時就會有不少類型(包括基本類型,結構體和類)轉換須要注意,好比c#調c++ dll,可能得本身造一個相對應與c++的結構體和類才能成功調用。可是若是咱們用了swig,這些咱們都不用考慮,咱們只須要考慮swig給咱們的接口類型是什麼,而後咱們只要按照swig給的接口類型傳入參數,就OK了。說白了就是swig代替了咱們利用c#去從新定義dll中所須要傳入的參數類型(如結構體或類)這個工做。c#

swig實現步驟

swig的安裝:

進入以下網址:http://www.swig.org/download.html
因爲我是windows系統,因此安裝以下版本:
這裏寫圖片描述
下載後,將其解壓至制定目錄,如:D:\SDK\swigwin-3.0.12windows

一、創建以下c++項目(應用程序類型選擇dll類型)和c#項目,還沒實現代碼,都是空項目。主要有.h .cpp .idl .cs文件(具體這四個文件怎麼建立我就不贅述了,想必能找到這篇博文就說明已具有了建立此文件的能力)。
這裏寫圖片描述安全

二、填寫代碼:
(1) c++_file.idl:
(網上說的都是.i文件,其實就是vs裏的.idl文件)ide

%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.hvisual-studio

#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();

三、build .idl接口文件。在.cpp所在目錄下用命令框輸入
D:\SDK\swigwin-3.0.12\swig.exe -csharp -c++ c++_file.idl
回車後會發現當前文件夾中出現如下幾個文件:
這裏寫圖片描述

四、分別在c++項目和c#項目中引用各自須要的文件,引用完後,應該和以下圖同樣。
這裏寫圖片描述

五、在生成dll以前,先將.idl文件的屬性改成以下圖所示:
這裏寫圖片描述

六、生成c++ dll:從新生成 c++項目便可,在debug文件夾中會發現有一個c++_project.dll文件,說明生成成功。
七、運行c#項目,將c#項目設爲啓動項。將c++_project.dll該名爲.idl文件中的module名(cppdll.dll),並放入bin/debug/中.以下圖所示:
這裏寫圖片描述

八、而後直接運行可得以下結果:
這裏寫圖片描述

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

相關文章
相關標籤/搜索