这个月学习了很多内容,而且还各不相关。特此记录一下如何生成dll,如何使用dll。
生成dll
新建win32控制台应用程序项目,点击dll项目,然后点击空项目。
首先我们肯定需要写好自己的类。
class FlowNet :public Model_Loader_Base {
public:
FlowNet() {
build_flow_map(colorwheel, ncols);
};
Mat flowImage;
bool predict(const vector<std::pair<string, Tensor> >&) ;
float colorwheel[55][3];
unsigned char ncols;
std::string output_node = "up_sampling2d_1/ResizeBilinear";
public:
void build_flow_map(float colorwheel[55][3], unsigned char &ncols);
void flo2img(cv::Mat& flo, cv::Mat& img, float colorwheel[55][3], unsigned char ncols);
Tensor input_1 = Tensor(DT_FLOAT, TensorShape({ 1,512,512,3 }));
Tensor input_2 = Tensor(DT_FLOAT, TensorShape({ 1,512,512,3 }));
void preProcessing(const Mat&, const Mat&);
};
我这边定义一个FlowNet类。然后我们新建一个cpp源文件。包含我们定义类的头文件。
还要包含,一定要包含这个头文件。
#include <Windows.h> // W是大写的
然后定义一个全局指针。
FlowNet* flownet = NULL;
我们需要设计自己需要使用的接口了,这个设计方式需要根据自己的情况。
比如博主要用这个类实现初始化模型,完成预测,和卸载模型,一共三个功能,所以需要设计三个接口。
extern "C" __declspec(dllexport) bool InitFlowNet(string pb_file)
{
flownet = new FlowNet();
if (NULL != flownet)
{
std::cout << "successfully new a FlowNet class " << std::endl;
}
else
{
std::cout << "fail to new a FlowNet class... " << std::endl;
}
if (!flownet->init()) {
cout << "fait to init flownet" << std::endl;
return false;
}
else {
return flownet->load(pb_file);
}
}
第一个接口函数是InitFlowNet,在函数前面加上
extern "C" __declspec(dllexport)
预测函数就不展示了,因为不通用。卸载接口是和初始化接口是必要的,因为new了指针,就必然对应delete嘛
extern "C" __declspec(dllexport) void ReleaseFlowNet()
{
if (NULL != flownet)
{
delete flownet;
flownet = NULL;
//showLog << "完成释放" << endl;
}
}
然后CTRL+F5运行。没有错误的话,就可以在项目的x64的release下看到和项目名称相同的dll和lib文件了。(x64和release对应自己编译的环境)。
使用dll
使用dll的方式有两种,分为静态调用和动态调用,(是这么叫吧,我不是专业学C++的)。我仅介绍动态调用,因为真的好用。
新建一个新的空项目(直接点击空项目),把上一步生成的dll放到项目工程里面,和源文件cpp文件一个目录下。然后我们新建一个源.cpp文件。
还是要包含
#include <windows.h>
之后需要定义接口的函数指针。我仅展示我之前展示的初始化接口和卸载接口。
typedef bool(*pInit)(string);
typedef void(*pRelease)();
然后设置这些指针指向NULL;
pInit pInitFun = NULL;
pRelease pReleaseFun = NULL;
那么pInitFun和pReleaseFun就是我们接下来调用的函数了。但是现在还不能直接用。
接下来导入dll
HINSTANCE hdll = LoadLibrary(" your dll name .dll");
if( !hdll)
{
cout<<"fail to import dll<<endl;
}
else
{
pInitFun = (pInit)GetProcAddress(hdll,"InitFlowNet");
pReleaseFun = (pRelease)GetProcAddress(hdll."ReleaseFlowNet");
}
然后pInitFun和pReleaseFun就指向我们在生成dll的文件中定义的接口了。之后就可以愉快的使用这两个函数在任何win电脑上了。
错误记录
如果导入dll失败,用GetLastError发现输出126,则说明生成的dll使用了另一个dll,而那个dll没有拷贝到当前项目中。