如何把核心模块化设计的优点设计为动态链接库

&&&&&&&&&&&&&&&&&&
posts - 107,comments - 3,trackbacks - 0
(本章节中例子都是用 VS2005 编译调试的)
动态链接概述
所谓动态链接,就是把一些经常会共用的代码(静态链接的OBJ程序库)制作成DLL档,当可执行文件调用到DLL档内的函数时,windows操作系统才会把DLL档加载存储器内,DLL档本身的结构就是可执行文件,当程序需求函数才进行链接.通过动态链接方式,存储器浪费的情形将可大幅降低.
DLL的文档格式与视窗EXE文档一样&&也就是说,等同于32位视窗的可移植执行文档(PE)和16位视窗的New Executable(NE).作为EXE格式,DLL可以包括源代码、数据和资源的多种组合.
在使用动态库的时候,往往提供两个文件:一个引入库(LIB)和一个动态链接库(DLL).引入库(LIB)包含被动态连接库(DLL)所导出的函数和变量的符号名,动态连接库(DLL)包含实际的函数和数据.在编译链接可执行文件时,只需要链接引入库(LIB),动态连接库(DLL)中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问动态链接库(DLL)中导出的函数.
动态链接库(DLL)通常都不能直接运行,也不能接收消息.它们是一些独立的文件,其中包含能被可执行程序或其它动态连接库(DLL)调用来完成某项工作的函数.只有在其它模块调用动态链接库(DLL)中的函数时,它才发挥作用.但是动态连接库(DLL)被多进程调用时候,动态链接库(DLL)中进程访问到动态链接库(DLL)的成员时,系统会为它开辟一个新的数据成员页面给访问进程提供单独的动态连接库(DLL)数据区.
& & & & & & &
特征(来自维基百科)
在Win32中,DLL文档按照片段(sections)进行组织.每个片段有它自己的属性,如可写或是只读、可执行(代码)或者不可执行(数据)等等.DLL代码段通常被使用这个DLL的进程所共享;也就是说它们在物理内存中占据一个地方,并且不会出现在页面文档中.如果代码段所占据的物理内存被收回,它的内容就会被放弃,后面如果需要的话就直接从DLL文档重新加载.与代码段不同,DLL的数据段通常是私有的;也就是说,每个使用DLL的进程都有自己的DLL数据副本.作为选择,数据段可以设置为共享,允许通过这个共享内存区域进行进程间通信.但是,因为用户权限不能应用到这个共享DLL内存,这将产生一个安全漏洞;也就是一个进程能够破坏共享数据,这将导致其它的共享进程异常.例如,一个使用访客账号的进程将可能通过这种方式破坏其它运行在特权账号的进程.这是在DLL中避免使用共享片段的一个重要原因.当DLL被如UPX这样一个可执行的packer压缩时,它的所有代码段都标记为可以读写并且是非共享的.可以读写的代码段,类似于私有数据段,是每个进程私有的并且被页面文档备份.这样,压缩DLL将同时增加内存和磁盘空间消耗,所以共享DLL应当避免使用压缩DLL.
符号解析和绑定
DLL输出的每个函数都由一个数字序号唯一标识,也可以由可选的名字标识.同样,DLL引入的函数也可以由序号或者名字标识.对于内部函数来说,只输出序号的情形很常见.对于大多数视窗API函数来说名字是不同视窗版本之间保留不变的;序号有可能会发生变化.这样,我们不能根据序号引用视窗API函数.按照序号引用函数并不一定比按照名字引用函数性能更好:DLL输出表是按照名字排列的,所以对半查找可以用来在在这个表中根据名字查找这个函数.另外一方面,只有线性查找才可以用于根据序号查找函数.将一个可执行文件绑定到一个特定版本的DLL也是可能的,这也就是说,可以在编译时解析输入函数(imported functions)的地址.对于绑定的输入函数,连结工具保存了输入函数绑定的DLL的时间戳和校验和.在运行时Windows检查是否正在使用同样版本的库,如果是的话,Windows将绕过处理输入函数;否则如果库与绑定的库不同,Windows将按照正常的方式处理输入函数.绑定的可执行文件如果运行在与它们编译所用的环境一样,函数调用将会较快,如果是在一个不同的环境它们就等同于正常的调用,所以绑定输入函数没有任何的缺点.例如,所有的标准Windows应用程序都绑定到它们各自的Windows发布版本的系统DLL.将一个应用程序输入函数绑定到它的目的环境的好机会是在应用程序安装的过程.
运行时显式链接
对每个DLL来说,Windows存储了一个全局计数器,每多一个进程使用便多额外一个.LoadLibrary与FreeLibrary指令影响每一个进程内含的计数器;动态链接则不影响.因此借由调用FreeLibrary多次,从存储器反加载一DLL是很重要的.一个进程可以从它自己的VAS注销此计数器.DLL文档能够在运行时使用LoadLibrary(或者LoadLibraryEx)API函数进行显式调用,这个的过程微软简单地称为运行时动态调用.API函数GetProcAddress根据查找输出名称符号、FreeLibrary卸载DLL.这些函数类似于POSIX标准API中的dlopen、dlsym、和dlclose.注意微软简单称为运行时动态链接的运行时隐式链接,如果不能找到链接的DLL文档,Windows将提示一个错误消息并且调用应用程序失败.应用程序开发人员不能通过编译链接来处理这种缺少DLL文档的隐式链接问题.另外一方面,对于显式链接,开发人员有机会提供一个完善的出错处理机制.运行时显式链接的过程在所有语言中都是相同的,因为它依赖于Windows API而不是语言结构.
与静态链接库的区别
静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,动态链接库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息.
Windows 下 3 个重要的 DLL
Windows API中的所有函数都包含在DLL中。其中有3个最重要的DLL
Kernel32.dll,它包含用于管理内存、进程和线程的各个函数
User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数
GDI32.dll,它包含用于画图和显示文本的各个函数
动态链接库的优点
可以采用多种编程语言来编写
我们可以采用自己熟悉的开发语言编写DLL,然后由其他语言编写的可执行程序来调用这些DLL.例如,可以利用VB来编写程序界面,然后利用VC++或Delphi编写的完成程序作业逻辑的DLL
增强产品的功能
在发布产品时,可以发布产品功能实现的动态链接库规范,让其他公司或个人遵照这种规范开发自己的DLL,以取代产品原有的DLL.让产品调用新的DLL,从而实现功能的增强,在实际工作中,我们看到许多产品都提供了界面插件功能,允许用户动态地更换程序的界面,这就可以通过更换界面DLL来实现
提供二次开发的平台
在销售产品时,可以采用DLL的形式提供一个二次开发的平台,让用户可以利用该DLL调用其中实现的功能,编写符合自己业务需要的产品,从而实现二次开发
简化项目管理
在一个大型项目开发中,通常都是由多个项目小组同时开发,如果采用串行开发,则效率非常低的,我们可以将项目细分,将不同功能交由各个项目小组以多个DLL方式实现,这样各个项目小组就可以同时进行开发了
可以节省磁盘空间和内存
如果多个应用程序需要访问同样的功能,那么可以将该功能以DLL的形式提供,这样在机器上只需要存在一份该DLL文件就可以了,从而节省了磁盘空间.另外如果多个应用程序使用同一个DLL,该DLL的页面只需要放入内存一次,所有的应用程序就都可以共享它的页面了.这样,内存的使用将更加有效如下图所示就是一个动态链接库被两个进程调用时的内存示意图,当进程被加载时,系统为它分配4GB的地址空间,接着分析该可执行模块,找到该程序要调用那些DLL模块,然后系统搜索这些DLL,找到后就加载它们,并为它们分配虚拟的内存空间,最后将DLL的页面映射到进程的地址空间.,从此可以导致多个程序中共享DLL的同一份代码,这样就可以节省空间
有助于资源的共享
DLL可以包含对话框模板,字符串,图标和位图等多种资源,多个应用程序可以使用DLL来共享这些资源.在实际工作中,可以写一个纯资源的动态链接库文件,供其他应用程序访问
有助于实现应用程序的本地化
如果产品需要提供多语言版本,那么就可以使用DLL来支持多语言,可以为每种语言创建一个只支持这种语言的动态链接库
1.动态链接库入口函数 DllMain
(在加载动态连接库时候会自动被调用,作用如控制台的main函数,窗体程序的WinMain函数)
  BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved);
  动态链接库模块句柄.当DLL初次被加载时,它的句柄会通过此参数传递进来,就好像WinMain函数有一个当前实例句柄参数一样,因此,在编写DLL程序时,如果这些函数需要用到当前的DLL模块句柄,那么  就可以为该DLL提供DllMain函数,然后将通过参数hinstDLL传递进来的模块句柄保存到一个全局变量中,供其他函数使用
