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 &quot;C&quot; functions. No C++ classes or member functions.

<B>3</B>- Make sure you have an extern &quot;C&quot; {} 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.

     &gt; 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:

     &gt; 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 &quot;C&quot; functions. No C++ classes or member functions.

<B>3</B>- Make sure you have an extern &quot;C&quot; {} 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 &quot;C&quot; functions. No C++ classes or member functions.

<B>3</B>- Make sure you have an extern &quot;C&quot; {} 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.

     &gt; impdef mydll.def mydll.dll

<B>7</B>- Use Microsoft's LIB tool to create a COFF import library from the DEF file.

     &gt;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 &quot;C&quot; functions. No C++ classes or member functions.

<B>3</B>- Make sure you have an extern &quot;C&quot; {} 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 + -
显示快捷键?