前言
在C#开发软件的过程中,要经常调用C/C++生成的dll,本文主要介绍用C/C++生成dll的步骤,以及用C/C++、C#两种语言实现dll的引用实现。本文使用的IDE是VS2019,文章通过具体实例进行讲解,大家可以跟着自己动手进行测试。
一、生成dll
新建项目-C+±动态链接库(DLL)
项目-右键-属性-C/C+±预编译头:不使用预编译头。
项目-右键-属性-C/C+±高级:编译为:C。(也可以不更改,默认就好)
删除原有所有.c、.h文件,新建.c、.h文件
#include<stdio.h>
#include"Mydll.h"
void test_print(char const* str)
{
printf("测试输出的内容是:%s\n", str);
}
int test_sum(int a, int b)
{
return a + b;
}
#include<stdio.h>
_declspec(dllexport) void test_print(char const* str);
_declspec(dllexport) int test_sum(int a, int b);
特别说明: 如果上图写错的话,则在depends.exe或dumpbin.exe(VS自带)中无法查看C/C++生成的DLL中的函数
dumpbin.exe的使用方法: dumpbin.exe路径:【C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x86】(说明:不同版本的VS,只需更改2017为相应版本号)
定位到上述的路径,然后在文件路径中输入cmd, 定位到路径下。 执行命令:dumpbin.exe -exports “xxx.dll”(dll的路径)
depends.exe下查找dll的函数名: 使用depends.exe打开一个dll文件【注:下图中打开的文件是C/C++随便生成的dll,不要看!】
- 生成.dll和.lib文件:
二、C/C++调用dll
将生成的DLL文件拷贝到项目目录的Debug下
项目右键-属性-VC++目录-库目录-将.dll和.lib所在文件夹目录写入库目录中
项目-资源文件右键添加现有项-将.lib添加进去 或者 直接#pragma comment(lib,“Dll1.lib”)(本方法可省略此步)
C++源代码:
需要使用三个函数:LoadLibraryA,GetProcAddress和FreeLibrary
#include <stdlib.h>
#include <windows.h>
#include<stdio.h>
int main(int argc, char const* argv[])
{
void(*test_print)(char const*) = NULL;
int(*test_sum)(int, int) = NULL;
HMODULE module = LoadLibraryA("Dll1.dll");
if (module == NULL)
{
system("error load");
}
test_print = (void(*)(char const*))GetProcAddress(module, "test_print");
test_sum = (int(*)(int, int))GetProcAddress(module, "test_sum");
if (test_print != NULL)
{
test_print("输出测试");
}
else
{
system("function p_test_print can not excute");
}
int sum_result;
if (test_sum != NULL)
{
sum_result = test_sum(234, 432);
printf("求和结果是:%d\n", sum_result);
}
else
{
system("function p_test_print can not excute");
}
FreeLibrary(module);
system("pause");
return 0;
}
运行结果:
三、C#调用dll
将生成的DLL文件拷贝到C#项目目录的Debug下
C#源代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ConsoleApp2
{
class Program
{
[DllImport("Dll1.dll", EntryPoint = "test_sum", CallingConvention = CallingConvention.Cdecl)]
public static extern int test_sum(int a, int b);
static void Main(string[] args)
{
int a = 234, b = 432;
int sum = 0;
Console.WriteLine("{0}+{1}={2}", a, b, test_sum(a, b));
Console.ReadKey();
}
}
}
运行结果:
补充:
.lib和.dll的区别
引用网上的资料:
(1)lib是编译时需要的,dll是运行时需要的。 如果要完成源代码的编译,有lib就够了。 如果要使动态连接的程序运行起来,有dll就够了。 在开发和调试阶段,当然最好都有。
(2)一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。**如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。**如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。
(3)在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行时再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL文件必须随应用程序一起发行,否则应用程序将会产生错误。
调用DLL
引入dll的方法:
1、LoadLibray 一般是动态加载DLL时(不需要对应的头文件和LIB)。动态调用方式是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,使用上较为复杂,但是能更加有效的使用内存,是编制大型应用程序时的重要方式。(本文采用)
2、#pragma comment 一般是静态加载DLL时(对应的头文件、DLL和LIB缺一不可,并且生产的EXE没有找到DLL文件就会导致“应用程序初始化失败”)。静态调用方式由编译系统完成对DLL的加载和应用程序时DLL卸载的编码,简单实用但不灵活。
3、#import指令用于从一个类型库中结合信息。该类型库的内容被转换为C++类,主要用于描述COM界面。
总结
以上就是关于用C/C++ 生成dll,并用C/C++和C#调用dll的学习,希望对大家有帮助。
本文源码链接
https://download.csdn.net/download/sinat_40003796/85202652
|