C#調(diào)用C/C++動(dòng)態(tài)庫 封送結(jié)構(gòu)體,結(jié)構(gòu)體數(shù)組 因?yàn)楣疽恢倍际亲鯟++開發(fā)的,因客戶需要要提供C#版本接口,研究了一下C#,發(fā)現(xiàn)其強(qiáng)大簡(jiǎn)潔, 在跨語言調(diào)用方面封裝的很徹底,提供了強(qiáng)大的API與之交互.這點(diǎn)比JNA方便多了. java與C#都只能調(diào)用C格式導(dǎo)出動(dòng)態(tài)庫,因?yàn)镃數(shù)據(jù)類型比較單一,容易映射. 兩者都是在本地端提供一套與之映射的C#/java描述接口,通過底層處理這種映射關(guān)系達(dá)到調(diào)用的目的.
一.結(jié)構(gòu)體的傳遞
Cpp代碼
- #defineJNAAPIextern"C"__declspec(dllexport)//C方式導(dǎo)出函數(shù)
- typedefstruct
- {
- intosVersion;
- intmajorVersion;
- intminorVersion;
- intbuildNum;
- intplatFormId;
- charszVersion[128];
- }OSINFO;
- //1.獲取版本信息(傳遞結(jié)構(gòu)體指針)
- JNAAPIboolGetVersionPtr(OSINFO*info);
- //2.獲取版本信息(傳遞結(jié)構(gòu)體引用)
- JNAAPIboolGetVersionRef(OSINFO&info);
可以通過二種方式來調(diào)用:
C#代碼
- //OSINFO定義
- [StructLayout(LayoutKind.Sequential)]
- publicstructOSINFO
- {
- publicintosVersion;
- publicintmajorVersion;
- publicintminorVersion;
- publicintbuildNum;
- publicintplatFormId;
- [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]
- publicstringszVersion;
- }
1. 方式一(傳入結(jié)構(gòu)體引用),在C#中,結(jié)構(gòu)體是以傳值方式傳遞,類才是以傳地址方式傳遞,加關(guān)鍵字ref即可. C端傳遞了兩種不同類型的參數(shù),都可以通過引用來解決.
C#代碼
- [DllImport("jnalib.dll",EntryPoint="GetVersionPtr")]
- publicstaticexternboolGetVersionPtr(refOSINFOinfo);
- publicstaticexternboolGetVersionRef(refOSINFOinfo);
2. 方式二(傳入IntPtr(平臺(tái)通用指針))
Cpp代碼
- IntPtrpv=Marshal.AllocHGlobal(148);//結(jié)構(gòu)體在使用時(shí)一定要分配空間(4*sizeof(int)+128)
- Marshal.WriteInt32(pv,148);//向內(nèi)存塊里寫入數(shù)值
- if(GetVersionPtr(pv))//直接以非托管內(nèi)存塊地址為參數(shù)
- {
- Console.WriteLine("--osVersion:{0}",Marshal.ReadInt32(pv,0));
- Console.WriteLine("--Major:{0}",Marshal.ReadInt32(pv,4));//移動(dòng)4個(gè)字節(jié)
- Console.WriteLine("--BuildNum:"+Marshal.ReadInt32(pv,12));
- Console.WriteLine("--szVersion:"+Marshal.PtrToStringAnsi((IntPtr)(pv.ToInt32()+20)));
- }
- Marshal.FreeHGlobal(pv);//處理完記得釋放內(nèi)存
二.結(jié)構(gòu)體數(shù)組的傳遞
Cpp代碼
- //傳遞結(jié)構(gòu)體指針
- JNAAPIboolGetVersionArray(OSINFO*info,intnLen);
調(diào)用代碼:
C#代碼
- /**
- *C#接口,對(duì)于包含數(shù)組類型,只能傳遞IntPtr
- */
- [DllImport("jnalib.dll",EntryPoint="GetVersionArray")]
- publicstaticexternboolGetVersionArray(IntPtrp,intnLen);
- //源目標(biāo)參數(shù)
- OSINFO[]infos=newOSINFO[2];
- for(inti=0;i<infos.Length;i++)
- {
- infos[i]=newOSINFO();
- }
- IntPtr[]ptArr=newIntPtr[1];
- ptArr[0]=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO))*2);//分配包含兩個(gè)元素的數(shù)組
- IntPtrpt=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO)));
- Marshal.Copy(ptArr,0,pt,1);//拷貝指針數(shù)組
- GetVersionArray(pt,2);//調(diào)用
- //還原成結(jié)構(gòu)體數(shù)組
- for(inti=0;i<2;i++)
- {
- infos[i]=(OSINFO)Marshal.PtrToStructure((IntPtr)(pt.ToInt32()+i*Marshal.SizeOf(typeof(OSINFO))),typeof(OSINFO));
- Console.WriteLine("OsVersion:{0}szVersion:{1}",infos[i].osVersion,infos[i].szVersion);
- }
三.復(fù)雜結(jié)構(gòu)體的傳遞
1. 輸出參數(shù),結(jié)構(gòu)體作為指針傳出
Cpp代碼
- typedefstruct
- {
- charname[20];
- intage;
- doublescores[30];
- }Student;
- //Class中包含結(jié)構(gòu)體數(shù)組類型
- typedefstruct
- {
- intnumber;
- Studentstudents[50];
- }Class;
- //傳入復(fù)雜結(jié)構(gòu)體測(cè)試
- JNAAPIintGetClass(Class*pClass,intlen);
Cpp代碼
- //接口定義
- [DllImport("jnalib.dll",EntryPoint="GetClass")]
- publicstaticexternintGetClass(IntPtrpv,intlen);
- //結(jié)構(gòu)體定義
- //Student
- [StructLayout(LayoutKind.Sequential)]
- publicstructStudent
- {
- [MarshalAs(UnmanagedType.ByValTStr,SizeConst=20)]
- publicstringname;
- publicintage;
- [MarshalAs(UnmanagedType.ByValArray,SizeConst=30)]
- publicdouble[]scores;
- }
- //Class
- [StructLayout(LayoutKind.Sequential)]
- publicstructClass
- {
- publicintnumber;
- [MarshalAs(UnmanagedType.ByValArray,SizeConst=50)]//指定數(shù)組尺寸
- publicStudent[]students;//結(jié)構(gòu)體數(shù)組定義
- }
- //調(diào)用復(fù)雜結(jié)構(gòu)體測(cè)試
- intsize=Marshal.SizeOf(typeof(Class))*50;
- IntPtrpBuff=Marshal.AllocHGlobal(size);//直接分配50個(gè)元素的空間,比Marshal.copy方便多了
- GetClass(pBuff,50);
- Class[]pClass=newClass[50];
- for(inti=0;i<50;i++)
- {
- IntPtrptr=newIntPtr(pBuff.ToInt64()+Marshal.SizeOf(typeof(Class))*i);
- pClass[i]=(Class)Marshal.PtrToStructure(ptr,typeof(Class));
- }
- Marshal.FreeHGlobal(pBuff);//釋放內(nèi)存
2. 輸入?yún)?shù), 給復(fù)雜結(jié)構(gòu)體賦值后作為輸入?yún)?shù)傳入
對(duì)于比較大的結(jié)構(gòu)體指針,無法直接應(yīng)用結(jié)構(gòu)體類型,轉(zhuǎn)化成IntPtr類型, 此時(shí)需要將原生類型轉(zhuǎn)化為指針,并給指針賦值
調(diào)用方法: Marshal.StructureToPtr(stu, ptr1, true)