Create a DLL that can be used by Visual C in C Builder
ShadowStar's Home: http://shadowstar.126.com/ Source: http://www.bcbdev.com/articles/bcbdll.htm In the first two articles, we discussed how to call in C Builder Engineering The DLL created by MS Visual C . This article discusses the opposite situation. For example, how to create a DLL with C Builder, allowing it to call in Visual C engineering.
Introduction: Why this is so difficult to guide the policy Example 1: Implicit Connection example 2: Explicit Connection Example 3: Using #define Assemble Implicit Connection Example 4: Use STDCALL Function Implicit Conclusions Introduction: Why is this so difficult? BCB creates a DLL that can be called by the BCB executable file, you know that this way of using the DLL is not difficult. When you construct a DLL, BCB generates an introduction library with ".lib" extension. Add this lib file to your project. The connector determines the internal call of the DLL according to the introduction library. When you run your program, the DLL implicit loaded, you don't have to consider the DLL internal call job is. When the EXE file is compiled by Microsoft Visual C , the situation will become more complicated. There are three main issues. First, BCB and MSVC are inconsistent with the function naming method in the DLL. BCB uses a habit, MSVC uses another habit. Of course, two habits are incompatible. Name the problem has been discussed in how the DLL compiled in the C Builder engineering has been discussed. Table 1 summarizes each compiler in their respective call habits, exported myFunction functions. Note that Borland has added a next line before the __cdecl function, and the MSVC is not. On the other hand, MSVC believes that the exported __stdcall function has underlined, and there are some garbage behind. Table 1: Visual C And C Builder Name Habit
Calling habits vc named VC (using DEF) C Builder naming
-------------------------------------------------- ---------------------
__stdcall _myfunction @ 4 myfunction myfunction
__cdecl myfunction myfunction_myfunction
The second question is that the Borland introduction library is not binary compatible with MSVC. When you compile the DLL, the introduction library created by BCB cannot be used by the MSVC. If you want to use implicit connections, then you need to create an introduction library in the MSVC format. Another optional approach is to adopt an explicit connection (loadLibrary and getProcaddress). The third question is not to export C classes and member functions from the DLL, if you want MSVC users to call it. Ok, that is not completely true. Your DLL can export a C class, but MSVC can't use them. The reason is that the C member function name is adapted to the compiler. This adapted name is DLL. In order to call the function adapted in the DLL, you must know which function is adapted. Borland and Microsoft use different name adaptation schemes. As a result, MSVC can't just see the C class and member functions in the DLL compiled by Borland. note:
Borland and Microsoft are not adopted in the same way, because in accordance with the ANSI C standard, the C compiler is not assumed to follow the same guidelines. The name adaptation is just the details of the implementation.
These three problems make the DLL created by Borland can be called very difficult in the MSVC, but is not impossible. This article describes a set of guidelines that you can follow the BCB DLL compatible with Microsoft. We discuss four different technologies. Three kinds of introduction libraries implicit connection is used, one is explicitly connected at runtime. Guidelines Summary You can build your DLL with the guidelines below. The first list discussion implicit connection; the second list describes explicit connections; the third technology uses #define assembly implicit connections; the last example uses the false MSVC DLL project to create an introduction library. Technology 1: Implicit connection
-------------------------------------------------- ----------------------------
1- Use the __cdecl calling habit instead __stdcall.
2- Export a simple "C" style function, no C class or member function.
3 - Make sure you have an extern "c" {} surrounded by your function prototype.
4- Create a DEF file, containing an alias that is compatible with Microsoft. Alias is also the next underscore.
The DEF file is as follows:
Exports
; MSVC Name = Borland Name
Foo = _foo
Bar = _bar
5 - Add the DEF file to your project recompilation.
6 - Copy the DLL and DLL header to your MSVC project directory.
7 - Create the 2nd DEF file for the DLL of the ImpDef. This DEF file is used to create an introduction library.
> impdef mydll.def mydll.dll
8 - Run the Lib tool for Microsoft, create a COFF to create a COFF with the DEF file created in the previous step. The call format is:
> lib / def mydll.def
9 - Add a lib file created with lib.exe to your MSVC project.
Technology 2: Explicit connection -------------------------------------------- ---------------------------------- 1-Use __cdecl or __stdcall, if you use __stdcall to jump Take over the 4th, 5 steps. 2- Export a simple "C" style function, no C class or member function. 3 - Make sure you have an extern "c" {} surrounded by your function prototype. 4- If you use __cdecl, then you may want to take out the underscale in front of the function, but you don't have to do this. You can use the 4th, 5 steps of Example 1 to remove the underline. If you don't remove the download line, the function name must be in front of the function name when calling the getProcAddress function. 5 - Copy the DLL to the MSVC project. 6 - In the MSVC application, use the LoadLibrary API function to load the DLL. 7 - Call the GetProcAddress API in the DLL to find the call function you want, save the function pointer returned by the getProcAddress function. When you want to modify the function, extract the function pointer. 8 - When you use the DLL to call FreeElibrary. Technology 3: Using #define assembly implicit connection -------------------------------------- -------------------------------------- 1-Use __cdecl call habits instead __stdcall. 2- Export a simple "C" style function, no C class or member function. 3 - Make sure you have an extern "c" {} surrounded by your function prototype. 4 - Create a #define for each export function name in your DLL header file. #Define will call the precompiler to add an underscore in front of each function. Because we just want to create an alias for MSVC, the code checks _msc_ver. #Ifdef _msc_ver #define foo _foo #define bar _bar # ENDIF5 - Copy the DLL and DLL header files to the MSVC project directory. 6 - Run the impdef for the DLL function DEF file. > Impdef mydll.def mydll.dll7- Use Microsoft's lib tool to create a COFF format for the DEF file. > Lib / def mydll.def8 - Add lib.exe to the lib.exe to the MSVC project. Technology 4: Use __stdcall function implicit connection --------------------------------------- -------------------------------------- 1 - Use __stdcall call when building your DLL habit. 2- Export a simple "C" style function, no C class or member function. 3 - Make sure you have an extern "c" {} surrounded by your function prototype. 4- Create an introduction library for MSVC. This part is more difficult. You can't create an introduction library with lib.exe to the __stdcall function. You must create a fake DLL compiled by MSVC. Doing this, press these steps: 4A- Create a DLL 4B-DLL 4B-copy from BCB to copy the DLL header file and DLL source code 4c- edit your DLL source code, let the function body of each routine Some, use a fake return value to return 4D-Configure the MSVC engineering generated DLL, use the name of the BCB DLL 4E-Add the DEF file to the MSVC project, prohibit it to modify the __stdcall naming (_foo @ 4) 5 - Compiling the false DLL project from step 4. This will generate a DLL (you can throw it into the trash) and a lib file (this is what you need).
6 - Add the lib file obtained from step 5 to you need to call this BCB DLL MSVC project. The lib file ensures connection. Configuring BCB DLL (not false DLL) for MSVC executables. note:
Under normal circumstances, implicit connections are prioritized than explicit connections, as it is easier to connect to programmers, and it is safe (error when the error is connected instead of runtime). Regardless of the method of use, when you share a DLL between the compiler, if you choose to stick to the implicit connection, you must create a compatible introduction library for each compiler. Creating a compatible introduction library is to pay attention to more requirements than using explicitly increasing burden.
note:
If you want your DLL to be used by Visual Basic's developers, explicitly connected guidelines is equally applicable. If you want to give your DLL to the VC developer, use the __stdcall call habit to use the explicit connection guidelines.
Each technique is described in detail below. Example 1: Explicit connection This example details the guidelines of the previous section of the technical 1. The guidelines of technology 1 can be divided into two groups. 1-5 Processing DLL in BCB, 6-9 items, using DLLs on MSVC. We will discuss this main line. In this example, we will build a DLL with BCB, which exports two functions: foo and bar. Both functions returns a full value. Function original is: int Foo (int value);
Int bar (void);
Then we built a test exe in the MSVC to call the Borland DLL. Compiling DLLs under BCB The following two programs contain our DLL source code. Listing 1 To share the header file shared between BCB and MSVC; Listing 2 contains our DLL function implementation section. Create a BCB DLL project to paste the code from Listing 1 and 2 to the project. Or you can download the source code of this article to save time. BCB DLL project has been set up for you. (See the bottom download section) / / -------------------------------------------------------------------------------------------------------------------------------- --------
// listing 1- DLL Header File
#ifndef bcbdll_h
#define bcbdll_h
#ifdef __cplusplus
Extern "C" {
#ENDIF
#ifdef build_dll
#define import_export __declspec (dllexport)
#ELSE
#define import_export __declspec (dllimport)
#ENDIF
Import_export int __cdecl foo (int value);
Import_export int __cdecl bar (void);
#ifdef __cplusplus
}
#ENDIF
#ENDIF
// ----------------------------------------------
// ----------------------------------------------
// listing 2- DLL SOURCE CODE
#include
#pragma HDRSTOP
#define build_dll
#include "bcbdll.h"
INT __CDECL FOO (int value)
{
Return Value 1;
}
INT __CDECL BAR (VOID)
{
Static int Ret = 0;
Return Ret ;
}
// ----------------------------------------------
About the header file has two places to pay attention to. First, observe that the method we use extern "C" to ensure that the function name will not be adapted by the C compiler; secondly, it is noted that the export function has a special indication prefix __declspec (DLLEXPort) when we build a DLL. When we use the DLL from the MSVC, the function prefix becomes __declspec (dllimport). The change in this indication is implemented by the Import_Export macro. Finally, note that we explicitly declare __cdecl as call habits. Technically, we can omit the __cdecl keyword because __cdecl is already default. However, I want to listen out to it. It is a good habit. By listing the call habits, you explicitly tell people that you choose __cdecl as a premise. Similarly, the default call habit can change by compilation switch in two compilers. You definitely don't want these compiler switches to affect the availability of your DLL. The header file itself meets 1-3 items in the guidelines. The next thing we need to do is to process the 4th item: establish an alias for the export function. First, build a DLL code according to the current situation. Second, the function name that runs the TDUMP tool check function contains the previous underscore. C:> TDUMP -M -EE BCBDLL.DLTURBO DUMP VERSIG 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 = '___ cppdebughofhook'
note:
Don't forget to use the -m switch when using TDUMP. TDUMP Try Anti-Adaptation The name is modified, making them easier to read. However, when you check a DLL, wise choice is to view the original format of the function. The -m switch tells TDUMP to display the original function name.
As you can see, Foo and Bar include front-end underline. As for __cppdebughof, you can ignore it, it is behind the scenes, when it doesn't have it. It doesn't make sense to you, you can't let it go, so don't put it in your heart. In order to remove the underline with an alias, we need to do three things: first create a DLL DEF file; then adjust the DEF file, create a MSVC alias for the Borland name; Finally, add the DEF file to your BCB engineering, rebuild the DLL. To create a DEF file, run the iMPDef tool for the DLL. C:> Impdef BCBDLLLX.DEF BCBDLL.DLL
I chose bcbdllx.def as a file name, because later (before we create MSVC introduction library), we will use other DEF files. I want to avoid confusion. The BCBDLLX.DEF content is as follows: library bcbdll.dll
Exports
_Bar @ 1; _bar
_Foo @ 2; _foo
___Cppdebughbook @ 3; ___cppdebughofhook
Note the underscore in the front end of the Foo and BOO. If the DLL exports the foo and bar to _foo and _bar, the connection error will be seen when the MSVC user is trying to build their project. We need to strip downline. We have implemented the method of the function alias in the DEF file. The DEF file alias allows us to export a function name that acts as a proxy or placeholder for real functions. The real function in the DLL is still _foo and _bar. Agent name will be Foo and Bar (notice that there is no underscore). When we give two functions alley, the DLL will export two symbols that are homologous to the original function. Complete alias, edit the DEF file, change to the following: library bcbdll.dllexports
Bar = _bar
Foo = _foo
This DEF file creates two new exits, foo, and bar, which acts on _foo and _bar point characters respectively. Save this DEF file to your hard drive. Once you have completed these work, you can add the DEF file to your BCB engineering, use the Project-Add menu item. After adding, BCB will display a DEF file in the tree structure of the Project Manager. Once you join the DEF file to the project, make a complete reconstruction. After the engineering connection, run TDUMP again to the DLL, check the underlined function exported from the DLL. > 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 = '___ cppdebughofhook'
There are two things to pay attention to the output of TDUMP. First, observe Foo and Bar (there is no front end underline). Now the DLL export function name is consistent with MSVC. Still notice the original function, _foo and _bar, still there. The modified function is still exported from the DLL. Using the DEF file alias does not hide the original function. You may want to hide this two functions. However, this will hazard to people who use DLL from BCB Engineering. Remember that the BCB connector expects to have a front end underline. If you really use what method hide from _foo and _bar (in my knowledge is impossible), then your DLL will be called very difficult from the BCB. If the output of TDUMP does not list a proxy function (without a downline function), then return to the previous step and check your DEF file. You need to get an aliased appearance before you can continue. If the DLL looks OK, it is time to go to MSVC. Adjust from the MSVC DLL Once you have a DLL model that is an anti-modified __cdecl function outlet, the next step is to generate an introduction library for the MSVC user. For this, you will need to create a DLL that uses Borland's ImpDef utility (again), and lib.exe tool from MSVC. The first step is to create a DLL DEF file. For this, I suggest you copy the DLL and DLL header to your MSVC project catalog, work there. C:> impdef bcbdll.def bcbdll.dll
Impdef will create a DEF file, the content is as follows: c:> impdef bcbdll.def bcbdll.dll
Library BCBDLL.DLLEXPORTS
Bar @ 4; bar
Foo @ 5; foo
_BAR @ 2; _bar
_Foo @ 1; _foo
___Cppdebughbook @ 3; ___cppdebughofhook
Open the DEF file, change its content: library bcbdll.dll
Imports
Bar @ 4; bar
Foo @ 5; foo
Note that we removed the functionality that contains underscore, and debug hook functions. We also changed Export to Imports because we are now introducing functions, not exporting them (I suspect that it will be different for MSVC LIB.exe). Next, we use Microsoft Lib.exe to create a copy of the Coff format from the DEF file. The grammar is: lib /def :bcbdll.def /out :bcbdll_msvc.lib
note:
The MSVC command line utility is not in your configuration by default. You may need a batch file that runs an MSVC band, so that lib.exe can be called directly. The batch file is called vcvars32.bat, which is located in the / vc / bin subdirectory of the DevStudio installation path.
Here, all hard work is done. Now you need to do your DLL, MSVC lib file, and DLL files to your MSVC client. To use a DLL, you need to add a lib file to the MSVC engineering, and in the source code #include dll header file. I have prepared a simple project of MSVC to prove the above concept. Listing 3 gives the source code for the client DLL. Nothing special place is a main function, a #include of a DLL header file, and several functions to the DLL. Mainly, you have added the introduction library correctly, which is added to the MSVC engineering by lib.exe. // ----------------------------------------------
// Listing 3- MSVC DLL Client Code
#include
#include
Using namespace std;
#include "bcbdll.h"
int main ()
{
COUT << "foo (10) =" << foo (10) << Endl;
COUT << "bar () =" << bar () << Endl;
COUT << "bar () =" << bar () << Endl;
COUT << "bar () =" << bar () << Endl;
Return 0;
}
// ----------------------------------------------
Example 2: Explicit connection This example shows you how to compile the BCB from the MSVC to call the BCB. With explicit connections, you don't have to settle the creation of an MSVC compatible introduction library. It is not good for that it needs to do more work in the user, it does not have a secure connection type, error is extended to runtime instead of connection. Although there are many unfavorable factors in explicit connection, it is still very useful in some cases. In this example, we will create a DLL that exports two functions: foo and bar. The prototype of the function is the same as the previous example. Int foo (int value); int BAR (void);
This explicit connection guidelines are similar to implicit connections. We need to export simple C functions and need to prevent C names to adapt. If we use __cdecl call habits, then we may want to establish an alias for the function of BCB to remove the underscore. If we choose to remove the next line, we must contain underscores when you use the name to load the function. In other words, when you play the __cdecl function, you must process the underscore at some point. You can also process underscores when you build a DLL, or process it when you call the DLL at runtime. We use __stdcall instead __cdecl to avoid the next line problem of the entire discussion. This is what we have to do in this example. The source code given by the list 4 and 5.
note:
If you export the __stdcall function, it is critical to let the client application know. Some people are prone to a mistake, thinking that using __stdcall is just the underscore in front of the __cdecl function. Don't fall into this trap. __stdcall function processing stack mode is also __cdecl is different. If the client application calls __stdcall as a __cdecl function (that is, the stack will be destroyed, the client program will die very difficult), some errors will occur.
// ----------------------------------------------
// listing 4- DLL Header File
#ifndef bcbdll_h
#define bcbdll_h
#ifdef __cplusplus
Extern "C" {
#ENDIF
#ifdef build_dll
#define import_export __declspec (dllexport)
#ELSE
#define import_export __declspec (dllimport)
#ENDIF
Import_Export Int __stdcall foo (int value);
IMPORT_EXPORT INT __STDCALL BAR (VOID);
#ifdef __cplusplus
}
#ENDIF
#ENDIF
// ----------------------------------------------
// ----------------------------------------------
// listing 5- DLL SOURCE CODE
#include
#define build_dll
#include "bcbdll.h"
INT __STDCALL FOO (INT VALUE)
{
Return Value 1;
}
INT __STDCALL BAR (VOID)
{
Static int Ret = 0;
Return Ret ;
}
// ----------------------------------------------
Note that this code is almost the same as implicit connection. The only different place is to change the Calling habits of Foo and Bar to __stdcall instead __cdecl. Let's take a look at the MSVC program code for calling the DLL. The code is shown in Listing 6. / / ---------------------------------- // Listing 6- MSVC Client Code
#include
#include
Using namespace std;
Hinstance HDLL = 0;
TypedEf Int (__stdcall * foo_type) (int value);
TYPEDEF INT (__stdcall * bar_type) ();
FOO_TYPE FOO = 0;
BAR_TYPE BAR = 0;
Void dllinit ()
{
HDLL = LoadLibrary ("bcbdll.dll");
Foo = (foo_type) GetProcaddress (HDLL, "FOO");
Bar = (bar_type) getProcaddress (HDLL, "BAR");
}
Void DLLFree ()
{
Freelibrary (HDLL);
}
int main ()
{
Dllinit ();
COUT << "foo () =" << foo (10) << ENDL;
COUT << "bar () =" << bar () << Endl;
COUT << "bar () =" << bar () << Endl;
COUT << "bar () =" << bar () << Endl;
Dllfree ();
Return 0;
}
// ----------------------------------------------
There are many places that need to be digested in this code snippet. The first is also the most important, and the observation code itself is the compiler. You can compile it in BCB or MSVC. I first compiled it in BCB and confident that it can work according to what I think. Second, notice that the code is not worried about #include bcbdll.h. There is an important reason. BCBDLL.H is the prototype defined by the Foo and BAR function. However, we don't connect our code with any predefined prototypes. Typically, these prototypes come from the introduction library. But this example demonstrates explicitly connected. When you display the ground, it is not used in the introduction library, and the Foo and BAR prototypes in the header file are not much significant. Thirdly, things are the TypeDef and function pointers that appear in this code, located near the top of the source file. The sway connection requires you to get the address of the DLL function with API GetProcadDrress when running. You must store the results returned by getProcAddress to a place. The best location is to store the results into the function pointer. By storing the function address to the function pointer, you can use the normal function to call the syntax call function (such as Foo (10)). The TypeDef declaration creates two new types: foo_type and bar_type. They are all function pointer types. Foo_type declares a type of __stdcall function, this function is a complete parameter, returns a integer value. BAR_TYPE defines a function that points to __stdcall type, no parameters, with a full return value. These typedef have produced two effects. First, they provide a clear way to declare the function pointer variables foo and bar. Second, they make us very convenient to convert the results returned by getProcAddress. The result returned from getProcAddress is a function that points to __stdcall type, no parameters, with a function of an integer return value. Unless your function is the same as this format, you need to convert the result of getProcadDress (this conversion is the reason why the explicit connection is more securely connected to the implicit connection.). There are two variables foo and bar in Typedef. These two are function pointer variables. They will save the address of the two functions we want to call. Note that the names of these variables are arbitrary. I choose Foo and Bar to make the code like implicit connection. Don't make such errors, the Foo and BAR variable names are not established with the real functions in the DLL. We can name the variable Guido and Bjarne if you want. In the function pointer declaration, you will see two function entities called Dllinit and DLLFree. These two entities are loaded into the DLL, find the export function, and release the library after we use the game. With this method, the rest of the code doesn't know that the DLL is explicitly connected. It can call foo and bar (or guido and bjarne if you change the name). The only thing to coordinate is that you must call DLLINIT before calling any DLL programs. We should also be meticulous and call the DLLFree release library. note:
When the Borland compiler and the Microsoft compiler, getProcAddress is your last line of defense. This includes borland __cdecl named a front-end underline (such as _foo). Also included adaptation C names. If someone supports the DLL you use to adapt the function name, you can pass these grunge parameters, put the adaptive name to getProcAddress. No matter what you can actually call the function, you have not encountered anything else, but at least you will have a chance.
this is all. Compile the code in MSVC, you will do it. You don't have to play the DEF file or introduce the library. But there are some trivial work in your code. Example 3: Using #define Implicit Connection This example shows the simplest way to call BCB DLL from the MSVC engineering, but it may also be a way to have the most attractive. The code uses a cunning #define, when checking the __cdecl function, add the underscore before the Microsoft compiler. That is, we have simple #define foo as _foo. The advantage of this technology is that we do not have to implement any alias. We can directly export the __cdecl function containing the underscore. However, we must still create an MSVC-compatible introduction library with Microsoft's lib.exe. This technology is that the key is that the MSVC is not expected to have any modifications (see Table 1). They should look like it looks like. If the MSVC application tries to execute a __cdecl function foo, it expects to find a function foo without underscore in the DLL. If we change the MSVC code, let it call _foo, then it will try to find a function called _foo in the DLL. Borland gave the __cdecl function before adding the underscore. We can kid the MSVC, let it add a next line in front of the function name when calling the function. I just want to add a next line in MSVC, instead of Borland. #Define assembled DLL code is exactly the same as the code of the list 2 in Example 1. The only difference is a DLL header file. When the MSVC is detected, the DLL header is added to each function prototype. Listing 7 shows the modified header file. / / ---------------------------------- // Listing 7-DLL Header File
#ifndef bcbdll_h
#define bcbdll_h
#ifdef __cplusplus
Extern "C" {
#ENDIF
#ifdef build_dll
#define import_export __declspec (dllexport)
#ELSE
#define import_export __declspec (dllimport)
#ENDIF
// #define kludge. if We Are Being Compiled with MSVC, The Just Tack ON A
// LEADING Underscore Because Borland C Will Export Foo and Bar AS _foo
// and _bar respectively
#ifDef _MSC_VER
#define foo _foo
#define bar_bar
#ENDIF
Import_export int __cdecl foo (int value);
Import_export int __cdecl bar (void);
#ifdef __cplusplus
}
#ENDIF
#ENDIF
// ----------------------------------------------
In the header file, except #define assembly, you must also create an MSVC compatible introduction library. You can do it in front of the steps. Run the compiled DLL to run the impdef to get a DEF file. Then run the Microsoft Lib.exe tool to create an introduction library in a COFF format. At this time, you don't have to consider editing the DEF file. Finally, copy DLL, Coff introduction library, and DLL files to your MSVC project. Add the lib file to your MSVC project, rebuild. This is a command line example of creating a MSVC introduction library. Note that we don't have to edit DEF files. We just pass it to lib.exe. // Create Def File> Impdef BCBDLL.DEF BCBDLL.DLL
// Create Coff Import Library Using MS LIB.exe
> lib / def bcbdll.def
Example 4: Using the __stdcall function Implicit Connection Before we conduct, let us investigate why we need to discuss the __stdcall function separately. The MSVC does not provide a tool with a Borland's IMPLIB. You can't draw a DLL, generate an introduction library available for MSVC. The closest tool is lib.exe, which can create an introduction library through a DEF file. The DEF file must be manually created, or use Borland's IMPDEF tools to generate. Nothing is not big? You can still create a MSVC introduction library, just create a DEF file through the intermediate step, then pass it to the lib.exe tool. Correct, when you use the __cdecl function. When you go to __stdcall, the problem happens. The problem is that Microsoft's lib.exe tool is unable to generate the DLL generated library for export __stdcall functions. For this reason, I use __stdcall implicit connection to separate as part of it. We need to create a Microsoft compatible introduction library with the order of different steps. (Also noted that I put this part of the last good reason, at least these steps are long-takingable). Since we can't use lib.exe to generate introduction libraries with __stdcall's BCB DLL, we need to propose a different policy. There is a way to generate an introduction library (which may be a unique method), depending on however, as long as you build a DLL, MSVC can generate an introduction library. If you build an MSVC DLL that contains the __stdcall function, the compiler, and connector will correctly decompose the export __stdcall function, generate the introduction library. Then you will ask how it will help us? After all, we are using Borland C compile DLL. What is the benefit of creating a DLL project in MSVC? We want EXE to compile with MSVC, but the DLL should remain in BCB. The answer to this question is that we compile false DLL projects in MSVC, the only purpose is to generate an introduction library of __stdcall. The DLL created by MSVC can be thrown into the trash. We don't need it. This technology is based on a false DLL project. We created a false DLL project in MSVC, which is the benefits of generating Microsoft compatible introduction libraries. So we can combine this introduction library and BCB, and then provide the MSVC user so that they can call our Borland DLL with the __stdcall function. This is a few steps necessary for this technology. First, compile your DLL with BCB. Use __stdcall call habits, export simple C functions, and package all declarations with Extern "C". The DLL code is the same as the code of the list 4 and 5 in Example 2, so I don't list them again. The second step is to create a false DLL project in MSVC. Compile false DLL projects, stealing the generated introduction library. The final step is to add this introduction library to any MSVC project to call the Borland DLL. The most challenging of this technology is the genes surrounding false DLL projects and introduction library. Build a false DLL project, create a Non-MFC DLL workspace with MSVC. Edit the MSVC engineering settings to make the function generated DLL matches the name of the BCB DLL (in our example is BCBDLL.DLL). This setting can be found under Project-Settings-Link. Copy your DLL header file source code to the false DLL project directory from the Borland project directory. If your project consists of multiple CPP files, simply copy the header file containing the export declaration. Add a CPP source code file to a false work area. Next, enter the definition of each export function, delete the code for each function entity. By ending with a bunch of empty functions. If the function has a return value, returns the return statement in the appropriate location. Just some false return values (such as 0).
Remove any unnecessary #include statement (you should be able to move some #include because all of the function bodies are empty). Our BCB DLL and Example 2 list 4 and 5 contain the same code. Listing 8 shows the same version of the version being trimmed. This trimming version is added to the false DLL workspace. / / ---------------------------------- // Listing 8- Dummy DLL Source Code
#define build_dll
#include "bcbdll.h"
INT __STDCALL FOO (INT VALUE)
{
Return 0;
}
INT __STDCALL BAR (VOID)
{
Return 0;
}
// ----------------------------------------------
At this time, we should be able to compile false DLL work in MSVC. But before we compile, we must reach a step to fight some features of the Microsoft compiler. Our false DLL export __stdcall function. When the Microsoft DLL exports the __stdcall function, it usually has made a modification to make a function name, adding a front end underline, attaching the '@' symbol and the end of a number (see Table 1 at the beginning of the article). For example, FOO will be exported to _foo @ 4. This is not what we want. The full purpose of the false DLL is to generate an MSVC introduction library for our BCB DLL. Our BCB DLL contains simple, no underscore, __ stdcall functions (foo and bar). It did not bring any benefits to the generated introduction library, because the name of the modified name (_foo @ 4 and _bar @ 0) does not match the DLL contains simple, no underscore, __ stdcall functions (foo and bar). It does not bring any benefits to the generated introduction library, because it does not match the name of the modified name (_foo @ 4 and _bar @ 0). Fortunately, we can prevent the MSVC to modify the false __stddcall function, the method is to add a DEF file to the false DLL project. The DEF file simply lists each function to be exported. The content is as follows: Library BCBDLL.DLL
Exports
Bar
Foo
note:
The library name in the DEF file should match the false DLL name generated by the MSVC, and it should match the DLL name created with BCB. If these three do not match, you will run a variety of different errors (usually unresolved connector errors).
Add a DEF file to a false DLL project to build a false DLL. When MSVC builds a DLL project, it creates an introduction library. This introduction library is to let MSVC users can call the key factors of the BCB DLL exported __stdcall functions by implicit connection, and provide it with your DLL to MSVC users. Your users should add this introduction library to any MSVC project that calls your BCB DLL. Conclusion This article provides four technologies that allow Microsoft Visual C to call DLL compiled by BCB. I hope this article is very sufficient to describe each technology (these content is not easy to understand). In order to help you understand each technology, I have made an example code for each of the commercially used technologies, which can be downloaded from here. The zip file decompresses four subdirectories, one corresponding to one technology. Each subdirectory contains a DLL directory with BCB5 DLL projects, and an EXE directory for calling the MSVC project of BCB DLL. The MSVC project is VC 5 project, but they should work properly under MSVC 6. download
This article downloads the source code of all 4 technologies of BCBDLL.zip (130 KB).