yakin

有了舞台就好好表演,没有舞台就静静地做观众

导航

函式定义 DLL内的函式名 摘要说明

(http://www.lzu.edu.cn/netteach/jiaochen/c++/ch5/chap52.htm)

函式定义 DLL内的函式名 摘要说明

void DllName01(void) @DllName01$qv 因为是CPP程式码

void _stdcall DllName02(void) @DllName02$qqsv 所以函式名都被修

void _cdecl DllName03(void) @DllName03$qv 饰过。

void _pascal DllName04(void) @DLLNAME04$QV

void _fastcall DllName05(void) @DllName05$qqrv

  • 以上结果是否令你丈二金钢、摸不着头绪。这是因为我们的程式名称若以CPP为延伸名,C++Builder会以C++ 特有的命名方式来为函式命名,这种命名方式会在函式名称後加上其使用参数的性质,如参数类别等。这在C++ 中有一个特别的名称,叫做mangled name,这是一种为了要实作出多载函式所发出的命名规则。(注:在C++ 中Add(int) 和Add(double) 可以同时存在,因此必须在object code区分之)。同时这种命名方式由於各个编译器厂商使用的方式各不相同,因此在撰写DLL时要避免使用之。为了要避开以上问题,我们改以下列的宣告方式:

#define _DLLNAME01_H_

#ifndef DLLNAME

#define EXTERN __declspec(dllimport)

#else

#define EXTERN __declspec(dllexport)

#endif

extern "C" {

EXTERN void DllName011(void);

EXTERN void _stdcall DllName022(void);

EXTERN void _cdecl DllName033(void);

EXTERN void _pascal DllName044(void);

EXTERN void _fastcall DllName055(void);

};

#endif

其中extern "C" {琕琕.}; 是用来告诉编译器使用C的命名方式,不要使用C++ 的mangled name。若是其中只有一个函式时,你可以直接以下列方式宣告之:

extern "C" void __stdcall ShowImage();

现在我们可以检视除去mangled name後的函式名称:

函式定义 DLL内的函式名 摘要说明

void DllName01(void) _DllName01 名称加底线

void _stdcall DllName02(void) DllName02 名称未变

void _cdecl DllName03(void) _DllName03 名称加底线

void _pascal DllName04(void) DLLNAME04 名称大写

void _fastcall DllName05(void) @DllName05 名称加@

以上我们可得知,在未加修饰字时和使用_cdecl修饰字时的名称是一样的。而 _pascal修饰字所产生的函式名则和16位元的标准DLL 函式名相同(这在VC++ 是不被接受的),__fastcall的函式名称则加上 @。

其中在WIN32中使用最多的是 _stdcall修饰字,这也是你要撰写一个可以和其他语言共同使用时所使用的修饰字,其次则为 __cdecl修饰字,这是用来传送不定参数型别的函式如printf、sprintf等使用的。其馀两者几乎在DLL没有机会使用。

结论:

由上可知,在C++Builder中撰写DLL时必须注意以下事项:

使用 __declspec(dllimport)及 __declspec(dllexport)的标准型式。

  1. 注意C++ 的函式名称编码(mangled name)。
  2. 注意修饰字的使用。除非使用不定参数的函式,否则必使用 __stdcall修饰字。

(4) 不要把 __declspec的使用和 __stdcall混淆了。此二者并没有绝对的相关性。即使是程式老手都可能栽在此处,切记,切记!

怎麽样,在看完了以上的介绍後,是否有晃然大悟的感觉。在了解以上的规则後,今後不论在撰写或是使用DLL时遭遇连结的问题时,应该难不倒你吧!

最後,我们将标准的DLL宣告方式列於後,以加深你的印象:

#ifndef _SHOWIMG_H_

#define _SHOWIMG_H_

#ifndef IMGDLL

#define EXTERN __declspec(dllimport)

#else

#define EXTERN __declspec(dllexport)

#endif

extern "C" EXTERN void __stdcall ShowImage(void);

#endif

语言双雄' C++Builder 和Visual C++ 连结

前面我们已经把关於C++Builder撰写DLL所应注意到的事项介绍完了,现在我们来谈另一个重点 - C++Builder和Visual C++ 的连结。若是你没有使用过Visual C++ 的话,可以将此部份略去。若是你在程式设计时必须使用到Visual C++ 的DLL或是必须提供DLL给VC++ 或是VB使用时,也许会带给你意想不到的收获。

VC++ 使用C++Builder的DLL函式

在Visual C++ 中使用C++Builder的DLL的函式方法和在C++Builder中使用大同小异,唯有几件事情必须要注意。

(一)Visual C++ 的LIB档格式和C++Builder的LIB格式不同,因此你必须重新产生一个 LIB。不过,可惜的是VC++ 在32位元的版本中并未提供IMPLIB.EXE函式(这点一直令许多人百思不解),因此你无法很方便地产生LIB档。解决方法有二:其一是在VC++ 内撰写一个同名称的空的DLL函式,令其产生LIB档,其二则是使用 LoadLibrary、GetProcAddress式的明确呼叫方式。

(二)使用前面提到的标准写法。

C++Builder中使用VC++ 的DLL函式

在C++Builder中使用VC++ 的DLL函式时要注意的是Microsoft在Visual C++ 中使用的特殊命名规则。在VC++ 中命名规则除了前面谈到的几项之外,它还使用了一个特殊的参数命名法,简言之,就是在函数名称後面加上参数的大小,这种命名方法会造成C++Builder,VB,Delphi使用的上的困扰。举例来说

extern "C" _declspec(dllexport) void __stdcall ShowImage(void);

在VC++ 中产生的函式名称为ShowImage@0(其中0表示参数大小),而不是如在C++Builder中产生的ShowImage,这是VC++ 已知的问题,这个问题也造成了很多使用non-VC++ 的使用者的问题,解决之道是在该DLL的DEF档中加上以下的叙述

EXPORTS

ShowImage=ShowImage@0

如此便可以产生正确的函式名了,若是你不想修改DEF档,你也可以在程式中加入以下的连结指引

#pragma comment(linker,"/exports:ShowImage=ShowImage@0")

假设你不确定其正确的名称,可以利用DumpBin或是TDump观察之。

以上是针对VC++ 的程式设计的所作的额外说明。最後我们以一个VC++ 程式呼叫本单元的About Dialog DLL做为结束。


此程式的关键程式码如下:

void CVcusedllApp::OnAppAbout()

{

    void (*ShowImage)(void);

    HINSTANCE hInst;

    hInst = LoadLibrary("DLLSAMP2.DLL");

    (FARPROC &)ShowImage=GetProcAddress(hInst,"ShowImage");

    ShowImage();

    FreeLibrary(hInst);

}

posted on 2005-05-08 11:02  yakin  阅读(520)  评论(0编辑  收藏  举报