bcbdll.htm
来自「C++builder学习资料C++builder」· HTM 代码 · 共 1,000 行 · 第 1/4 页
HTM
1,000 行
<H3>
<A NAME="example1">Example 1: Implicit linking</A>
</H3>
<P>
This example elaborates on the guidelines in Technique 1 from the previous section. The
guidelines for Technique 1 can be split into two groups. Items 1-5 deal with compiling the
DLL on the BCB side. Items 6-9 deal with using the DLL from the MSVC side. We
will separate our discussion along these lines.
</P>
In this example, we will build a DLL with BCB that exports two functions: <TT>Foo</TT>
and <TT>Bar</TT>. Both functions return an integer value. The functions look like this:
<pre>
<b>int</b> Foo <b>(</b><b>int</b> Value<b>)</b><b>;</b>
<b>int</b> Bar <b>(</b><b>void</b><b>)</b><b>;</b>
</pre>
We will then build a test EXE in MSVC that calls the Borland DLL.
<H4>Compiling the DLL with BCB</H4>
The following two listings contain the source code for our DLL. Listing 1 is
a header file that will be shared by both BCB and MSVC. Listing 2 contains
the implementations of our DLL functions. Create a BCB DLL project and paste in the the code
from listings 1 and 2. Or you can save time by dowloading the source code for this article.
The BCB DLL project is already already set up for you. (see the Downloads section at the very bottom).
<pre>
<font color="navy">// ----------------------------------------------</font>
<font color="navy">// Listing 1- DLL header file</font>
<font color="green">#ifndef BCBDLL_H</font>
<font color="green">#define BCBDLL_H</font>
<font color="green">#ifdef __cplusplus</font>
<b>extern</b> <font color="blue">"C"</font> <b>{</b>
<font color="green">#endif</font>
<font color="green">#ifdef BUILD_DLL</font>
<font color="green">#define IMPORT_EXPORT __declspec(dllexport)</font>
<font color="green">#else</font>
<font color="green">#define IMPORT_EXPORT __declspec(dllimport)</font>
<font color="green">#endif</font>
IMPORT_EXPORT <b>int</b> <b>__cdecl</b> Foo <b>(</b><b>int</b> Value<b>)</b><b>;</b>
IMPORT_EXPORT <b>int</b> <b>__cdecl</b> Bar <b>(</b><b>void</b><b>)</b><b>;</b>
<font color="green">#ifdef __cplusplus</font>
<b>}</b>
<font color="green">#endif</font>
<font color="green">#endif</font>
<font color="navy">// ----------------------------------------------</font>
</pre>
<pre>
<font color="navy">// ----------------------------------------------</font>
<font color="navy">// Listing 2- DLL source code</font>
<font color="green">#include <windows.h></font>
<font color="green">#pragma hdrstop</font>
<font color="green">#define BUILD_DLL</font>
<font color="green">#include "bcbdll.h"</font>
<b>int</b> <b>__cdecl</b> Foo <b>(</b><b>int</b> Value<b>)</b>
<b>{</b>
<b>return</b> Value <b>+</b> <font color="blue">1</font><b>;</b>
<b>}</b>
<b>int</b> <b>__cdecl</b> Bar <b>(</b><b>void</b><b>)</b>
<b>{</b>
<b>static</b> <b>int</b> ret <b>=</b> <font color="blue">0</font><b>;</b>
<b>return</b> ret<b>++</b><b>;</b>
<b>}</b>
<font color="navy">// ----------------------------------------------</font>
</pre>
<P>
There are couple of points to notice about the header file.
First, observe how we use <TT>extern "C"</TT> to ensure that the function names are not mangled by the C++
compiler. Second, notice that the exported functions are prefixed by the special directive <TT>__declspec(dllexport)</TT>
when we build the DLL. When we use the DLL from MSVC, the prefix changes to <TT>__declspec(dllimport)</TT>. The directive
is controlled via the <TT>IMPORT_EXPORT #define</TT>.
</P>
<P>
Lastly, note that we explicitly declare <TT>__cdecl</TT> to be the calling convention. Technically, we could omit the
<TT>__cdecl</TT> keyword, since <TT>__cdecl</TT> is already the default. However, I think it is a good practice to list
it anyway. By listing the calling convention, you explicitly tell people that you chose <TT>__cdecl</TT> for a reason.
Also, the default calling convention in both compilers can be changed via compiler switches. You don't want these
compiler switches to interfere with the usability of your DLL.
</P>
<P>
The header file alone satisfies Items 1-3 in our list of guidelines. The next thing we need to
do is handle item #4: aliasing the exported functions names.
</P>
<P>
First, build the DLL code as it stands now. Next, run the <TT>TDUMP</TT> tool to verify to yourself that the exported
function names really do contain a leading underscore.
</P>
<PRE>
c:> tdump -m -ee bcbdll.dll
Turbo Dump Version 5.0.16.12 Copyright (c) 1988, 2000 Inprise Corporation
Display of File BCBDLL.DLL
EXPORT ord:0001='_Bar'
EXPORT ord:0002='_Foo'
EXPORT ord:0003='___CPPdebugHook'
</PRE>
<P>
<TABLE WIDTH="100%">
<TR>
<TD VALIGN="top">
<IMG SRC="images/exclamation.gif" ALT="Tip" BORDER=0 HSPACE="0" ALIGN="top" width="32" height="48">
</TD>
<TD valign="top">
<b>Note:</b>
<hr size = 1>
Don't forget to use the -m switch with <TT>TDUMP</TT>. <TT>TDUMP</TT> attempts to unmangle decorated names so they
are easier to read. However, when you are working with DLLs, it is wise to see the functions in their raw
format. The -m switch tells <TT>TDUMP</TT> to display raw function names.
<hr size = 1>
</TD>
</TR>
</TABLE>
<P>
As you can see, both <TT>Foo</TT> and <TT>Bar</TT> contain a leading underscore. As for that <TT>__CPPdebugHook</TT> stuff, you can
simply ignore that man behind the curtain. Pretend <TT>__CPPdebugHook</TT> doesn't exist. It doesn't mean much to you, and you
can't make it go away, so there isn't much point worrying about it.
</P>
<P>
In order to alias away the underscores, we need to do three things: First create a DEF file from the DLL. Next, tweak the DEF
file to alias from Borland names to MSVC names. Lastly, add this DEF file to your BCB project and rebuild the DLL.
</P>
<P>
To create the DEF file, run Borland's <TT>IMPDEF</TT> tool on the DLL.
</P>
<PRE>
C:> impdef bcbdllx.def bcbdll.dll
</PRE>
<P>
I chose to name the DEF file <TT>bcbdllx.def</TT> because we will make another DEF later on (just before we create the
MSVC import library). I wanted to avoid confusion between the two. <TT>bcbdllx.def</TT> should look like this:
</P>
<PRE>
LIBRARY BCBDLL.DLL
EXPORTS
_Bar @1 ; _Bar
_Foo @2 ; _Foo
___CPPdebugHook @3 ; ___CPPdebugHook
</PRE>
<P>
Notice the leading underbar in front of <TT>Foo</TT> and <TT>Bar</TT>. If the DLL exports <TT>Foo</TT> and <TT>Bar</TT>
as <TT>_Foo</TT> and <TT>_Bar</TT>, MSVC users will see linker errors when they try to build their projects. We need to
strip the underbars away. We do this by aliasing the function names in the DEF file.
</P>
<P>
DEF file aliasing allows us to export a function name that acts as a proxy, or placeholder, for the real function. The real
functions in the DLL will still be <TT>_Foo</TT> and <TT>_Bar</TT>. The proxy names will be <TT>Foo</TT> and <TT>Bar</TT> (note the
missing underscores). When we alias the two original functions, the DLL will export two new symbols that refer back to the originals.
</P>
<P>
To perform the alias, edit the DEF file and change it so it looks like this:
</P>
<PRE>
LIBRARY BCBDLL.DLL
EXPORTS
Bar = _Bar
Foo = _Foo
</PRE>
<P>
This DEF file creates two new exports, <TT>Foo</TT> and <TT>Bar</TT>, that act as placeholders for <TT>_Foo</TT> and
<TT>_Bar</TT> respectively. Save this DEF file back to your hard drive. Once you have done that, add the DEF file to your
BCB project using the Project-Add To Project menu item. BCB will display the DEF file in the project manager tree after you add it.
</P>
<P>
Once you have the DEF file added to your project, do a complete rebuild. After the project has linked, run <TT>TDUMP</TT> on the
DLL again to verify that the undecorated functions are being exported from the DLL.
</P>
<PRE>
>tdump -m -ee bcbdll.dll
Turbo Dump Version 5.0.16.12 Copyright (c) 1988, 2000 Inprise Corporation
Display of File BCBDLL.DLL
EXPORT ord:0004='Bar'
EXPORT ord:0005='Foo'
EXPORT ord:0002='_Bar'
EXPORT ord:0001='_Foo'
EXPORT ord:0003='___CPPdebugHook'
</PRE>
<P>
There are a couple things to notice about the output from <tt>TDUMP</tt>. First, obsverve the presence of <TT>Foo</TT> and <TT>Bar</TT>
(without the leading underscore). Now the DLL is exporting function names that agree with MSVC. Also notice that the original
functions, <TT>_Foo</TT> and <TT>_Bar</TT>, are still there. The decorated functions are still exported from the DLL. Using a DEF file
to alias the names does not hide the originals.
</P>
<P>
You might think that it would be advantageous to somehow hide the original two functions, <TT>_Foo</TT> and <TT>_Bar</TT>. However,
this would be detrimental to people who want to use your DLL from a BCB project. Remember that the BCB linker expects the
leading underscore to be there. If you were to somehow hide <TT>_Foo</TT> and <TT>_Bar</TT> from the DLL (which is not
possible to the best of my knowledge), then your DLL would be difficult to call from BCB.
</P>
<P>
If the output from <TT>TDUMP</TT> does not list the proxy functions (the ones without the underscore), then go back and check your
DEF file. You need to get the alias names to appear before you can proceed. If the DLL looks OK, then it is time to move over to
the MSVC side.
</P>
<P>
<H4>Calling the DLL from MSVC</H4>
<P>
Once you have the DLL molded into shape so that it exports unmangled, <TT>__cdecl</TT> functions, the next step is to generate an
import library for your MSVC users. For this, you will need the DLL that you just created, Borland's <TT>IMPDEF</TT> utility (again),
and the <TT>LIB.EXE</TT> tool from MSVC. The first step is to create a DEF file from the DLL. For this, I suggest that you copy the
DLL and the DLL header file over to your MSVC project directory, and work from there.
</P>
<PRE>
C:> impdef bcbdll.def bcbdll.dll
</PRE>
<P>
Impef will create a DEF file that looks like this:
</p>
<PRE>
C:> impdef bcbdll.def bcbdll.dll
LIBRARY BCBDLL.DLL
EXPORTS
Bar @4 ; Bar
Foo @5 ; Foo
_Bar @2 ; _Bar
_Foo @1 ; _Foo
___CPPdebugHook @3 ; ___CPPdebugHook
</PRE>
<P>
Open the DEF file in an editor, and alter it so it looks like this:
<PRE>
LIBRARY BCBDLL.DLL
IMPORTS
Bar @4 ; Bar
Foo @5 ; Foo
</PRE>
<P>
Notice that we removed the functions that contain underscores, and the debug hook function. We also changed the word
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?