C++Builder建立及调用DLL

  • Post author:
  • Post category:其他


C++Builder建立及调用DLL

DLL简称动态链接库,是Windows中程序的重要组成部分。想象一下,一个程序需要多人共同完成开发,怎么个共同法?这时我们就要考虑把程

序分为好几个模块,团队每一个成员开发一个模块。问题来了:如何将模块组合并成一个完整系统?还有,我们开发的软件需要不断升级,如

何升级?难道每次非得把整个工程重新编译一次再发布给用户吗?解决这些问题的科学办法,就是开发动态链接库DLL。

现在以开发myDLL.dll动态链接库为例,讲讲BCB中开发动态链接库的方法。

1、新建立一个工程:File-New-Other…在New卡中选择DLL Wizard

2、将工程存为myDLL.bpr

3、在myDLL.cpp中写接口代码:

—————————————————————————

#include<vcl.h>

#include <windows.h>

#pragma hdrstop

—————————————————————————

Important note about DLL memory management when your DLL usesthe

static version of the RunTime Library:

If your DLL exports any functions that pass String objects (orstructs/

classes containing nested Strings) as parameter or functionresults,

you will need to add the library MEMMGR.LIB to both the DLLproject and

any other projects that use the DLL. You will also need to useMEMMGR.LIB

if any other projects which use the DLL will be performing newor delete

operations on any non-TObject-derived classes which areexported from the

DLL. Adding MEMMGR.LIB to your project will change the DLL andits calling

EXE’s to use the BORLNDMM.DLL as their memory manager. Inthese cases,

the file BORLNDMM.DLL should be deployed along with your DLL.

To avoid using BORLNDMM.DLL, pass string information using”char *” or

ShortString parameters.

If your DLL uses the dynamic version of the RTL, you do notneed to

explicitly add MEMMGR.LIB as this will be done implicitly foryou

—————————————————————————

extern “C” __declspec(dllexport) __stdcall int myAdd(int,int);

extern “C” __declspec(dllexport) __stdcall AnsiString aboutMe(void);

int add(int n1,int n2);

#pragma argsused

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*lpReserved)

{


return 1;

}

—————————————————————————

__declspec(dllexport) __stdcall int myAdd(int n1,int n2)

{


int T;

T=add(n1,n2);

return T;

}

int add(int n1,int n2)

{


return n1+n2;

}

__declspec(dllexport) __stdcall AnsiString aboutMe(void)

{


return “曾棕根好你个大笨蛋,居然现在才学会用DLL!半年前施勇强就告诉了你呀!研究进度太慢!”;

}

4、需要注意的是,在编写DLL这样的程序时,要力求简单,少用大量内存分配,尽量按照标准C的程序设计方法,以模块化结构设计为好,少采

用面向对象的程序设计方法。

5、进入Project-Options:

勾掉Linker页中的Use Dynamic RTL

勾掉Packages页中的Build with runtime packages

按一次Compiler中的Release按钮

在Version Info页中勾选Include version information in project,并勾选Auto-incrementbuild number,再在里面设置好版权信息

6、现在可以进入Project-Build myDLL生成myDLL.dll和myDLL.lib这两个文件。

二 静态调用动态链接库DLL

调用DLL有两种方式,一种是静态调用,另一种就是动态调用。静态调用需要LIB库文件和DLL文件,程序编译时,需要用到LIB文件,发布时这

个LIB文件就不再需要,而且,编译系统时,这个动态链接库已编译进程序,这样,在程序一开始运行时就会查找这个DLL文件,如果这个DLL文

件不存在,那么,程序是启动不起来的。相反,动态调用DLL则不是这样,它只需要DLL文件,程序运行时,程序不需要知道这个DLL文件当前是

否存在,只有当程序运行到某个点,才需要去调用DLL文件多个应用程序调用DLL时,DLL在内存中只产生一个实例,因此,可以有效地节省内

存空间,提高系统的运行效率。注意到,DLL 的编制与编程语言无关,只要遵守DLL的接口规范,许多语言都可以开发出高效的DLL程序,其它

语言开发的DLL,同样可以在BCB中调用。

下面介绍以myDLL.dll为例静态调用DLL的步骤:

1、将myDLL.dll和myDLL.lib文件拷入到开发工程中,注意到,应用程序发布时,这个lib文件是不需要的。如果是其它语言开发的DLL,在没有

lib文件的情况下,可以用implib.exe工具程序,生成一个lib文件,

