C#调用C++ Dll


现在项目基本都是旁边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 }

还说那句话:种一棵树最好的时间是十年前,其次是现在。

WPF