現在項目基本都是旁邊C++的哥們做好dll扔給我,然後我調用。好久之前晚上down了一份c#調用c++dll的方法,出處早已經遺忘。閒來無事,放上來好了。原作者看到後可以留言,我會把您鏈接放上的,幫了我很多!!!
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Reflection.Emit; 6 using System.Runtime.InteropServices; 7 using System.Text; 8 9 namespace TEDS_App 10 { 11 public enum ModePass 12 { 13 ByValue = 0x0001, 14 ByRef = 0x0002 15 } 16 public class FaultFunc 17 { 18 [DllImport("kernel32.dll")] 19 static extern IntPtr LoadLibrary(string lpFileName); 20 [DllImport("kernel32.dll")] 21 static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); 22 [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)] 23 static extern bool FreeLibrary(IntPtr hModule); 24 private IntPtr hModule = IntPtr.Zero; 25 private IntPtr farProc = IntPtr.Zero; 26 public void LoadDll(string lpFileName) 27 { 28 hModule = LoadLibrary(lpFileName); 29 if (hModule == IntPtr.Zero) 30 { 31 throw (new Exception("沒有找到:" + lpFileName + ".")); 32 } 33 } 34 public void LoadDll(IntPtr HMODULE) 35 { 36 if (HMODULE == IntPtr.Zero) 37 { 38 throw (new Exception("所傳入的函數庫模塊的句柄為空")); 39 } 40 hModule = HMODULE; 41 } 42 public void LoadFun(string lpProcName) 43 { 44 if (hModule == IntPtr.Zero) 45 { 46 throw (new Exception("函數庫模塊的句柄為空,確保已進行加載dll操作")); 47 } 48 farProc = GetProcAddress(hModule, lpProcName); 49 if (farProc == IntPtr.Zero) 50 { 51 throw (new Exception("沒有找到:" + lpProcName + "這個函數的入口點")); 52 } 53 } 54 public void LoadFun(string lpFileName, string lpProcName) 55 { 56 hModule = LoadLibrary(lpFileName); 57 if (hModule == IntPtr.Zero) 58 { 59 throw (new Exception("沒有找到:" + lpFileName + ".")); 60 } 61 farProc = GetProcAddress(hModule, lpFileName); 62 if (farProc == IntPtr.Zero) 63 { 64 throw (new Exception("沒有找到:" + lpProcName + "這個函數的入口點")); 65 } 66 } 67 public void UnLoadDll() 68 { 69 FreeLibrary(hModule); 70 hModule = IntPtr.Zero; 71 farProc = IntPtr.Zero; 72 } 73 public object Invoke(object[] ObjArray_Parameter, Type[] TypeArray_parameterType, ModePass[] ModePassArray_Parameter, Type Type_Return) 74 { 75 if (hModule == IntPtr.Zero) 76 throw (new Exception("函數庫模塊的句柄為空,請確保進行了LoadLll操作")); 77 if (farProc == IntPtr.Zero) 78 throw (new Exception("函數指針為空,請確保已進行LoadFun操作")); 79 if (ObjArray_Parameter.Length != ModePassArray_Parameter.Length) 80 throw (new Exception("參數個數及其傳遞方式的個數不匹配")); 81 AssemblyName MyAssemblyName = new AssemblyName(); 82 MyAssemblyName.Name = "InvokeFun"; 83 AssemblyBuilder MyAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName, AssemblyBuilderAccess.Run); 84 ModuleBuilder MyModuleBuilder = MyAssemblyBuilder.DefineDynamicModule("InvokeDll"); 85 MethodBuilder MyMethodBuilder = MyModuleBuilder.DefineGlobalMethod("FaultFun", MethodAttributes.Public | MethodAttributes.Static, Type_Return, TypeArray_parameterType); 86 ILGenerator IL = MyMethodBuilder.GetILGenerator(); 87 int i; 88 for (i = 0; i < ObjArray_Parameter.Length; i++) 89 { 90 switch (ModePassArray_Parameter[i]) 91 { 92 case ModePass.ByValue: 93 IL.Emit(OpCodes.Ldarg, i); 94 break; 95 case ModePass.ByRef: 96 IL.Emit(OpCodes.Ldarga, i); 97 break; 98 default: 99 throw (new Exception("第" + (i + 1).ToString() + "個參數沒有給定正確的傳遞方式")); 100 } 101 } 102 if (IntPtr.Size == 4) 103 { 104 IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32()); 105 } 106 else if (IntPtr.Size == 8) 107 { 108 IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64()); 109 } 110 else 111 { 112 throw new PlatformNotSupportedException(); 113 } 114 IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, Type_Return, TypeArray_parameterType); 115 IL.Emit(OpCodes.Ret); 116 MyModuleBuilder.CreateGlobalFunctions(); 117 MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("FaultFun"); 118 return MyMethodInfo.Invoke(null, ObjArray_Parameter); 119 } 120 public object Invoke(IntPtr IntPtr_Function, object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return) 121 { 122 if (hModule == IntPtr.Zero) 123 throw (new Exception("函數庫模塊的句柄為空,請確保已進行LoadDll操作")); 124 if (IntPtr_Function == IntPtr.Zero) 125 throw (new Exception("函數指針IntPtr_Function為空")); 126 farProc = IntPtr_Function; 127 return Invoke(ObjArray_Parameter, TypeArray_ParameterType, ModePassArray_Parameter, Type_Return); 128 } 129 } 130 131 }
一直以來,對於C++程序員報以崇高的敬意。。。一直覺得他們屌屌的,哈哈。
調用方式如下:
1 PlusFunction.LoadDll(@"C:\win32dll.dll");//PlusFunction為調用類的實例 2 PlusFunction.LoadFun("MyFun"); 3 byte[] a = File.ReadAllBytes(@"E:\19-bw\19-73.jpg"); 4 object[] Parameters = new object[] {a}; // 實參為a 5 Type[] ParameterTypes = new Type[] { typeof(byte[])}; // 實參類型為byte[] 6 ModePass[] themode = new ModePass[] {ModePass.ByValue}; // 傳送方式為值傳 7 Type Type_Return = typeof(int); // 返回類型為int 8 ret = (int)PlusFunction.Invoke(Parameters, ParameterTypes, themode, Type_Return);
其實,c++與c#主要的就是數據類型的對應了。簡單點的還好說,稍微復雜的各種麻煩。。。關鍵是不好調試。
下面舉些我用到的例子,以後遇到其他的再補充。日積月累- -
1 c++ c# 2 char* char[](string.tochararray) 3 byte* byte[] 4 int int 5 int* int[] 6 結構體 7 c++ 8 typedef struct SRectChange_TAG 9 { 10 //NV_RECT rect; 11 int x;//左上角x軸坐標 12 int y;//左上角y軸坐標 13 int width;//寬 14 int height;//高 15 int degree;//報錯級別;1最低,目前暫時設定3級 16 } 17 SRectChange; 18 c# 19 [StructLayout(LayoutKind.Sequential)] 20 public struct SRectChange 21 { 22 public int x; 23 public int y; 24 public int width; 25 public int height; 26 public int degree; 27 } 28 結構體傳遞 29 [DllImport("win32dll.dll", EntryPoint = "MyFun", CallingConvention = CallingConvention.Cdecl)] 30 public static extern int MyFun(ref SRectChange rect, char[] str, char[] str2); 31 c++結構體 32 typedef struct 33 { 34 int osVersion; 35 int majorVersion; 36 int minorVersion; 37 int buildNum; 38 int platFormId; 39 char szVersion[128]; 40 }OSINFO; 41 c# 42 // OSINFO定義 43 [StructLayout(LayoutKind.Sequential)] 44 public struct OSINFO 45 { 46 public int osVersion; 47 public int majorVersion; 48 public int minorVersion; 49 public int buildNum; 50 public int platFormId; 51 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 52 public string szVersion; 53 } 54 55 結構體數組傳遞 56 c#代碼 57 [DllImport("win32dll.dll", EntryPoint = "MyFun", CallingConvention = CallingConvention.Cdecl)] 58 public static extern int MyFun(IntPtr p, char[] str, char[] str2); 59 數組傳指針 60 char[] newpic = ("123123123123").ToCharArray(); 61 char[] oldpic = ("231231234123").ToCharArray(); 62 SRectChange[] rects = new SRectChange[5]; 63 for (int i = 0; i < rects.Length; i++) 64 { 65 rects[i] = new SRectChange(); 66 } 67 IntPtr[] ptArr = new IntPtr[1]; 68 ptArr[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SRectChange)) * 5); //分配包含兩個元素的數組 69 IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SRectChange))); 70 Marshal.Copy(ptArr, 0, pt, 1); //拷貝指針數組 71 MyFun(pt, newpic, oldpic); 72 for (int i = 0; i < 5; i++) 73 { 74 rects[i] = (SRectChange)Marshal.PtrToStructure((IntPtr)(pt.ToInt32() + i * Marshal.SizeOf(typeof(SRectChange))), typeof(SRectChange)); 75 Console.WriteLine("x:{0} y:{1}", rects[i].x, rects[i].y); 76 }
還說那句話:種一棵樹最好的時間是十年前,其次是現在。