BCB编写DLL终极手册
当前位置:以往代写 > C/C++ 教程 >BCB编写DLL终极手册
2019-06-13

BCB编写DLL终极手册

BCB编写DLL终极手册

副标题#e#

一. 编写DLL

File/New/Dll 生成Dll的领导,然后可以添加导出函数和导出类

导出函数:extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)

导出类:class __declspec(dllexport) ExportType ClassName{…}

例子:(说明:只是生成了一个DLL.dll )

#include "DllForm.h" // TDllFrm 界说
USERES("Dll.res");
USEFORM("DllForm.cpp", DllFrm);
class __declspec(dllexport) __stdcall MyDllClass { //导出类
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
TDllFrm* DllMyForm2;
extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//导出函数
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
//---------------------------------------------------------------------------
MyDllClass::MyDllClass()
{
}
void MyDllClass::CreateAForm()
{
DllMyForm = new TDllFrm(Application);
DllMyForm->Show();
}
//---------------------------------------------------------------------------
void __stdcall CreateFromFunct()
{
DllMyForm2 = new TDllFrm(Application);
DllMyForm2->Show();
}

二. 静态挪用 DLL

利用 $BCB path\Bin\implib.exe 生成 Lib 文件,插手到工程文件中

将该文件拷贝到当前目次,利用 implib MyDll.lib MyDll.dll 生成

// Unit1.h // TForm1 界说
#include "DllForm.h" // TDllFrm 界说
//---------------------------------------------------------------------------
__declspec(dllimport) class __stdcall MyDllClass {
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();
class TForm1 : public TForm{...}
// Unit1.cpp // TForm1 实现
void __fastcall TForm1::Button1Click(TObject *Sender)
{ // 导出类实现,导出类只能利用静态方法挪用
DllClass = new MyDllClass();
DllClass->CreateAForm();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{ // 导出函数实现
CreateFromFunct();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
delete DllClass;
}


#p#副标题#e#

三. 动态挪用 DLL

// Unit1.h
class TForm1 : public TForm
{
...
private: // User declarations
void (__stdcall *CreateFromFunct)();
...
}
// Unit1.cpp // TForm1
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
if (DLLInst) {
CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
"CreateFromFunct");
if (CreateFromFunct) CreateFromFunct();
else ShowMessage("Could not obtain function pointer");
}
else ShowMessage("Could not load DLL.dll");
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if ( DLLInst ) FreeLibrary (DLLInst);
}

四. DLL 作为 MDIChild (子窗体) 【只编写动态挪用的例子】

实际上,挪用子窗体的 DLL 时,系统只是查抄应用措施的 MainForm 是否为 fsMDIForm 的窗体,这样只

要把挪用措施的 Application 的 Handle 通报给 DLL 的 Application 即可;同时退出 DLL 时也要规复

Application
// MDIChildPro.cpp // Dll 实现 CPP
#include "unit1.h" // TForm1 界说
TApplication *SaveApp = NULL;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
if ( (reason==DLL_PROCESS_DETACH) && SaveApp )
Application = SaveApp ; // 规复 Application
return 1;
}
extern "C" __declspec(dllexport) __stdcall void TestMDIChild(  //1024X768
TApplication* mainApp,
LPSTR lpCaption)
{
if ( NULL == SaveApp ) // 生存 Application,通报 Application
{
SaveApp = Application;
Application = mainApp;
}
// lpCaption 为子窗体的 Caption
TForm1 *Form1 = new TForm1 ( Application, lpCaption );
Form1->Show();
}

注:上面的措施利用 BCB 3.0 编译乐成

五. BCB 挪用 VC 编写的 DLL

1. 名字解析:

没有名字解析的函数

TestFunction1 // __cdecl calling convention

@TestFunction2 // __fastcall calling convention

TESTFUNCTION3 // __pascal calling convention

TestFunction4 // __stdcall calling convention

有名字解析的函数

@TestFunction1$QV // __cdecl calling convention

@TestFunction2$qv // __fastcall calling convention

TESTFUNCTION3$qqrv // __apscal calling convention

@TestFunction4$qqrv // __stdcall calling convention

利用 extern "C" 不会解析函数名

利用 Impdef MyLib.def MyLib.DLL 生成 def 文件查察是否利用了名字解析

#p#副标题#e#

2. 挪用约定:

__cdecl 缺省

是 Borland C++ 的缺省的 C 名目定名约定,它在标识符前加一下划线,以保存

它本来所有的全程标识符。参数按最右边参数优先的原则通报给栈,然后清栈。

extaern "C" bool __cdecl TestFunction();

在 def 文件中显示为

TestFunction @1

注释: @1 暗示函数的顺序数,将在“利用别名”时利用。

__pascal Pascal名目

这时函数名全部酿成大写,第一个参数先压栈,然后清栈。

TESTFUNCTION @1 //def file

__stdcall 尺度挪用

最后一个参数先压栈,然后清栈。

TestFunction @1 //def file

__fastcall 把参数通报给寄存器

第一个参数先压栈,然后清栈。

@TestFunction @1 //def file

3. 办理挪用约定:

Microsoft 与 Borland 的 __stdcall 之间的区别是定名方法。 Borland 回收

__stdcall 的方法去掉了名字起前的下划线。 Microsoft 则是在前加上下划线,在

#p#分页标题#e#

后加上 @ ,再后跟为栈保存的字节数。字节数取决于参数在栈所占的空间。每一个参数都舍入为 4 的倍数加起来。这种 Miocrosoft 的 DLL 与系统的 DLL 纷歧样。

4. 利用别名:

利用别名的目标是使挪用文件 .OBJ 与 DLL 的 .DEF 文件相匹配。假如还没有

