网站首页 > 技术文章 正文
第一种方式:C++导出函数, c#dllimport 的方式
在很多地方都看到过,如[dllimport “user32.dll”]这种代码,调用windows API,就是通过这种方式实现。
例子:新建C++项目,创建动态链接库(DLL),然后添加头文件textdll.h
#pragma once
#ifdef A_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
extern "C" DLL_API void MessageBoxShow(); //通过extern “C” 使MessageBoxShow方法为一个导出方法,外部可见
然后,dllmain.cpp中添加代码:
#include "stdafx.h"
#include "textdll.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#ifdef _MANAGED
#pragma managed(push, off)
#endif
void MessageBoxShow()
{
MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
编译通过后,找到目录下生成的DLL(TESTDLL.dll),拷贝出来,放到C#的debug目录(程序目录)下, 然后新建C#程序:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; //必须要添加该引用
using System.Text;
using System.Threading.Tasks;
namespace dlltest
{
class Program
{
[DllImport("TESTDLL.dll")] //最关键的,导入该dll
public extern static void MessageBoxShow();
static void Main(string[] args)
{
MessageBoxShow();
}
}
}
然后运行可以看到结果:成功的调用了C++DLL中的方法。
第二种方式:
通过C++/CLI作为中间层,因为C++/CLI即可调用.NET的类库,又可调用C++原生库,
所以可以通过C# 调用 C++/CLI 再调用 C++ DLL这样的三层调用方式完成。
1、创建一个c++空项目
项目创建完成,我们添加一个类,写几个方法,这儿就简单写一个计算器的加减乘除吧!
在CaculateData.h中添加如下代码,定义几个函数声明;
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef CaculateDLL_EXPORTS
#define Calculate_EXPORTS __declspec(dllexport)
#else
#define Calculate_EXPORTS __declspec(dllimport)
#endif
extern "C" Calculate_EXPORTS int Add(int numberA, int numberB);
extern "C" Calculate_EXPORTS int Subtract(int numberA, int numberB);
extern "C" Calculate_EXPORTS int Multiplication(int numberA, int numberB);
extern "C" Calculate_EXPORTS int Divided(int numberA, int numberB);
class CaculateData
{
public:
CaculateData();
~CaculateData();
};
可以看到,#ifdef的宏没有定义,所以我们需要添加一个宏:
项目右键---属性---配置属性---C/C++---预处理器---预处理器定义,将定义的宏添加进去;
可以看到,定义好了,颜色就变成紫色的,说明已经声明了宏;
在CaculateData.cpp中实现这几个方法;
#include "CaculateData.h"
#include <iostream>
CaculateData::CaculateData()
{
}
CaculateData::~CaculateData()
{
}
Calculate_EXPORTS int Add(int numberA, int numberB)
{
return numberA + numberB;
}
Calculate_EXPORTS int Subtract(int numberA, int numberB)
{
return numberA - numberB;
}
Calculate_EXPORTS int Multiplication(int numberA, int numberB)
{
return numberA * numberB;
}
Calculate_EXPORTS int Divided(int numberA, int numberB)
{
if (numberB == 0) {
std::cout << "除数不能为空" << std::endl;
}
return numberA / numberB;
}
修改C++工程项目输出目录,这儿主要是便于CLI引用,我们这儿同意定义到Testinvoking项目的输出目录..\bin\Debug\netcoreapp2.2
(修改步骤:项目右键—属性—配置属性—常规—输出目录)
配置类型修改为:动态库.dll (修改步骤:项目右键—属性—配置属性—常规—配置类型)
然后生成;
2、新建一个CLR项目
这个项目就是来实现C#调用C++的
因为需要调用Caculate.dll,所以需要引用它;
配置属性—VC++目录—库目录(把刚刚生成Caculate.dll的路径添加进去)
同时引用库:
添加一个类InvokeCon.cpp,用它来调用Caculate.dll中的方法
InvokeCon.cpp代码如下:
#include "InvokeCon.h"
InvokeCon::InvokeCon()
{
}
int InvokeCon::AddCli(int numberA, int numberB)
{
return Add(numberA, numberB);
}
int InvokeCon::SubtractCli(int numberA, int numberB)
{
return Subtract(numberA, numberB);
}
int InvokeCon::MultiplicationCli(int numberA, int numberB)
{
return Multiplication(numberA, numberB);
}
int InvokeCon::DividedCli(int numberA, int numberB)
{
return Divided(numberA, numberB);
}
InvokeCon.h代码:
#pragma once
#include <iostream>
#include "C:\Users\tjy\source\repos\TestInvoking\Caculate\CaculateData.h"//引用库声明对应文件路径
public ref class InvokeCon
{
public:
InvokeCon();
int AddCli(int numberA, int numberB);
int SubtractCli(int numberA, int numberB);
int MultiplicationCli(int numberA, int numberB);
int DividedCli(int numberA, int numberB);
};
然后编译,修改编译类型为动态库dll
3、c#通过引用CliDll.dll来调用Caculate中的方法
然后生成:此时就产生了CliDll.dll库
1、添加对Dll的引用;
2、在C#项目中添加测试代码:
可以看到,此时就能够调用多个方法,而且会有方法名提示!
using System;
namespace TestInvoking
{
public class Program
{
public static void Main(string[] args)
{
try
{
Console.WriteLine("---------c#通过CLI调用C++类方法---------");
Console.Write("请输入numberA:");
int numberA = Convert.ToInt32(Console.ReadLine());
Console.Write("请输入numberB:");
int numberB = Convert.ToInt32(Console.ReadLine());
InvokeCon invoke = new InvokeCon();
int addResult = invoke.AddCli(numberA, numberB);
int subResult = invoke.SubtractCli(numberA, numberB);
int mutilResult = invoke.MultiplicationCli(numberA, numberB);
int divResult = invoke.DividedCli(numberA, numberB);
Console.WriteLine(#34;the {numberA} And {numberB} sum is:{addResult};sub is:{subResult};Mutil is:{mutilResult};div is:{divResult}");
}
catch(Exception ex)
{
Console.WriteLine(#34;ex:{ex}");
}
Console.WriteLine("执行成功");
Console.ReadLine();
}
}
}
OK,完成!
猜你喜欢
- 2025-06-08 深入理解C#,首推这六本书(c#入门经典书籍)
- 2025-06-08 C语言有何意义(c语言的含义)
- 2025-06-08 Java、C语言、C++、Python等编程该选哪一个
- 2025-06-08 iOS开发生涯的初恋:详解Objective-C多项改进
- 2025-06-08 各种不同的转义字符内部揭秘(常见转义字符)
- 2025-06-08 如何在C#中调用C++方法(c#调用c++的类)
- 2025-06-08 软件行业的误解以及赚钱的途径(软件行业怎么了)
- 2025-06-08 C语言-基本概念(c语言基础知识概念)
- 2025-06-08 C++语言为什么跨平台?(c语言跨平台且可移植性好)
- 2025-06-08 什么?C#也能开发操作系统了?(c#一般用来开发什么)
- 1522℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 640℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 527℃MySQL service启动脚本浅析(r12笔记第59天)
- 492℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 492℃启用MySQL查询缓存(mysql8.0查询缓存)
- 479℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 461℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 459℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- windowsscripthost (69)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)