2。 在C#中创建DLL接口的声明
C#没有全局函数,必须使用静态函数实现全局函数。
1) DllImport类似C++中的__declspec(dllimport),第一个参数为必选参数,为DLL的路径,一般以相对路径即可,只需要将DLL文件放到工作目录中即可
2) EntryPoint表示对应的函数名称,这个与C++ DLL工程中.def文件中导出的函数名同
使用C#调用C++时不支持C++的函数名重载(至少还没有找到办法),如果参数不同必须使用不同的函数名用以区分,但在C#中可以使用相同的函数名
3) C#中的声明的函数名不一定与实际的函数名一样,比如
public static extern int PassString(string msg);
中的PassString可以使用任何名称,与C++中的对应关系只需要DllImport中的EntryPoint参数保持一致。
一般地只需要给出DLL文件名、EntryPoint两个参数就可以了。
using System;
using System.Runtime.InteropServices;
using Noock.TTest;
public static class CFuncs
{
[DllImport("dlldemo.dll", EntryPoint = "PassString", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
public static extern int PassString(string msg);
[DllImport("dlldemo.dll", EntryPoint = "Power", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
public static extern double Power(double x, int y);
public struct Location
{
public int x;
public int y;
}
[DllImport("dlldemo.dll", EntryPoint = "GetDistance1D", CharSet = CharSet.Auto)]
public static extern int GetDistance(int x1, int x2);
[DllImport("dlldemo.dll", EntryPoint = "GetDistance2D", CharSet = CharSet.Auto)]
public static extern double GetDistance(Location x1, Location x2);
[DllImport("dlldemo.dll", EntryPoint = "CopyValues", CharSet = CharSet.Auto)]
public static extern int CopyValues(out int dst, ref int src, int length);
[DllImport("dlldemo.dll", EntryPoint = "GetValue", CharSet = CharSet.Auto)]
public static extern int GetValue(out int value);
[DllImport("dlldemo.dll", EntryPoint = "CopyArray2D", CharSet = CharSet.Auto)]
public unsafe static extern int CopyArray2D(ref byte* dst, ref byte* src, int m, int n);
[DllImport("dlldemo.dll", EntryPoint = "CopyPointerArray2D", CharSet = CharSet.Auto)]
public unsafe static extern int CopyPointerArray2D(ref byte* dst, ref byte* src, int m, int n);
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Person{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string name;
public byte age;
[MarshalAs(UnmanagedType.U1)]
public bool isFemale;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string email;
};
[DllImport("dlldemo.dll", EntryPoint = "GetPerson", CharSet = CharSet.Auto)]
public static extern bool GetPerson(ref Person p, string name);
[DllImport("dlldemo.dll", EntryPoint = "SetEnable", CharSet = CharSet.Auto)]
public static extern bool SetEnable( bool enabled);
}
需要注意的是在结构体Persion中的isFemail字段采用的是bool类型,C#与C++中的bool都是通过1个字节来实现的,而且实现机制非常类似,所以将期视作单字节的无符号类型处理。
3。 在C#中调用C++的函数,下面的测试代码使用了前面实现的TTest测试框架(http://blog.csdn.net/nocky/article/details/7687559)。
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to quit");
#if WRITE_TO_FILE
// Write to file
using (FileStream fs = new FileStream(string.Format("Test_{0}.log", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")),FileMode.CreateNew)) {
using (StreamWriter sw = new StreamWriter(fs)) {
Test.Out = sw;
Test.Run();
Test.Out = Console.Out;
}
}
#else
TTest.Run();
#endif
Console.Read();
}
[TestCase(Target="int __stdcall PassString(char* msg)")]
private static void TestPassString()
{
string msg1 = "Message #1";
int ret = CFuncs.PassString(msg1);
TTest.AreEqual(0, ret, "return value error");
}
[TestCase(Target="long double __stdcall Power(double x, int y)")]
private static void TestPower()
{
double x = 2.0;
int y = 3;
double p = CFuncs.Power(x, y);
TTest.AreEqual(8.0, p);
}
[TestCase(Target="int _stdcall GetDistance(int x1, int x2)")]
private static void TestGetDistance()
{
int x = 20, y = 30;
int dist = CFuncs.GetDistance(x, y);
TTest.AreEqual(10, dist);
}
[TestCase(Target = "double __stdcall GetDistance(Location p1, Location p2)")]
private static void TestGetDistance2()
{
CFuncs.Location p1 = new CFuncs.Location() { x = 0, y = 0 };
CFuncs.Location p2 = new CFuncs.Location() { x = 3, y = 4 };
double dist = CFuncs.GetDistance(p1, p2);
TTest.AreEqual(5, dist);
}
[TestCase(Target = "int __stdcall CopyValues(int* dst, int* src, int length)")]
private static void TestCopyValues()
{
int[] src = new int[] { 0, 1, 5, 10, 15, 20, 25, 30 };
int[] dst = new int[src.Length];
int ret = CFuncs.CopyValues(out dst[0], ref src[0], src.Length);
TTest.AreEqual(src.Length, ret);
for (int i = 0; i < src.Length; ++i) {
TTest.AreEqual(src[i], dst[i]);
}
}
[TestCase(Target = "int __stdcall GetValue(int& dst)")]
private static void TestGetValue()
{
int value;
int ret = CFuncs.GetValue(out value);
TTest.AreEqual(ret, value);
}
[TestCase(Target = "int __stdcall CopyArray2D(unsigned char** dst, unsigned char** src, int m, int n)")]
private static void TestCopyArray2D()
{
byte[,] src = new byte[2, 5] { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 } };
byte[,] dst = new byte[2, 5];
unsafe {
fixed (byte* psrc = &src[0,0], pdst = &dst[0,0]) {
// psrc and pdst are fixed pointer, they are not allowed to pass as arguments
// error CS1657: Cannot pass 'psrc' as a ref or out argument because it is a 'fixed variable'
// the following 2 lines are used to cheat compiler
byte* psrc2 = psrc;
byte* pdst2 = pdst;
int n = CFuncs.CopyArray2D(ref pdst2, ref psrc2, 2, 5);
TTest.AreEqual(10, n);
// CFuncs.CopyPointerArray2D(ref pdst2, ref psrc2, 2, 5); // OK
}
}
TTest.AreEqual(src, dst);
}
[TestCase(Target = "int __stdcall CopyPointerArray2D(unsigned char** dst, unsigned char** src, int m, int n)")]
private static void TestCopyPointerArray2D()
{
byte[][] src = new byte[2][] { new byte[] { 1, 2, 3, 4, 5 }, new byte[]{ 6, 7, 8, 9, 10} };
byte[][] dst = new byte[2][] { new byte[5], new byte[5] };
unsafe {
byte*[] psrc = ConvertType(src);
byte*[] pdst = ConvertType(dst);
int n = CFuncs.CopyPointerArray2D(ref pdst[0], ref psrc[0], 2, 5);
TTest.AreEqual(10, n);
// CFuncs.CopyArray2D(ref pdst[0], ref psrc[0], 2,5); // ERROR
}
TTest.AreEqual(src, dst);
}
private static unsafe byte*[] ConvertType(byte[][] pptr)
{
if (pptr == null)
throw new ArgumentNullException("pptr");
var len = pptr.GetUpperBound(0) + 1;
var buffer = new byte*[len];
for (var i = 0; i < len; ++i) {
if (pptr[i] == null)
throw new NullReferenceException(string.Format("pptr[{0}]", i));
fixed (byte* ptr = pptr[i]) {
buffer[i] = ptr;
}
}
return buffer;
}
[TestCase(Target="bool __stdcall GetPerson(Person* p, char* name)")]
private static void TestGetPerson( )
{
string name = "Jobs";
CFuncs.Person jobs = new CFuncs.Person();
jobs.age = sizeof(bool);
bool b = CFuncs.GetPerson(ref jobs, name);
TTest.AreEqual(true, b);
TTest.AreEqual("Steve Jobs", jobs.name,false, "Check name");
TTest.AreEqual(100, jobs.age, "Check Age");
TTest.AreEqual("Steve.Jobs@apple.com", jobs.email, false, "Check email");
TTest.AreEqual(false, jobs.isFemale, "Check Sex");
}
[TestCase(Target = "bool __stdcall SetEnable(bool enabled)")]
private static void TestSetEnable()
{
TTest.AreEqual(false, CFuncs.SetEnable(true));
TTest.AreEqual(true, CFuncs.SetEnable(false));
}
}
需要特别注意的是 CopyPointerArray2D与CopyArray2D虽然两个函数的声明完全一样,但在C++中实际处理的方式是完全不同的,产者是看作一维指针数组来处理的,可以允许“二维数组”是不连续的,而后者是将其看作连续的存储空间,即C/C++中的二维数组的数据存储方式处理的,所以在示例代码中使用CopyArray2D处理byte[][]类型的锯齿数组是不可以的,会造成内存的非法访问破坏内存数据。
还没有研究多维数组的传递,其传递方式会比较复杂,应该不会用到吧,如果确实出现的话是该考虑一下设计问题了。
对于C++ class定义的类型以及如何调用对象的方法一下步再研究。(待续)
分享到:
相关推荐
c++动态库调用另一个动态库 c++动态库调用c动态库 c#等其他语言调用c/c++动态库
C#可以通过P/Invoke调用C/C++写的DLL,一般在从DLL接收字符串时比较麻烦,本人在某个项目中遇到这个问题, 从DLL收读取字符串时遇到中文乱码,这里总结一下C#收取字符串时的处理。 C/C++字符串一般通过char* ...
在C#开发软件的过程中,要经常调用C/C++生成的dll,本文主要介绍用C/C++生成dll的步骤,以及用C/C++、C#两种语言实现dll的引用实现。本文使用的IDE是VS2019,文章通过具体实例进行讲解,大家可以跟着自己动手进行...
1.C#调用C++封装的动态库dll 2.结构体含union共同体的C++转C#示例 3.C#结构体指针的调用演示 4.C#读取USB数据设备的示例 5.C#动态调用C++dll库示例 6.C#静态调用C++dll库示例 注意:UsbLibDotNet使用时候需要先安装...
C#使用CLR调用C++的DLL库的windows完整解决方案 说明如下: 1、工程一:C++的DLL 2、工程二:C++的CLR的类库 3、工程三:C#的exe
C#调用C++中动态链接库DLL中的结构体使用方法,范例。。。
c#调用c++ 动态链接库 dll
实例代码说明如何在托管的C#代码中调用非托管的Win32 API或者自己用C/C++写的Dll中的函数,以及如何传递输入、输出字符串参数,结构类型参数等问题。
c#开发框架下调用c++开发的dll动态库,实现跨语言开发功能。
C#调用C++动态链接库DLL的方法大全[归纳].pdf
C#动态调用DLL文件(有的DLL是用C++或其它语言写的不能直接调用,但可以用态调用)
c#调用c++DLL,DLL里是二维数组 ,c#里如何调用二维数组
演示c# 通过设置DLL文件 生成操作 为 嵌入的资源 后,DLL文件嵌入生成的EXE里,然后动态调用DLL,妈妈再也不用担心我找不到DLL文件了
C#调用C++DLL的参数传入,传出,string类型的传出等 1.数据类型转换问题 2.指针或者地址传送问题
资源代码演示的是c#代码调用c++ DLL 的方式。该演示为原创,绝非搬砖。解决了c# 调用 C++ Dll获取相关信息之如何传递结构体数组引用以及如何处理获取到的结构体数组数据的问题。
本解决方案包含两个工程,一个是生成动态链接库dll(Mydll),一个工程test_mydll用于调用生成的动态链接库mydll.dll,适合初学者
C++调用C#的DLL实例程序,压缩包中包含部分程序说明,很小的几行代码,但是C++调用C#的DLL目的已经达到。
本例子适用范围:程序初学者。...2.c# 调用 QT C++ Dll (QT 工程中提供了 QTC++调用QTC++DLL例子) CSharp_Call_Cplusplus_Dll 例子: 针对2说明,目前只实现了网络连接,数据发送暂不行 能力有限,不喜勿碰,仅供参考
使用C++开发dll供C#调用_百度文库.htm