C#调用C++dll小结

最近做了一个工程,用到c#调用c++dll,将遇到的情况作了一些小结,方便学习总结

c#代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Connecter
{
    /// <summary>
    /// 总结  当参数有ref修饰符 或者IntPtr 是将引用类型传递 会映射到c++ 参数为 * 或者& 的方法(最终 参数 和返回值相同 才能为找到正确方法)

  ///  如果c++ byte*   传给c#使用,如果c# byte[]  按照数组接收是要提前声明数组长度    

///   例如 public delegate bool ByteArrDllcallBack([MarshalAs(UnmanagedType.LPArray, SizeConst = 64)] byte[] arr, int length);
    /// [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
    /// 如 static extern int xxx(IntPtr md,int a); 
    /// 会映射到c++ int __stdcall xxx(int * md,int a){} 或者int __stdcall xxx(int &md,int a){} 
    /// xxx 方法名 c# 可以随便取 根据参数类型 和返回值映射到对应的c++中指定的函数中
    /// </summary>
    public partial class ConnectControler : Form
    {

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct MyData
        {
            public Double a;
            public float b;
            public int l; //c++ long 对应c# int
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] szVal;
        }

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern int StructFunc(ref MyData md);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern int StructFunc(IntPtr md);


        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool StructFuncPointer(ref MyData md);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool StructFuncPointer(IntPtr md);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern int StructFuncNormal(MyData md);


        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern int StructFuncNormal(IntPtr md);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool CharFunc(IntPtr a);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool CharFunc(ref string a); //对应c++ char* 当引用类型传递的话有问题,用StringBuilder

 [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool CharFunc(StringBuilder a);  //对应c++ char* 当引用类型传递

 

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool CharFunc(string a);  // static extern bool CharFunc([MarshalAs(UnmanagedType.LPStr)]string a); 意思相同

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool CharFunc(char[] a);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool IntSigleFunc(int para);

        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool IntFunc(ref int para);

        /// <summary>
        /// 含有委托的方法
        /// </summary>
        /// <returns></returns>
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate int DllcallBack(int a, float b, string sz);
        [DllImport("/Plugins/CreateDLL.dll", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        static extern bool CallBackFunc(DllcallBack dcb);

        public ConnectControler()
        {
            InitializeComponent();
        }

        # region 涉及到结构体部分
        private void btn_structFuncIntPtr_Click(object sender, EventArgs e)
        {

            /*
             * 对应c++的int __stdcall StructFunc(MyData &md)   备注: 与 __stdcall StructFuncPointer(MyData * md) c#在调用上没有区别
             * 将MyData 通过 Marshal 转换成IntPtr
             */
            MyData md = new MyData();
            IntPtr a = Marshal.AllocHGlobal(Marshal.SizeOf(md));
            Marshal.StructureToPtr(md, a, true);
            int backValue = StructFunc(a);
            md = (MyData)Marshal.PtrToStructure(a, typeof(MyData));
            StringBuilder sb = new StringBuilder();
            Console.WriteLine("==> md.szVal.Length:" + md.szVal.Length);
            foreach (char c in md.szVal)
            {
                if (!c.Equals("\0"))
                {
                    sb.Append(c);
                }

            }
            string content = sb.ToString();  //256个char 对应的string 没有填充的为(\0 结束符)
            int index = content.IndexOf("\0");
            content = content.Substring(0, index);
            //content = content.Replace("\0", "");
            Console.WriteLine("==>content.lenth:" + content.ToCharArray().Length);
            string text = "参数-" + "==>a:" + md.a + "==>l:" + md.l + "==>szVal:" + content + "==>回调值:" + backValue;
            Console.WriteLine(text);
            label_content.Text = text;
            Marshal.FreeHGlobal(a);
        }

        private void StFucSt_Click(object sender, EventArgs e)
        {

            /*
             * 对应c++的int __stdcall StructFunc(MyData &md)  备注: 与 __stdcall StructFuncPointer(MyData * md) c#在调用上没有区别
             * 将MyData 直接当成结构体传入
             */
            MyData md = new MyData();
            //md.a = 1;
            //md.b = 2;
            //md.l = 3;
            //md.szVal = new char[256];   //可以不需要事先给结构体赋值
            int backValue = StructFunc(ref md);
            StringBuilder sb = new StringBuilder();
            foreach (char c in md.szVal)
            {
                sb.Append(c);
            }
            var content = sb.ToString();  //256个char 对应的string 没有填充的为空字符
            int index = content.IndexOf("\0");
            content = content.Substring(0, index);
            label_content.Text = "参数-" + "==>a:" + md.a + "==>l:" + md.l + "==>szVal:" + content + "==>回调值:" + backValue;
        }


        private void btn_SctFucSctNormal_Click(object sender, EventArgs e)
        {
            /*
            * 对应c++的int __stdcall StructFuncNormal(MyData md) 
            * 将MyData 直接当成结构体传入
            */

            MyData md = new MyData();
            md.szVal = new char[256];
            md.a = 0.1;
            md.b = 0.2f;
            md.l = 3;
            int backValue = StructFuncNormal(md);
            label_content.Text = "参数-" + "==>a:" + md.a + "==>b:" + md.b + "==>回调值:" + backValue;
        }

        private void btn_SFSNormalIntPtr_Click(object sender, EventArgs e)
        {
            /*
             * 注意: 这有个注意点
             *       本意想 对应c++的int __stdcall StructFuncNormal(MyData md) 
             *       实际运行对应是c++的int __stdcall StructFunc(MyData &md) (将结构体MyData 当成对象使用)
             *  导致这样的原因 :
             *  如static extern int StructFuncNormal(IntPtr md);  中StructFuncNormal 可以随意定义,根据参数类型 和返回值映射到对应的c++中指定的函数中
             *  static extern int StructFuncNormal(ref MyData md); 也会映射到c++的int __stdcall StructFunc(MyData &md)
             * 将MyData 直接当成结构体传入
             */
            MyData md = new MyData();
            md.szVal = new char[256];
            md.a = 0.1;
            md.b = 0.2f;
            md.l = 3;
            IntPtr a = Marshal.AllocHGlobal(Marshal.SizeOf(md));
            Marshal.StructureToPtr(md, a, true);
            int backValue = StructFunc(a);
            md = (MyData)Marshal.PtrToStructure(a, typeof(MyData));
            StringBuilder sb = new StringBuilder();
            foreach (char c in md.szVal)
            {
                sb.Append(c);
            }
            var content = sb.ToString();  //256个char 对应的string 没有填充的为空字符
            int index = content.IndexOf("\0");
            content = content.Substring(0, index);
            label_content.Text = "参数-" + "==>a:" + md.a + "==>l:" + md.l + "==>szVal:" + content + "==>回调值:" + backValue;
            Marshal.FreeHGlobal(a);
        }
        #endregion

        #region char
        private void btn_charFuncIntPtr_Click(object sender, EventArgs e)
        {
            string par = "btn_charFuncIntPtr_Click";
            IntPtr ip = Marshal.StringToHGlobalAnsi(par);
            bool value = CharFunc(ip);
            par = Marshal.PtrToStringAnsi(ip);
            label_content.Text = "参数-" + "==>par:" + par;
            Marshal.FreeHGlobal(ip);
        }

        private void btn_charFuncOther_Click(object sender, EventArgs e)
        {
            /*
             *   这几种定义都是按照 值传递 par 值不会被改变
              static extern bool CharFunc(ref string a); // dll c++ 通过这种方式复制的话  sprintf(a, " %s", "CreateDLL CharFunc a"),c# 会报错

             static extern bool CharFunc(string a);  // static extern bool CharFunc([MarshalAs(UnmanagedType.LPStr)]string a); 意思相同

             static extern bool CharFunc(char[] a);
             */
           //这样用才能当引用类型传递
            StringBuilder sb = new StringBuilder();
            sb.Append("value default");
            bool value = CharFunc(sb);
            label_content.Text = "参数-" + "==>par:" + sb.ToString() + "==>返回值:" + value;

        }
        #endregion

        #region 基础数据类型 int string float 等
        private void btn_IntFuncRef_Click(object sender, EventArgs e)
        {
            /*
           * 对应c++的bool __stdcall IntFunc(int *value)
           */

            int par = 0;
            bool value = IntFunc(ref par);
            label_content.Text = "参数-" + "==>par:" + par + "==>返回值:" + value;
        }

        private void btn_IntFuncSample_Click(object sender, EventArgs e)
        {
            /*
             *  想对应c++的bool __stdcall IntSigleFunc(int *value)
             *  实际对应是c++的bool __stdcall IntFunc(int *value)
             *  c#调用c++dll 中 参数相同 返回值相同 方法名不同这种情况 后续遇到需要进一步研究
             */
            int par = 0;
            bool value = IntSigleFunc(par);
            label_content.Text = "参数-" + "==>par:" + par + "==>返回值:" + value;
        }
        #endregion

        #region 传递回调方法
        private void btn_callBackFunc_Click(object sender, EventArgs e)
        {
            /*
             * 对应c++的bool __stdcall CallBackFunc(lpCallBackFun callBack)
             *  CallBackFunc 方法名必须和c++方法名一致 
             */
            bool value = CallBackFunc((a, b, c) =>
            {
                label_content.Text = "参数-" + "==>a:" + a + "==>b:" + b + "==>c:" + c;
                return 1;
            });
        }
        #endregion

    }
}
 

C++代码

// CreateDll.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "CreateDLL.h"
#include <iostream>


int __stdcall StructFuncNormal(MyData md){
    md.a = 1;
    md.b = 2;
    md.l = 3;
    strcpy_s(md.szVal, "来自CreateDLL StructFuncNormal");
    return 20;
}

int __stdcall StructFunc(MyData &md){
    md.a = 10;
    md.b = 20;
    md.l = 30;
    strcpy_s(md.szVal, "来自CreateDLL StructFunc");
    return 200;
}

bool __stdcall StructFuncPointer(MyData * md){
    md->a = 100;
    md->b = 200;
    md->l = 300;
    strcpy_s(md->szVal, "来自CreateDLL StructFuncPointer");
    return true;
}

bool __stdcall CharFunc(char * a){
    //a = "CreateDLL CharFunc a"; 这样复制其实是直接辅助给指针,并不能改变指针a对应内存的值, 指针a存放是内存的地址,和引用 功能一样叫法不同
    sprintf(a, " %s", "CreateDLL CharFunc a");
    return true;
}
bool __stdcall IntSigleFunc(int value){
    value = 10;
    return false;
}

bool __stdcall IntFunc(int *value){
    *value = 20;
    return true;
}

bool __stdcall CallBackFunc(lpCallBackFun callBack){
    callBack(10, 11, "CallBackFunc");
    return true;
}

测试工程目录简介 Conecter 为C#工程   CreateDll为C++dll工程

测试工程以及总结文档连接:https://pan.baidu.com/s/1cAd2suA1nzV7JHpCKVZ1nQ

创建c++dll工程参考:https://blog.csdn.net/qq385105501/article/details/82253725

c#调用c++dll总结文档:https://wenku.baidu.com/view/db475ca280eb6294dd886cc3.html?from_page=view&from_mod=download

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值