fdwReason  一个标记值,用来调用该DLL入口函数的原因.该参数的取值是下列值之一
  值            
说明                 
  DLL_PROCESS_ATTACH  
当进程第一次加载DLL并调用DllMain函数
  DLL_THREAD_ATTACH    当前进程正创建一个新线程
  DLL_THREAD_DETACH  
  DLL_PROCESS_DETACH  
lpvReserved
  保留参数.不需关心此参数,但可以检测这个指针,如果DLL被动态加载,则此参数为NULL,如果是静态加载,则此参数非NULL值
  如果提供了DllMain函数,那么在此函数中不要进行太复杂的调用.因为在动态链接库时,可能还有一些核心动态链接库没有加载.例如,我们自己编写的某个DLL被加载时,user32.dll或GDI32.dll这  两个核心动态链接库还没有被加载.前面的内容已经介绍了,程序在运行时,加载程序会依次加载该进程需要的dll,而我们自己编写的DLL可能会比较靠前地被加载,如果自己编写的DllMain函数需要调用  这些核心的DLL中的某个函数的话,这时就会失败,从而导致程序终止
2.加载动态库 LoadLibrary
  HMODULE LoadLibrary(LPCTSTR lpFileName);
  lpFileName:  一个字符串类型参数,该参数指定了可执行模块的名称,既可以是一个.dll文件,也可以是一个.exe文件.
  如果调用成函数返回所加载的那个模块的句柄.该函数的返回类型是HMODULE(和HINSTANCE类型可以通用)
  该函数不仅可以加载DLL(.dll),还可以加载可执行模块(.exe),一般来说,当可加载可执行模块时,主要是为了访问该模块内的一些资源,例如对话框资源,位图资源或图标资源等.
