QT DLL 总结(全)

1、链接库概念


静态链接库和动态链接库介绍    

     我们可以创建一种文件里面包含了很多函数和变量的目标代码,链接的时候只要把这个文件指示给链接程序就自动地从文件中查找符合要求的函数和变量进行链接,整个查找过程根本不需要我们操心。

     这个文件叫做 “库(Libary)”,平时我们把编译好的目标代码存储到“库”里面,要用的时候链接程序帮我们从库里面找出来。

 

静态链接库:

  在早期库的组织形式相对简单,里面的目标代码只能够进行静态链接,所以我们称为“静态库”,静态库的结构比较简单,其实就是把原来的目标代码放在一起,链接程序根据每一份目标代码的符号表查找相应的符号(函数和变量的名字),找到的话就把该函数里面需要定位的进行定位,然后将整块函数代码放进可执行文件里,若是找不到需要的函数就报错退出。

     静态库的两个特点:

      1、链接后产生的可执行文件包含了所有需要调用的函数的代码,因此占用磁盘空间较大。

      2、如果有多个(调用相同库函数的)进程在内存中同时运行,内存中就存有多份相同的库函数代码,因此占用内存空间较多。


动态链接库:

      动态链接库就是为了解决这些问题而诞生的技术,顾名思义,动态链接的意思就是在程序装载内存的时候才真正的把库函数代码链接进行确定它们的地址,并且就算有几个程序同时运行,内存也只存在一份函数代码。

  动态库的代码必须满足这样一种条件:能够被加载到不同进程的不同地址,所以代码要经过特别的编译处理,我们把这种经过特别处理的代码叫做“位置无关代码(Position independed Code .PIC)”.

  根据载入程序何时确定动态代码的逻辑地址,可以把动态装载分为两类。


      1、静态绑定(static binding)

     使用静态绑定的程序一开始载入内存的时候,载入程序就会把程序所有调用到的动态代码的地址算出确定下来,这种方式使程序刚运行的初始化时间较长,不过旦完成动态装载,程序的运行速度就很快。


      2、动态绑定(dynamic binding)

      使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态绑定的程序。


      平时默认进行链接的标准 C/C++ 函数就是动态库。


 2、链接库常识
      目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。 
      静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。 
      动态库一般会有对应的导入库,方便程序静态载入动态链接库,否则你可能就需要自己LoadLibary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。
     导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。 这也是实际上很多开源代码发布的惯用方式:
     1. 预编译的开发包:包含一些.dll文件和一些.lib文件。其中这里的.lib就是导入库,而不要错以为是静态库。但是引入方式和静态库一样,要在链接路径上添加找到这些.lib的路径。而.dll则最好放到最后产生的应用程序exe执行文件相同的目录。这样运行时,就会自动调入动态链接库。
      2. 用户自己编译: 下载的是源代码,按照readme自己编译。生成很可能也是.dll + .lib(导入库)的库文件
      3. 如果你只有dll,并且你知道dll中函数的函数原型,那么你可以直接在自己程序中使用LoadLibary调入DLL文件,GetProcAddress
DLL: 
      动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。 
      动态链接与静态链接的不同之处在于它允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。 
         使用动态链接代替静态链接有若干优点。扩展了应用程序的特性、 、可以用许多种编程语言来编写 、简化了软件项目的管理 、有助于节省内存 、有助于资源共享 、有助于应用程序的本地化 、有助于解决平台差异 、可以用于一些特殊的目的。windows使得某些特性只能为DLL所用。

3、动态链接库的调用
      有两种类型的链接:隐式链接和显式链接。

