⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000004.htm

📁 水木清华关于C++Builder程序的代码
💻 HTM
📖 第 1 页 / 共 2 页
字号:
&nbsp;<BR>hInst&nbsp;=&nbsp;LoadLibrary(&quot;DLLSAMP.DLL&quot;)&nbsp;是用来载入DLLSAMP.DLL&nbsp;&nbsp;<BR>,同时传回该DLL的HINSTANCE值,它是据以使用DLL的权杖。&nbsp;<BR>&nbsp;<BR>(FARPROC&nbsp;&amp;)ShowImage=GetProcAddress(hInst,&quot;ShowImage&quot;)&nbsp;&nbsp;<BR>利用前面得到的HINSTANCE值,呼叫GetProcAddress来得到ShowImage函&nbsp;<BR>式的位址,因为GetProcAddress所传回的值为FARPROC&nbsp;&nbsp;<BR>,因此我们必须做型别转换。在此我是利用&nbsp;(FARPROC&nbsp;&amp;)&nbsp;以reference做&nbsp;<BR>型别转换。&nbsp;&nbsp;<BR>&nbsp;<BR>FreeLibrary(hInst)&nbsp;使用完後,利用FreeLibrary&nbsp;将该DLL释放。&nbsp;&nbsp;<BR>输入函式及输出函式的标准写法&nbsp;<BR>&nbsp;<BR>前面我们使用输入函式及输出函式时,为了简化程式的写法,因此使用了&nbsp;<BR>Borland为了和16位元程式相容而使用的&nbsp;&nbsp;<BR>_export编译指令,在此我必须指出,这种写法是非标准的写法,其实&nbsp;<BR>Microsoft在32位元程式中使用了另一种定义输入函式及输出函式的写法,&nbsp;<BR>那才是一个放诸四海皆准的写法,使用&nbsp;&nbsp;<BR>_export式的旧有写法在诸如Visual&nbsp;C++&nbsp;的编译器中是无法通过编译的。&nbsp;&nbsp;<BR>&nbsp;<BR>在理论上,我们希望可以使用单一的关键字来定义一个输出函式,就如同&nbsp;&nbsp;<BR>_export一般,然而Microsoft却在它的32位元程式中使用了另一种关键字&nbsp;<BR>来定义输入及输出函式,那就是&nbsp;&nbsp;<BR>__declspec关键字,它可以传入dllimport及dllexport两个叁数,用来分&nbsp;<BR>别代表输入函式及输出函式。&nbsp;&nbsp;<BR>&nbsp;<BR>换句话说,若你要撰写输出函式,你必须使用&nbsp;__declspec(dllexport)&nbsp;来&nbsp;<BR>定义该函式,反之若你要使用输入函式,则你必须使用&nbsp;&nbsp;<BR>__declspec(dllimport)&nbsp;来定义该函式。&nbsp;<BR>&nbsp;<BR>因此由於输入及输出函式的使用方式不同,你必须使用两个不同的include&nbsp;<BR>档来分别定义之。若你不想如此麻烦,那麽就必须要使用巨集定义来达到一&nbsp;<BR>体多用的目的罗,这对少数人持反对论点的人来说,简直是罪恶(还有人称&nbsp;<BR>之为巨集巫毒--macro&nbsp;&nbsp;<BR>woodoo)。&nbsp;<BR>&nbsp;<BR>Windows的实作名家Jeffrey&nbsp;Richter,也就是Advanced&nbsp;&nbsp;<BR>Windows的作者建议我们使用以下的方法来达到一体多用的效果(同样是透&nbsp;<BR>过巨集巫毒)。&nbsp;&nbsp;<BR>&nbsp;<BR>#ifndef&nbsp;_SHOWIMG_H_&nbsp;&nbsp;<BR>#define&nbsp;_SHOWIMG_H_&nbsp;<BR>&nbsp;<BR>#ifndef&nbsp;IMGDLL&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllimport)&nbsp;&nbsp;<BR>#else&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllexport)&nbsp;&nbsp;<BR>#endif&nbsp;&nbsp;<BR>void&nbsp;EXTERN&nbsp;ShowImage(void);&nbsp;&nbsp;<BR>#endif&nbsp;<BR>&nbsp;<BR>如此一来,当你在撰写DLL时撰写可以撰写如下函式:&nbsp;<BR>&nbsp;<BR>#define&nbsp;IMGDLL&nbsp;&nbsp;<BR>#include&nbsp;&quot;image.h&quot;&nbsp;<BR>&nbsp;<BR>当使用者在使用DLL时,则只要直接含入image.h即可。如此一来算是解决&nbsp;<BR>了利用&nbsp;__declspec(dllimport)&nbsp;和&nbsp;&nbsp;<BR>__declspec(dllexport)&nbsp;的不便了。&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;必也正名乎的DLL函式命名&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;谈完了标准写法,再来我们要谈谈一个更容易搞混的函式命名原则。本&nbsp;<BR>来在正常情况下,我们是不需要理会编译器的函式命名规则的,因为在使用&nbsp;<BR>同一样编译器的情况下,不会有什麽太大的问题。然而问题来了,由於DLL&nbsp;<BR>是动态连结函式库,因此它的目标就是希望可以让多个程式共享程式及资&nbsp;<BR>源。所以若是DLL只能为同一种编译器所使用,那麽它的用途就大打折扣了。&nbsp;<BR>因此我们还是必须了解函式的命名方法。同时由於函式命名方式在各种不同&nbsp;<BR>的编译器各不相同,因此我们也必须了解其相异处,最重要的是,我们必须&nbsp;<BR>找出其沟通的方式。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>C++&nbsp;Builder的命名规则&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;除了前面提到的&nbsp;__declspec编译指令之外,在C++&nbsp;Builder尚有几种&nbsp;<BR>修饰字会影响到函数的命名,&nbsp;它们就是&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;__cdecl,__stdcall,__pascal,__fastcall四个修饰字。为了了解该&nbsp;<BR>修饰字对於函式命名的影响,我们可以用以下的程式来测试之:&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>#ifndef&nbsp;_DLLNAME01_H_&nbsp;&nbsp;<BR>#define&nbsp;_DLLNAME01_H_&nbsp;&nbsp;<BR>#ifndef&nbsp;DLLNAME&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllimport)&nbsp;&nbsp;<BR>#else&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllexport)&nbsp;&nbsp;<BR>#endif&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;DllName01(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_stdcall&nbsp;DllName02(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_cdecl&nbsp;DllName03(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_pascal&nbsp;DllName04(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_fastcall&nbsp;DllName05(void);&nbsp;&nbsp;<BR>};&nbsp;&nbsp;<BR>#endif&nbsp;<BR>&nbsp;<BR>以上为程式的定义,同时我们可以在&nbsp;.CPP档中撰写相对应的空函式,然後&nbsp;<BR>将其编译成DLL档,再利用TDUMP.EXE或是VC++&nbsp;&nbsp;<BR>内的DUMPBIN.EXE来观察其内容,由於TDUMP会将函式命名解码,反而会使&nbsp;<BR>混淆原来的名称,因此以下的输出是由DUMPBIN.EXE得来。&nbsp;&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>函式定义&nbsp;DLL内的函式名&nbsp;摘要说明&nbsp;&nbsp;<BR>void&nbsp;DllName01(void)&nbsp;@DllName01$qv&nbsp;因为是CPP程式码&nbsp;&nbsp;<BR>void&nbsp;_stdcall&nbsp;DllName02(void)&nbsp;@DllName02$qqsv&nbsp;所以函式名都被修&nbsp;&nbsp;<BR>void&nbsp;_cdecl&nbsp;DllName03(void)&nbsp;@DllName03$qv&nbsp;饰过。&nbsp;&nbsp;<BR>void&nbsp;_pascal&nbsp;DllName04(void)&nbsp;@DLLNAME04$QV&nbsp;&nbsp;<BR>void&nbsp;_fastcall&nbsp;DllName05(void)&nbsp;@DllName05$qqrv&nbsp;&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;以上结果是否令你丈二金钢、摸不着头绪。这是因为我们的程式名称若&nbsp;<BR>以CPP为延伸名,C++Builder会以C++&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;特有的命名方式来为函式命名,这种命名方式会在函式名称後加上其使&nbsp;<BR>用叁数的性质,如叁数类别等。这在C++&nbsp;中有一个特别的名称,叫做mangled&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;name,这是一种为了要实作出多载函式所发出的命名规则。(注:在C++&nbsp;中&nbsp;<BR>Add(int)&nbsp;和Add(double)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;可以同时存在,因此必须在object&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;code区分之)。同时这种命名方式由於各个编译器厂商使用的方式各不&nbsp;<BR>相同,因此在撰写DLL时要避免使用之。为了要避开以上问题,我们改以下&nbsp;<BR>列的宣告方式:&nbsp;&nbsp;<BR>#define&nbsp;_DLLNAME01_H_&nbsp;&nbsp;<BR>#ifndef&nbsp;DLLNAME&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllimport)&nbsp;&nbsp;<BR>#else&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllexport)&nbsp;&nbsp;<BR>#endif&nbsp;&nbsp;<BR>extern&nbsp;&quot;C&quot;&nbsp;{&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;DllName011(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_stdcall&nbsp;DllName022(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_cdecl&nbsp;DllName033(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_pascal&nbsp;DllName044(void);&nbsp;&nbsp;<BR>EXTERN&nbsp;void&nbsp;_fastcall&nbsp;DllName055(void);&nbsp;&nbsp;<BR>};&nbsp;&nbsp;<BR>#endif&nbsp;<BR>&nbsp;<BR>其中extern&nbsp;&quot;C&quot;&nbsp;{厖厖.};&nbsp;是用来告诉编译器使用C的命名方式,不要使用&nbsp;<BR>C++&nbsp;的mangled&nbsp;&nbsp;<BR>name。若是其中只有一个函式时,你可以直接以下列方式宣告之:&nbsp;&nbsp;<BR>extern&nbsp;&quot;C&quot;&nbsp;void&nbsp;__stdcall&nbsp;ShowImage();&nbsp;&nbsp;<BR>&nbsp;<BR>现在我们可以检视除去mangled&nbsp;name後的函式名称:&nbsp;<BR>&nbsp;<BR>函式定义&nbsp;DLL内的函式名&nbsp;摘要说明&nbsp;&nbsp;<BR>void&nbsp;DllName01(void)&nbsp;_DllName01&nbsp;名称加底线&nbsp;&nbsp;<BR>void&nbsp;_stdcall&nbsp;DllName02(void)&nbsp;DllName02&nbsp;名称未变&nbsp;&nbsp;<BR>void&nbsp;_cdecl&nbsp;DllName03(void)&nbsp;_DllName03&nbsp;名称加底线&nbsp;&nbsp;<BR>void&nbsp;_pascal&nbsp;DllName04(void)&nbsp;DLLNAME04&nbsp;名称大写&nbsp;&nbsp;<BR>void&nbsp;_fastcall&nbsp;DllName05(void)&nbsp;@DllName05&nbsp;名称加@&nbsp;&nbsp;<BR>&nbsp;<BR>以上我们可得知,在未加修饰字时和使用_cdecl修饰字时的名称是一样的。&nbsp;<BR>而&nbsp;_pascal修饰字所产生的函式名则和16位元的标准DLL&nbsp;函式名相同(这&nbsp;<BR>在VC++&nbsp;&nbsp;<BR>是不被接受的),__fastcall的函式名称则加上&nbsp;@。&nbsp;<BR>&nbsp;<BR>其中在WIN32中使用最多的是&nbsp;_stdcall修饰字,这也是你要撰写一个可以&nbsp;<BR>和其他语言共同使用时所使用的修饰字,其次则为&nbsp;&nbsp;<BR>__cdecl修饰字,这是用来传送不定叁数型别的函式如printf、sprintf等&nbsp;<BR>使用的。其馀两者几乎在DLL没有机会使用。&nbsp;&nbsp;<BR>&nbsp;<BR>结论:由上可知,在C++Builder中撰写DLL时必须注意以下事项:&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;使用&nbsp;__declspec(dllimport)及&nbsp;__declspec(dllexport)的标准型&nbsp;<BR>式。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;注意C++&nbsp;的函式名称编码(mangled&nbsp;name)。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;注意修饰字的使用。除非使用不定叁数的函式,否则必使用&nbsp;__stdcall&nbsp;<BR>修&nbsp;&nbsp;<BR>饰字。&nbsp;&nbsp;<BR>(4)&nbsp;不要把&nbsp;__declspec的使用和&nbsp;__stdcall混淆了。此二者并没有绝对&nbsp;<BR>的相关性。即使是程式老手都可能栽在此处,切记,切记!&nbsp;&nbsp;<BR>&nbsp;<BR>怎麽样,在看完了以上的介绍後,是否有晃然大悟的感觉。在了解以上的规&nbsp;<BR>则後,今後不论在撰写或是使用DLL时遭遇连结的问题时,应该难不倒你吧!&nbsp;&nbsp;<BR>最後,我们将标准的DLL宣告方式列於後,以加深你的印象:&nbsp;&nbsp;<BR>&nbsp;<BR>#ifndef&nbsp;_SHOWIMG_H_&nbsp;&nbsp;<BR>#define&nbsp;_SHOWIMG_H_&nbsp;&nbsp;<BR>#ifndef&nbsp;IMGDLL&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllimport)&nbsp;&nbsp;<BR>#else&nbsp;&nbsp;<BR>#define&nbsp;EXTERN&nbsp;__declspec(dllexport)&nbsp;&nbsp;<BR>#endif&nbsp;&nbsp;<BR>extern&nbsp;&quot;C&quot;&nbsp;EXTERN&nbsp;void&nbsp;__stdcall&nbsp;ShowImage(void);&nbsp;&nbsp;<BR>#endif&nbsp;<BR>&nbsp;<BR>语言双雄'&nbsp;C++Builder&nbsp;和Visual&nbsp;C++&nbsp;连结&nbsp;<BR>&nbsp;<BR>前面我们已经把关於C++Builder撰写DLL所应注意到的事项介绍完了,现&nbsp;<BR>在我们来谈另一个重点&nbsp;-&nbsp;C++Builder和Visual&nbsp;C++&nbsp;&nbsp;<BR>的连结。若是你没有使用过Visual&nbsp;C++&nbsp;的话,可以将此部份略去。若是你&nbsp;<BR>在程式设计时必须使用到Visual&nbsp;C++&nbsp;的DLL或是必须提供DLL给VC++&nbsp;&nbsp;<BR>或是VB使用时,也许会带给你意想不到的收获。&nbsp;&nbsp;<BR>&nbsp;<BR>VC++&nbsp;使用C++Builder的DLL函式&nbsp;<BR>&nbsp;<BR>在Visual&nbsp;C++&nbsp;中使用C++Builder的DLL的函式方法和在C++Builder中使&nbsp;<BR>用大同小异,唯有几件事情必须要注意。&nbsp;&nbsp;<BR>&nbsp;<BR>(一)Visual&nbsp;C++&nbsp;的LIB档格式和C++Builder的LIB格式不同,因此你必&nbsp;<BR>须重新产生一个&nbsp;LIB。不过,可惜的是VC++&nbsp;&nbsp;<BR>在32位元的版本中并未提供IMPLIB.EXE函式(这点一直令许多人百思不&nbsp;<BR>解),因此你无法很方便地产生LIB档。解决方法有二:其一是在VC++&nbsp;&nbsp;<BR>内撰写一个同名称的空的DLL函式,令其产生LIB档,其二则是使用&nbsp;&nbsp;<BR>LoadLibrary、GetProcAddress式的明确呼叫方式。&nbsp;&nbsp;<BR>(二)使用前面提到的标准写法。&nbsp;<BR>&nbsp;<BR>C++Builder中使用VC++&nbsp;的DLL函式&nbsp;<BR>&nbsp;<BR>在C++Builder中使用VC++&nbsp;的DLL函式时要注意的是Microsoft在Visual&nbsp;C++&nbsp;&nbsp;<BR>中使用的特殊命名规则。在VC++&nbsp;&nbsp;<BR>中命名规则除了前面谈到的几项之外,它还使用了一个特殊的叁数命名法,&nbsp;<BR>简言之,就是在函数名称後面加上叁数的大小,这种命名方法会造成&nbsp;<BR>C++Builder,VB,Delphi使用的上的困扰。举例来说&nbsp;&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>extern&nbsp;&quot;C&quot;&nbsp;_declspec(dllexport)&nbsp;void&nbsp;__stdcall&nbsp;ShowImage(void);&nbsp;<BR>&nbsp;<BR>在VC++&nbsp;中产生的函式名称为ShowImage@0(其中0表示叁数大小),而不是&nbsp;<BR>如在C++Builder中产生的ShowImage,这是VC++&nbsp;&nbsp;<BR>已知的问题,这个问题也造成了很多使用non-VC++&nbsp;的使用者的问题,解决&nbsp;<BR>之道是在该DLL的DEF档中加上以下的叙述&nbsp;&nbsp;<BR>EXPORTS&nbsp;&nbsp;<BR>ShowImage=ShowImage@0&nbsp;&nbsp;<BR>如此便可以产生正确的函式名了,若是你不想修改DEF档,你也可以在程式&nbsp;<BR>中加入以下的连结指引&nbsp;&nbsp;<BR>#pragma&nbsp;comment(linker,&quot;/exports:ShowImage=ShowImage@0&quot;)&nbsp;&nbsp;<BR>假设你不确定其正确的名称,可以利用DumpBin或是TDump观察之。&nbsp;&nbsp;<BR>&nbsp;<BR>以上是针对VC++&nbsp;的程式设计的所作的额外说明。最後我们以一个VC++&nbsp;程&nbsp;<BR>式呼叫本单元的About&nbsp;Dialog&nbsp;DLL做为结束。&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>此程式的关键程式码如下:&nbsp;&nbsp;<BR>void&nbsp;CVcusedllApp::OnAppAbout()&nbsp;&nbsp;<BR>{&nbsp;&nbsp;<BR>void&nbsp;(*ShowImage)(void);&nbsp;&nbsp;<BR>HINSTANCE&nbsp;hInst;&nbsp;&nbsp;<BR>hInst&nbsp;=&nbsp;LoadLibrary(&quot;DLLSAMP2.DLL&quot;);&nbsp;&nbsp;<BR>(FARPROC&nbsp;&amp;)ShowImage=GetProcAddress(hInst,&quot;ShowImage&quot;);&nbsp;&nbsp;<BR>ShowImage();&nbsp;&nbsp;<BR>FreeLibrary(hInst);&nbsp;&nbsp;<BR>}&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>--&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;面对未知的世界因恐惧而发抖&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;<BR>※&nbsp;来源:·BBS&nbsp;水木清华站&nbsp;bbs.net.tsinghua.edu.cn·[FROM:&nbsp;166.111.49.104]&nbsp;<BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -