【cmake实战六】如何使用编译的库(动态库dll)——windows系统

一、文件目录

在这里插入图片描述

1、main.cpp

#include<iostream>
#include<windows.h>
using namespace std;
void loadDll(string dllname, HMODULE& handle)
{
	//handle = (handle_t)::LoadLibrary(dllname.c_str());
	handle = (HMODULE)::LoadLibrary(dllname.c_str());
}

bool freeDll(HMODULE& handle)
{
	bool re = FreeLibrary(handle);
	return re;
}
int main()
{
	cout<<"hello world"<<endl;
	//handle_t handle = nullptr;
	HMODULE handle = nullptr;
	loadDll("C:\\Users\\jx\\Desktop\\test06\\lib\\Debug\\haha.dll", handle);
	if (nullptr == handle)
	{
		cout << "fail to load dll" << endl;
	}
	
	cout << "sucess to load dll" << endl;

	typedef void (*print)();

	print hahafunc=(print)GetProcAddress(handle, "haha");
	hahafunc();

	bool re = freeDll(handle);
	if (re)
	{
		cout << "success to unload dll" << endl;
	}

	return 0;
}

2、CmakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)

PROJECT(NEWHELLO)

ADD_EXECUTABLE(hello main.cpp)

ADD_SUBDIRECTORY(haha)

SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")

3、haha

  • haha.h
#ifndef HAHA_H
#define HAHA_H

#include<iostream>

extern "C" __declspec(dllexport) void haha();
#endif

  • haha.cpp
#include "haha.h"
using namespace std;
void haha()
{
	cout<<"haha"<<endl;
}
  • CmakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)

SET(TARGET "haha")

#ADD_LIBRARY(haha STATIC haha.cpp)
ADD_LIBRARY(haha SHARED haha.cpp)

SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")

二、构建、编译、运行

1、构建(新建build目录,在build目录下执行)

cmake ..

2、编译

devenv.com NEWHELLO.sln /Build "Debug|x64"

3、运行

.\hello.exe

在这里插入图片描述

三、知识讲解

1、LoadLibrary

2、FreeLibrary

  • 当不再需要 DLL 模块时,显式链接到 DLL 的进程会调用 FreeLibrary 函数。 此函数使模块的引用计数递减。 而且,如果引用计数为零,则从进程的地址空间取消映射。
  • FreeLibrary微软提供,linux下不可用,同linux下的dlclose

参考- https://docs.microsoft.com/zh-cn/cpp/build/freelibrary-and-afxfreelibrary?view=msvc-170

3、GetProcAddress

  • 显式链接到 DLL 的进程会调用 GetProcAddress,以获取 DLL 中导出函数的地址。 可使用返回的函数指针调用 DLL 函数。 GetProcAddress 采用 DLL 模块句柄(由 LoadLibrary返回)作为参数,并采用要调用的函数的名称或函数的导出序号。
  • 微软提供,linux下无法使用,同linux下的dlsym

参考:https://docs.microsoft.com/zh-cn/cpp/build/getprocaddress?view=msvc-170
https://www.cnblogs.com/avexer/p/3258291.html

4、__declspec

  • dllexportdllimport存储类属性是特定于 C 和 C++ 语言的扩展。 可以使用它们从 DLL 中导出或向其中导入函数、数据和对象。
  • 微软提供的,linux下无法使用,同linux下的__attribute__ ((visibility(“default”)))

参考:https://docs.microsoft.com/zh-cn/cpp/cpp/dllexport-dllimport?view=msvc-170
https://blog.csdn.net/yu704645129/article/details/53171315

5、extern “C”

四、问题

1、去掉extern “C" 会发生什么???

  • GetProcAddress(handle, “haha”);会失败

2、是否有办法去掉extern “C"

  • 结论,如果导出的c++的接口,不可以
  • 结论,或者,只需要把haha更改为c语言就可以了,如下
  • haha.h
#ifndef HAHA_H
#define HAHA_H

#include<stdio.h>

//extern "C" __declspec(dllexport) void haha();
__declspec(dllexport) void haha();
#endif


  • haha.c
#include "haha.h"

void haha()
{
	printf("haha\n");
}
  • CmakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)

SET(TARGET "haha")

#ADD_LIBRARY(haha STATIC haha.cpp)
ADD_LIBRARY(haha SHARED haha.c)

SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")

3、为啥c++就需要extern “C”,在

C++的编译方式考虑了函数重载,所以对函数名进行了新的修饰,产生了所谓的破坏性命名。

  • 这样实际上,我们在exe中调用的函数名字就是已经被修饰过的,所以我们直接按照原来的函数名自然就找不到了!为什么GetProcAddress返回值总为0?[解决方案]
  • c++代码,有extern “C”,使用depend查看haha.dll,函数名字为haha

在这里插入图片描述

  • c++代码,无extern “C”,使用depend查看haha.dll,函数名字为?haha@@YAXXZ

在这里插入图片描述

4、参考问题3的答案,问题2的另外一种方法

	print hahafunc=(print)GetProcAddress(handle, "haha");

更改为

	print hahafunc=(print)GetProcAddress(handle, "?haha@@YAXXZ");

1.使用LoadLibrary函数来加载dll库
2.C/C++中extern关键字详解
3.

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑同学的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值