BCB 编写 DLL 终极手册

来源:互联网 发布:学淘宝客服几天上手 编辑:程序博客网 时间:2024/05/21 07:03

  BCB 编写 DLL 终极手册

前言
网络上流传的BCB编写和调用DLL的方法多来源于一篇《BCB 编写 DLL 终极手册》,多数网站在转载此文章时也并未注明出处和作者,甚为心寒,且在转载过程中难免有纰漏,致使一些例子无法正确运行,我根据网络资料,重新整理了一下,发布出来。
如欲转载,请注明出处和作者,并向作者发一封邮件,谢谢。

.注意:
创建动态链接库时,如果想你创建的动态链接库并非只用于Borland开发工具,那么就需要遵循以下规则:
(1).
在导出函数的返回值和参数中不要使用Borland特有的数据类型和结构体,如AnsiString之类,请使用C/C++标准的数据类型或使用C/C++标准数据类型定义的结构体(特别不要使用String数据类型,BCB DLL向导生成的DLL工程文件中大篇幅的说明就是对此的说明,请自己查阅)
(2).
请使用extern "C"命名约定,这样,生成的DLL中的导出函数,就不会使用C++的命名约定,而是使用的C命名约定,即导出函数不会名字分解,而是和你定义的函数相同;
(3).
导出函数请使用WIN32 API的调用方式__stdcall(WINAPI)VCBorlandC++的调用约定__cdecl,不要使用Borland特有的__fastcall调用约定,否则只有Borland开发工具才可以使用这些动态链接库;

 

.实例:
(1).
导出函数(不使用
VCL)
使用BCB建立DLL向导来建立一个工程,选择不使用VCL,代码如下:

 

//---------------------------------------------------------------------------
#include 
//
---------------------------------------------------------------------------
//
   Important note about DLL memory management when your DLL uses the
//
   static version of the RunTime Library:
//

//   If your DLL exports any functions that pass String objects (or structs/
//
   classes containing nested Strings) as parameter or function results,
//
   you will need to add the library MEMMGR.LIB to both the DLL project and
//
   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//
   if any other projects which use the DLL will be performing new or delete
//
   operations on any non-TObject-derived classes which are exported from the
//
   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//
   EXE's to use the BORLNDMM.DLL as their memory manager.  In these 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 not need to
//
   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    
return 1
;
}

//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) int __stdcall Calc(int a, int b) //导出函数
{
    
return a+
b;
}

//---------------------------------------------------------------------------

保存工程为DLLs,编译,就会在工程目录下生成DLLs.dll(大小应该是8K),同时还会自动在同一目录下生成DLLs.lib静态库,如果没有生成,请自己手动使用implib.exe工具生成(使用方法见本文说明)

 

(2).导出函数(使用VCL)
使用BCB DLL向导建立一个工程,选择使用VCL支持,新建立一个窗体(采用默认名称TForm1)存为Unit1.cpp,设置窗体大小为一般OKCANCEL对框的大小(这里设为277*119),在窗体上添加两个按钮:Button1标签为"确定",ModalResultmrOk,Button2标签为"取消"ModalResultmrCancel

然后在DLL主程序中引用刚才建立的窗体,并添加导出函数,代码如下:

 

//---------------------------------------------------------------------------
#include 
#include 
#pragma hdrstop

//---------------------------------------------------------------------------
//
   Important note about DLL memory management when your DLL uses the
//
   static version of the RunTime Library:
//

//   If your DLL exports any functions that pass String objects (or structs/
//
   classes containing nested Strings) as parameter or function results,
//
   you will need to add the library MEMMGR.LIB to both the DLL project and
//
   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//
   if any other projects which use the DLL will be performing new or delete
//
   operations on any non-TObject-derived classes which are exported from the
//
   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//
   EXE's to use the BORLNDMM.DLL as their memory manager.  In these 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 not need to
//
   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------

#include "Unit.h" //引用设计的窗体
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    
return 1
;
}

//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) int __stdcall UserClick(void//导出函数
{
    TForm1 
*Form1 = new
 TForm1(NULL);
    
if(Form1->ShowModal() == mrOk) 
{
        delete Form1;
        
return 1
;
    }
 else {
        delete Form1;
        
return 0
;
    }

}

//---------------------------------------------------------------------------

保存工程为DLLs,编译,就会在工程目录下生成DLLs.dll,同时还会自动在同一目录下生成DLLs.lib静态库,如果没有生成,请自己手动使用implib.exe工具生成。

 

(3).导出类
使用BCB建立DLL向导来建立一个工程,选择不使用VCL(本例不使用VCL,是否支持VCL是视你自己的应用而定),代码如下:

//---------------------------------------------------------------------------
#include 
//
---------------------------------------------------------------------------
//
   Important note about DLL memory management when your DLL uses the
//
   static version of the RunTime Library:
//

//   If your DLL exports any functions that pass String objects (or structs/
//
   classes containing nested Strings) as parameter or function results,
//
   you will need to add the library MEMMGR.LIB to both the DLL project and
//
   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//
   if any other projects which use the DLL will be performing new or delete
//
   operations on any non-TObject-derived classes which are exported from the
//
   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//
   EXE's to use the BORLNDMM.DLL as their memory manager.  In these 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 not need to
//
   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    
return 1
;
}

