推荐你看《BCB编写DLL终极手册》这篇文章
如下片段:
二. 静态调用 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;
}

三. 动态调用 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 文件查看是否使用了名字分解

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 则是在前加上下划线,在
后加上 @ ,再后跟为栈保留的字节数。字节数取决于参数在栈所占的空间。每一个
参数都舍入为 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,因此产生了大写函数名。这样链接程序不会出错。

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='_BCBLoadVCWin32Stdcall@0'
*/
if ( !DllInst )
DllInst = LoadLibrary ( "VCWin32.dll" );
if ( DllInst )
{
BCBLoadVCWin32Stdcall = (LPSTR (__stdcall *) () )
GetProcAddress ( DllInst, "_BCBLoadVCWin32Stdcall@0" ); //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::',而是 '@BCBLoadVCWin32Fastcall@0'?
BCBLoadVCWin32Fastcall = (LPSTR (__fastcall *) () )
//GetProcAddress ( DllInst, "BCBLoadVCWin32Fastcall::" );
GetProcAddress ( DllInst, "@BCBLoadVCWin32Fastcall@0" );
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):
LIBRARY VCWIN32.DLL

IMPORTS
@BCBLoadVCWin32Fastcall = VCWIN32.@BCBLoadVCWin32Fastcall@0
_BCBLoadVCWin32Cdecl = VCWIN32.BCBLoadVCWin32Cdecl
BCBLoadVCWin32Stdcall = VCWIN32._BCBLoadVCWin32Stdcall@0

对应的函数声明和实现如下:
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 编译成功
参考资料:http://www.programfan.com/article/showarticle.asp?id=2271

BCB怎么调用DLL中的函数的更多相关文章

  1. 在VS2012中采用C++中调用DLL中的函数 (4)

    这两天因为需要用到VS2012来生成一个DLL代码,但是之前并没有用过DLL相关的内容,从昨天开始尝试调试DLL的文件调用,起初笔者在网络上找到了3片采用VSXXX版本进行调试的例子,相关的内容见本人 ...

  2. 在C++中调用DLL中的函数 (3)

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

  3. 在C++中调用DLL中的函数 (2)

    应用程序使用DLL可以采用两种方式: 一种是隐式链接,另一种是显式链接.在使用DLL之前首先要知道DLL中函数的结构信息. Visual C++6.0在VC\bin目录下提供了一个名为Dumpbin. ...

  4. 在C++中调用DLL中的函数

    如何在C++中调用DLL中的函数 应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接.在使用DLL之前首先要知道DLL中函数的结构信息.Visual C++6.0在VC\bin目录下 ...

  5. 【原创】在VS2012中采用C++中调用DLL中的函数(4)

    这两天因为需要用到VS2012来生成一个DLL代码,但是之前并没有用过DLL相关的内容,从昨天开始尝试调试DLL的文件调用,起初笔者在网络上找到了3片采用VSXXX版本进行调试的例子,相关的内容见本人 ...

  6. 在C++中调用DLL中的函数(3)

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

  7. 在C++中调用DLL中的函数(2)

    本文转自:http://blog.sina.com.cn/s/blog_53004b4901009h3b.html 应用程序使用DLL可以采用两种方式: 一种是隐式链接,另一种是显式链接.在使用DLL ...

  8. 在VS2012中采用C++中调用DLL中的函数(4)

    转自:http://www.cnblogs.com/woshitianma/p/3683495.html 这两天因为需要用到VS2012来生成一个DLL代码,但是之前并没有用过DLL相关的内容,从昨天 ...

  9. 调用 Dll 中的函数时,出现栈(STACK)的清除问题 -> 故障模块名称: StackHash_0a9e

    在一个名为 test.dll 文件中,有一个 Max() 函数的定义是: #ifdef BUILD_DLL #define DLL_EXPORT __declspec(dllexport) __std ...

随机推荐

  1. this.$router.go()和this.$router.push()的差别

    1.this.$router.go(val) => 在history记录中前进或者后退val步,当val为0时刷新当前页面. 2.this.$router.push(path) => 在h ...

  2. 11-MySQL-Ubuntu-数据表中数据的删除(四)

    数据的删除(delete) (1)物理删除(不可逆,公司不会采取这种方法,如现在一般不会出现注销,数据具有无限价值) 删除整张表的数据!!! delete from 表名; 删除部分给定条件的数据: ...

  3. 数组模拟stack

    package com.cxy.springdataredis.data; import java.util.Scanner; public class StackDemo { public stat ...

  4. Face-Resources

    Face-Resources Following is a growing list of some of the materials I found on the web for research ...

  5. Java 局部变量

    Java 局部变量 局部变量声明在方法.构造方法或者语句块中: 局部变量在方法.构造方法.或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁: 访问修饰符不能用于局部变量: 局部变量只在声明 ...

  6. [JZOJ6272] 2019.8.4【NOIP提高组A】整除

    题目 题目大意 求方程\((x^m-x)\mod n=0\)在整数范围\([1,n]\)的解的个数. \(n=\sum_{i=1}^{c}p_i\) 给出\(c\)和\(p_i\) 思考历程 作为数论 ...

  7. ForkJoin学习笔记

    1.Fork/Join框架:(分治算法思想) 在必要的情况下,将一个大任务,进行拆分(fork) 成若干个子任务(拆到不能再拆,这里就是指我们制定的拆分的临界值),再将一个个小任务的结果进行join汇 ...

  8. FP function programming

    fp是函数式编程,也是一种编程方法,同面向对象的编程方法一样. 所谓的functional programming 就是函数式编程,这也是一种编程方法,或者说是编程模式,同面向过程的编程,以及面向对象 ...

  9. IENumerable_Test

    using System; using System.Collections; using System.Collections.Generic; using System.Linq; using S ...

  10. Mysql优化系列之查询性能优化前篇3(必须知道的几个事实)

    事实一:临时表没有任何索引 最常见的临时表莫过于在from子句中写子查询,遇到这种情况,Mysql会先将其查询结果放到一张临时表中, 然后将这个临时表当做普通表对待 事实二:执行计划优化 大多数的sq ...