C#調用非託管C++的DLL檔案函數

來源:互聯網
上載者:User

extern "C" __declspec(dllexport) int __stdcall testfunc(char* astr,int* a);
 

extern ”C”

  通常來說,C++編譯器可能會改變函數和變數的名字,從而導致嚴重的連結程式問題。例如,假設使用C++編寫一個DLL,當建立DLL時,Microsoft的編譯器就會改變函數的名字。函數名將被設定一個前置底線,再加上一個@符號的首碼,後隨一個數字,表示作為參數傳遞給函數的位元組數。例如,下面的函數是作為DLL的輸出節中的_MyFunc@8輸出的:

__declspec(dllexport) LONG __stdcall MyFunc(int a, int b);
  如果用另一個供應商的工具建立了一個可執行模組,它將設法連結到一個名叫MyFunc的函數,該函數在Microsoft編譯器已有的DLL中並不存在,因此連結將失敗。

  使用extern “C”關鍵字可以使編譯器按照C語言的方式編譯DLL檔案,即編譯時間不改變函數名。

 

__declspec(dllexport)

  在 32 位編譯器版本中,可以使用__declspec(dllexport) 關鍵字從DLL匯出資料、函數、類或類成員函數。__declspec(dllexport) 會將匯出指令添加到對象檔案中,因此不需要使用.def檔案。

  若要匯出函數,__declspec(dllexport) 關鍵字必須出現在呼叫慣例關鍵字的左邊(如果指定了關鍵字)。例如:

__declspec(dllexport) void __cdecl Function1(void);
 

__stdcall

  表明被呼叫者清理堆棧。

 

C#中的函式宣告
using System.Runtime.InteropServices;
      …

public class Program
{
[DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
public static extern int testfunc(StringBuilder abuf,ref int a);
}

using System.Runtime.InteropServices;

  System.Runtime.InteropServices 命名空間提供各種各樣支援 COM interop 及平台叫用服務的成員,使程式可以與Unmanaged 程式碼進行互動操作。

 

[DllImport(“dllfile path”)]

  代碼中DllImport關鍵字作用是告訴編譯器進入點在哪裡,並將打包函數捆綁在這個類中。在聲明的時候還可以添加幾個屬性:

[DllImport("MyDLL.dll",
EntryPoint="mySum",
CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
  EntryPoint: 指定要調用的 DLL 進入點。預設進入點名稱是託管方法的名稱 。
  CharSet: 控制名稱重整和封送 String 參數的方式 (預設是UNICODE)
  CallingConvention指示進入點的函數呼叫慣例(預設WINAPI)

  注意:必須在標記為”static”和”extern”的方法上指定”DllImport”屬性。

 

資料傳遞方法
1.基礎資料型別 (Elementary Data Type)的傳遞
  函數參數和傳回值可以是C#和C++的各種基礎資料型別 (Elementary Data Type),如int, float, double, char(注意不是char*)等。
  樣本:
  C#代碼:

using System;
using System.Text;
using System.Runtime.InteropServices;

class Program
{
    [DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
    public static extern int testfunc(int a,float b,double c,char d);

    static void Main(string[] args)
    {
        int a = 1;
        float b = 12;
        double c = 12.34;
        char d = ‘A‘;
        testfunc(a,b,c,d);
        Console.ReadKey();
    }
}
  C++代碼:

#include <iostream>
using namespace std;

extern "C"
{
 _declspec(dllexport) int __stdcall testfunc(int a,float b,double c,char d)
 {
  cout<<a<<", "<<b<<", "<<c<<", "<<d<<endl;
  return 0;
 }
}

2.向DLL傳入字串
  C#中使用string定義字串,將字串對象名傳給DLL。
  注意:在DLL中更改字串的值,C#中的值也會改變。
  缺點:無法改變字串的長度,建議使用第3種方法。
  C#代碼:

using System;
using System.Text;
using System.Runtime.InteropServices;

class Program
{
    [DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
    public static extern int testfunc(string a);

    static void Main(string[] args)
    {
        string a="Hello World!";
        testfunc(a);
        Console.ReadKey();
    }
}  C++代碼:

#include <iostream>
using namespace std;

extern "C"
{
 _declspec(dllexport) int __stdcall testfunc(char* astr)
 {
  cout<<astr<<endl;
  *astr=‘A‘;//更改字串的資料
  cout<<astr<<endl;
  return 0;
 }
}

3.DLL傳出字串
  C#中使用StringBuilder對象建立變長數組,並設定StringBuilder的Capacity為數組最大長度。將此對象名傳遞給DLL,使用char*接收。
  C#代碼:

using System;
using System.Text;
using System.Runtime.InteropServices;

class Program
{
    [DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
    public static extern int testfunc(StringBuilder abuf);

    static void Main(string[] args)
    {
        StringBuilder abuf=new StringBuilder();
        abuf.Capacity = 100;//設定字串最大長度
        testfunc(abuf);
        Console.ReadKey();
    }
   
}  C++代碼:

#include <iostream>
using namespace std;

extern "C"
{
 _declspec(dllexport) int __stdcall testfunc(char* astr)
 {
  *astr++=‘a‘;
  *astr++=‘b‘;//C#中abuf隨astr改變
  *astr=‘\0‘;

  return 0;
 }
}

4.DLL傳遞結構體(需要在C#中重新定義,不推薦使用)
  C#中使用StructLayout重新定義需要使用的結構體。
  注意:在DLL改變結構體成員的值,C#中隨之改變。
  C#代碼:

using System;
using System.Text;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct Point
{
    public double x;
    public double y;
}

class Program
{
    [DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
    public static extern int testfunc(Point p);

    static void Main(string[] args)
    {
        Point p;
        p.x = 12.34;
        p.y = 43.21;
        testfunc(p);
        Console.ReadKey();
    }   
}

C++代碼:

#include <iostream>
using namespace std;

struct Point
{
    double x;
    double y;
};

extern "C"
{
 _declspec(dllexport) int __stdcall testfunc(Point p)
 {
  cout<<p.x<<", "<<p.y<<endl;
  return 0;
 }
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.