//---------------------------------------------------------------------------
__declspec(dllexport) __stdcall class TTest{    //声明导出类
    int a,b;
public
:
    
void __stdcall SetValue(int x, int
 y);
    
int __stdcall Calc(void
);
}
;
//---------------------------------------------------------------------------

void __stdcall TTest::SetValue(int x, int y)    //类的实现
{
    
this->=
 x;
    
this->=
 y;
}

//---------------------------------------------------------------------------
int __stdcall TTest::Calc(void//类的实现
{
    
return this->+ this->
b;
}

//---------------------------------------------------------------------------

保存工程为DLLs,编译,就会在工程目录下生成DLLs.dll,同时还会自动在同一目录下生成DLLs.lib静态库,如果没有生成,请自己手动使用implib.exe工具生成。
注意,并非所有的代码都需要在工程DLL主文件中写,导出函数和类等都可以在其它单元中设计,然后在主文件中#include即可,看自己的习惯,当然了,一个巨大的DLL工程,不可能写在一个文件中的。

 

(4).使用(1)创建的DLL
新建一个工程。

[1].
静态调用:
向工程中添加(1)中生成的静态库DLLs.lib,然后在.h中添加导出函数的定义,如下:
extern "C" __declspec(dllimport) int __stdcall Calc(int,int); //
导出DLL中函数
然后就可以在这个单元中使用int __stdcall Calc(int,int)这个函数了,如:
ShowMessage(IntToStr(Calc(5,10));
[2].
动态调用
不需要添加静态库.lib文件,只要在需要调用时才载入DLL,如下:

 (5).使用(2)创建的DLL
[1].
静态调用:

向工程中添加(2)中生成的静态库DLLs.lib,然后在.h中添加导出函数的定义,如下:
extern "C" __declspec(dllimport) int __stdcall UserClick(void); //
导出DLL中函数
然后就可以在这个单元中使用int __stdcall UserClick(void)这个函数了,如:

    HINSTANCE Hdl;
    
int __stdcall (*Calc)(int,int); //定义函数原型

    Hdl = ::LoadLibrary("DLLs.dll"); //载入DLL
    if(Hdl != NULL) {
        Calc 
= (int __stdcall (*)(int,int))::GetProcAddress(Hdl,"Calc"); //获取函数入口地址

        if(Calc != NULL) {
            ShowMessage(IntToStr(Calc(
5,10))); //调用DLL中函数

        }
 else {
            ShowMessage(
"不能找到函数入口!"
);
        }

        ::FreeLibrary(Hdl); 
//一定不要忘记调用完毕后释放DLL
    }
 else {
        ShowMessage(
"不能载入DLL!"
);
    }

 

 [2].动态调用
不需要添加静态库.lib文件,只要在需要调用时才载入DLL,如下:

  if(UserClick()) {
        ShowMessage(
"用户点击“确定”"
);
    }
 else {
        ShowMessage(
"用户点击“取消”或直接关闭"
);
    }

 

  

    HINSTANCE Hdl;
    
int __stdcall (*UserClick)(void
);
    Hdl 
= ::LoadLibrary("DLLs.dll"
);
    
if(Hdl != NULL) 
{
        UserClick 
= (int __stdcall (*)(void))::GetProcAddress(Hdl,"UserClick"
);
        
if(UserClick != NULL) 
{
            
if(UserClick()) 
{
                ShowMessage(
"用户点击“确定”"
);
            }
 else {
                ShowMessage(
"用户点击“取消”或直接关闭"
);
            }

        }
 else {
            ShowMessage(
"不能找到函数入口!"
);
        }

        ::FreeLibrary(Hdl);
    }
 else {
        ShowMessage(
"不能载入DLL!"
);
    }

6).使用(3)创建的DLL
DLL
中导出的类,只能使用表态的方式来调用。本例中的DLL调用方法如下:

向工程中添加(3)中生成的静态库DLLs.lib,然后在.h中添加导出类的声明,如下:

 

__declspec(dllimport) __stdcall class TTest{
    
int
 a,b;
public
:
    
void __stdcall SetValue(int x, int
 y);
    
int __stdcall Calc(void
);
}
;

然后就可以在这个单元中使用TTest这个类了,如:

 

    TTest *Inst = new TTest;
    Inst
->SetValue(5,10
);
    ShowMessage(IntToStr(Inst
->
Calc()));
    delete Inst;

.一些工具:
(1).impdef.exe
用法:impdef.exe deffile.def yourdll.dll
生成指定DLL文件的def文件,可以用它来查看DLL中的函数声明。例如,BCB使用VCDLL时,可能需要查看一下VC中导出函数的函数名;或者未使用extern "C"调用约定时,可以用它来查看DLL中导出函数的C++命名方式,从而可以正确调用。

(2).implib.exe
用法:implib.exe libfile.lib yourdll.dll
用此工具来生成DLL调用的静态库,用于DLL的静态调用方式。

(3).vctobpru.exe
用此工具可以把VC的工程导入到BCB工程中,它自动转换VC的工程文件为BCB工程文件,生成相应的.bpr等文件。
(4).tdump.exe(VC
中为dumpbin.exe)
用法:
tdump.exe [options] [inputfile] [listfile] [options]
用此工具可以查看DLL中的导出函数声明等等,具体用法请运行tdump.exe(不加参数)

 
原创粉丝点击