系列文章目录
前言
程序对动态链接库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中遇到的坑基本上都踩了一遍,把上文中提到的注意点处理好,基本上就能正常使用了。