C#中使用DLL文件

首先,咱們須要在C++程序中導出DLL文件。我使用的是Visual Studio開發,把項目"屬性"中的「配置類型」改成"動態庫dll",而後添加以下導出代碼:ide

extern "C" __declspec(dllexport) void AS3911FindTag(Tag tags[], int &tagNum, int slot);//find tags
extern "C" __declspec(dllexport) bool GetTagInformation(Tag& tag);//get tag information
extern "C" __declspec(dllexport) int usbDeviceAttached(int waitTime);//initialize usb connect

而後運行程序,能夠找到生成的DLL文件。在C#項目中使用,把DLL文件和生成的exe文件放在一塊兒便可,而後C#中添加頭部引用:函數

using System.Runtime.InteropServices;

類中聲明:工具

[DllImport("AS3911Test.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void AS3911FindTag(IntPtr tags, ref int tagNum, int slot); [DllImport("AS3911Test.dll", CallingConvention = CallingConvention.Cdecl)] public static extern bool GetTagInformation(ref Tag tag);
[DllImport(
"AS3911Test.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int usbDeviceAttached(int waitTime);

聲明後,能夠直接使用這些方法了。不過要注意一點,C#和C++的交互,最麻煩的是數據類型的轉換。我這裏在參數中使用了Tag這個結構體,在C++中以下:ui

struct Tag { char id[20]; char dsfid[4]; char afi[4]; unsigned int blockNum; unsigned int bytesPerBlock; char info[1024]; };

在C#中對應的聲明以下:spa

public struct Tag { /// char[]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 20)] public string id; /// char[]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 4)] public string dsfid; /// char[]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 4)] public string afi; /// unsigned int
public uint blockNum; /// unsigned int
public uint bytesPerBlock; /// char[]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 1024)] public string info; }

注意C#中參數部分的ref,至關於C++中指針。涉及到數據類型對應轉換時,能夠藉助CLRInsideOut這個工具。下面以AS3911FindTag(IntPtr tags, ref int tagNum, int slot)這個函數爲例,看看如何使用。指針

static void FindTag() { ComInit(); usbDeviceAttached(500); ISO15693Init(); int num = 0; int size = Marshal.SizeOf(typeof(Tag)) * Max_Tag_Num; IntPtr pBuff = Marshal.AllocHGlobal(size); Tag[] mytag = new Tag[Max_Tag_Num]; AS3911FindTag(pBuff, ref num, 16); for (int i = 0; i < num; i++) { IntPtr p = new IntPtr(pBuff.ToInt64() + Marshal.SizeOf(typeof(Tag)) * i); mytag[i] = (Tag)Marshal.PtrToStructure(p, typeof(Tag)); Console.WriteLine(mytag[i].id); } Marshal.FreeHGlobal(pBuff); ISO15693DeInit(); usbDeviceDeAttached(); ComDeInit(); }

直接看到AS3911FindTag(pBuff, ref num, 16)這段代碼,這裏的pBuff是C#中的引用,而後用Marshal.AllocHGlobal(size)分配了一塊內存,傳入函數的是一塊內存的引用。第二個參數比較簡單,表示經過該函數給num賦值。AS3911FindTag這個函數運行完後,pBuff所指向的內存塊會被賦值,咱們下面就試着取出數據。咱們使用告終構體Tag並聲明瞭大小,因此能夠從這裏着手解決問題。看到for循環中第二行代碼,這裏的p表示從何處讀取數據,最後作類型轉換可。Marshal.PtrToStructure這個函數能夠將數據從非託管內存塊封送到新分配的指定類型的託管對象,這裏從DLL中的非託管內存封送到當前C#託管內存。最後,用Marshal.FreeHGlobal(pBuff)釋放內存。code

相關文章
相關標籤/搜索