.DEF 文件,就应该先建一个。然后把 DEF 文件插手 Project。利用别名应不绝

修改外部错误,假如没有,还需要将 IMPORTS 部门插手 DEF 文件。

IMPORTS

TESTFUNCTIOM4 = DLLprj.TestFunction4

TESTFUNCTIOM5 = DLLprj.WEP @500

TESTFUNCTIOM6 = DLLprj.GETHOSTBYADDR @51

这里需要说明的是,挪用应用措施的 .OBJ 名与 DLL 的 .DEF 文件名是等价的,

并且老是这样。甚至不消思量挪用约定,它会自动匹配。在前面的例子中,函数被

说明为 __pascal,因此发生了大写函数名。这样链接措施不会堕落。

#p#副标题#e#

5. 动态挪用例子

VC DLL 的代码如下:

extern "C" __declspec(dllexport) LPSTR __stdcall BCBLoadVCWin32Stdcall()
{
static char strRetStdcall[256] = "BCB Load VC_Win32 Dll by __stdcall mode is OK!";
return strRetStdcall;
}
extern "C" __declspec(dllexport) LPSTR __cdecl BCBLoadVCWin32Cdecl()
{
static char strRetCdecl[256] = "BCB Load VC_Win32 Dll by __cdecl mode is OK!";
return strRetCdecl;
}
extern "C" __declspec(dllexport) LPSTR __fastcall BCBLoadVCWin32Fastcall()
{
static char strRetFastcall[256] = "BCB Load VC_Win32 Dll by __fastcall mode is OK!";
return strRetFastcall;
}

其实动态挪用与挪用 BCB 编写的 DLL 没有区别,要害是查察 DLL 的导出函数名字可以利用 tdump.exe(BCB东西) 可能 dumpbin.exe(VC东西) 查察

tdump -ee MyDll.dll >1.txt (查察 1.txt 文件即可)
由于 VC6 不支持 __pascall 方法,下面给出一个三种方法的例子
void __fastcall TForm1::btnBLVCWin32DynClick(TObject *Sender)
{
/*cmd: tdbump VCWin32.dll >1.txt
Turbo Dump Version 5.0.16.4 Copyright (c) 1988, 1998 Borland International
Display of File VCWIN32.DLL
EXPORT ord:0000='BCBLoadVCWin32Fastcall::'
EXPORT ord:0001='BCBLoadVCWin32Cdecl'
EXPORT ord:0002='[email protected]'
*/
if ( !DllInst )
DllInst = LoadLibrary ( "VCWin32.dll" );
if ( DllInst )
{
BCBLoadVCWin32Stdcall = (LPSTR (__stdcall *) () )
GetProcAddress ( DllInst, "[email protected]" ); //VC Dll
// GetProcAddress ( DllInst, "BCBLoadVCWin32Stdcall" ); //BCB Dll
if ( BCBLoadVCWin32Stdcall )
{
ShowMessage( BCBLoadVCWin32Stdcall() );
}
else ShowMessage ( "Can't find the __stdcall Function!" );
BCBLoadVCWin32Cdecl = (LPSTR (__cdecl *) () )
GetProcAddress ( DllInst, "BCBLoadVCWin32Cdecl" );
if ( BCBLoadVCWin32Cdecl )
{
ShowMessage( BCBLoadVCWin32Cdecl() );
}
else ShowMessage ( "Can't find the __cdecl Function!" );
//Why?不是 'BCBLoadVCWin32Fastcall::',而是 '@[email protected]'?
BCBLoadVCWin32Fastcall = (LPSTR (__fastcall *) () )
//GetProcAddress ( DllInst, "BCBLoadVCWin32Fastcall::" );
GetProcAddress ( DllInst, "@[email protected]" );
if ( BCBLoadVCWin32Fastcall )
{
ShowMessage( BCBLoadVCWin32Fastcall() );
}
else ShowMessage ( "Can't find the __fastcall Function!" );
}
else ShowMessage ( "Can't find the Dll!" );
}

6. 静态挪用例子

静态挪用有点贫苦,从动态挪用中可以知道导出函数的名字,可是直接时(插手 lib 文件到工程文件)

Linker 提示不能找到函数的实现

从 4 看出,可以插手 def 文件毗连

(可以通过 impdef MyDll.def MyDll.dll 得到导出表)

成立与 DLL 文件名一样的 def 文件与 lib 文件一起插手到工程文件

上面的 DLL(VCWIN32.dll) 的 def 文件为(VCWIN32.def):

#p#分页标题#e#

LIBRARY   VCWIN32.DLL
IMPORTS
@BCBLoadVCWin32Fastcall   = [email protected]@0
_BCBLoadVCWin32Cdecl    = VCWIN32.BCBLoadVCWin32Cdecl
BCBLoadVCWin32Stdcall    = [email protected]

对应的函数声明和实现如下:

extern "C" __declspec(dllimport) LPSTR __fastcall BCBLoadVCWin32Fastcall();
extern "C" __declspec(dllimport) LPSTR __cdecl BCBLoadVCWin32Cdecl();
extern "C" __declspec(dllimport) LPSTR __stdcall BCBLoadVCWin32Stdcall();
void __fastcall TfrmStatic::btnLoadDllClick(TObject *Sender)
{
ShowMessage ( BCBLoadVCWin32Fastcall() );
ShowMessage ( BCBLoadVCWin32Cdecl() );
ShowMessage ( BCBLoadVCWin32Stdcall() );
}

留意:在 BCB 5.0 中,大概直接按下 F9 是不能通过 Linker 的,请先 Build 一次

注:上面的措施利用 BCB 5.0 与 VC6.0 编译乐成

    关键字:

在线提交作业