3.获得动态库的函数地址 GetProcAddress
  FARPROC GetProcAddress(HMODULE hModule,LPCSTR lpProcName);
  hModule:  指定动态链接库模块的句柄,即LoadLibrary函数的返回值
  lpProcName: 一个指向常量的字符指针(必须是改编后C++函数的名字),指定DLL导出函数的名字或者函数的序号(函数名和函数序号可以由dumpbin工具去查看),这里应该注意,如果参数指定的   是导出函数的序号,那么序号必须在低字节中,高字节必须是0(可以用MAKEEINTRESOURCE宏,该宏会吧指定的函数序列号转换为相应的函数名字字符串)
  成功返回函数的函数地址,失败的话返回NULL
4.释放函数动态连接库链接 FreeLibrary
  BOOL FreeLibrary( HMODULE hLibModule);
  hLibModule:  指向连接库的句柄
5.获得动态连接库句柄 GetModuleHandle
  HMODULE GetModuleHandle ( LPCTSTR lpModuleName);
  plModuleName:一个指字符串用于表示模块名字,一个动态连接库(name.dll)或者执行文件的名字(name.exe),若没有加后缀默认是动态连接库即系统会在帮你加上后缀.dll .
  若函数成功返回对应句柄,若失败返回空
编写动态连接库
本程序使用的编译环境是VS2005,如果是使用VC6.0环境的可以去网上找孙鑫关于VC的视频,视频第19讲讲的就是动态连接库编写.
编写动态链接库
建立DLL项目
Win32 -& Win32项目 -& DLL(D)
MFC -& MFC DLL
生成导出函数,类,成员函数
生成导出函数:  在函数前添加_declspec(dllexport)[导出标示符]生成导出函数,
生成导出类:   & 在class后类名前添加_declspec(dllexport)[[导出标示符]这样就可以导出整个类,但是访问类的函数时候,仍然受限于函数自身的范围权限.也就是说,如果该函数访问权限是private或protect的话,那么外部程序仍然无法访问这个函数
生成导出成员函数:在成员函数的返回类型后在函数的函数名前面加_declspec(dllexport)
代码示例()
加载动态连接库
隐式链接方式加载动态库()
加载dll.lib文件
VC6.0:      点击 Project/Settings后对话框下Link的Object/library modules下添加dll的lib文件
VS/VC6.0:   & &在文件中利用#pragma comment(lib,"链接库地址")
加载dll.dll文件&  把dll文件放在下面路径的一种中
path环境变量中列出的路径中
利用extern / _declspec(dllimport)[导出标示符]声明动态链接库的函数
_declspec(dllimport)  可以调用dll中非导出函数[没有_declspec(dllexport)的函数]
extern         & &只能调用dll中导出函数[有_declspec(dllexport)的函数]
与使用extern关键字这种方式相比,使用_declspec(dllimport)标识符声明外部函数时,它将告诉编译器该函数是从动态链接库中引用的,编译器可以生成运行效率更高的代码,因此,如果是调用的函数来自动态链接库DLL中,应该采用这种方式调用函数
显示加载方式加载DLL()
将最新的dll文件复制到以下路径中
path环境变量中列出的路径中
调用LoadLibrary,加载动态库
声明需要的动态链接的函数指针类型(此处可以要可以不要,这样只是方便以后定义相关函数指针)
//例如下面要调用动态链接库中的 int max_dll(int a,int b) 函数
//所以需要定义相关类型的指针声明
typedef int (/*_stdcall*/ *INTMAX)(int a,int b);
//以后就可以用INTMAX来定义相关指针如
INTMAX pMaxI
获得函数地址GetProcAddress
调用FreeLibrary释放动态链接库
两种加载方式的比较
  动态加载和隐式链接这两种加载DLL的方式各有优点.如果采用动态加载的方式,那么可以在需要加载时才加载DLL.而隐式链接方式实现起来比较简单,在编写客户端代码时就可以把链接工作做好,在程序中可以随时调用DLL导出的函数,但是访问十多个DLL,如果都采用隐式链接的方式链接加载他们的话,那么在启动程序时候,这些DLL都需要加载到内存中,并映射到调用进程的地址空间,这样将加大启动程序的时间,而且,一般来说,在程序运行过程中只是在某个条件满足时候,这时才会访问某个DLL中的某个函数,其他情况下都不需要访问这些DLL,但是,这时所有的DLL都被已经加载到内存中,资源浪费会比较严重,这种情况下,就可以采用动态加载DLL技术,也就是说,在需要时,DLL才会被加载到内存中,并被映射到进程的地址空间中,有一点需要说明的是,实际上,采用隐式链接的方式访问DLL时,在启动时也是通过调用LoadLibrary函数加载到该进程需要的动态链接库的
动态连接库源程序代码
// .h 头文件 -----------------------------------------------------
#ifndef DLL_API
#define DLL_API _declspec(dllimport)
DLL_API int max_dll(int a,int b);
DLL_API double max_dll(double a,double b);
class DLL_API testClass{
testClass();
int getValue();
// .cpp 源程序 ---------------------------------------------------
#define DLL_API _declspec(dllexport)
#include "test.h"
int max_dll(int a,int b){
return a&b?a:b;
double max_dll(double a,double b){
return a&b?a:b;
testClass::testClass():value(100)
int testClass::getValue()
隐式调用动态链接
#include&iostream&
#include&cstdlib&
//加载动态连接库头文件
#include"../dll/test.h"
//加载动态连接库的引入库(LIB)
#pragma comment(lib, "../release/dll.lib")
using namespace
void main(){
int a=6,b=10;
double a1=11.1,b1=32.22;
//调用动态连接库中的类
//调用动态链接库函数
cout&&"the max:"&&max_dll(a,b)&&
cout&&"the max:"&&max_dll(a1,b1)&&
//调用动态链接库成员函数
cout&&"the c.value is "&&c.getValue()&&
system("pause");
显示调用动态链接库
#include"windows.h"
#include&iostream&
#include&cstdlib&
//加载动态连接库头文件
#include"../dll/test.h"
using namespace
//声明函数指针类型
typedef int (/*_stdcall*/ *MAXINT)(int a,int b);
typedef double (/*_stdcall*/ *MAXDOUBLE)(double a,double b);
void main(){
int a=6,b=10;
double a1=11.1,b1=32.22;
HINSTANCE hI
hInst=LoadLibrary("../release/dll.dll");
//动态加载动态链接库中的函数 int max_dll(int a,int b)
//MAXINT max_int=(MAXINT)GetProcAddress(hInst,"?max_dll@@YAHHHH@Z");//用函数名调用
//获取函数指针
MAXINT max_int=(MAXINT)GetProcAddress(hInst,MAKEINTRESOURCE(4));//用函数序号调用
if(!max_int)
cout&&"获取max_int函数地址失败!"&&
system("pause");
//动态加载动态链接库中的函数 double max_dll(double a,double b)
//获取函数指针
MAXDOUBLE max_double=(MAXDOUBLE)GetProcAddress(hInst,"?max_dll@@YANNN@Z");//用函数名调用
//MAXDOUBLE max_double=(MAXDOUBLE)GetProcAddress(hInst,MAKEINTRESOURCE(5));//用函数序号调用
if(!max_double)
cout&&"获取max_double函数地址失败!"&&
system("pause");
//调用动态链接库函数
cout&&"the max:"&&max_int(a,b)&&
cout&&"the max:"&&max_double(a1,b1)&&
//释放动态连接库链接
FreeLibrary(hInst);
system("pause");
dumpbin 工具
查看dll与exe相关导入导出函数信息
dumpbin程序的文件位置
VC6.0:  VC98 \ bin
VS2005:  Microsoft Visual Studio 8\VC\bin
-exports 文件名.dll&&   (查看导出函数和导出类)
-imports 文件名.exe&  (查看导入函数)
设置VC++使用环境信息
  VCVAR32.bat 建立VC++使用环境信息,但是注意当在命令行界面下执行VCVARS32.bat文件后,该文件所设置的环境信息只是在当前命令行窗口生效.如果关闭该窗口,再次启动一个新的命令行窗口后,仍需要运行   VCVAR32.bat文件
以上面的DLL源程序为例子,做个使用说明,先打开控制台(如下图)
然后,把建立VC++使用环境信息,把VCVAR32.bat(批处理的位置和dumpbin一样)拖到控制台界面中(如下图).
然后回车,便建立好了VC++使用环境信息(如下图).这样就可以是用 dumpbin 这个命名了.
然后切换到工程目录中的 debug 或 release 中去.(如下图)
接着用 dumpbin 查看工程生成的 dll.dll 动态链接库的导出函数(如下图)(注意:这个函数必须有_declspec(dllexport)修饰,否则在这里是看不到).
流程图如下:
C++名字改编(C++名字粉碎)
在上面使用 dumpbin 程序查看 dll.dll 的导出函数发现函数名有点奇怪,我们定义的函数名max_dll两个重载函数名在这里变成了 ?max_dll@@YAHHH@Z&与 ?max_dll@@YANNN@Z,因为C++支持函数重载,对于重载的多个函数来说,其函数名都是一样的,为了加以区分,在编译连接时,C++会按照自己的规则篡改函数名字,这一过程为"名字改编".有的书中也称为"名字粉碎".不同的C++编译器会采用不同的规则进行名字改编,这个的话,利用不同的C++编译器生成的程序在调用对方提供的函数时,可能会出现问题
解决名字改变问题
在定义导出函数时,需要加上限定符: extern"C" (双引号中的C一定要大写)
使动态链接库文件在链接时,导出函数的函数名称不发生改变.
利用 extern "C" 可以解决 C++ 和 C 语言之间相互调用时函数命名的问题.但是这种方法有一个缺陷,就是不能用于导出一个类成员函数,只能导出全局函数这种情况
如果导出函数的调用约定发生了改变,那么即使使用了限定符: extern "C" ,该函数的名字仍然会发生改编.
记得导出和导入都要加入 extern "C" 否则在调用动态链接库时候会发生找不到函数这个现象.
利用 extern"C" 解决名字改编
动态连接库程序源码
// .h 头文件 ---------------------------------------------------------
#ifndef DLL_API
#define DLL_API extern "C" _declspec(dllimport)
DLL_API int max_dll(int a,int b);
// .cpp 源文件 -------------------------------------------------------
#define DLL_API extern "C"_declspec(dllexport)
#include "test.h"
int max_dll(int a,int b){
return a&b?a:b;
主程序源码
#include&iostream&
#include&cstdlib&
//加载动态连接库头文件
#include"../dll/test.h"
//加载动态连接库的引入库(LIB)
#pragma comment(lib, "../release/dll.lib")
using namespace
void main(){
int a=6,b=10;
//调用动态链接库函数
cout&&"the max:"&&max_dll(a,b)&&
system("pause");
利用 dumpbin 查看命名
四种调用方式:
__cdecl调用约定又称为 C 调用约定,是 C/C++ 语言缺省的调用约定。参数按照从右至左的方式入栈,函数本身不清理栈,此工作由调用者负责,返回值在EAX中。由于由调用者清理栈,所以允许可变参数函数存在,如int sprintf(char* buffer,const char* format,...);。
__stdcall 很多时候被称为 pascal 调用约定。pascal 语言是早期很常见的一种教学用计算机程序设计语言,其语法严谨。参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。
__fastcall
顾名思义,__fastcall 的特点就是快,因为它通过 CPU 寄存器来传递参数。他用 ECX 和 EDX 传送前两个双字(DWORD)或更小的参数,剩下的参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在 EAX 中。
__thiscall
这是 C++ 语言特有的一种调用方式,用于类成员函数的调用约定。如果参数确定,this 指针存放于 ECX 寄存器,函数自身清理堆栈;如果参数不确定,this指针在所有参数入栈后再入栈,调用者清理栈。__thiscall 不是关键字,程序员不能使用。参数按照从右至左的方式入栈。
代码示例(编译环境VS2005):
使用 extern "C" 时
动态连接库源码:
// .h 头文件----------------------------------------------------------
#ifndef DLL_API
#define DLL_API extern "C" _declspec(dllimport)
DLL_API int __stdcall stdcall_max_dll(int a,int b);
DLL_API int __cdecl cdecl_max_dll(int a,int b);
DLL_API int __fastcall fastcall_std_max_dll(int a,int b);
// c.pp 源文件--------------------------------------------------------
#define DLL_API extern "C" _declspec(dllexport)
#include "test.h"
int __stdcall stdcall_max_dll(int a,int b){
return a&b?a:b;
int __cdecl cdecl_max_dll(int a,int b){
return a&b?a:b;
int __fastcall fastcall_std_max_dll(int a,int b){
return a&b?a:b;
用 dumpbin 查看导出函数:
未使用 extern "C" 时
动态连接库源码:
// .h 头文件 --------------------------------------------------------------
#ifndef DLL_API
#define DLL_API /*extern "C"*/ _declspec(dllimport)
DLL_API int __stdcall stdcall_max_dll(int a,int b);
DLL_API int __cdecl cdecl_max_dll(int a,int b);
DLL_API int __fastcall fastcall_std_max_dll(int a,int b);
// .cpp 源文件 -----------------------------------------------------------
#define DLL_API /*extern "C"*/ _declspec(dllexport)
#include "test.h"
int __stdcall stdcall_max_dll(int a,int b){
return a&b?a:b;
int __cdecl cdecl_max_dll(int a,int b){
return a&b?a:b;
int __fastcall fastcall_std_max_dll(int a,int b){
return a&b?a:b;
用 dumpbin 查看导出函数:
阅读(...) 评论()以分离的模块提供软件更新的系统及其方法
一种以分离的模块提供软件更新的系统及其方法,其通过将更新程序分离为预更新模块以及核心模块后,当预更新模块判断出与核心模块对应的更新档案存在时,会先以更新档案更新核心模块,再加载更新后的核心模块,使核心模块更新软件所包含的目标档案的技术手段,可以让更新程序更新自身,并达成避免使用者需要手动更新更新程序的技术功效。
1.一种以分离的模块提供软件更新的方法,应用于一软件的一更新程序中,其特征在于,该方法至少包含下列步骤:分离该更新程序为一预更新模块及一核心模块;该预更新模块判断与该核心模块对应的一更新档案存在后,以该更新档案更新该核心模块;
该预更新模块加载更新后的该核心模块;及该核心模块更新该软件所包含的至少一目标档案。
2.如权利要求1所述的以分离的模块提供软件更新的方法,其特征在于,该方法于该预更新模块判断与该核心模块对应的该更新档案存在的步骤前,更包含该预更新模块显示一使用者接口的步骤。
3.如权利要求1所述的以分离的模块提供软件更新的方法,其特征在于,该预更新模块判断与该核心模块对应的该更新档案存在的步骤是该预更新模块联机至一服务器判断该服务器中储存该更新档案后,判断该更新档案存在。
4.如权利要求1所述的以分离的模块提供软件更新的方法,其特征在于,该核心模块更新该软件所包含的该目标档案的步骤更包含该核心模块更新该预更新模块的步骤。
5.如权利要求1所述的以分离的模块提供软件更新的方法,其特征在于,该方法于该核心模块更新该目标档案的步骤前,更包含该预更新模块或该核心模块结束该预更新模块的执行的步骤。
6.如权利要求1所述的以分离的模块提供软件更新的方法,其特征在于,该预更新模块加载更新后的该核心模块的步骤是该预更新模块以动态链接库技术或反射技术载入更新后的该核心模块。
7.一种以分离的模块提供软件更新的系统,应用于一软件的一更新程序中,其特征在于,该系统至少包含:一核心模块,用以更新该软件所包含的至少一目标档案;及一预更新模块,属于该目标档案其中之一,其中更包含:一判断单元,用以判断与该核心模块对应的一更新档案是否存在;一更新单元,用以于判断单元判断该更新档案存在时,以该更新档案更新该核心模块;及
一核心加载单元,用以加载该核心模块。
8.如权利要求7所述的以分离的模块提供软件更新的系统,其特征在于,该预更新模块更包含一使用者接口,该预更新模块更用以于该使用者接口中显示互动信息。
9.如权利要求7所述的以分离的模块提供软件更新的系统,其特征在于,该预更新模块更包含一传输单元,用以联机至一服务器,该判断单元更用以通过该传输单元判断该服务器中是否储存该更新档案,该传输单元更用以至该服务器下载该更新档案。
10.如权利要求7所述的以分离的模块提供软件更新的系统,其特征在于,该预更新模块或该核心模块更用以结束执行该预更新模块。
以分离的模块提供软件更新的系统及其方法技术领域
一种软件更新的系统及其方法,特别是指一种以分离的模块提供软件更新的系统及其方法。
软件是一系列按照特定顺序组织的计算机数据和指令的集合,其依据执行的主机的位置,可以分为执行在本地端的软件以及执行在远程的软件。
软件在存在错误的程序、开发者开发出效率更好资源使用更少的相同程序、或是开发者欲增加软件的功能时,通常会需要进行更新。由于执行在本地端的软件是安装在客户端中,因此当软件需要更新时,只能依靠使用者手动更新或是由软件中的更新程序自动更新,因此,软件中的更新程序是很重要的。
虽然以软件中的更新程序进行软件更新的更新方式对使用者而言是比较方便的。
不过,因为软件中需要被更新的档案通常会储存在开发厂商所提供的服务器上,因此再进行软件更新时,更新程序需要与开发厂商所提供的服务器配合。一旦服务器所执行的与更新程序搭配的服务程序因为被开发者更新等原因发生改变,则在执行在客户端中的更新软件往往需要同步更新;但是,这实际上是有困难的,因为软件的特性,当程序文件在执行中的时候,被执行的程序文件无法被修改,也就是说,更新程序无法对自己进行更新,要是服务器所执行的服务程序发生改变,这将使得更新程序无法进行软件更新,如此,使用者势必得要手动更新更新程序。
综上所述,可知现有技术中长期以来一直存在软件的更新程序无法更新自身的问题,因此有必要提出改进的技术手段,来解决此一问题。
有鉴于现有技术存在更新程序无法更新自身的问题,本发明遂提供一种以分离的模块提供软件更新的系统及其方法,其中:
本发明所提供的以分离的模块提供软件更新的系统,至少包含:核心模块以及预更新模块,核心模块用以更新软件所包含的目标档案;预更新模块,属于目标档案其中之一,其中更包含:判断单元,用以判断与核心模块对应的更新档案是否存在;更新单元,用以于判断单元判断更新档案存在时,以更新档案更新核心模块;核心加载单元,用以加载核心模块。
本发明所提供的以分离的模块提供软件更新的系统,其中,预更新模块更包含使用者接口,预更新模块更用以于使用者接口中显示互动信息;另外,预更新模块或核心模块更用以结束执行预更新模块。
本发明所提供的以分离的模块提供软件更新的系统,其中,预更新模块更包含传输单元,用以联机至服务器,判断单元更用以通过传输单元判断服务器中是否储存更新档案,传输单元更用以至服务器下载更新档案。
本发明所提供的以分离的模块提供软件更新的方法,其步骤至少包括:分离更新程序为预更新模块及核心模块;预更新模块判断与核心模块对应的更新档案存在后,以更新档案更新核心模块;预更新模块加载更新后的核心模块;核心模块更新软件所包含的目标档案。
本发明所提供的以分离的模块提供软件更新的方法,其中,于预更新模块判断与核心模块对应的更新档案存在前,更包含预更新模块显示使用者接口。另外,于核心模块更新目标档案前,更包含预更新模块或核心模块结束预更新模块的执行。
本发明所提供的以分离的模块提供软件更新的方法,其中,预更新模块判断与核心模块对应的更新档案存在的步骤是预更新模块联机至服务器判断服务器中储存更新档案后,判断更新档案存在;核心模块更新软件所包含的目标档案的步骤更包含核心模块更新该预更新模块的步骤;预更新模块加载更新后的核心模块的步骤是预更新模块以动态链接库(DynamicLinkingLibrary,DLL)技术或反射技术加载更新后的核心模块。
本发明所提供的系统与方法如上,与现有技术之间的差异在于本发明通过将更新程序分离为核心模块以及预更新模块,当预更新模块判断对应核心模块的更新档案存在时,会先以更新档案更新核心模块,再加载更新后的核心模块,使核心模块更新软件所包含的目标档案,藉以解决现有技术所存在的问题,并可以达成避免使用者需要手动更新更新程序的技术功效。
图1为本发明所提供的分离更新程序为两模块的示意图;
图2为本发明所提供的以分离的模块提供软件更新的系统架构图;
图3为本发明所提供的以分离的模块提供软件更新的方法流程图;
图4A为本发明实施例所提供的使用动态链接库加载核心模块的程序代码示意图;
图4B为本发明实施例所提供的使用反射技术加载核心模块的程序代码示意图;
图5为本发明实施例所提供的使用者接口的示意图。
【主要组件符号说明】
200更新程序
210核心模块
220预更新模块
221判断单元
222更新单元
223核心加载单元
224传输单元
225使用者接口
401程序代码
402程序代码
具体实施方式
以下将配合图式及实施例来详细说明本发明的特征与实施方式,内容足以使本领域技术人员能够轻易地充分理解本发明解决技术问题所应用的技术手段并据以实施,藉此实现本发明可达成的功效。
本发明如「图1」所示,将软件的更新程序200由一个完整的模块再进一步分离为具有不同功能的两个模块,两个模块中的一个或两个模块包含更新另一个模块的功能。事实上,本发明并不将更新程序分离为两个模块为限,凡一个完整的更新程序可以分离为两个以上的模块,且其中的任一模块存在更新其它模块的功能时,即可以使用本发明。
以下先以「图2」本发明所提供的以分离的模块提供软件更新的系统架构图来说明本发明的系统运作。如「图2」所示,本发明的系统含有核心模块210、以及预更新模块220。
核心模块210负责以公知的软件更新方式,如依靠使用者手动更新或是由软件中的更新程序自动更新等方式更新软件中的目标档案。被核心模块210更新的目标档案通常是包含在本发明的软件中,不属于更新程序200的其它程序,但本发明并不以此为限。在实务上,目标档案除了不包含核心模块210之外,也可以包含预更新模块220。
值得一提的是,由于软件中不属于更新程序200的其它程序都是由核心模块210进行更新,因此,核心模块210是更新程序200中最主要的部分。
预更新模块220主要负责在加载核心模块210前,更新核心模块210。为了达到这样的功能,预更新模块220至少更包含判断单元221、更新单元222、以及核心加载单元223。
判断单元221负责判断与核心模块210对应的更新档案是否存在。被判断单元221判断存在与否的更新档案即为更新核心模块210的档案,值得一提的是,更新档案可以被储存于包含本发明的软件的执行环境(本地端)中,也可以被储存于远程的服务器中。当更新档案被储存于本地端时,判断单元221可以通过本地端的档案系统判断更新档案是否存在;而当更新档案被储存于服务器时,判断单元221可以通过传输单元224联机至服务器判断更新档案是否存在。
不论更新档案储存于软件的执行环境或是储存于远程的服务器中,判断单元221更可以由组成核心模块210的各档案的更新日期是否较更新档案的更新日期更早来判断可以被用来更新核心模块210的更新档案是否存在,或是由预存于本地端特定储存位置的设定文件中所记录的核心模块210的版本编号是否较更新档案中所记录的版本编号为小来判断更新核心模块210的更新档案是否存在,甚至可以由本地端的特定的储存位置是否存在特定名称的档案(如文件名称即为前次更新的日期的档案)来判断更新档案是否存在,但判断单元221判断更新档案是否存在的方式并不以此为限。
传输单元224负责与储存更新档案的服务器联机,藉以于判断单元221判断更新档案存在后,至服务器中下载更新档案,使下载至服务器的更新档案被储存于本地端中的特定位置,例如专门用来存放更新档案的目录等,但本发明并不以此为限。另外,传输单元224更可以提供判断单元221通过其所建立的联机至服务器判断更新档案是否存在。
更新单元222负责在判断单元221判断出与核心模块210对应的更新档案存在后,于本地端中读取对应核心模块210的更新档案,并以被读出的更新档案更新核心模块210,使得核心模块210被更新。其中,更新单元222可以依据预定的存放路径读取预定文
件名称的更新档案,也可以依据系统设定文件中所记录的存放路径与文件名称读取更新档案,但更新单元222读取更新档案的方式并不以此为限。
更新单元222可以直接以更新档案覆盖组成核心模块210的档案,依据更新档案中所记录的数据修改或删除组成核心模块210的特定档案等,藉以更新核心模块210,但更新单元222更新核心模块210的方式并不以此为限。
核心加载单元223负责加载核心模块210,使得核心模块210开始执行。其中,当判断单元221判断出对应核心模块210的更新档案存在时,核心加载单元223会于更新单元222完成核心模块210的更新后,才加载核心模块210,若判断单元221判断出对应核心模块210的更新档案不存在,则会直接加载核心模块210。
特别值得一提的是,核心加载单元223是以延迟加载核心模块210的方式来完成更新程序200中最重要部分的更新,而核心加载单元223随着软件开发平台的不同,将会以不同的方式加载核心模块210,例如,核心加载单元223中可以包含「图4A」所示的程序代码401,程序代码401以动态链接库(DynamicLinkingLibrary,DLL)的方式加载核心模块210,或是核心加载单元223中也可以包含「图4B」所示程序代码402,程序代码402以「反射」的技术加载核心模块210,但核心加载单元223加载核心模块210的方式并不以上述两程序代码所使用的方式为限。
另外,本发明所提供的预更新模块220中更可以包含使用者接口225,预更新模块220可以通过使用者接口显示互动信息,藉以与使用者互动,但使用者接口225并不以此为限。其中,互动信息例如软件更新状态、档案下载完成度等,本发明并不以此为限。
使用者接口225更可以提供使用者输入进行软件更新的触发信号,例如在使用者接口225中提供更新按键,当使用者点击更新按键时,软件更新的触发信号会被输入,判断单元221更可以在使用者输入进行软件更新的触发信号后,才判断对应核心模块210的更新档案是否存在。
此外,预更新模块220或核心模块210都可以结束预更新模块220的执行,例如在核心加载单元223加载核心模块210后,已无其它功用时,预更新模块220可以唤起自身包含的释放程序,藉以结束执行。而核心模块210则是会在需要更新预更新模块220时,唤起结束预更新模块220的程序,藉以结束预更新模块220的执行。
接着以一个实施例来解说本发明的运作系统与方法,并请参照「图3」本发明所提的以分离的模块提供软件更新的方法流程图。在本实施例中,假设包含本发明的软件为健康状态记录软件,但本发明所提的软件并不以此为限。
当使用者在执行环境中点击(click)代表健康状态记录软件,藉以在执行环境中执行健康状态记录软件后,若健康状态记录软件会再开始执行时,先进行版本的更新,则健康状态记录软件的更新程序200会被执行。
若更新程序200包含本发明,则更新程序200会被开发者分离为核心模块210以及预更新模块220(步骤301)。在更新程序200开始执行后,预更新模块220中的判断单元221会先判断对应核心模块210的更新档案是否存在(步骤350)。假设在本实施例中,对应核心模块210的更新档案被储存在健康状态记录软件的开发厂商所提供的服务器上,则判断单元221会先通过预更新模块220中的传输单元224,联机到储存有对应核心模块210的更新档案的服务器(步骤351)。若判断单元221会通过传输单元224判断出健康状
态记录软件的开发厂商所提供的服务器上储存有更新档案,则判断单元221会通过传输单元224读取服务器所记录的更新档案的最后更新日期,假设为「」,跟着,判断单元221会在比对服务器所记录的更新档案的最后更新日期「」与核心模块210的前次更新日期「」后,判断出服务器上存在对应核心模块210的更新档案,如此,传输单元224会至服务器中下载与核心模块210相对应的更新档案(步骤356),并储存于健康状态记录软件所执行的执行环境中。
在预更新模块220中的判断单元221判断出对应核心模块210的更新档案存在
(步骤350)后,预更新模块220中的更新单元222会至健康状态记录软件所执行的执行环境中读取与核心模块210相对应的更新档案,并以更新档案对核心模块210进行更新(步骤360)。
在预更新模块220中的更新单元222更新核心模块210后,预更新模块220中的核心加载单元223会加载核心模块210(步骤370),使得经过更新单元222更新后的核心模块210开始执行,藉以更新属于健康状态记录软件的目标档案(步骤390)。如此,包含本发明的更新程序200所包含的更新属于健康状态记录软件的目标档案的核心模块210将可以被更新,不会因为更新程序200正在执行中而造成无法更新程序200所包含的核心模块210。
在上述的实施例中,若核心模块210在更新健康状态记录软件时,被更新的目标档案中包含组成预更新模块220的档案,为了避免无法完成预更新模块220的更新,则核心模块210会结束预更新模块220的执行(步骤380)。
综上所述,可知本发明与现有技术之间的差异在于将更新程序200分离为预更新模块220以及核心模块210后,当预更新模块220判断出与核心模块210对应的更新档案存在时,会先以更新档案更新核心模块210,再加载更新后的核心模块210,使核心模块210更新软件所包含的目标档案的技术手段,藉由此一技术手段可以解决现有技术所存在更新程序无法更新自身的问题,进而达成避免使用者需要手动更新更新程序的技术功效。
在上述的实施例中,若对应核心模块210的更新档案被使用者下载后直接储存在健康状态记录软件所执行的执行环境中,则判断单元221会直接通过健康状态记录软件所执行的执行环境的档案系统,读取健康状态记录软件所执行的执行环境中所储存的更新档案的版本,假设为「8.4.13」,而若系统设定文件中所记录的核心模块210的版本为「8.2.8」时,判断单元221判断出健康状态记录软件所执行的执行环境上存在对应核心模块210的更新档案(步骤350)。如此,预更新模块220中的更新单元222会至健康状态记录软件所执行的执行环境中读取与核心模块210相对应的更新档案,并以更新档案对核心模块210进行更新(步骤360)。
另外,若预更新模块220中包含使用者接口225,则当健康状态记录软件在进行更新的过程中,预更新模块220中的判断单元221判断对应核心模块210的更新档案存在(步骤350)后,预更新模块220可以产生如「图5」所示的使用者接口225(步骤310),而后,使用者可以点击使用者接口225上所显示的「更新」按键521,藉以输入更新软件的触发信号
(步骤355),如此,将使得后续步骤被执行。另外,在实务上,预更新模块220也可以在产生使用者接口225(步骤310)后,先提供使用者点击使用者接口225上所显示的「更新」按键521以输入触发信号(步骤355),再判断对应核心模块210的更新档案是否存在(步骤
虽然本发明所公开的实施方式如上,惟所述的内容并非用以直接限定本发明的专利保护范围。任何本发明所属技术领域中的技术人员,在不脱离本发明所公开的精神和范围的前提下,对本发明的实施的形式上及细节上作些许的更动润饰,均属于本发明的专利保护范围。本发明的专利保护范围,仍须以所附的权利要求书所界定者为准。}

我要回帖

更多关于 模块化设计的优点 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信