隐式链接
      应用程序的代码调用导出 DLL 函数时发生隐式链接。 当调用可执行文件的源代码被编译或被汇编时,DLL 函数调用在对象代码中生成一个外部函数引用。 若要解析此外部引用,应用程序必须与 DLL 的创建者所提供的导入库(.LIB 文件)链接。
      导入库仅包含加载 DLL 的代码和实现 DLL 函数调用的代码。 在导入库中找到外部函数后,会通知链接器此函数的代码在 DLL 中。 要解析对 DLL 的外部引用,链接器只需向可执行文件中添加信息,通知系统在进程启动时应在何处查找 DLL 代码。
      系统启动包含动态链接引用的程序时,它使用程序的可执行文件中的信息定位所需的 DLL。 如果系统无法定位 DLL,它将终止进程并显示一个对话框来报告错误。 否则,系统将 DLL 模块映射到进程的地址空间中。
       如果任何 DLL 具有(用于初始化代码和终止代码的)入口点函数,操作系统将调用此函数。 在传递到入口点函数的参数中,有一个指定用以指示 DLL 正在附带到进程的代码。 如果入口点函数没有返回 TRUE,系统将终止进程并报告错误。
       最后,系统修改进程的可执行代码以提供 DLL 函数的起始地址。
       与程序代码的其余部分一样,DLL 代码在进程启动时映射到进程的地址空间中,且仅当需要时才加载到内存中。 因此,由 .def 文件用来在 Windows 的早期版本中控制加载的 PRELOAD 和 LOADONCALL 代码特性不再具有任何意义。

显式链接
      大部分应用程序使用隐式链接,因为这是最易于使用的链接方法。 但是有时也需要显式链接。 下面是一些使用显式链接的常见原因:
      直到运行时,应用程序才知道需要加载的 DLL 的名称。 例如,应用程序可能需要从配置文件获取 DLL 的名称和导出函数名。
      如果在进程启动时未找到 DLL,操作系统将终止使用隐式链接的进程。 同样是在此情况下,使用显式链接的进程则不会被终止,并可以尝试从错误中恢复。 例如,进程可通知用户所发生的错误,并让用户指定 DLL 的其他路径。
      如果使用隐式链接的进程所链接到的 DLL 中有任何 DLL 具有失败的 DllMain 函数,该进程也会被终止。 同样是在此情况下,使用显式链接的进程则不会被终止。
      因为 Windows 在应用程序加载时加载所有的 DLL,故隐式链接到许多 DLL 的应用程序启动起来会比较慢。 为提高启动性能,应用程序可隐式链接到那些加载后立即需要的 DLL,并等到在需要时显式链接到其他 DLL。
      显式链接下不需将应用程序与导入库链接。 如果 DLL 中的更改导致导出序号更改,使用显式链接的应用程序不需重新链接(假设它们是用函数名而不是序号值调用 GetProcAddress),而使用隐式链接的应用程序必须重新链接到新的导入库。

     下面是需要注意的显式链接的两个缺点:

     如果 DLL 具有 DllMain 入口点函数,则操作系统在调用 LoadLibrary 的线程上下文中调用此函数。 如果由于以前调用了 LoadLibrary 但没有相应地调用 FreeLibrary 函数而导致 DLL 已经附加到进程,则不会调用此入口点函数。 如果 DLL 使用 DllMain 函数为进程的每个线程执行初始化,显式链接会造成问题,因为调用 LoadLibrary(或 AfxLoadLibrary)时存在的线程将不会初始化。
      如果 DLL 将静态作用域数据声明为 __declspec(thread),则在显式链接时 DLL 会导致保护错误。 用 LoadLibrary 加载 DLL 后,每当代码引用此数据时 DLL 就会导致保护错误。 (静态作用域数据既包括全局静态项,也包括局部静态项。)因此,创建 DLL 时应避免使用线程本地存储区,或者应(在用户尝试动态加载时)告诉 DLL 用户潜在的缺陷。

4、显示链接和隐式链接的区别

一、Implicit Linking(隐式连接)
       Implicit Linking(隐式连接) ,又叫静态载入,所谓静态载入是指程序在连接时期即与dlls所对应的import libraries作静态连接,于是可执行文件中便对所有的dll函数都有一份重定位表格(relocation table)和待修正记录(fixup record)。当程序被windows载入器载入内存中时,载入器会自动修正所有的fixup records,而这个fixup records 就是记录DLL中所有输出资源的正确位置地址,经过这样的程序动态连接便自动产生。也就是说,程序开始执行时,会用静态载入的方式时所使用的DLLs都载入到程序的内存里。
      静态载入方式的优点
      1、静态载入方式所使用的dll会在应用程序执行时载入,然后就可以调用所有dll中提供的函数,就像是程序中一样。
      2、处理简单,载入的方法有编译器负责处理,不需动脑筋。
 
      静态载入方式的缺点
      1、当程序机构态载入方式所使用的dll不存在时,程序开始就会报dll无法找到的错误而使得程序无法运行。
编译时需要加入import library。
      2、若调用的dll很多,载入应用程序的速度就会很慢。
不同的c++编译器静态载入的方式也不一样。
 
二、Explicit Linking(显式连接)
          所谓Explicit Link(显式连接)又叫动态载入,使用dll的可执行文件必须明确调用载入和御载dll的函数调用(Function Call),并且存取dll的输出函数。用户端必须通过函数声明调用函数。
          可执行文件可以使用任何一种连接方式的相同低dll。并且,这些机制之间并不会相互排斥,因此,当一个可执行文件隐式的连接dll时,其他程序还可以显示地连接它。
 
      动态载入方式的优缺点:
       1、dll只有需要时才载入内存中,这样可以更有效地使用存储空间。
      2、应用程序载入速度较隐式连接较快,因为当程序开始载入时并不需要把dll载入到程序中。
      3、编译时不需要额外的import library。
      4、可以让用户个清楚地知道dll的载入流程。      
      缺点就是必须多写一点代码。  
      动态载入基本流程
      必须使用LoadLibrary这个Windows API来手动载入DLL,并使用GetProcessAddress来取得所需要使用的函数的函数指针,最后用FreeLibrary将DLL释放。所以学会动态载入DLL时,必须先知道函数指针的用法。

最近看了不少Qt的DLL例子,总结一下如何创建和调用QT 动态链接库。

 

先讲一下对QT动态链接库的调用方法,主要包括:

1、显式链接DLL,调用DLL的全局函数,采用Qt的QLibrary方法

2、显示链接DLL,调用DLL中类对象、成员函数。(通过对象即可实现类成员函数的调用)

 

①用虚函数表的方法,这也是COM使用的方法,利用Qt的QLibrary技术调用;

②用GetProcAddress直接调用。

用Qt的QPluginLoader类直接调用生成的DLL插件类对象

3、隐式链接DLL:也是采用Qt的Qlibrary方法

关于这种三种方法,下面详细叙说

 

详细分类叙述

 

前提:两个项目文件目录

1、TestDLL项目:testdll_global.h,TestDll.h,TestDll.cpp

2、TestMain exe应用项目:main.cpp

 

testdll_global.h 文件源代码一直不变

 

#ifndef TESTDLL_GLOBAL_H
#define TESTDLL_GLOBAL_H

#include <QtCore/qglobal.h>

#ifdef TESTDLL_LIB
# define TESTDLL_EXPORT Q_DECL_EXPORT
#else
# define TESTDLL_EXPORT Q_DECL_IMPORT
#endif

#endif // TESTDLL_GLOBAL_H

 DLL的显式链接在某些时候比隐式链接具有更大的灵活性。比如,如果在运行时发现DLL无法找到,程序可以显示一个错误信息并能继续运行。当你想为你的程序提供插件服务时,显式链接也很有用处

 

1、采用显示链接调用DLL中全局函数,只需要一个TestDLL.dll。

        通常Windows下程序显示调用dll的步骤分为三步(三个函数):LoadLibrary()、GetProcAdress()、FreeLibrary()

        其中,LoadLibrary() 函数用来载入指定的dll文件,加载到调用程序的内存中(DLL没有自己的内存!)

         GetProcAddress() 函数检索指定的动态链接库(DLL)中的输出库函数地址,以备调用

         FreeLibrary() 释放dll所占空间 

      而QT的QLibrary类显示链接调用DLL的步骤:load()、resolve(const char * symbol )、unload()和VC步骤类似

 

TestDll.dll项目中的TestDLL.h源码


#ifndef TESTDLL_H
#define TESTDLL_H

#include "testdll_global.h"

class TESTDLL_EXPORT TestDll
{
public:
	TestDll();
	~TestDll();	
private:


};
extern "C" TESTDLL_EXPORT void helloWorld();     
extern "C" TESTDLL_EXPORT int add(int a,int b);  
#endif // TESTDLL_H

TestDll.dll项目中的TestDLL.cpp源码


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

TestDll::TestDll()
{

}

TestDll::~TestDll()
{

}

void helloWorld()
{
	std::cout << "hello,world!";
}
int add(int a,int b)
{
	return a + b;
}


注:1)建立成功DLL项目后,可以在VS命令提示行中用命令"dumpbin -exports DllTest.dll"来查看(也可以用VC工具包中的depends使用程序来查看)  
   注:2)必须使用extern "C"链接标记,否则C++编译器会产生一个修饰过的函数名,这样导出函数的名字将不再是helloworld,而是一个形如" ?helloWorld@TestDll@@UAEXXZ”的名字。为什么名字不是helloworld呢?这是因为C++为了支持函数的重载,会在编译时将函数的参数类型信息以及返回值类型信息加入到函数名中,这样代码中名字一样的重载函数,在经过编译后就互相区分开了,调用时函数名也经过同样的处理,就能找到对应的函数了。详细可以看这篇文章 动态链接库(Dynamic Link Library)学习笔记


TestMain项目 main.cpp

#include <QtCore/QCoreApplication>
#include <iostream>
#include <QLibrary>

typedef int (*Fun)(int,int); //定义函数指针,int add(int a,int b);    
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	
	QLibrary mylib("TestDll.dll");   //声明所用到的dll文件
	int result;
	//判断是否正确加载
	if (mylib.load())              
		{
			std::cout << "DLL load is OK!"<<std::endl;
			//调用外部函数 add()
			Fun add = (Fun)mylib.resolve("add");   
			//是否成功连接上 add() 函数
			if (add)                  
				{
					std::cout << "Link to add Function is OK!"<<std::endl;
					 //这里函数指针调用dll中的 add() 函数
					result = add(5,6);     
					std::cout << result;
				}
			else
				std::cout << "Link to add Function failed!!"<<std::endl;

			
	}
	//加载失败
	else
		std::cout << "DLL is not loaded!"<<std::endl;
	 

	return a.exec();
} 

2、采用显示链接,调用C++类中的类对象、成员函数 

     如果你想导出并显式链接一组C++类中的成员函数又该怎么办呢?这里有两个问题。第一是C++成员函数名是经过修饰的(即使指定extern "C"标记也是这样);第二是C++不允许将指向成员函数的指针转换成其它类型。这两个问题限制了C++类的显式链接。下面介绍两种方法来解决这个问题:

①用虚函数表的方法,这也是COM使用的方法,利用Qt的QLibrary技术调用;

②用GetProcAddress直接调用。

用Qt的QPluginLoader类直接调用生成的DLL插件类对象

     ①虚函数表的方法,QLibrary 技术调用

TestDll.h代码


#ifndef TESTDLL_H
#define TESTDLL_H

#include "testdll_global.h"

class TESTDLL_EXPORT TestDll
{
public:
	TestDll();
	virtual~TestDll();	
	virtual void helloWorld(); //类成员函数
private:


};   
extern "C" TESTDLL_EXPORT TestDll* getTestDll(); //获取类TestDll的对象
#endif // TESTDLL_H

TestDll.cpp源码


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

TestDll::TestDll()
{

}

TestDll::~TestDll()
{

}

void TestDll::helloWorld()
{
	std::cout << "hello,world!";
}

TestDll* getTestDll()
{
	return new TestDll();
}

 TestMain项目中的main.cpp源码


#include <QtCore/QCoreApplication>
#include <iostream>
#include <QLibrary>
#include "../TestDll/TestDll.h"  //头文件还是需要加的,否则无法解析TestDll类
typedef TestDll* (*GetTestDll)();//定义函数指针,获取类TestDLL对象;  
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);

	QLibrary mylib("TestDll.dll");   //声明所用到的dll文件
	int result;
	//判断是否正确加载
	if (mylib.load())              
		{
			GetTestDll getTestDll = (GetTestDll)mylib.resolve("getTestDll");
			if(getTestDll)
			{
				TestDll *testDll = getTestDll();
				testDll->helloWorld();
				delete testDll;
			}
	}
	//加载失败
	else
		std::cout << "DLL is not loaded!"<<std::endl;
	return a.exec();
}


 这个方法的使用得用户可以很容易地为你的程序制作插件。它的缺点是创建对象的内存必须在dll中分配

 

 

②用GetProcAddress直接调用类对象中的成员函数

这个方法,我没测试,对我没对大作用,还得用def导出DLL函数,有兴趣的就参考一下这篇文章。DLL中类的显式链接

        ③用Qt的QPluginLoader类直接调用生成的DLL插件类对象

           这个方法,我单独写一篇总结,请看QPluginLoader的简单小例子VS2008+Qt 使用QPluginLoader访问DLL

 

3、采用隐式链接方法,通过QLibrary类对DLL中类对象、全局函数的调用

 

TestDll.h

#ifndef TESTDLL_H
#define TESTDLL_H

#include "testdll_global.h"

class TESTDLL_EXPORT TestDll
{
public:
	TestDll();
	~TestDll();	
	void helloWorld(); //类成员函数
private:


};   
extern "C" TESTDLL_EXPORT int add(int a,int b);  //自定义的外部函数
#endif // TESTDLL_H

TestDll.cpp源码


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

TestDll::TestDll()
{

}

TestDll::~TestDll()
{

}

void TestDll::helloWorld()
{
	std::cout << "hello,world!";
}
int add(int a,int b)
{
	return a + b;
}

TestMain项目中的main.cpp ,需要稍微配置头文件和lib文件

1、在项目中主程序引入TestDll.h头文件,

2、配置项目属性:加入TestDLL.lib的文件目录,在Linker/General/Additional Library Diretories里面选择TestDll.lib的文件目录D:\VSWorkSpace\Test\Debug

3、配置项目属性:加入TestDll.lib文件,在Linker/Input/Additional Dependencies 中加入 TestDll.lib

 

main.cpp源码

#include <QtCore/QCoreApplication>
#include <iostream>
#include <QLibrary>
#include "../TestDll/TestDll.h"
//引入TestDll.lib文件,和上面的2,3步工作同理
//#pragma comment(lib, "../Debug/TestDll.lib")
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	int result = add(5,6);
	std::cout << result;
	TestDll dll;
	dll.helloWorld();
        return a.exec();
}


开发环境:VS2008、Qt4.7.4,附件有源码可供下载

         最近在总结如何访问DLL中的类对象及其成员函数,其中一种方法利用Qt的QPluginLoader类就可以方便快捷的访问DLL中的类,以及其中的类成员函数。

 

文件结构如下图

解决方案名:TestPlugin

1、Qt的Library项目(PluginDll):PlugInterface.h、PluginInstance.h、PluginInstance.cpp

2、Qt的Console Application项目(PluginConsole):main.cpp、PlugInterface.h(从上面的项目拷贝过来的)

 

 

 

程序建立步骤

 

 

步骤一、在VS里新建立一个DLL项目,名称PluginDll。

  1.      把自动生成的三个代码文件(PluginDll.h、PluginDll_global.h、PluginDll.cpp)直接删掉,这三个是Qt自己的建立Qt Dll的推荐方法,我们暂时用不到。
  2.      自己新建如下三个文件PlugInterface.h、PluginInstance.h、PluginInstance.cpp    
    备注:如果步骤一建立成一个exe应用项目,也可以通过改两个项目配置参数实现,生成DLL。
    一是修改Configuration Properties/General/Configuration type的值,将Application (.exe)改成Dynamic Library (.dll) ,
    二是修改Configuration Properties/Linker/General/Output File 的值,将$(OutDir)\$(ProjectName).exe改成$(OutDir)\$(ProjectName).dll
// PlugInterface.h
//接口类
#ifndef PLUGINTERFACE_H
#define PLUGINTERFACE_H

#include <QtPlugin>
class PlugInterface
{
public:
	virtual ~PlugInterface(){}
	//接口中的成员函数必须是纯虚函数
	virtual void testPlugin() = 0;
	virtual void helloWorld() = 0;
};
QT_BEGIN_NAMESPACE
//这个宏用声明接口
//Q_DECLARE_INTERFACE(接口类名,接口标识符)
Q_DECLARE_INTERFACE(PlugInterface, "PlugInterfaceDll/1.0");
QT_END_NAMESPACE
#endif // PLUGINTERFACE_H
 
//接口标识符必须唯一,所以一般加个版本号1.
//This macro is normally used right after the class definition for ClassName, in a header file.
//If you want to use Q_DECLARE_INTERFACE with interface classes declared in a namespace,
//then you have to make sure the Q_DECLARE_INTERFACE is not inside a namespace though. 

// PluginInstance.h
//业务类的头文件
#ifndef PLUGININSTANCE_H
#define PLUGININSTANCE_H

#include "PlugInterface.h"
#include <QObject>
//PluginInstance必须继承QObject类,才能使用如下Qt的方法
//PluginInstance还得继承接口PlugInterface
class PluginInstance : public QObject, PlugInterface
{
	Q_OBJECT
		//Q_INTERFACES宏定义告诉Qt MOC,PluginInstance类继承了插件PlugInterface
		//将该接口注册到Qt的meta-object system
		Q_INTERFACES(PlugInterface)
public:
	PluginInstance();
	~PluginInstance();
	//业务成员1
	void testPlugin();
	//业务成员2
	void helloWorld();
};

#endif // PLUGININSTANCE_H

// PluginInstance.cpp
//业务类成员函数定义
#include "PluginInstance.h"
#include <QtCore>
PluginInstance::PluginInstance()
{
}
PluginInstance::~PluginInstance()
{
}
void PluginInstance::testPlugin()
{
	qDebug() << "test";
}
void PluginInstance::helloWorld()
{
	qDebug() << "helloWorld";
}
//这个宏用来导出动态链接库
//Q_EXPORT_PLUGIN2(插件名, 类名)
//Q_EXPORT_PLUGIN2("PluginDll", PluginInstance)
Q_EXPORT_PLUGIN2("PluginInstance", PluginInstance)
//插件名最好和TARGET有关,而我们PluginDll项目转换成Qt项目的.pro文件,target = PluginDll
//所以说这里名字不影响编程,只是为了方便理解,让插件名和项目名一致最好。
//对于一个Qt插件来说,最好只有一个Q_EXPORT_PLUGIN2宏定义,并且最好在实现的文件里出现,而非头文件中。

步骤二、在VS里新建立一个ApplicationL项目,名称PluginConsole。

  1.     将前面PluginDll项目中的接口头文件PlugInterface.h拷贝到PluginConsole项目中;
  2.     因为plugin.dll已经在解决方案的Debug文件中了,暂时就不需要拷贝到PluginConsole项目中来了。如果没有需要拷贝过来才能引用
    在main.cpp中通过QPluginLoader调用PluginDll.dll
#include <QtCore/QCoreApplication>
#include "PlugInterface.h"
#include <QPluginLoader>
#include <QDebug>
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	PlugInterface *plugObject; 
	//不知道为啥,路径我写成下面就出错呢?编译可以通过,运行时会提示异常
	//QPluginLoader  pluginLoader("PluginDll.dll"); 
	//加载插件
	QPluginLoader  pluginLoader("../Debug/PluginDll.dll"); 
	//
	QObject *plugin = pluginLoader.instance();   
	if (plugin)
	{
		qDebug() << "instance success";
		//使用qobject_cast将QObject类型转换成我们想要的PlugInterface类对象
		plugObject= qobject_cast<PlugInterface *>(plugin);    
		plugObject->helloWorld();    
		plugObject->testPlugin();
	}
	else
		qDebug() << "instance fail";
	return a.exec();
}

综合了网上很多的例子,很难直接运行,最后自己总结出来的例子在附件上,可以直接运行。
那些参考链接,就不一一引用了,在此谢谢各位的帮助!





  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值