在c++builder中如何创建dll头文件

在c++builder中如何创建dll头文件,第1张

 如果你用BCB创建了一个DLL,它可以被BCB的可执行文件调用,你知道这种使用DLL的方式没什么难度。当你构造一个DLL,BCB生成一个带“.LIB”扩展名的引入库。把这个LIB文件添加到你的工程里。连接器按引入库决定DLL内部调用。当你运行你的程序时,DLL隐式的被载入,你不必去考虑DLL内部调用工作是。

当EXE文件是由Microsoft Visual C++编译的时候,情况会变得比较复杂。有3个主要的问题。首先,BCB和MSVC对DLL中的函数命名方式是不一致的。BCB使用一种习惯,MSVC使用另一种不同的习惯。当然,两种习惯是不兼容的。命名问题在如何在C++Builder工程里使用VC++编译的DLL那篇文章里已经讨论过了。表1总结了各个编译器在各自的调用习惯下,导出的MyFunction函数。注意Borland给__cdecl函数前加了一个下划线,而MSVC没有。另一方面,MSVC认为导出的__stdcall函数前面带有下划线,后面还有一些垃圾。

表1: Visual C++ and C++Builder 命名习惯

调用习惯  VC++命名 VC++(使用了DEF) C++Builder命名

-----------------------------------------------------------------------

__stdcall _MyFunction@4 MyFunction MyFunction

__cdecl MyFunction MyFunction _MyFunction

第2个问题是Borland引入库与MSVC不是二进制兼容的。当你编译DLL时,由BCB创建的引入库不能被MSVC用来连接。如果你想使用隐式连接,那么你需要创建一个MSVC格式的引入库镇指。另一种可选择的办法就是采用显式连接(LoadLibrary和GetProcAddress)。

第3个问题是不能从DLL里导出C++类和成员函数,如果你想让MSVC的用户也可以调用它。好吧,那不完全属实。你的DLL能导出C++类,但是MSVC不能使用它们。原因就是C++成员函数名被编译器改御罩配编(mangled)。这个改编的名字结果了DLL。为了调用在DLL里被改编的函数,你必需知道被改编的是哪个函数。Borland和Microsoft使用了不同的名字改编方案。结果是,MSVC不能恰好看到Borland编译的DLL里的C++类和成员函数。

注意:

Borland和Microsoft没有采用相同的方式改编函数,因为依照ANSI C++标准,C++编译器不被假定追随相同的指导方针。名字改编只是实现的细节。

这三个问题使得Borland创建闷拿的DLL可以在MSVC里被调用变得非常困难,但并非不可能的。这篇文章描述了一套指导方针,你可以跟着制作与Microsoft兼容的BCB DLL。我们讨论四种不同的技术。三种采用引入库隐式连接调用,一种在运行时利用显式连接。

指导方针摘要

你可以跟着下面的指导方针摘要列表建造你的DLL。第1个列表讨论隐式连接;第2个列表描述显式连接;第3种技术采用#define组装隐式连接;最后一个例子利用假的MSVC DLL工程为__stdcall函数创建引入库。

技术1: 隐式连接

------------------------------------------------------------------------------

1- 使用__cdecl调用习惯代替__stdcall。

2- 导出简单的"C"风格函数,没有C++类或成员函数。

3- 确定你有一个 extern "C" {} 包围你的函数原型。

4- 创建DEF文件,包含与Microsoft兼容的导出函数别名。别名也就是不包含前面的下划线。

DEF文件内容如下:

EXPORTS

MSVC name= Borland name

Foo = _Foo

Bar = _Bar

5- 把DEF文件加入到你的工程里重新编译它。

6- 把DLL和DLL头文件拷贝到你的MSVC工程目录里。

7- 运行impdef为DLL创建第2个DEF文件。这个DEF文件用来创建引入库。

>impdef mydll.def mydll.dll

