实习时需要在Epanet源码中添加新函数并在自己实现的QGIS插件中调用,在生成和调用dll过程中遇到了一些问题,记录下这些问题和解决过程。
生成DLL文件和LIB文件
1. epanet源代码
我是下载的同济大学的汉化版,代码比较简洁一些
下载地址:EPANETH2中文版
2.创建动态链接库
打开VS2019,创建新项目,选择动态链接库
将EPANETH2源代码中所有头文件和源文件放入项目中
直接生成解决方案会报一些错误,需要进行下面两个设置
项目属性->C/C+±>预编译头,设置不使用预编译头
项目属性->C/C+±>预处理器,在预处理器定义里添加 _CRT_SECURE_NO_DEPRECATE
3.编译动态链接库
生成解决方案后,在项目的Release文件夹下生成了dll文件。在其他项目中进行显示调用,通过LoadLibrary函数调用dll时成功,通过GetProcAddress函数获取EPANET.dll中的方法却失败了
打开VS2019命令提示符
定位到dll文件所在目录路径,输入dumpbin /exports dll文件名,可以看到dll文件没有导出函数接口
发现在预处理器定义里没有DLL,只有_USERDLL
将toolkith.h中定义DLLECPORT代码第一个#ifdef DLL改为预处理器定义中存在的#ifdef _USERDLL
再次通过命令提示符查看dll的函数接口
接口是完整的,自己新写的函数接口也有。接下来在项目中再次调用试试
在项目中调用
1.控制台应用调用EPANET动态链接库文件
显示调用dll是成功的,但是在隐式调用时头文件epanet2h.h报错,无法运行
对epanet2h.h进行一些修改
在工具箱函数声明部分添加extern “C”{ }
// --- 声明EPANET工具箱函数
extern "C" {
int DLLEXPORT ENepanet(char*, char*, char*, void (*) (char*));
int DLLEXPORT ENopen(char*, char*, char*);
int DLLEXPORT ENsaveinpfile(char*);
int DLLEXPORT ENclose(void);
int DLLEXPORT ENsolveH(void);
int DLLEXPORT ENsaveH(void);
int DLLEXPORT ENopenH(void);
int DLLEXPORT ENinitH(int);
int DLLEXPORT ENrunH(long*);
int DLLEXPORT ENnextH(long*);
int DLLEXPORT ENcloseH(void);
int DLLEXPORT ENsavehydfile(char*);
int DLLEXPORT ENusehydfile(char*);
int DLLEXPORT ENsolveQ(void);
int DLLEXPORT ENopenQ(void);
int DLLEXPORT ENinitQ(int);
int DLLEXPORT ENrunQ(long*);
int DLLEXPORT ENnextQ(long*);
int DLLEXPORT ENstepQ(long*);
int DLLEXPORT ENcloseQ(void);
int DLLEXPORT ENwriteline(char*);
int DLLEXPORT ENreport(void);
int DLLEXPORT ENresetreport(void);
int DLLEXPORT ENsetreport(char*);
int DLLEXPORT ENgetcontrol(int, int*, int*, float*,
int*, float*);
int DLLEXPORT ENgetcount(int, int*);
int DLLEXPORT ENgetoption(int, float*);
int DLLEXPORT ENgettimeparam(int, long*);
int DLLEXPORT ENgetflowunits(int*);
int DLLEXPORT ENgetpatternindex(char*, int*);
int DLLEXPORT ENgetpatternid(int, char*);
int DLLEXPORT ENgetpatternlen(int, int*);
int DLLEXPORT ENgetpatternvalue(int, int, float*);
int DLLEXPORT ENgetqualtype(int*, int*);
int DLLEXPORT ENgeterror(int, char*, int);
int DLLEXPORT ENgetnodeindex(char*, int*);
int DLLEXPORT ENgetnodeid(int, char*);
int DLLEXPORT ENgetnodetype(int, int*);
int DLLEXPORT ENgetnodevalue(int, int, float*);
int DLLEXPORT ENgetlinkindex(char*, int*);
int DLLEXPORT ENgetlinkid(int, char*);
int DLLEXPORT ENgetlinktype(int, int*);
int DLLEXPORT ENgetlinknodes(int, int*, int*);
int DLLEXPORT ENgetlinkvalue(int, int, float*);
int DLLEXPORT ENgetversion(int*);
int DLLEXPORT ENsetcontrol(int, int, int, float, int, float);
int DLLEXPORT ENsetnodevalue(int, int, float);
int DLLEXPORT ENsetlinkvalue(int, int, float);
int DLLEXPORT ENaddpattern(char*);
int DLLEXPORT ENsetpattern(int, float*, int);
int DLLEXPORT ENsetpatternvalue(int, int, float);
int DLLEXPORT ENsettimeparam(int, long);
int DLLEXPORT ENsetoption(int, float);
int DLLEXPORT ENsetstatusreport(int);
int DLLEXPORT ENsetqualtype(int, char*, char*, char*);
int DLLEXPORT OpenGisData(char*, int);
}
再次测试在项目中调用
通过控制台打印信息可以看到调用成功了
2. QGIS插件中调用EPANET动态链接库文件
我的QGIS插件是C++实现的
把dll放在插件动态链接库项目的Release文件夹中,在项目属性->C/C+±>常规->附加包含目录添加epanet.h所在文件夹目录,项目属性->链接器->常规->附加目录库中添加lib文件所在文件夹目录,项目属性->链接器->输入->附加依赖项添加lib
在我的QGIS插件中显示调用dll,QGIS插件dll文件放入QGIS的plugins中,在QGIS中测试没有反应,隐式调用插件则直接失效
同时将epanet生成的dll放在plugins目录中,可以成功调用了
参考文章:
https://blog.csdn.net/xingbaoqiliaozhan/article/details/107837653
https://blog.csdn.net/zhanglifu3601881/article/details/80666755
https://zhuanlan.zhihu.com/p/146546063
https://blog.csdn.net/cnhk1225/article/details/76167469