系列文章目录
文章目录
前言
程序对动态链接库dll、静态链接库lib想必都很熟悉了,网上也有很多的相关介绍。但网上介绍的一般都是C语言函数介绍,很少看到有自定义类导出dll。下面我就和大家一起讨论一下如何使用visual studio2019开发工具把自定义的类导出dll。
一、具体操作步骤
1.创建动态链接库工程(DLL)
2.头文件声明
#ifdef ConfigJsonDataDll_Exports #define ConfigJsonDataDll_API __declspec(dllexport) #else #define ConfigJsonDataDll_API __declspec(dllimport) #endif #include <iostream> #include <fstream> #include <sstream> #include <map> #include "nlohmann/json.hpp" using namespace std; using nlohmann::json; namespace ConfigJsonData { class ConfigJsonDataDll_API ConfigData { public: ConfigData(); ~ConfigData(); public: void loadJsonFile(const string& fileName); void loadJsonString(const string& jsonString); json toJson(); void fromJson(); void saveToJsonFile(const string& fileName); public: // Getter 和 Setter 方法 const json& getJsonData() const { return _jsonData; } void setJsonData(const json& jsonData) { _jsonData = jsonData; } const string& getFileName() const { return _fileName; } void setFileName(const string& fileName) { _fileName = fileName; } const string& getAdcType() const { return _adcType; } void setAdcType(const string& adcType) { _adcType = adcType; } map<string, int>& getFpgaMap() { return _FpgaMap; } void setFpgaMap(const map<string, int>& fpgaMap) { _FpgaMap = fpgaMap; } const map<string, string>& getCameraInfoMap() const { return _cameraInfoMap; } void setCameraInfoMap(const map<string, string>& cameraInfoMap) { _cameraInfoMap = cameraInfoMap; } const map<string, vector<int>>& getGainMap() const { return _gainMap; } void setGainMap(const map<string, vector<int>>& gainMap) { _gainMap = gainMap; } const map<string, vector<int>>& getOffsetMap() const { return _offsetMap; } void setOffsetMap(const map<string, vector<int>>& offsetMap) { _offsetMap = offsetMap; } const map<string, map<string, map<string, int>>>& getIndexBankRegMap() const { return _indexBankRegMap; } void setIndexBankRegMap(const map<string, map<string, map<string, int>>>& indexBankRegMap) { _indexBankRegMap = indexBankRegMap; } private: string _fileName; string _adcType; map<string, int> _FpgaMap; map<string, string> _cameraInfoMap; map<string, vector<int>> _gainMap; map<string, vector<int>> _offsetMap; map<string, map<string, map<string, int>>> _indexBankRegMap; json _jsonData; }; }
3.实现文件定义
#include "ConfigData.h" using namespace ConfigJsonData; ConfigData::ConfigData() { //_jsonData = std::make_shared<json>(); } ConfigData::~ConfigData() { _FpgaMap.clear(); _cameraInfoMap.clear(); _gainMap.clear(); _offsetMap.clear(); } void ConfigData::loadJsonString(const string& jsonString) { _jsonData = json::parse(jsonString); } void ConfigData::fromJson() { try { //取出CameraInfor数据 if (_jsonData.find("CameraInfor") != _jsonData.end()) { nlohmann::json cameraJson = _jsonData.at("CameraInfor"); for (auto& elem : cameraJson.items()) { cout << "cameraInfo.key=" << elem.key() << ", cameraInfo.value=" << elem.value().get<std::string>() << endl; _cameraInfoMap[elem.key()] = elem.value().get<std::string>(); string adcTypeKey = elem.value().get<string>(); _adcType = adcTypeKey; } } std::cout << "ADC Type = " << _jsonData["CameraInfor"]["ADC_TPYE"] << std::endl; for (auto& i : _jsonData["FPGA"].items()) { std::cout << i.key() << " : " << i.value() << std::endl; _FpgaMap[i.key()] = i.value(); } auto adc_type = json::string_t(_jsonData["CameraInfor"]["ADC_TPYE"]); for (auto& i : _jsonData["ADC_" + adc_type].items()) { string indexKey = i.key(); for (auto& j : i.value().items()) { string bankKey = j.key(); for (auto& k : j.value().items()) { string registKey = k.key(); auto Index = json::string_t(i.key()); auto Bank = json::string_t(j.key()); auto Register = json::string_t(k.key()); auto Value = json::number_integer_t(k.value()); printf("[ADC Index] = %s, [ADC Bank] = %s, ADC Register %s = %zd\n", Index.c_str(), Bank.c_str(), Register.c_str(), Value); _indexBankRegMap[indexKey][bankKey][registKey] = Value; } } } cout << "*************验证三层嵌套的map否已正确存储**************" << endl; //验证_indexBankRegMap中的数据是否已正确存储 for (const auto& index_pair : _indexBankRegMap) { cout << "[ADC Index]=" << index_pair.first << endl; for (const auto& bank_pair : index_pair.second) { cout << " [ADC Bank]=" << bank_pair.first << endl; for (const auto& reg_pair : bank_pair.second) { cout << " ADC Register:" << reg_pair.first << " = " << reg_pair.second << endl; } } } //取出Gaim string adcGainKey = "GAIN_" + _adcType; if (_jsonData.contains(adcGainKey)) { string gainKey; vector<int> gainValueVec; for (auto &elem : _jsonData[adcGainKey].items()) { gainKey = json::string_t(elem.key()); nlohmann::json gainValue = elem.value(); if (gainValue.is_array()) { for (auto &elem : gainValue) { if (elem.is_number()) { auto gainTemp = json::number_integer_t(elem); cout << "gain temp valuel=" << gainTemp << endl; gainValueVec.push_back(gainTemp); } } } } _gainMap[gainKey] = gainValueVec; } //取出offset string adcOffsetKey = "OFFSET_" + adc_type; if (_jsonData.contains(adcOffsetKey)) { string offsetKey; vector<int> offsetValueVec; for (auto &elem : _jsonData[adcOffsetKey].items()) { offsetKey = nlohmann::json::string_t(elem.key()); nlohmann::json offsetValue = elem.value(); if (offsetValue.is_array()) { for (auto &elem : offsetValue) { if (elem.is_number()) { auto offsetTemp = json::number_integer_t(elem); cout << "offset Temp value=" << offsetTemp << endl; offsetValueVec.push_back(offsetTemp); } } } } _offsetMap[offsetKey] = offsetValueVec; } } catch (const json::exception& e) { std::cerr << "Error parsing JSON: " << e.what() << std::endl; return ; } return ; } void ConfigData::loadJsonFile(const string& fileName) { std::ifstream file(fileName); if (!file.is_open()) { //throw runtime_error("Failed to open file: " + fileName); std::cerr << "Failed to open the file." << std::endl; return ; } file >> _jsonData; file.close(); } void ConfigData::saveToJsonFile(const string& fileName) { ofstream file(fileName); if (!file.is_open()) { std::cerr << "open file failed!" << endl; return; } file << _jsonData.dump(4) << endl; file.close(); } json ConfigData::toJson() { nlohmann::json j; j["ADC_TPYE"] = _adcType; j["FPGA"] = _FpgaMap; j["CameraInfor"] = _cameraInfoMap; j["GAIN_AK8446"] = _gainMap; j["OFFSET_AK8446"] = _offsetMap; j["ADC_AK8446"] = _indexBankRegMap; _jsonData = j; return j; }
说明,动态链接库dll定义头文件,与普通的exe工程中的头文件唯一区别,就是文件头
需要加入导出dll的宏定义,以及要在类名前加上ConfigJsonDataDll_API:
#ifdef ConfigJsonDataDll_Exports #define ConfigJsonDataDll_API __declspec(dllexport) #else #define ConfigJsonDataDll_API __declspec(dllimport) #endif #include <iostream> #include <fstream> #include <sstream> #include <map> #include "nlohmann/json.hpp" using namespace std; using nlohmann::json; namespace ConfigJsonData { class ConfigJsonDataDll_API ConfigData
4.生成dll工程
这是在visual studio2019配置项中会自动生成预处理器宏,一般情况下都能正常生成dll和lib文件的,如果在生成的debug和release中发现只用dll而没有lib,一般都是忘记2点:
1.导出宏忘记在头文件中声明了
#ifdef ConfigJsonDataDll_Exports #define ConfigJsonDataDll_API __declspec(dllexport) #else #define ConfigJsonDataDll_API __declspec(dllimport) #endif
2.类名前忘记加宏定义了关键字ConfigJsonDataDll_API
class ConfigJsonDataDll_API ConfigData
5 使用dll
1.生成ConfigJsonDataDllTest测试工程,配置类型是exe
2.这里为了能调试dll中的源码我使用静态库方式使用
(1)把在dll工程中的头文件ConfigData.h拷贝到ConfigJsonDataDllTest测试工程下。
注意:如果你的dll工程中依赖其他第三方的头文件和lib和dll库的话,也要把这些依赖库的头文件和lib以及dll库拷贝到你的exe工程中
(2)把dll工程中的dll文件拷贝到你的exe工程中,把dll文件拷贝到exe同级目录
(3)如果需要调试dll源码,需要把ConfigJsonDataDll.pdb文件连同ConfigJsonDataDll.dll一起拷贝到exe同级目录下
3.测试dll代码
// ConfigJsonDataDllTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <map> #include "ConfigData.h" using namespace ConfigJsonData; using namespace std; #pragma comment(lib, "ConfigJsonDataDll.lib") int main() { ConfigData config; config.loadJsonFile("config.json"); config.fromJson(); map<string,int>fpgaMap = config.getFpgaMap(); for (const auto& item : fpgaMap) { cout << "item.key=" << item.first << ", item.value=" << item.second << endl; } }
注意:如果在你的exe工程中配置编译器设置使用预编译宏时,需要把预编译宏加入到你的配置选项中。
在预处理其中加入宏:ConfigJsonDataDll_API
总结
在使用dll中遇到的坑基本上都踩了一遍,把上文中提到的注意点处理好,基本上就能正常使用了。