您的位置:首页 > 编程语言 > C语言/C++

学习C++动态链接库基础知识 (主要关于QT项目)PART2

2015-06-29 14:22 656 查看
这部分主要参考博客:
http://blog.csdn.net/crich_moon/article/details/6039939 
与前一篇笔记相比,这部分主要记录一下显式调用一个动态库。动态库的头文件,在这部分是不需要的,同样的,在工程文件中也并不要对连接器进行设置。

下面贴出动态库的头文件和源文件

工程文件 helloworld3.pro

QT       -= gui

TARGET = helloworld3
TEMPLATE = lib

DEFINES += HELLOWORLD3_LIBRARY

SOURCES += helloworld3.cpp

HEADERS += helloworld3.h\
helloworld3_global.h
工程文件定义了需生成的文件类型,还有所包含的头文件以及源文件。

头文件 helloworld3_global.h:

#ifndef HELLOWORLD3_GLOBAL_H
#define HELLOWORLD3_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(HELLOWORLD3_LIBRARY)
#  define HELLOWORLD3SHARED_EXPORT Q_DECL_EXPORT
#else
#  define HELLOWORLD3SHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // HELLOWORLD3_GLOBAL_H
这部分和上篇笔记的功能是一样的,但是其实这个部分在此次练习中是不需要的,可直接将所需要用的函数定义成 Q_DECL_EXPORT

头文件 helloworld3.h:

#ifndef HELLOWORLD3_H
#define HELLOWORLD3_H

#include "helloworld3_global.h"

extern "C" HELLOWORLD3SHARED_EXPORT void Helloworld3();

#endif // HELLOWORLD3_H


顶一个一个叫 Helloworld3的函数。
源文件 helloworld3.cpp

#include "helloworld3.h"
#include <iostream>

void Helloworld3()
{
std::cout<<"hello"<<std::endl;
}
函数的实现部分,头文件里的一些关键字在这里不需要出现,包括 extern "C" 以及 Q_DECL_EXPORT。

生成一个.dll动态库,我们可以把这个库用在其他程序中来调用他。

我随意的新建了一个Qt的 Mainwindow 项目, 在构造函数中想调用这个动态库。我不需要在代码中包含动态库的头文件,而且我也不需要在此项目的工程文件中做任何修改,单单使用操作系统的一些API即可实现调用函数的功能。

代码如下:

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "Windows.h"
#include <iostream>
typedef void (*hello)();
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
HINSTANCE someDll; //handler
hello printHello=NULL; //function pointer
someDll=LoadLibraryW(L"helloworld3.dll");
if(someDll)
{
std::cout<<"someDll"<<std::endl;
printHello=(hello)GetProcAddress(someDll,"Helloworld3");
}
if(printHello)
{
std::cout<<"print"<<std::endl;
printHello();
}
//FreeLibrary(someDll);

}

MainWindow::~MainWindow()
{
delete ui;
}
首先typedef一个函数指针,没有返回,没有参行,和在动态库里定义的函数的形式是一样的。

HINSTANCE与HMODULE是等价的(从百度知道得知)。 定义一个句柄叫someDll,type是HINSTANCE。
定义一个叫printHello的函数指针,指向NULL避免让他成为野指针。

loadLibraryW(L"helloworld3.dll"),此函数返回一个句柄,这里看到"helloworld3.dll"是我动态库的文件名, 我并没有指定地址,在我当前win7的环境下默认地址似乎是构造后的exe文件所在的PWD。此PWD经过查找Qt Creator的构建路径可以得知。一般情况下假设exe文件在构建文件夹的子目录debug文件夹里,PWD是debug的上层文件夹即我们项目所设定的构建文件夹。

此函数介绍为:

Loads the specified module into the address space of the calling process. The specified module may
cause other modules to be loaded.

If the function succeeds, the return value is a handle to the module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

(hello)GetProcAddress(someDll,"Helloworld3");用GetProcAddress()函数来返回一个函数指针,此指针在这里要被转换成我们所需要的函数指针。此函数通过某种方式可以在DLL里查找函数的名字,然后再返回一个地址。
函数介绍为:
Retrieves the address of an exported function or variable from the
specified dynamic-link library (DLL).

If the function succeeds, the return value is the address of the exported function or variable.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.
代码中的连个if判断用于避免读出的handle或者函数为NULL。经过MSVC和MINGW测试过发现动态库里的函数是可以调用的。在这个练习中我遇到了一些问题。例如如果我将
<span style="font-size:10px;">someDll=LoadLibraryW(L"helloworld3.dll");写成了 someDll=LoadLibraryW("helloworld3.dll");</span>
<span style="font-size:10px;">出现错误:</span>
<span style="font-size:10px;">mainwindow.cpp:13: error: C2664: 'LoadLibraryW' : cannot convert parameter 1 from 'const char [16]' to 'LPCWSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
</span>
加上大写L或者把函数写成someDll=LoadLibraryA("helloworld3.dll");可避免此问题。
DLL文件所放置的路径也是根据各个系统有所不同的,这个信息是在查阅 msdn的dynamic-link library search order得到的信息,网址如下:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx
此说明太长,有空再读。

Qt里有封装好的QLibrary类来做类似的工作,根据Qt的帮助文件例子:

QLibrary myLib("mylib");
typedef void (*MyPrototype)();
MyPrototype myFunction = (MyPrototype) myLib.resolve("mysymbol");
if (myFunction)
myFunction();

发现Qt用法和直接用API用法差不多,但是毕竟封装的可以夸平台,还是推荐用Qt的库里的现成的比较好,以上例子还可以用reslove()函数的static版本调用:
typedef void (*MyPrototype)();
MyPrototype myFunction =
(MyPrototype) QLibrary::resolve("mylib", "mysymbol");
if (myFunction)
myFunction();

简单用法大概就这些,如何调用动态库里类的某个函数,还需要研究一下。

a1c0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: