大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE稳定放心使用
原创文章,转载请注明出处。
如果Windows系统有缺失的DLL文件,可以去这个链接下载。点击去这里寻找
C++ DLL简介以及使用
1>认识DLL(动态链接库)
动态链接库DLL(Dynamic-Link Library)通常包含程序员自定义的变量和函数, 可以在运行时动态链接到可执行文件(我们的exe程序)中。
2 >格式后缀
Windows上:(.dll)
Linux上:(.so)
Android上:(.so)
IOS上:(.dylib)
3 >DLL优点
1)模块化,耦合小:大规模软件开发中,开发过程独立,耦合度小,比如UE4里面的模块(每一个.build.cs)都是一个DLL。
2)扩展性:DLL文件与EXE文件是独立的,只要接口不变,升级程序只需更新DLL文件不需要重新编译应用程序。并且我们的EXE文件较小。
3)复用性:DLL的编制与具体的编程语言以及编译器无关,不同语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数。
4)节省内存:当应用程序使用动态链接时,多个应用程序可以共享磁盘上单个DLL副本。
5)隐私性:可以当做黑盒使用,可以将我们的具体实现代码隐藏起来,比如我们想将算法的具体实现隐藏起来,不让别人看到我是怎么做的。一般SDK接入时候,里面的具体算法实现都是不会公开cpp的。
4 >DLL缺点
如果是动态loaddll的话,会牺牲部分性能吧。微乎其微的。
5 >加载DLL
1>动态加载(运行时加载)通过LoadLibary加载, GetProcAddress调用。
如果加载失败,通过GetLastError()获取失败原因。
下面是LoadLibary的示例代码
第一步,在.h中声明了static HMODULE hDLL;
#include<Windows.h> //加载的头文件
class QIDCardReader : public QMainWindow
{
Q_OBJECT
public:
QIDCardReader(QWidget* parent = 0);
private:
static HMODULE hDLL;
};
第二步,定义要调用的dll中的方法。并通过LoadLibrary给hDLL赋值
#include "QIDCardReader.h"
//CPP中预声明一下我要调用dll里面的方法
typedef int(*MyRouton_RepeatRead)(bool);
typedef int(*MyInitComm)(int);
typedef int(*MyAuthenticate)();
typedef int(*MyReadBaseInfosPhoto)(char * , char * , char * ,
char *, char * , char * ,
char *, char * , char* , char * );
typedef int(*MyCloseComm)();
HMODULE QIDCardReader::hDLL;
QIDCardReader::QIDCardReader(QWidget* parent) : QMainWindow(parent)
,ui_(new Ui::QIDCardReaderClass)
{
hDLL = LoadLibrary(L"D:\\bimvr-vrlauncher\\test\\Sdtapi.dll"); //加载dll文件
//如果加载失败的话, 通过GetLastError()进行获取,看失败原因。
auto code5 = GetLastError();
}
第三步,调用dll中的方法 GetProcAddress(hDLL, “实际的dll端函数导出名称”)
//调用1
if (hDLL)
{
MyRouton_RepeatRead MyRouton_RepeatReadFunc = (MyRouton_RepeatRead)GetProcAddress(hDLL, ("Routon_RepeatRead"));//直接使用原工程函数名
if (MyRouton_RepeatReadFunc)
{
MyRouton_RepeatReadFunc(true);
}
}
//调用2
int iPort = 1001;
//int ret = InitComm(iPort);
int ret = -1000;
if (hDLL)
{
MyInitComm MyInitCommFunc = (MyInitComm)GetProcAddress(hDLL, ("InitComm"));//直接使用原工程函数名
if (MyInitCommFunc)
{
ret = MyInitCommFunc(iPort);
}
}
if (ret)
{
//ret = Authenticate();
if (hDLL)
{
MyAuthenticate MyAuthenticateFunc = (MyAuthenticate)GetProcAddress(hDLL, ("Authenticate"));//直接使用原工程函数名
if (MyAuthenticateFunc)
{
ret = MyAuthenticateFunc();
}
}
if (ret)
{
char user_name[31] = {
0 };
char user_gender[3] = {
0 };
char user_folk[11] = {
0 };
char user_birthday[9] = {
0 };
char user_code[19] = {
0 };
char user_address[71] = {
0 };
char user_agency[31] = {
0 };
char expire_start[9] = {
0 };
char expire_end[9] = {
0 };
QByteArray data_path = QString::fromStdWString(AppUtils::GetDataPath()).toLatin1();
ret = ReadBaseInfosPhoto(user_name, user_gender, user_folk, user_birthday, user_code,
user_address, user_agency, expire_start, expire_end, str/*data_path.data()*/);
if (hDLL)
{
MyReadBaseInfosPhoto MyReadBaseInfosPhotoFunc = (MyReadBaseInfosPhoto)GetProcAddress(hDLL, ("ReadBaseInfosPhoto"));//直接使用原工程函数名
if (MyReadBaseInfosPhotoFunc)
{
ret = MyReadBaseInfosPhotoFunc(user_name, user_gender, user_folk, user_birthday, user_code,
user_address, user_agency, expire_start, expire_end, str/*data_path.data()*/);
}
}
}
}
第四步,可以选择性调用FreeLibrary(hDLL)卸载Dll,这个是下面的静态三件套加载方式做不到的。
也就是说我们可以动态控制Dll的加载与卸载。
2>静态加载方式(.h .lib .dll三件套加载)
1>项目->属性->配置属性->VC++ 目录-> 在“包含目录”里添加头文件Sdtapi.h所在的目录
2>项目->属性->配置属性->VC++ 目录-> 在“库目录”里添加头文件Sdtapi.lib所在的目录
3>项目->属性->配置属性->链接器->输入-> 在“附加依赖项”里添加“Sdtapi.lib”(若有多个 lib 则以空格隔开)
也可以使用#pragma comment(lib, “Sdtapi.lib”)代替上面的1、2、3步骤。
QIDCardReader.cpp 包含.h,将.h添加到项目中
#include "sdtapi.h"
void QIDCardReader::onNotify()
{
Routon_RepeatRead(true);
int iPort = 1001;
int ret = InitComm(iPort);
if (ret)
{
ret = Authenticate();
if (ret)
{
char user_name[31] = {
0};
char user_gender[3] = {
0};
char user_folk[11] = {
0};
char user_birthday[9] = {
0};
char user_code[19] = {
0};
char user_address[71] = {
0};
char user_agency[31] = {
0};
char expire_start[9] = {
0};
char expire_end[9] = {
0};
QByteArray data_path = QString::fromStdWString(AppUtils::GetDataPath()).toLatin1();
ret = ReadBaseInfosPhoto(user_name, user_gender, user_folk, user_birthday, user_code,
user_address, user_agency, expire_start, expire_end, data_path.data());
}
}
}
现在是可以通过编译了,但是运行会报错 提示LinkError
因为程序分为编译和链接两步骤,这就是为什么报错误的原因。
我们解决这个报错就是将.dll放到和.exe同级目录就好了
如果最终exe找不到dll的话,会提示下面的错误。解决方法就是将dll放到和exe同级目录就好了。
谢谢,创作不易,大侠请留步… 动起可爱的双手,来个赞再走呗 <( ̄︶ ̄)>
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/187575.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...