分类: WINDOWS
2010-06-24 16:03:07
1.什么是静态连接库,什么是动态链接库
静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE
文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的
DLL
文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接
库。静态链接库与静态链接库调用规则总体比较如下。
对于静态链接库(比较简单):
首先,静态链接库的使用需要库的开发
者提供生成库的.h头文件和.lib文件。
生成库的.h头文件中的声明格式如下:
extern "C" 函数返回类型
函数名(参数表);
在调用程序的.cpp源代码文件中如下:
#include "..\lib.h"
#pragma
comment(lib,"..\\debug\\libTest.lib")
//指定与静态库一起链接
第二,
因为静态链接库是将全部指令都包含入调用程序生成的EXE文件中。因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况,要想
用就得全要!要不就都别要!:)
对于动态链接库:
动态链接库的使用,根据不同的调用方法,需要提供
不同的资源:
1. 静态加载------程序静态编译的时候就静态导入dll,这样的话就需要提供给库使用者(C客户)如下文件:*.lib文件和.dll文件和*.h。其有2个坏处:
1
程序一开始运行就需要载入整个dll,无法载入程序就不能开始运行;
2 由于载入的是整个dll,需要耗费资源较多
其调用方法如下:
#include "..\lib.h"
#pragma
comment(lib,"..\\debug\\libTest.lib")
但是这种方式的话可以调用Class method.
2.动态加载-----那么只需要提供dll文件。
因此调用程序若想调用DLL中的某个函数就要以某种形式或方式指明它到底想
调用哪一个函数。但是无法调用Class method了。
如果要调用Dll中的function,需要经历3个步骤:
Handle h=LoadLibrary(dllName) -->
GetProcAddress(h,functionName)
返回函数指针,通过函指针调用其function-->FreeLibrary(h)
例如:Another.dll有一个int
Add(int x,int y)函数。则完整的调用过程如下:
typedef int (*
FunPtr)(int,int);//定义函数指针
FunPtr funPtr;
Handle
h=LoadLibrary("Another.dll");
funPtr=
(FunPtr)GetProcAddress(h,"Add");
funPtr(2,3);//2+3;
FreeLibrary(h);
2.示例
示例之一:
静态链接库的创建过程:
例如:我们创建一个自定义字符串的类CHironString,
只需要在IDE里面
添加class即可,然后program相应函数体
代码如下所示:
SDLL.h文件
------------------------------------------------------------------------
// HironString.h: interface for the
CHironString class.
//
//////////////////////////////////////////////////////////////////////
#if
!defined(AFX_HIRONSTRING_H__B23C5E5E_0E8B_4030_B057_34A40C934C59__INCLUDED_)
#define
AFX_HIRONSTRING_H__B23C5E5E_0E8B_4030_B057_34A40C934C59__INCLUDED_
#if _MSC_VER > 1000
#pragma
once
#endif // _MSC_VER > 1000
class CHironString
{
private:
char* m_data;
public:
char *
GetData();
CHironString(CHironString &other);
int Length();
CHironString();
CHironString(char
* str);
CHironString& operator=(CHironString &other);
virtual
~CHironString();
};
#endif //
!defined(AFX_HIRONSTRING_H__B23C5E5E_0E8B_4030_B057_34A40C934C59__INCLUDED_)
SDLL.CPP如下:
--------------------------------------------------------------
// HironString.cpp: implementation of the
CHironString class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include
"HironString.h"
//////////////////////////////////////////////////////////////////////
//
Construction/Destruction
//////////////////////////////////////////////////////////////////////
CHironString::CHironString()
{
m_data=NULL;
}
CHironString::CHironString(char *
str)
{
int len=strlen(str);
m_data=new char[len+1];
strcpy(m_data,str);
}
CHironString::~CHironString()
{
delete
m_data;
}
int CHironString::Length()
{
return
strlen(m_data);
}
CHironString::CHironString(CHironString
&other)
{
int len=strlen(other.m_data)+1;
m_data=new
char[len];
strcpy(m_data,other.m_data);
}
CHironString&
CHironString::operator =(CHironString &other)
{
if(this==&other)
return
*this;
if(m_data!=NULL)
delete[] m_data;
int
len=strlen(other.m_data)+1;
m_data=new char[len];
strcpy(m_data,other.m_data);
return
*this;
}
char * CHironString::GetData()
{
return
m_data;
}
然后,将程序编译后生成sdll.lib。
客户调用:将CHironString.h和SDLL.lib发布给client,那么客户端就
可以调用我们编写的静态链接库了。
示
例之二:
动态链接库的创建
首先我们必须先注意到DLL内的函数分为两
种:
(1)DLL 导出函数,可供应用程序调用;
(2)DLL 内部函数,只能在 DLL 程序使用,应用程序无法调用它们。
我们还是创建一个自定义的字符串处理类CHironString,不同之处其是一个动态链接库Dll。
动态链接库的export
需要在在相应的头文件中编写相应的MACRO
MyDll.h:自定义了一些
类(函数)export 宏(该文件由IDE自动生成)如下
------------------------------------------------------------------
#ifdef
MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
这是导出类的宏定义,将导出
类必须加上该宏,才能被导出。
此处的MYDLL_EXPORTS会出现在
project-->settings-->C/C++页面上的 PreProcessor
definition中,这个MACRO表明其要定义一个导出宏
CHironString.h
自定义类头文件
----------------------------------------------------------------
// HironString.h: interface for the
CHironString class.
//
//////////////////////////////////////////////////////////////////////
#if
!defined(AFX_HIRONSTRING_H__518E9EC4_0837_4E45_9516_7D6A70CD3D0F__INCLUDED_)
#define
AFX_HIRONSTRING_H__518E9EC4_0837_4E45_9516_7D6A70CD3D0F__INCLUDED_
#if _MSC_VER
> 1000
#pragma once
#endif // _MSC_VER > 1000
#include
"MyDll.h"
class MYDLL_API CHironString
//加上MYDLL_API表明此为Export Class
{
private:
char* m_data;
public:
char
* GetData();
CHironString(CHironString &other);
int
Length();
CHironString();
CHironString(char * str);
CHironString&
operator=(CHironString &other);
virtual ~CHironString();
};
#endif //
!defined(AFX_HIRONSTRING_H__518E9EC4_0837_4E45_9516_7D6A70CD3D0F__INCLUDED_)
CHironString.Cpp
------------------------------------------------------------
// HironString.cpp: implementation of the
CHironString class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "HironString.h"
//////////////////////////////////////////////////////////////////////
//
Construction/Destruction
//////////////////////////////////////////////////////////////////////
CHironString::CHironString()
{
m_data=NULL;
}
CHironString::CHironString(char
* str)
{
int len=strlen(str);
m_data=new char[len+1];
strcpy(m_data,str);
}
CHironString::~CHironString()
{
delete
m_data;
}
int
CHironString::Length()
{
return strlen(m_data);
}
CHironString::CHironString(CHironString
&other)
{
int len=strlen(other.m_data)+1;
m_data=new
char[len];
strcpy(m_data,other.m_data);
}
CHironString&
CHironString::operator =(CHironString &other)
{
if(this==&other)
return
*this;
if(m_data!=NULL)
delete[] m_data;
int
len=strlen(other.m_data)+1;
m_data=new char[len];
strcpy(m_data,other.m_data);
return
*this;
}
char *
CHironString::GetData()
{
return m_data;
}
经过compile
之后,会生成MyDll.dll和MyDll.lib文件。
客户端的调用:
1.如果是静态加载,那么需要提供*.lib
和*.h,运行时候需提供*.dll
动态链接具有下列优点:
节省内存和减少交换操作。很多进程可以同时使用一个 DLL,在内存中共享该 DLL 的一个副本。相反,对于每个用静态链接库生成的应用程序,Windows 必须在内存中加载库代码的一个副本。
节省磁盘空间。许多应用程序可在磁盘上共享 DLL 的一个副本。相反,每个用静态链接库生成的应用程序均具有作为单独的副本链接到其可执行图像中的库代码。
升级到 DLL 更为容易。当 DLL 中的函数发生更改时,只要函数的参数和返回值没有更改,就不需重新编译或重新链接使用它们的应用程序。相反,静态链接的对象代码要求在函数更改时重新链接应用程序。
提供售后支持。例如,可修改显示器驱动程序 DLL 以支持当初交付应用程序时不可用的显示器。
支持多语言程序。只要程序遵循函数的调用约定,用不同编程语言编写的程序就可以调用相同的 DLL 函数。程序与 DLL 函数在下列方面必须是兼容的:函数期望其参数被推送到堆栈上的顺序,是函数还是应用程序负责清理堆栈,以及寄存器中是否传递了任何参数。
提供了扩展 MFC 库类的机制。可以从现有 MFC 类派生类,并将它们放到 MFC 扩展 DLL 中供 MFC 应用程序使用。
使国际版本的创建轻松完成。通过将资源放到 DLL 中,创建应用程序的国际版本变得容易得多。可将用于应用程序的每个语言版本的字符串放到单独的 DLL 资源文件中,并使不同的语言版本加载合适的资源。
使用 DLL 的一个潜在缺点是应用程序不是独立的;它取决于是否存在单独的 DLL 模块。
[使用MFC创建的DLL]