学习C++动态链接库基础知识 (主要关于QT项目)PART2
2015-06-29 14:22
656 查看
这部分主要参考博客:
http://blog.csdn.net/crich_moon/article/details/6039939
与前一篇笔记相比,这部分主要记录一下显式调用一个动态库。动态库的头文件,在这部分是不需要的,同样的,在工程文件中也并不要对连接器进行设置。
下面贴出动态库的头文件和源文件
工程文件 helloworld3.pro
头文件 helloworld3_global.h:
头文件 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里查找函数的名字,然后再返回一个地址。
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>
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
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
相关文章推荐
- boost::serialization学习笔记
- C++获取控制台输出
- C语言extern
- c/c++数组初始化误区
- C++关于二进制位操作小结
- LeetCode_Validate Binary Search Tree
- 黑马程序员-OC语言-函数和对象方法的区别(听课笔记)
- c++程序员经典面试题
- 黑马程序员-OC语言-#pragma mark指令的使用(听课笔记)
- C语言宏定义
- VC++ 自定义控件的建立及使用方法
- C++ CTreeview的checkbox使用方法
- c++正则表达式模板库GRETA的使用
- c++学习笔记4,调用派生类的顺序构造和析构函数(一个)
- VC++多线程编程
- 斐波那契数列-数组和递归-C语言
- (6)风色从零单排《C++ Primer》 结构体,头文件
- leetcode 日经贴,Cpp code -Majority Element II
- C++编译与链接-浅谈内部链接与外部链接
- 终端下编译运行一个简单C++程序流程