VS2017开发动态链接库并调试
一、创建动态链接库工程
-
启动VS2017,选择菜单栏文件 > 新建 > 项目 > 已安装 > Visual C++ > Windows桌面 > 具有导出项的(DLL)动态链接库,设置好工程名称和路径,单击确定完成工程创建。
-
动态链接库工程创建后,会生成一个模板工程,如图所示。在模板工程中给出了怎样导出类、变量和函数的例子。
-
在mydll.h文件中已经定义好了动态链接库的导出宏。
// 下列 ifdef 块是创建使从 DLL 导出更简单的 // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 MYDLL_EXPORTS // 符号编译的。在使用此 DLL 的 // 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将 // MYDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的 // 符号视为是被导出的。 #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endif
-
为了便于多文件导出目标函数,先对模板工程进行简单修改,在解决方案窗口中,右键mydll工程 > 添加 > 新建项 > 已安装 > Visual C++ > 头文件,将文件名修改为export.h,单击添加完成。
-
在export.h文件中添加如下代码。
#pragma once #ifndef MYDLL_EXPORT_H_ #define MYDLL_EXPORT_H_ // 下列 ifdef 块是创建使从 DLL 导出更简单的 // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 MYDLL_EXPORTS // 符号编译的。在使用此 DLL 的 // 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将 // MYDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的 // 符号视为是被导出的。 #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endif #endif // !MYDLL_EXPORT_H_
删除mydll.h中的如下代码
// 下列 ifdef 块是创建使从 DLL 导出更简单的 // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 MYDLL_EXPORTS // 符号编译的。在使用此 DLL 的 // 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将 // MYDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的 // 符号视为是被导出的。 #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endif
在最上方添加
#include "export.h"
当动态链接库工程包含多个文件时,只需在各文件引入头文件export.h即可完成目标接口的导出。
-
在菜单栏选择生成 > 生成解决方案,生成成功后会生成如下文件。
并可在VS2017输出窗口查看到编译成功的信息。
1>------ 已启动生成: 项目: mydll, 配置: Debug Win32 ------ 1>pch.cpp 1>dllmain.cpp 1>mydll.cpp 1>正在生成代码... 1> 正在创建库 E:\Code-of-C++\vs2017_test\mydll\Debug\MYDLL.lib 和对象 E:\Code-of-C++\vs2017_test\mydll\Debug\MYDLL.exp 1>mydll.vcxproj -> E:\Code-of-C++\vs2017_test\mydll\Debug\MYDLL.dll ========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
-
修改mydll.h和mydll.cpp,实现一些具体接口,便于下一步进行调试。
-
mydll.h
#include "export.h" #include <iostream> #include <string> /** * @enum INFO_TYPE * @brief 消息等级 */ enum INFO_TYPE { MY_INFO, ///< 普通消息 MY_WARNING, ///< 警告消息 MY_ERROR, ///< 错误消息 }; /** * @struct MY_INFO * @brief 定义消息结构体 */ typedef struct MY_MSG { INFO_TYPE infoType; ///< 消息等级 std::string msg; ///< 详细信息 std::string funcName; ///< 函数名称 } MY_MSG; /** * @class DllTest * @brief 动态链接库导出类测试 */ class MYDLL_API DllTest { public: /** * @brief 构造函数 */ DllTest(std::string &s); /** * @brief 析构函数 */ ~DllTest(); DllTest &setStr(std::string &s); /** ******************************************************************************* * @brief 输出字符串 * @ref \n * @return void * - 返回值描述 * @author AILEE * @date 2020-12-31 * @par 示例: * @code * @endcode * @see ******************************************************************************* */ void printStr(); private: std::string str; }; /** ******************************************************************************* * @brief 输出消息 * @param[in] MY_MSG & msg : 消息结构体 * @ref \n * @return void * - 无返回值 * @author AILEE * @date 2020-12-31 * @par 示例: * @code * @endcode * @see ******************************************************************************* */ MYDLL_API void printInfo(MY_MSG &msg);
-
mydll.cpp
// mydll.cpp : 定义 DLL 的导出函数。 // #include "pch.h" #include "framework.h" #include "mydll.h" DllTest::DllTest(std::string & s) :str(s) {} DllTest::~DllTest() {} DllTest & DllTest::setStr(std::string & s) { str = s; return *this; } void DllTest::printStr() { std::cout << str << std::endl; } void printInfo(MY_MSG &msg) { switch (msg.infoType) { case MY_INFO: std::cout << "[INFO]: " << msg.msg << std::endl; break; case MY_WARNING: std::cout << "[WARNING]: " << msg.funcName << ": " << msg.msg << std::endl; break; case MY_ERROR: std::cout << "[ERROR]: " << msg.funcName << ": " << msg.msg << std::endl; break; default: break; } }
-
-
重新编译
2. 创建控制台应用工程,调用动态链接库并进行联合调试。
-
选择解决方案窗口,右键解决方案 > 添加 > 新建项目 > 已安装 > Visual C++ > Windows桌面 > 控制台应用,设置好项目名称,单击确定完成。
-
右键解决方案列表中的mydll_example项目,选择设为启动项目。
-
右键解决方案列表中的mydll_example项目,选择生成依赖项 > 项目依赖项,在弹出的窗口中,勾选mydll。
-
右键解决方案列表中的mydll_example项目,选择属性,在弹出的属性页中,将配置改为所有配置,然后选择链接器 > 常规 > 附加库目录 > 编辑 > 宏,进行如下配置。
选择属性页 > 链接器 > 输入 > 附加依赖项 > 编辑,添加MYDLL.lib。
单击确定,完成属性设置。
-
在mydll_example.cpp的最上面添加,因为mydll工程和mydll_example工程是同一级目录,因此添加mydll.h头文件时需要先返回上一级目录。
#include "../mydll/mydll.h"
-
将mydll_example.cpp修改为如下内容
#include "../mydll/mydll.h" int main() { std::string str = "hello world!\n"; // 创建对象 DllTest dllTest(str); // 打印对象中的字符串 dllTest.printStr(); // 设置对象中的字符串 str = "hello dll!\n"; dllTest.setStr(str); // 打印对象中的字符串 dllTest.printStr(); // 调用打印消息函数,输出消息 std::string warning_msg = "this is a waring."; MY_MSG msg; msg.infoType = MY_WARNING; msg.funcName = __FUNCTION__; msg.msg = warning_msg; printInfo(msg); }
-
选择菜单栏中调试 > 开始执行(不调试),将在命令行窗口输出如下内容。
-
设置好断点,选择菜单栏中调试 > 开始调试,即可进行调试。
-
切换到Release配置,重新生成解决方案,即可在mydll工程文件夹下的Release文件夹下找到MYDLL.dll和MDLL.lib,将其拷贝一份,并复制工程对应的头文件,按如下方式组织,即可进行动态链接库的发布,方便以后使用。
- mydll_x86_release
- bin
- mydll.dll
- include
- export.h
- framework.h
- mydll.h
- pch.h
- lib
- mydll.lib
- bin
- mydll_x86_release