对于dll文件有两种读取方式
预备知识:
1、如果在没有导入库文件(.lib),而只有头文件(.h)与动态链接库(.dll)时,我们才需要显示调用,如果这三个文件都全的话,我们就可以使用简单方便的隐式调用。
2、通常Windows下程序显示调用dll的步骤分为三步(三个函数):LoadLibrary()、GetProcAdress()、FreeLibrary()
其中,LoadLibrary() 函数用来载入指定的dll文件,加载到调用程序的内存中(DLL没有自己的内存!)
GetProcAddress() 函数检索指定的动态链接库(DLL)中的输出库函数地址,以备调用
FreeLibrary() 释放dll所占空间
第一:隐式调用
对于完成的dll .lib 和.h文件。调用起来非常简单。平常用到的opencv,其实在调用的时候就是隐式调用。
配置opencv的过程就是对于dll的隐式调用的过程。
1)将.h文件的路径配置在工程属性 c/c++ ->附加包含目录
2)将.lib文件放在链接器-》附加库目录、
3)将****.lib的名字放在链接器-》输入-》附加依赖项里
3)将dll放在自己的输出目录就ok了
后面在程序里包含头文件之后就正常调用函数就ok了
第二 本文重点讲的是显式调用
显示调用是没有.lib的情况下怎么调用?
以qt为例!
#include <QApplication>
#include <QLibrary>
#include <QDebug>
#include <QMessageBox>
#include "dll.h" //引入头文件
typedef int (*Fun)(int,int); //定义函数指针,以备调用
int main(int argc,char **argv)
{
QApplication app(argc,argv);
QLibrary mylib("myDLL.dll"); //声明所用到的dll文件
int result;
if (mylib.load()) //判断是否正确加载
{
QMessageBox::information(NULL,"OK","DLL load is OK!");
Fun open=(Fun)mylib.resolve("add"); //援引 add() 函数
if (open) //是否成功连接上 add() 函数
{
QMessageBox::information(NULL,"OK","Link to Function is OK!");
result=open(5,6); //这里函数指针调用dll中的 add() 函数
qDebug()<<result;
}
else
QMessageBox::information(NULL,"NO","Linke to Function is not OK!!!!");
}
else
QMessageBox::information(NULL,"NO","DLL is not loaded!");
return 0; //加载失败则退出
}
这里有一个关键的一句代码
typedef int (*Fun)(int,int); //定义函数指针,以备调用
如果该函数指针定义的和dll中的函数接口不一致的话,后续在loadlibary的时候就会失败。所以为了在使用动态链接库的时候能够具有好的移植性,这里引入ini文件,具体的操作就是:
1)将动态链接库中的函数名称格式定好,(最好包含必须的输入元素以图象为例就是只声明输入为image,输出region)
2)所有在该函数中要输入的控制参数都写到ini文件中
3)在调用的时候,就是在ini文件中读取参数来调用。
生成dll的代码:
#include "stdafx.h"
#include<string>
#ifndef __APPLE__
# include "HalconCpp.h"
# include "HDevThread.h"
# if defined(__linux__) && !defined(__arm__) && !defined(NO_EXPORT_APP_MAIN)
# include <X11/Xlib.h>
# endif
#else
# ifndef HC_LARGE_IMAGES
# include <HALCONCpp/HalconCpp.h>
# include <HALCONCpp/HDevThread.h>
# else
# include <HALCONCppxl/HalconCpp.h>
# include <HALCONCppxl/HDevThread.h>
# endif
# include <stdio.h>
# include <HALCON/HpThread.h>
# include <CoreFoundation/CFRunLoop.h>
#endif
using namespace HalconCpp;
LPCWSTR stringToLPCWSTR(std::string orig);
std::string TCHAR2STRING(TCHAR* str);
extern "C" __declspec(dllexport) void testThreshold(HObject inputImg,HObject *outputImg)
{
TCHAR buf[MAX_PATH];
GetCurrentDirectory(MAX_PATH, buf);
std::string str1 = TCHAR2STRING(buf);
str1 += "\\testdll.ini";
float a = ::GetPrivateProfileInt(L"threshold", L"low", 0, stringToLPCWSTR(str1));
float b = ::GetPrivateProfileInt(L"threshold", L"up", 0, stringToLPCWSTR(str1));
Threshold(inputImg, outputImg, a, b);//阈值分割
//int c = a + b;
//std::string str = std::to_string(c);
::WritePrivateProfileString()
//::WritePrivateProfileString(L"y", L"c", stringToLPCWSTR(str), stringToLPCWSTR(str1));
//return c;
}
LPCWSTR stringToLPCWSTR(std::string orig)
{
size_t origsize = orig.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(orig.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
return wcstring;
}
/******************************************************************************************
Function: TCHAR2STRING
Description: TCHAR转string
Input: str:待转化的TCHAR*类型字符串
Return: 转化后的string类型字符串
*******************************************************************************************/
std::string TCHAR2STRING(TCHAR* str)
{
std::string strstr;
try
{
int iLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
char* chRtn = new char[iLen * sizeof(char)];
WideCharToMultiByte(CP_ACP, 0, str, -1, chRtn, iLen, NULL, NULL);
strstr = chRtn;
}
catch (std::exception e)
{
}
return strstr;
}
测试调用dll 用qt写的:
#include "Gui_test_dll.h"
#include<QSettings>
#include<string>
Gui_test_dll::Gui_test_dll(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.Btn_ReadImage, SIGNAL(pressed()), this, SLOT(Btn_ReadImage()));
connect(ui.pushButton_add, SIGNAL(pressed()), this, SLOT(pushButton_add()));
connect(ui.comboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(push_dllname(int)));
connect(ui.tableInfo_3, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableInfo_3(QTableWidgetItem *)));
ui.tableInfo_3->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); //设置水平与垂直自适应宽高
ui.tableInfo_3->verticalHeader()->setVisible(true); // 显示垂直表头
ui.tableInfo_3->horizontalHeader()->setVisible(true);//显示水平表头
ui.tableInfo_3->setColumnCount(2); //设置两列列表
}
//----------读取文件夹下的路径以及文件名称------
//---------显示文件夹名称------------
//---------依次显示文件夹下所有图片的名称----------
void Gui_test_dll::Btn_ReadImage()
{
//----------获取文件夹下的图片名以及图片路径--------------------------
QString pathname = QFileDialog::getExistingDirectory(
this,
tr("Open Directory"),
"/home",
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
QDir dir(pathname);
QDir dir1(pathname);
if (!dir.exists())
qDebug() << "Not File Exists" << endl;
/*ui.lineEdit->setText(pathname);*/
dir.setFilter(QDir::Files | QDir::NoSymLinks);
dir1.setFilter(QDir::Files | QDir::NoSymLinks);
QStringList filters, filters1;
filters << QString("*.dll");
filters1 << QString("*.ini");
dir.setNameFilters(filters);
dir1.setNameFilters(filters1);
int dir_cout = dir.count();
if (dir_cout <= 0)
qDebug() << "Not dll Exists" << endl;
for (int i = 0; i<dir_cout; i++)
{
QString file_name = dir[i]; //dll文件名称
QString file_name1 = dir1[i]; //dll文件名称
ui.comboBox->addItem(file_name);
ui.comboBox_2->addItem(file_name1);
}
//关闭信号tableweight的信号槽防止后面在加载ini文件里的初始划列表的时候,触发后面修改ini文件的信号
disconnect(ui.tableInfo_3, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableInfo_3(QTableWidgetItem *)));
}
void Gui_test_dll::push_dllname(int)
{
int i = 0;
QString string = ui.comboBox_2->currentText(); //获取当前的ini名称
if (string !=QString::fromLocal8Bit("请选择"))
{
//关闭信号tableweight的信号槽防止后面在加载ini文件里的初始划列表的时候,触发后面修改ini文件的信号
disconnect(ui.tableInfo_3, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableInfo_3(QTableWidgetItem *)));
QSettings fileSetting(string, QSettings::IniFormat);
QStringList str = fileSetting.allKeys();
ui.tableInfo_3->setRowCount(str.length()); //要设置行数与ini文件中的内容行数一致
foreach(QString key, str) //输出到tableweight上
{
ui.tableInfo_3->setItem(i, 0, new QTableWidgetItem(key));
ui.tableInfo_3->setItem(i, 1, new QTableWidgetItem(fileSetting.value(key).toString())); //读里边对应的值,输出到table
i++;
}
//------------当把整个ini文件的信息加载完成之后再链接信号---------------------------
connect(ui.tableInfo_3, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableInfo_3(QTableWidgetItem *)));
}
}
//-------添加参数-------------------------------
void Gui_test_dll::pushButton_add()
{
typedef void(*Fun)(); //定义函数指针,以备调用
QString string = ui.comboBox->currentText();
//---------QString借助string转成char*-------------
QString string1 = ui.lineEdit->text(); //读取要执行的函数名称
std::string str = string1.toStdString();
const char* ch = str.c_str();
QLibrary mylib(string); //声明所用到的dll文件
QString FunName;
if (mylib.load()) //判断是否正确加载
{
QMessageBox::information(NULL, "OK", "DLL load is OK!");
Fun open = (Fun)mylib.resolve(ch); //援引 add() 函数
if (open) //是否成功连接上 add() 函数
{
QMessageBox::information(NULL, "OK", "Link to Function is OK!");
open(); //这里函数指针调用dll中的 add() 函数
}
else
{
QMessageBox::information(NULL, "NO", "Linke to Function is not OK!!!!");
}
}
}
void Gui_test_dll::tableInfo_3(QTableWidgetItem *)
{
QString string;
QTableWidgetItem *item=ui.tableInfo_3->currentItem();
string = item->text();
/*QMessageBox::information(NULL, "OK", string);*/
QString string1 = ui.comboBox_2->currentText(); //获取当前的ini名称
QSettings fileSetting(string1, QSettings::IniFormat);
/*int row, col;*/
//------得出当前修改的item行列坐标-----------
int row = item->row();
int col = item->column();
QTableWidgetItem *item1 = ui.tableInfo_3->item(row, col - 1);
QString key = item1->text();
fileSetting.setValue(key, string); //将修改的值写进对应的ini文件中
}