8- 运行Microsoft的LIB工具,用上一步创建的DEF文件创建COFF引入库。调用格式为:

>lib /DEF mydll.def

9- 把用LIB.EXE创建的LIB文件添加到你的MSVC工程里。

技术2: 显式连接

------------------------------------------------------------------------------

1- 使用__cdecl或__stdcall,如果你使用__stdcall可以跳过第4,5步。

2- 导出简单的"C"风格函数,没有C++类或成员函数。

3- 确定你有一个extern "C" {}包围你的函数原型。

4- 如果你使用__cdecl,那么你可能想去掉导出函数前面的下划线,但你不必这么做。你可以用例1的第4,5步去掉下划线。如果你没有去掉下载线,在调用GetProcAddress函数时函数名必须前面的下划线。

5- 把DLL拷贝到MSVC工程目录里。

6- 在MSVC应用程序中,使用LoadLibrary API函数载入DLL。

7- 调用GetProcAddress API在DLL里查找你想要的调用函数,保存GetProcAddress函数返回的函数指针。当你想调用函数的时候,提取函数指针。

8- 当你用完DLL时调用FreeLibrary。

技术3: 用#define组装隐式连接

------------------------------------------------------------------------------

1- 用__cdecl调用习惯代替__stdcall。

2- 导出简单的"C"风格函数,没有C++类或成员函数。

3- 确定你有一个extern "C" {}包围你的函数原型。

4- 在你的DLL头文件里,为每一个导出函数名创建一个#define。

#define会调用预编译器在每一个函数名前加上下划线。因为我们只想为MSVC创建别名,所以代码检查_MSC_VER。

#ifdef _MSC_VER

#define Foo _Foo

#define Bar _Bar

#endif

5- 把DLL和DLL头文件拷贝到MSVC工程目录里。

6- 运行impdef为DLL函数DEF文件。

>impdef mydll.def mydll.dll

7- 使用Microsoft的LIB工具为DEF文件创建COFF格式的引入库。

>lib /def mydll.def

8- 把LIB.EXE创建的LIB文件添加到MSVC工程里。

技术4: 用__stdcall函数隐式连接

------------------------------------------------------------------------------

1- 当建造你的DLL时使用__stdcall调用习惯。

2- 导出简单的"C"风格函数,没有C++类或成员函数。

3- 确定你有一个extern "C" {}包围你的函数原型。

4- 为MSVC创建一个引入库。这一部分比较困难。你不能用LIB.EXE为__stdcall函数创建引入库。你必须创建一个由MSVC编译的的假的DLL。这样做,按这些步骤:

4a- 用MSVC创建一个不使用MFC的DLL

4b- 从BCB里拷贝覆盖DLL头文件和DLL源代码

4c- 编辑你的DLL源代码,抛开每一个例程的函数体部分,使用一个假的返回值返回

4d- 配置MSVC工程生成的DLL,采用和BCB DLL同的的名字

4e- 把DEF文件添加到MSVC工程,禁止它对__stdcall命名进行修饰(_Foo@4)

5- 编译第4步得到的虚假DLL工程。这将会生成一个DLL(你可以把它丢到垃圾筒里)和一个LIB文件(这是你需要的)。

6- 把从第5步得到的LIB文件添加到你需要调用这个BCB DLL的MSVC工程里。LIB文件会确保连接。为MSVC可执行文件配置BCB DLL(不是虚假DLL)。

DLL源代码中可以有头文件,这不必说;DLL目标代码不存在头文件概念。

你用VC或BC实际实践一个DLL项目就明白了!--

说白了,DLL,就是一个或一堆可调用的普通函数的集合;----使用时加个头文件将其包含进去,就像加<stdio。漏罩h>或加<windows.h>一样,道理是一样的----特别之处在于:DLL的目标代码和调用该DLL中函数的目标代码是锋大分开的!这个,一银搜竖定要清楚。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12300464.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存