C#项目调用C++的DLL程序

本程序参考:http://www.cnblogs.com/liping13599168/archive/2011/03/31/2000320.html

但是本程序需要说明一个非常重要的问题:

就是注意你注意DLL文件和调用它的位数上一定要一致;否则会出现错误;

本人使用的是X64架构的系统;所以这个要遵守;




首先创建一个C++解决方案;其次在下面的选项里面选择win32项目,这个一定注意; 不要选控制台或者MFC程序;


然后再程序设置中选择DLL;其他默认即可;


最后得到了下面的界面;


 我们可以看到这里有一些文件,其中dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟exe文件有个main或者WinMain入口函数是一样的,它就是作为DLL的一个入口函数,实际上它是个可选的文件。它是在静态链接时或动态链接时调用LoadLibrary和FreeLibrary时都会被调用。

以下是要注意的部分了:一定要对下面的Debug部分进行更改;这一点就是X64配合的主要步骤;


配置管理器更改如下图;


然后再CppDemo.cpp中输入以下代码:

//以下是我写的程序;
extern "C" __declspec(dllexport) int Sub(int x, int y)
{
	return x - y;
}

extern "C" __declspec(dllexport) int Multiply(int x, int y)
{
	return x * y;
}
extern "C" __declspec(dllexport) int Add(int x, int y)
{
	return x + y;
}
extern "C" __declspec(dllexport) int Divide(int x, int y)
{
	return x / y;
}

        extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。而被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。

      __declspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。

      extern "C" __declspec(dllexport)加起来的目的是为了使用DllImport调用非托管C++的DLL文件。因为使用DllImport只能调用由C语言函数做成的DLL。


下面创建C#控制台程序;

赋值CppDemo中的dll文件到 C#程序目录的X64的运行目录中


并且添加类:

public class CPPDLL
    {
        [DllImport("CppDemo.dll")]
        public static extern int Add(int x,int y);
        [DllImport("CppDemo.dll")]
        public static extern int Sub(int x, int y);
        [DllImport("CppDemo.dll")]
        public static extern int Multiply(int x, int y);
        [DllImport("CppDemo.dll")]
        public static extern int Divide(int x, int y);

    }

然后再在主程序中写入:

int result = CPPDLL.Add(10, 20);
            Console.WriteLine("10 + 20 = {0}", result);

            result = CPPDLL.Sub(30, 12);
            Console.WriteLine("30 - 12 = {0}", result);

            result = CPPDLL.Multiply(5, 4);
            Console.WriteLine("5 * 4 = {0}", result);

            result = CPPDLL.Divide(30, 5);
            Console.WriteLine("30 / 5 = {0}", result);

            Console.ReadLine();


运行结果如下:






下面说说类调用:

首先在CppDemo中添加一个UserInfo这个类:

其中,UserInfo.h  中添加下面程序;

class UserInfo
{
private:
	char* m_Name;
	int m_Age;
public:
	UserInfo(char* name, int age)
	{
		m_Name = name;
		m_Age = age;
	}
	virtual ~UserInfo(){ } //这里的virtual是留待以后实现的意思;
	int GetAge() { return m_Age; }
	char* GetName() { return m_Name; }
};

UserInfo.cpp的内容如下:

#include "stdafx.h"
#include "malloc.h"
#include "UserInfo.h"

typedef struct {
	char name[32];
	int age;
} User;//定义一个结构体命名为为User;

UserInfo* userInfo;//声明一个指向UserInfo对象的指针;

//下面这个是接口,返回一个指针指向的地址;
//注意:代码中的User*是个指针,返回也是一个对象指针,这样做为了防止方法作用域结束后的局部变量的释放。
extern "C" __declspec(dllexport) User* Create(char* name, int age)
{
	//malloc 向系统申请分配指定size个字节的内存空间。
	//返回类型是 void* 类型。void* 表示未确定类型的指针。
	User* user = (User*)malloc(sizeof(User));//分配给user一块内存;再用User进行格式化;

	userInfo = new UserInfo(name, age);

	//复制;
	strcpy(user->name, userInfo->GetName());
	user->age = userInfo->GetAge();

	return user;
}

然后再在我们之前建立的C#程序中添加:


项目中CPPDLL类中添加代码:

//类调用程序块;
        [DllImport("CppDemo.dll")]
        public static extern IntPtr Create(string name, int age); //IntPtr是表示平台特定指针,使用时指定;

        //StructLayout特性允许我们控制Structure语句块的元素在内存中的排列方式,
        //以及当这些元素被传递给外部DLL时,运行库排列这些元素的方式。
        [StructLayout(LayoutKind.Sequential)] //控制结构体字段的物理布局;括号中的意思是按出现顺序依次布局;
        public struct User
        {
            //MarshalAs属性指示如何在托管代码和非托管代码之间封送数据。
            //下面说明两个字段的数据占的能存大小,第一个是字符类型;第二个是32位int类型;
            //它有两个参数,所以能管到下面两行;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string Name;
            public int Age;
        }
在主程序中添加如下代码:

//下面是类的调用
            IntPtr ptr = CPPDLL.Create("Shawn", 25);
            //转换指针为User类型;因为返回的是一个object,所以要格式化成User;
            CPPDLL.User user = (CPPDLL.User)Marshal.PtrToStructure(ptr, typeof(CPPDLL.User));
            Console.WriteLine("Name: {0}, Age: {1}", user.Name, user.Age);


注意对C#程序进行重新编译

运行结果如下;


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值