用法:implib.exe 文件名.lib 文件名.DLL

2、Project-Add to project将myDLL.lib库导入到工程。

如果要从工程中清除库文件,方法有两种:

a、Project-Remove from project

b、View-Project Manager

3、在工程的Unit1.cpp中写程序代码:

—————————————————————————

#include<vcl.h>

#pragma hdrstop

#include”Unit1.h”

—————————————————————————

#pragma package(smart_init)

#pragma resource “*.dfm”

TForm1 *Form1;

extern “C” __declspec(dllimport) __stdcall int myAdd(int,int);

extern “C” __declspec(dllimport) __stdcall AnsiString aboutMe(void);

—————————————————————————

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{


}

—————————————————————————

void__fastcall TForm1::Button1Click(TObject *Sender)

{


int n;

n=myAdd(1,2);

ShowMessage(IntToStr(n));

}

—————————————————————————

void __fastcall TForm1::Button2Click(TObject *Sender)

{


ShowMessage(aboutMe());

}

—————————————————————————

三 动态调用动态链接库DLL

动态调用DLL函数可分为八步:

第一步:函数定义。这里的函数为地址转换函数。下面这个函数其实就是定义 int __stdcallmyAdd(int,int);

int __stdcall (*myAdd)(int,int);

第二步:定义模块句柄,全局变量,它是载入DLL文件后的实例

HINSTANCE HmyDLL;

第三步:装入DLL文件,同时获得它的句柄

HmyDLL=LoadLibrary(“myDLL.dll”);

第四步:定义函数地址变量

FARPROC P;

第五步:获取动态链接库内的某一函数的内存地址

P=GetProcAddress(HmyDLL,”myAdd”);

第六步:强制类型转换,即将所获取的函数地址强制转换为函数

myAdd=(int __stdcall (__cdecl*)(int,int))P;

第七步:函数调用

n=myAdd(10,20);

第八步:释放DLL

FreeLibrary(HmyDLL);

下面以动态调用myDLL.dll函数为例,进行讲解:

—————————————————————————

#include<vcl.h>

#pragma hdrstop

#include”Unit1.h”

—————————————————————————

#pragma package(smart_init)

#pragma resource “*.dfm”

TForm1 *Form1;

第一步:函数定义。这里的函数为地址转换函数。下面这个函数其实就是定义 int __stdcallmyAdd(int,int);

int __stdcall (*myAdd)(int,int);

AnsiString __stdcall (*aboutMe)(void);

第二步:定义模块句柄,全局变量,它是载入DLL文件后的实例

HINSTANCE HmyDLL;

—————————————————————————

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{


第三步:装入DLL文件,同时获得它的句柄

HmyDLL=LoadLibrary(“myDLL.dll”);

}

—————————————————————————

void__fastcall TForm1::Button1Click(TObject *Sender)

{


int n;

第四步:定义函数地址变量

FARPROC P;

if(HmyDLL!=NULL)

{


第五步:获取动态链接库内的某一函数的内存地址

P=GetProcAddress(HmyDLL,”myAdd”);

if(P==NULL)

{


ShowMessage(“打开myAdd()函数错误!”);

}

else

{


第六步:强制类型转换,即将所获取的函数地址强制转换为函数

myAdd=(int __stdcall (__cdecl*)(int,int))P;

第七步:函数调用

n=myAdd(10,20);

ShowMessage(IntToStr(n));

}

}

else

{


ShowMessage(“打开动态链接库文件myDLL.dll错误!”);

}

}

—————————————————————————

void__fastcall TForm1::FormDestroy(TObject *Sender)

{


第八步:释放DLL

FreeLibrary(HmyDLL);

}

—————————————————————————

void __fastcall TForm1::Button2Click(TObject *Sender)

{


FARPROC P;

if(HmyDLL!=NULL)

{


P=GetProcAddress(HmyDLL,”aboutMe”);

if(P==NULL)

{


ShowMessage(“打开aboutMe()函数错误!”);

}

else

{


aboutMe=(AnsiString __stdcall (__cdecl*)(void))P;

ShowMessage(aboutMe());

}

}

else

{


ShowMessage(“打开动态链接库文件myDLL.dll错误!”);

}

}

—————————————————————————

注意:动态调入myDLL.dll文件后,它在内存中只存在一个副本,这时,动态链接库文件已于关闭状态。

转自:http://blog.csdn.net/ww425/archive/2005/03/01/306500.aspx 转发请注明!!!!!