C++ dll库的封装及调用

进行dll库封装时的自我笔记,以便自己时常回顾。

一、dll库的封装

右击工程,点击属性,打开属性界面,在常规一栏中将配置类型从.exe改为.dll
在这里插入图片描述

1.建立一个dllmain源文件,加上定义dll应用程序的入口点的程序,如下:

//dllmain.cpp:定义DLL应用程序的入口点
#include "stdafx.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;
}


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

2.在主程序相对应的头文件中添加:

#ifdef  VISIONDll
#define  VISIONAPI extern"C" _declspec(dllexport)
#else
#define  VISIONAPI extern"C" _declspec(dllimport)
#endif

extern “C” _declspec(dllexport)与project2.h中的#ifdef…endif是将C++函数导出,才会生成lib文件

3.添加targetver.h头文件



// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。

// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。

#include <SDKDDKVer.h>#pragma once

包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。

4.添加stdafx.h头文件

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//


#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头中排除极少使用的资料
// Windows 头文件: 
#include <windows.h>



// TODO:  在此处引用程序需要的其他头文件

stdafx.h : 标准系统包含文件的包含文件,
或是经常使用但不常更改的
特定于项目的包含文件

5 . 在“.cpp”文件中对要导出的函数名前加上“VISIONAPI”这个宏;此方法为将函数直接封装为C接口,

VISIONAPI bool trigger( std::string&str_imageFilePath);

6 . 将这些设置好后,编译链接即可在工程目录下的Debug目录下生存“.dll”(动态连接库)和“.lib”(编译库此文件不同于静态库),这两个文件再加上“*.h”文件即为我们刚封装好的有效文件;

二、动态库的调用方式

(一)静态调用

1、添加动态库函数声明头文件 #include“*.h”

2.在.h文件中,在需要调接口函数的地方添加如下语句:
#pragma comment(lib, ".\.lib")
.\
.lib为动态库的绝对路径。
就可以调用动态库中的函数了。

(二)动态调用

dll显示调用
对于显示连接,即动态加载我们需要调用LoadLibrary
在MSDN中:HMODULE WINAPI LoadLibrary( __in LPCTSTR lpFileName);
它的功能是映射一个可执行模块到调用进程的地址空间。由此我们知道显示调用就是函数指针来调用函数。

1.声明头文件<windows.h>,说明我想用windows32方法来加载和卸载DLL

#include <windows.h>

2、定义一个与动态库函数接受参数类型和返回值均相同的函数指针类型。
即用typedef定义一个指针函数类型。这个指针类型,要和调用的函数类型和参数保持一致
typedef int (* lpAddFun)(int ,int);
lpAddFun addFun;

typedef bool(*pTrigger)(std::string str_imagePath);
pTrigger trigger;

3、定一个句柄实例,用来取DLL的实例地址。HINSTANCE hDll;
格式为:hDll=LoadLibrary(“DLL地址”)//动态加载DLL模块句柄

这里字符串类型是LPSTR,当是unicode字符集的时候会不行,
因此要在配置-属性-常规里面把默认字符集“unicode”改成支持多字符扩展即可。

HINSTANCE hInst = LoadLibrary(L"OCRDetect.dll");

4、取的地址要判断,返回的句柄是否为空,如果为无效句柄,那么要释放加载DLL所占用的内存。

	if (hInst == NULL)
	{
		FreeLibrary(hInst);
	}

5、定义一个函数指针,用来获取所加载DLL模块中函数的地址。
然后通过GetProcAdress来获取函数的地址,参数是DLL的句柄和想要调用的函数名:比如:addFun=(lpAddFun) GetProcAddress(hDll,“Add_new”);
这里也要判断要函数指针是否为空,如果没取到要求的函数,那么要释放句柄。

trigger = (pTrigger)::GetProcAddress(hInst, "trigger");

6、然后通过函数指针来调用函数。
7、调用结束后,就释放句柄FreeLibrary(hdll);

   FreeLibrary(hInst);

提示:若动态库程序和调用动态库的程序在一个解决方案中可以利用项目依赖项,定义项目生成顺序。也可以在调用动态库程序右键属性 -> c/c++ ->常规的附加包含目录中填入动态库目录。

然后用形如
#ifdef _DEBUG
#pragma comment(lib,"…\Debug\TestDll.lib")
#else
#pragma comment(lib,"…\Release\TestDll.lib")
#endif
这种方式静态加载动态库

调用动态库例程

#include <iostream>
#include <string>
#include <windows.h>
#include <WinBase.h>


typedef bool(*pTrigger)(std::string str_imagePath);
pTrigger trigger;


int main()
{
	HINSTANCE hInst = LoadLibrary("OCRDetect.dll");  //动态加载模块句柄
	if (hInst == NULL)
	{
		FreeLibrary(hInst);
		std::cout << "DLL加载失败!" << std::endl;
		return 0;
	}

	trigger = (pTrigger)::GetProcAddress(hInst, "trigger");
	if (hInst == NULL)
	{
		FreeLibrary(hInst);
	}
	std::string str_imageFile = "bottle2.png";

	trigger(str_imageFile);
    FreeLibrary(hInst);
	return 0;
}
  • 3
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

&Mr.Gong

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

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

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

打赏作者

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

抵扣说明:

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

余额充值