CAD工具之家's Archivers

From boitboy on 2015-06-10 14:42:10

C#调用C++DLL

在合作开发时,C#时常需要调用C++DLL,当传递参数时时常遇到问题,尤其是传递和返回字符串是,现总结一下,分享给大家 C#调用C++一般分为两种方式 静态调用和动态调用,两种方式各有利弊,下文会一一论述。 【一】C++中公布方法供DotNet调用 extern "C" {  void WINAPI  Test1(LPCTSTR str)  {   AfxMessageBox(str);  }  void WINAPI Test2(LPTSTR str)  {   lstrcpy(str,_T("我是测试的cadgj.com"));  } } 在.def文件中增加两行     Test1     Test2 这样方法Test1和Test2就分别被公布出来了,可以由外部调用。 【二】C#调用 (1)静态方法 通过DllImport实现 如需调用上面公开的方法Test1,只需要在相应的类中申明 [DllImport("InvokeDll.dll",EntryPoint="Test1",CharSet=CharSet.Unicode)]         public static extern void Test1(string str); 就可以直接调用C++的方法Test1。 利:使用非常方便,代码简洁。 弊:DllImport导入的DLL的路径必须是已知的,必须部署在exe文件同目录下。或者部署在system32目录下,如果是其它路径则必须使用全路径,比较不灵活。 (2)动态方法 通过Kernel32.dll中提供的方法LoadLibrary,FreeLibrary加载和释放C++的dll然后通过GetProcAddress得到函数指针。通过Marshal.GetDelegateForFunctionPointer转换成委托。 然后调用委托即可。 利:和静态方法相反,部署灵活,可以讲引用的C++ dll放置在任何地方,但是如果这个C++的dll也引用了其它dll,可能需要先加载这些引用的dll,不然单纯的放在dll一起,因为您启动的exe的程序目录不在同一个地方。 弊:使用较为繁琐,所有方法必须转换成委托。 二者的运行效率没有做具体的测试,但是实现机理类似,DllImport可以视为一种DotNet提供的简化版调用,所以我认为二者的运行效率应该相差不大。有兴趣的朋友可以测试一下。  关于C#和C++的类型对应请参见文章:C#与C++之间类型的对应 下面贴上DotNet的全套代码。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.IO; namespace InvokeTest {     public partial class Form1 : Form     {         public Form1()         {             InitializeComponent();         }         [DllImport("InvokeDll.dll",EntryPoint="Test1",CharSet=CharSet.Unicode)]         public static extern void Test1(string str);         [DllImport("InvokeDll.dll", EntryPoint = "Test2", CharSet = CharSet.Unicode)]         public static extern void Test2(StringBuilder sb);         private void button1_Click(object sender, EventArgs e)         {             // 静态调用             Test1("测试cadgj.com");             StringBuilder sb = new StringBuilder(200);             Test2(sb);             MessageBox.Show(sb.ToString());         }         private void button2_Click(object sender, EventArgs e)         {              //动态调用             InvokeDllInvoke.DllFileName = Path.Combine(Application.StartupPath, "InvokeDll.dll");             InvokeDllInvoke.InitModule();             InvokeDllInvoke.Test1("测试cadgj.com");             StringBuilder sb = new StringBuilder(200);             InvokeDllInvoke.Test2(sb);             MessageBox.Show(sb.ToString());             InvokeDllInvoke.UnInitModule();         }     }     public class DLLWrapper     {         ///<summary>         /// API LoadLibrary         ///</summary>         [DllImport("Kernel32")]         public static extern int LoadLibrary(String funcname);         ///<summary>         /// API GetProcAddress         ///</summary>         [DllImport("Kernel32")]         public static extern int GetProcAddress(int handle, String funcname);         ///<summary>         /// API FreeLibrary         ///</summary>         [DllImport("Kernel32")]         public static extern int FreeLibrary(int handle);         ///<summary>         /// 通过非托管函数名转换为对应的委托         ///</summary>         ///<param name="dllModule">通过 LoadLibrary 获得的 DLL 句柄</param>         ///<param name="functionName">非托管函数名</param>         ///<param name="t">对应的委托类型</param>         ///<returns>委托实例,可强制转换为适当的委托类型</returns>         public static Delegate GetFunctionAddress(int dllModule, String functionName, Type t)         {             int address = GetProcAddress(dllModule, functionName);             if (address == 0)                 return null;             else                 return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);         }         ///<summary>         /// 将表示函数地址的 intPtr 实例转换成对应的委托         ///</summary>         public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)         {             if (address == IntPtr.Zero)                 return null;             else                 return Marshal.GetDelegateForFunctionPointer(address, t);         }         ///<summary>         /// 将表示函数地址的 int  转换成对应的委托         ///</summary>         public static Delegate GetDelegateFromintPtr(int address, Type t)         {             if (address == 0)                 return null;             else                 return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);         }     }     public static class InvokeDllInvoke     {         /// <summary>         /// DLL文件名称         /// </summary>         public static string DllFileName = "";         /// <summary>         /// DLL实例         /// </summary>         private static int hModule = -1;         /// <summary>         /// 初始化实例         /// </summary>         /// <returns></returns>         public static bool InitModule()         {             if (hModule > 0)             {                 return true;             }             hModule = DLLWrapper.LoadLibrary(DllFileName);             if (hModule == 0)                 return false;             return true;         }         /// <summary>         /// 卸载实例         /// </summary>         /// <returns></returns>         public static bool UnInitModule()         {             if (hModule == 0)                 return false;             DLLWrapper.FreeLibrary(hModule);             hModule = 0;             return true;         }         private delegate void DTest1([MarshalAs(UnmanagedType.LPWStr)] string str);         private delegate void DTest2([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);         public static void Test1(string str)         {             DTest1 d = (DTest1)DLLWrapper.GetFunctionAddress(hModule, "Test1", typeof(DTest1));             if (d == null)                 return;             d(str);         }         public static void Test2(StringBuilder sb)         {             DTest2 d = (DTest2)DLLWrapper.GetFunctionAddress(hModule, "Test2", typeof(DTest2));             if (d == null)                 return;             d(sb);         }     } }

查看完整版本: C#调用C++DLL

Tags: c# 调用c++ dll, 动态, 静态


©CAD工具之家
创办于:2013年5月24日