📄 chap52.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>函式定义 DLL内的函式名 摘要说明 </title>
<link rel="stylesheet" href="../../../include/style.css">
</head>
<body>
<p><font SIZE="2"><small><a href="../../../index.htm">首页</a> >> <a href="../../program.htm">程序设计</a>
>> <a href="../cbuilder.htm">C++ Builder</a> >> </small>函式定义
DLL内的函式名 摘要说明</font> </p>
<p align="left"><font SIZE="2"><!--webbot bot="ImageMap" rectangle=" (40,1) (71, 23) ../ch6/chap06.htm" rectangle=" (4,1) (36, 23) chap51.htm" src="../ch1/NextBack.gif" width="72" height="24" alt="NextBack.gif (743字节)" border="0" startspan --><MAP NAME="FrontPageMap"><AREA SHAPE="RECT" COORDS="40, 1, 71, 23" HREF="../ch6/chap06.htm"><AREA SHAPE="RECT" COORDS="4, 1, 36, 23" HREF="chap51.htm"></MAP><a href="../../../_vti_bin/shtml.exe/program/C++/ch5/chap52.htm/map"><img ismap usemap="#FrontPageMap" border="0" height="24" alt="NextBack.gif (743字节)" src="../ch1/NextBack.gif" width="72"></a><!--webbot bot="ImageMap" endspan i-checksum="41981" --></font></p>
<p><font color="#FF0000"><font SIZE="2">函式定义 DLL内的函式名 摘要说明</font>
</font></p>
<p><font SIZE="2">void DllName01(void) @DllName01$qv 因为是CPP程式码</font> </p>
<p><font SIZE="2">void _stdcall DllName02(void) @DllName02$qqsv 所以函式名都被修</font>
</p>
<p><font SIZE="2">void _cdecl DllName03(void) @DllName03$qv 饰过。</font> </p>
<p><font SIZE="2">void _pascal DllName04(void) @DLLNAME04$QV </font></p>
<p><font SIZE="2">void _fastcall DllName05(void) @DllName05$qqrv </font>
<ul>
<li><font SIZE="2">以上结果是否令你丈二金钢、摸不着头绪。这是因为我们的程式名称若以CPP为延伸名,C++Builder会以C++
特有的命名方式来为函式命名,这种命名方式会在函式名称後加上其使用参数的性质,如参数类别等。这在C++
中有一个特别的名称,叫做mangled name,这是一种为了要实作出多载函式所发出的命名规则。(注:在C++
中Add(int) 和Add(double) 可以同时存在,因此必须在object code区分之)。同时这种命名方式由於各个编译器厂商使用的方式各不相同,因此在撰写DLL时要避免使用之。为了要避开以上问题,我们改以下列的宣告方式:</font>
</li>
</ul>
<p><font SIZE="2">#define _DLLNAME01_H_</font> </p>
<p><font SIZE="2">#ifndef DLLNAME</font> </p>
<p><font SIZE="2">#define EXTERN __declspec(dllimport)</font> </p>
<p><font SIZE="2">#else</font> </p>
<p><font SIZE="2">#define EXTERN __declspec(dllexport)</font> </p>
<p><font SIZE="2">#endif</font> </p>
<p><font SIZE="2">extern "C" {</font> </p>
<p><font SIZE="2">EXTERN void DllName011(void);</font> </p>
<p><font SIZE="2">EXTERN void _stdcall DllName022(void);</font> </p>
<p><font SIZE="2">EXTERN void _cdecl DllName033(void);</font> </p>
<p><font SIZE="2">EXTERN void _pascal DllName044(void);</font> </p>
<p><font SIZE="2">EXTERN void _fastcall DllName055(void);</font> </p>
<p><font SIZE="2">};</font> </p>
<p><font SIZE="2">#endif<br>
</font></p>
<p><font SIZE="2">其中extern "C" {琕琕.}; 是用来告诉编译器使用C的命名方式,不要使用C++
的mangled name。若是其中只有一个函式时,你可以直接以下列方式宣告之:</font>
</p>
<p><font SIZE="2">extern "C" void __stdcall ShowImage(); </font></p>
<p><font SIZE="2">现在我们可以检视除去mangled name後的函式名称:</font></p>
<p><font SIZE="2">函式定义 DLL内的函式名 摘要说明</font> </p>
<p><font SIZE="2">void DllName01(void) _DllName01 名称加底线</font> </p>
<p><font SIZE="2">void _stdcall DllName02(void) DllName02 名称未变 </font></p>
<p><font SIZE="2">void _cdecl DllName03(void) _DllName03 名称加底线</font> </p>
<p><font SIZE="2">void _pascal DllName04(void) DLLNAME04 名称大写</font> </p>
<p><font SIZE="2">void _fastcall DllName05(void) @DllName05 名称加@ </font></p>
<p><font SIZE="2">以上我们可得知,在未加修饰字时和使用_cdecl修饰字时的名称是一样的。而
_pascal修饰字所产生的函式名则和16位元的标准DLL 函式名相同(这在VC++
是不被接受的),__fastcall的函式名称则加上 @。</font></p>
<p><font SIZE="2">其中在WIN32中使用最多的是 _stdcall修饰字,这也是你要撰写一个可以和其他语言共同使用时所使用的修饰字,其次则为
__cdecl修饰字,这是用来传送不定参数型别的函式如printf、sprintf等使用的。其馀两者几乎在DLL没有机会使用。
</font></p>
<p><font color="#FF0000"><font SIZE="2">结论:</font></font></p>
<p><font SIZE="2">由上可知,在C++Builder中撰写DLL时必须注意以下事项:</font>
</p>
<p><font SIZE="2">使用 __declspec(dllimport)及 __declspec(dllexport)的标准型式。</font>
<ol>
<li><font SIZE="2">注意C++ 的函式名称编码(mangled name)。</font> </li>
<li><font SIZE="2">注意修饰字的使用。除非使用不定参数的函式,否则必使用
__stdcall修饰字。</font> </li>
</ol>
<p><font SIZE="2">(4) 不要把 __declspec的使用和 __stdcall混淆了。此二者并没有绝对的相关性。即使是程式老手都可能栽在此处,切记,切记!
</font></p>
<p><font SIZE="2">怎麽样,在看完了以上的介绍後,是否有晃然大悟的感觉。在了解以上的规则後,今後不论在撰写或是使用DLL时遭遇连结的问题时,应该难不倒你吧!</font>
</p>
<p><font SIZE="2">最後,我们将标准的DLL宣告方式列於後,以加深你的印象:
</font></p>
<p><font SIZE="2">#ifndef _SHOWIMG_H_</font> </p>
<p><font SIZE="2">#define _SHOWIMG_H_</font> </p>
<p><font SIZE="2">#ifndef IMGDLL</font> </p>
<p><font SIZE="2">#define EXTERN __declspec(dllimport)</font> </p>
<p><font SIZE="2">#else</font> </p>
<p><font SIZE="2">#define EXTERN __declspec(dllexport)</font> </p>
<p><font SIZE="2">#endif</font> </p>
<p><font SIZE="2">extern "C" EXTERN void __stdcall ShowImage(void);</font> </p>
<p><font SIZE="2">#endif</font></p>
<p><font SIZE="2" color="#FF0000">语言双雄' C++Builder 和Visual C++ 连结</font></p>
<p><font SIZE="2">前面我们已经把关於C++Builder撰写DLL所应注意到的事项介绍完了,现在我们来谈另一个重点
- C++Builder和Visual C++ 的连结。若是你没有使用过Visual C++
的话,可以将此部份略去。若是你在程式设计时必须使用到Visual C++
的DLL或是必须提供DLL给VC++ 或是VB使用时,也许会带给你意想不到的收获。
</font></p>
<p><font SIZE="2">VC++ 使用C++Builder的DLL函式</font></p>
<p><font SIZE="2">在Visual C++ 中使用C++Builder的DLL的函式方法和在C++Builder中使用大同小异,唯有几件事情必须要注意。
</font></p>
<p><font SIZE="2">(一)Visual C++ 的LIB档格式和C++Builder的LIB格式不同,因此你必须重新产生一个
LIB。不过,可惜的是VC++ 在32位元的版本中并未提供IMPLIB.EXE函式(这点一直令许多人百思不解),因此你无法很方便地产生LIB档。解决方法有二:其一是在VC++
内撰写一个同名称的空的DLL函式,令其产生LIB档,其二则是使用
LoadLibrary、GetProcAddress式的明确呼叫方式。</font> </p>
<p><font SIZE="2">(二)使用前面提到的标准写法。</font></p>
<p><font SIZE="2">C++Builder中使用VC++ 的DLL函式</font></p>
<p><font SIZE="2">在C++Builder中使用VC++ 的DLL函式时要注意的是Microsoft在Visual
C++ 中使用的特殊命名规则。在VC++
中命名规则除了前面谈到的几项之外,它还使用了一个特殊的参数命名法,简言之,就是在函数名称後面加上参数的大小,这种命名方法会造成C++Builder,VB,Delphi使用的上的困扰。举例来说
</font></p>
<p><font SIZE="2">extern "C" _declspec(dllexport) void __stdcall
ShowImage(void);</font></p>
<p><font SIZE="2">在VC++ 中产生的函式名称为ShowImage@0(其中0表示参数大小),而不是如在C++Builder中产生的ShowImage,这是VC++
已知的问题,这个问题也造成了很多使用non-VC++
的使用者的问题,解决之道是在该DLL的DEF档中加上以下的叙述</font></p>
<p><font SIZE="2">EXPORTS</font> </p>
<p><font SIZE="2">ShowImage=ShowImage@0</font> </p>
<p><font SIZE="2">如此便可以产生正确的函式名了,若是你不想修改DEF档,你也可以在程式中加入以下的连结指引</font>
</p>
<p><font SIZE="2">#pragma comment(linker,"/exports:ShowImage=ShowImage@0")</font>
</p>
<p><font SIZE="2">假设你不确定其正确的名称,可以利用DumpBin或是TDump观察之。
</font></p>
<p><font SIZE="2">以上是针对VC++
的程式设计的所作的额外说明。最後我们以一个VC++
程式呼叫本单元的About Dialog DLL做为结束。</font></p>
<p><img SRC="IMG00005.GIF" WIDTH="460" HEIGHT="329"><br>
</p>
<p><font SIZE="2">此程式的关键程式码如下:</font> </p>
<p><font SIZE="2">void CVcusedllApp::OnAppAbout()</font> </p>
<p><font SIZE="2">{</font> </p>
<p><font SIZE="2"> void (*ShowImage)(void);</font> </p>
<p><font SIZE="2"> HINSTANCE hInst;</font> </p>
<p><font SIZE="2"> hInst = LoadLibrary("DLLSAMP2.DLL");</font>
</p>
<p><font SIZE="2"> (FARPROC
&)ShowImage=GetProcAddress(hInst,"ShowImage");</font> </p>
<p><font SIZE="2"> ShowImage();</font> </p>
<p><font SIZE="2"> FreeLibrary(hInst);</font> </p>
<p><font SIZE="2">}<br>
</font></p>
<p align="right"><font SIZE="2"><!--webbot bot="ImageMap" rectangle=" (40,1) (71, 23) ../ch6/chap06.htm" rectangle=" (4,1) (36, 23) chap51.htm" src="../ch1/NextBack.gif" width="72" height="24" alt="NextBack.gif (743字节)" border="0" startspan --><MAP NAME="FrontPageMap1"><AREA SHAPE="RECT" COORDS="40, 1, 71, 23" HREF="../ch6/chap06.htm"><AREA SHAPE="RECT" COORDS="4, 1, 36, 23" HREF="chap51.htm"></MAP><a href="../../../_vti_bin/shtml.exe/program/C++/ch5/chap52.htm/map1"><img ismap usemap="#FrontPageMap1" border="0" height="24" alt="NextBack.gif (743字节)" src="../ch1/NextBack.gif" width="72"></a><!--webbot bot="ImageMap" endspan i-checksum="15280" --></font></p>
<p><font SIZE="2"><small><a href="../../../index.htm">首页</a> >> <a href="../../program.htm">程序设计</a>
>> <a href="../cbuilder.htm">C++ Builder</a> >> </small>函式定义
DLL内的函式名 摘要说明</font> </p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -