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#分类目录,贴了, , 标签。将固定链接加入收藏夹。

发表评论