目录
1.C#调用C++(类)的dll文件
C#端的代码:
C++端的代码:
被调用的类的头文件
被调用类的实现SampleCppClass.cpp
封装成dll的头文件
封装成dll的实现
2.使用委托调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//c#调用c++
//c++使用extern "C" __declspec(dllexport) 指示使用c编译器来编译代码
//然后使用DLL调用
namespace ConsoleAppTest1
{
class Program
{
[System.Runtime.InteropServices.DllImport("E:/program/C#/ConsoleAppTest1/Sample.dll")]
private static extern int Add(int n1, int n2);
[System.Runtime.InteropServices.DllImport("E:/program/C#/ConsoleAppTest1/Sample.dll")]
private static extern int Sub(int n1, int n2);
static void Main(string[] args)
{
int a = Add(1, 2);
Console.Write(a);
}
}
}
/*************************************************************************
【 名 称 】SampleCppClass.h
【 功 能 】定义为_declspec(dllexport)的类,可以将函数都封装在dll里面,便于c#调用
【 参 数 】
【返 回 值】
【 说 明 】此方法是以C语言接口的方式导出,,以便于c#调用
【开 发 者】 Yh
【 日 期 】2019.3.11
更改记录:
【修改说明】
【开 发 者】
【 日 期 】
*************************************************************************/
#pragma once
class _declspec(dllexport) SampleCppClass
{
public:
SampleCppClass();
~SampleCppClass();
int Add(int a, int b);
int Sub(int a, int b);
};
#include "SampleCppClass.h"
SampleCppClass::SampleCppClass()
{
}
SampleCppClass::~SampleCppClass()
{
}
int SampleCppClass::Add(int a, int b)
{
return a + b;
}
int SampleCppClass::Sub(int a, int b)
{
return a - b;
}
/*************************************************************************
【 名 称 】SampleCppWrapper.h
【 功 能 】定义了两个使用C编译器编译的函数,
【 参 数 】
【返 回 值】
【 说 明 】
【开 发 者】 Yh
【 日 期 】2019.3.11
更改记录:
【修改说明】
【开 发 者】
【 日 期 】
*************************************************************************/
#pragma once
#include "SampleCppClass.h"
namespace SampleCppWrapper
{
extern "C" __declspec(dllexport) int __stdcall Add(int n1, int n2);
extern "C" __declspec(dllexport) int __stdcall Sub(int n1, int n2);
}
/*************************************************************************
【 名 称 】SampleCppWrapper.cpp
【 功 能 】直接将SampleCppClass的函数封装成接口,直接可以被调用
【 参 数 】
【返 回 值】
【 说 明 】
【开 发 者】 Yh
【 日 期 】2019.3.11
更改记录:
【修改说明】
【开 发 者】
【 日 期 】
*************************************************************************/
#include "stdafx.h"
#include "SampleCppWrapper.h"
namespace SampleCppWrapper
{
SampleCppClass* g_pObj = new SampleCppClass();
int __stdcall Add(int n1, int n2)
{
return g_pObj->Add(n1, n2);
}
int __stdcall Sub(int n1, int n2)
{
return g_pObj->Sub(n1, n2);
}
}
//调用hello函数(利用委托)
delegate void HelloDelegate(string name);
static void HelloWoorld()
{
HelloDelegate hello;
IntPtr hModule = LoadLibrary("E:/program/C#/CSharpConnectCPlusTest2/CPlusConnectCSharpTest2.dll");
if (hModule != IntPtr.Zero)
{
IntPtr hProc = GetProcAddress(hModule, "HelloWorld");
if (hProc != IntPtr.Zero)
{
hello = (HelloDelegate)Marshal.GetDelegateForFunctionPointer(hProc, typeof(HelloDelegate));
//在这里可以调用
hello("lihua");
}
}
}
#define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数
typedef struct
{
int osVersion;
int majorVersion;
int minorVersion;
int buildNum;
int platFormId;
char szVersion[128];
}OSINFO;
// 1. 获取版本信息(传递结构体指针)
JNAAPI bool GetVersionPtr( OSINFO *info );
// 2.获取版本信息(传递结构体引用)
JNAAPI bool GetVersionRef(OSINFO &info);
C#端结构体定义
// OSINFO定义
[StructLayout(LayoutKind.Sequential)]
public struct OSINFO
{
public int osVersion;
public int majorVersion;
public int minorVersion;
public int buildNum;
public int platFormId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szVersion;
}
C#调用法一:
[DllImport("jnalib.dll", EntryPoint = "GetVersionPtr")]
public static extern bool GetVersionPtr(ref OSINFO info);
public static extern bool GetVersionRef(ref OSINFO info);
C#调用法二:
IntPtr pv = Marshal.AllocHGlobal(148); //结构体在使用时一定要分配空间(4*sizeof(int)+128)
Marshal.WriteInt32(pv,148); //向内存块里写入数值
if (GetVersionPtr(pv)) //直接以非托管内存块地址为参数
{
Console.WriteLine("--osVersion:{0}", Marshal.ReadInt32(pv, 0));
Console.WriteLine("--Major:{0}",Marshal.ReadInt32(pv, 4)); //移动4个字节
Console.WriteLine("--BuildNum: " + Marshal.ReadInt32(pv, 12));
Console.WriteLine("--szVersion: "+Marshal.PtrToStringAnsi((IntPtr)(pv.ToInt32()+20)));
}
Marshal.FreeHGlobal(pv); //处理完记得释放内存
cpp端代码
// 传递结构体指针
JNAAPI bool GetVersionArray(OSINFO *info,int nLen);
C#端代码
/**
* C#接口,对于包含数组类型,只能传递IntPtr
*/
[DllImport("jnalib.dll", EntryPoint = "GetVersionArray")]
public static extern bool GetVersionArray(IntPtr p, int nLen);
// 源目标参数
OSINFO[] infos = new OSINFO[2];
//分配指针的内存
IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO))* 2);
GetVersionArray(pt, 2); //调用
//还原成结构体数组
for (int i = 0; i < 2; i++)
{
infos[i]=(OSINFO)Marshal.PtrToStructure((IntPtr)(pt.ToInt32()+i*Marshal.SizeOf(typeof(OSINFO))),typeof(OSINFO));
Console.WriteLine("OsVersion:{0} szVersion:{1}", infos[i].osVersion, infos[i].szVersion);
}
Marshal.FreeHGlobal(pt); // 释放内存
C++端
typedef struct
{
char name[20];
int age;
double scores[30];
}Student;
// Class中包含结构体数组类型
typedef struct
{
int number;
Student students[50];
}Class;
// 传入复杂结构体测试
JNAAPI int GetClass(Class *pClass,int len);
C#端
// 接口定义
[DllImport("jnalib.dll", EntryPoint = "GetClass")]
public static extern int GetClass(IntPtr pv,int len);
// 结构体定义
// Student
[StructLayout(LayoutKind.Sequential)]
public struct Student
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=20)]
public string name;
public int age;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public double[] scores;
}
// Class
[StructLayout(LayoutKind.Sequential)]
public struct Class
{
public int number;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] // 指定数组尺寸
public Student[] students; // 结构体数组定义
}
// 调用复杂结构体测试
int size = Marshal.SizeOf(typeof(Class)) * 50;
IntPtr pBuff = Marshal.AllocHGlobal(size); // 直接分配50个元素的空间,比Marshal.copy方便多了
GetClass(pBuff, 50);
Class[] pClass = new Class[50];
for (int i = 0; i < 50; i++)
{
IntPtr ptr = new IntPtr(pBuff.ToInt64() + Marshal.SizeOf(typeof(Class)) * i);
pClass[i] = (Class)Marshal.PtrToStructure(ptr, typeof(Class));
}
Marshal.FreeHGlobal(pBuff); // 释放内存