bcbdll.htm
来自「C++builder学习资料C++builder」· HTM 代码 · 共 1,000 行 · 第 1/4 页
HTM
1,000 行
<HTML>
<HEAD>
<TITLE> Creating DLLs in BCB that can be used from Visual C++</TITLE>
<META NAME="Author" CONTENT="Harold Howe">
</HEAD>
<BODY>
<CENTER>
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH="640">
<TR>
<TD>
<H2>
Creating DLLs in BCB that can be used from Visual C++
</H2>
<P>
In a <A HREF="vcdll.htm">past article</A>, we discussed how to call a DLL created by MS Visual C++ from a C++Builder
project. This article reverses that scenario by illustrating how to create a DLL with C++Builder that you can call from
a Visual C++ project.
</P>
<UL>
<LI><A HREF="#introduction" >Introduction: why is this so difficult</A>
<LI><A HREF="#guidelines" >Summary of guidelines</A>
<LI><A HREF="#example1" >Example 1: Implicit linking</A>
<LI><A HREF="#example2" >Example 2: Explicit linking</A>
<LI><A HREF="#example3" >Example 3: Implicit linking with a #define kludge</A>
<LI><A HREF="#example4" >Example 4: Implicit linking with stdcall functions</A>
<LI><A HREF="#conclusion" >Conclusion</A>
</UL>
<BR>
<H3>
<A NAME="introduction">Introduction: why is this so difficult</A>
</H3>
<P>
If you have ever created a DLL with BCB that you called from another BCB executable, then you know that using DLLs in this
manner is not that difficult. When you build a DLL, BCB generates an import library with a .LIB file exension. You take this
LIB file and add it to the project for your application. The linker uses the import library to resolve calls into the DLL. When you
run your program, the DLL is implicitly loaded for you, and calls into the DLL work without much thought required on your part.
</P>
<P>
The situation becomes more complex when the EXE is compiled with Microsoft Visual C++. There are 3 main problems. First, BCB and MSVC
do not agree on how functions should be named in the DLL. BCB uses one convention, and MSVC uses a different convention. Of course,
the two conventions are not compatible. The naming problems are discussed in the article on how to <A HREF="vcdll.htm">use VC++ compiled DLLs in BCB</A>.
Table 1 summarizes how each compiler would export a function called MyFunction based on its calling convention. Notice that Borland
prepends a leading underscore to exported <TT>__cdecl</TT> functions. MSVC does not. On the other hand, MSVC does expect
<TT>__stdcall</TT> functions to be exported with a leading underscore and some garbage at the end.
</P>
<PRE>
<B>Table 1: Visual C++ and C++Builder naming conventions</B>
Calling convention VC++ name VC++ (DEF used) C++Builder Name
-----------------------------------------------------------------------
__stdcall _MyFunction@4 MyFunction MyFunction
__cdecl MyFunction MyFunction _MyFunction
</PRE>
<P>
The second problem is that Borland import libraries are not binary compatible with MSVC. The import library that BCB creates when you
compile the DLL cannot be linked with MSVC. If you want to use implicit linking, then you need to create an MSVC import library. The
other alternative is to switch to explicit linking (<TT>LoadLibrary</TT> and <TT>GetProcAddress</TT>).
</P>
<P>
The third problem is that you can't export C++ classes and member functions from your DLL if you want MSVC users to be able to call it.
Well, that's not entirely true. Your DLL can export C++ classes and member functions, but MSVC will not be able to use them. The reason
is that C++ member function names are mangled by the compiler. This mangled name ends up in the DLL. In order to call a mangled function
in a DLL, you have to know how that function was mangled. Borland and Microsoft do not use the same name mangling scheme. As a
reasult, MSVC cannot even see C++ classes and member functions in a Borland compiled DLL.
</P>
<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>
Borland and Microsoft do not mangle functions the same way because C++ compilers
are not supposed to adhere to the same guidelines, according to the ANSI C++ standard. Name mangling
is something that is implementation specific.
<hr size = 1>
</TD>
</TR>
</TABLE>
<P>
These three issues make it difficult to create a DLL in Borland that can be called from MSVC, but it isn't impossible.
This article describes a set of guidelines that you can follow to make your BCB DLLs Microsoft compatible. We will
discuss four different techniques. Three involve implicit linking with an import library, and one technique utilizes
explicit linking at runtime.
</P>
<H3>
<A NAME="guidelines">Summary of guidelines</A>
</H3>
<P>
The following lists summarize the guidelines that you should follow for building
your DLL. The first list discusses implicit linking. The second list describes
explicit lnking. The third technique uses implicit linking and a <TT>#define</TT> trick.
The last example utilizes a dummy MSVC DLL project to create a import library for
<TT>__stdcall</TT> functions.
</P>
<PRE>
<B>Technique 1: Implicit linking</B>
------------------------------------------------------------------------------
<B>1</B>- Use the __cdecl calling convention instead of __stdcall.
<B>2</B>- Export plain "C" functions. No C++ classes or member functions.
<B>3</B>- Make sure you have an extern "C" {} around your function prototypes.
<B>4</B>- Create a DEF file that aliases the exported functions to a Microsoft
compatible name. Alias the names so they don't contain a leading
underscore. The DEF file will look like this:
EXPORTS
; MSVC name = Borland name
Foo = _Foo
Bar = _Bar
<B>5</B>- Add the DEF file to your BCB DLL project and rebuild it.
<B>6</B>- Copy the DLL and the DLL header file to your MSVC project directory.
<B>7</B>- Run impdef on the DLL to create a second DEF file for the DLL. This DEF
file is used to create the import library.
> impdef mydll.def mydll.dll
<B>8</B>- Run Microsoft's LIB tool to create a COFF import library from the DEF file
created in the previous step. The format is:
> lib /DEF mydll.def
<B>9</B>- Add the LIB file created by LIB.EXE to your MSVC project.
</pre>
<BR>
<PRE>
<B>Technique 2: Explicit linking</B>
------------------------------------------------------------------------------
<B>1</B>- Use either __cdecl or __stdcall. If you use __stdcall, you can skip steps
4 and 5.
<B>2</B>- Export plain "C" functions. No C++ classes or member functions.
<B>3</B>- Make sure you have an extern "C" {} around your function prototypes.
<B>4</B>- If you are using __cdecl, then you may want to strip off the leading
underscore in your exported function names, but you don't have to. You can
strip off the unscore by following steps 4 and 5 from Example 1. If you
don't strip off the underscores, users will have to include the underscore
in the function name when they call <TT>GetProcAddress</TT>.
<B>5</B>- Copy the DLL to the MSVC project directory.
<B>6</B>- From the MSVC app, use the API LoadLibrary routine to load the DLL.
<B>7</B>- Call the API GetProcAddres function to find functions in the DLL. Store the
result of GetProcAddress in a function pointer. Dereference the function
pointer when you want to call the function.
<B>8</B>- Call FreeLibrary when you are done using the DLL.
</pre>
<BR>
<PRE>
<B>Technique 3: Implicit linking with a #define kludge</B>
------------------------------------------------------------------------------
<B>1</B>- Use the __cdecl calling convention instead of __stdcall.
<B>2</B>- Export plain "C" functions. No C++ classes or member functions.
<B>3</B>- Make sure you have an extern "C" {} around your function prototypes.
<B>4</B>- In your DLL header file, create a #define for each exported function name.
The #define will tell the preprocessor to add a leading underscore to each
function name. The code checks for _MSC_VER because we only want to do this
aliasing from MSVC.
#ifdef _MSC_VER
#define Foo _Foo
#define Bar _Bar
#endif
<B>5</B>- Copy the DLL and the DLL header file to your MSVC project directory.
<B>6</B>- Run impdef on the DLL to create a DEF file for the DLL.
> impdef mydll.def mydll.dll
<B>7</B>- Use Microsoft's LIB tool to create a COFF import library from the DEF file.
>lib /def mydll.def
<B>8</B>- Add the LIB file created by LIB.EXE to your MSVC project.
</pre>
<BR>
<PRE>
<B>Technique 4: Implicit linking with __stdcall functions</B>
------------------------------------------------------------------------------
<B>1</B>- Use the __stdcall calling convention when building your DLL.
<B>2</B>- Export plain "C" functions. No C++ classes or member functions.
<B>3</B>- Make sure you have an extern "C" {} around your function prototypes.
<B>4</B>- Create an import library for MSVC. This is the difficult part. You cannot
create an import library for __stdcall functions with LIB.EXE. You must
create the import library by compiling a dummy DLL in MSVC. To do so,
follow these steps:
<B>4a</B>- Create a non-MFC DLL project with MSVC
<B>4b</B>- Copy over your DLL header file and DLL source code from BCB
<B>4c</B>- Edit your DLL source code and rip out the function bodies of each
routine. Use dummy return statements in routines that return values.
<B>4d</B>- Configure the MSVC project to generate a DLL with the same file name
as the BCB DLL.
<B>4e</B>- Add a DEF file to the MSVC project to suppress its hoaky __stdcall
name decorations (_Foo@4)
<B>5</B>- Compile the dummy DLL project from step 4. This will generate a DLL (which
you can pitch in the trash) and a LIB file (which you need).
<B>6</B>- Add the LIB file from step 5 to any MSVC project the needs to call the BCB
DLL. The LIB file will satisfy the linker. Deploy the MSVC executable with
the BCB DLL (not the dummy DLL).
</pre>
<BR>
<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>
Under normal circumstances, implicit linking is preferred over explicit linking
simply because implicit linking is easier for the programmer and because it is more
typesafe (errors are generated at link time as opposed to runtime). However, when you
share a DLL across compilers, you must create compatible import libraries for
each compiler if you choose to stick with implicit linking. The added burden of
creating compatible import libraries makes explicit linking at runtime look
more appealling.
<hr size = 1>
</TD>
</TR>
</TABLE>
<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>
The guidelines for explicit linking also apply if you want to make your DLL
available to Visual Basic developers. If you want to give your DLL to VB
developers, follow the explicit linking guidelines, and use the <TT>__stdcall</TT>
calling convention.
<hr size = 1>
</TD>
</TR>
</TABLE>
<P>
The next 4 sections describe each technique in detail.
</P>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?