Link to home
Start Free TrialLog in
Avatar of mortenj
mortenj

asked on

Calling a standard DLL from Visual C++

I'm using MS Visual C++ 6.0

I have a DLL called "Adding". It's programmed in Borland Delphi (that really doesn't matter). I know the dll exports a function called "Add" which has the following header (in C++):

int __stdcall Add(int X, int Y);

Now I want to call the "Add" function from Visual C++. So I create a LIB-file by first creating a DEF file with the following content:

LIBRARY
  Adding
EXPORTS
  Add

and call lib from the commandline:
lib /DEF:Adding.def

And a LIB file is created. I also create a header file with the following content:

#ifdef __cplusplus
extern "C" {
#endif

int __stdcall Add(int X, int Y);

#ifdef __cplusplus
}
#endif

When I compile my project everything works fine, but the linker complains that it can't find a function called "_Add@8".

How do I make the LIB-file know that the decorated name "_Add@8" should link to the undecorated name "Add" in the DLL?

It must be possible, because if you inspect the DLL's that come with Windows then they contain no decorated names; but the LIB-files that ships with Visual C++ contains decorated names that links to the undecorated names in the DLL's!

Has Microsoft a secret trick, or am I missing something?

Thanks
Morten
Avatar of jkr
jkr
Flag of Germany image

>>Has Microsoft a secret trick, or am I missing something?

I assume that it is a problem resulting of the MS/Delphi combination.

Try

dumpbin /exports adding.dll

to see with what naming convention the function is exported
Avatar of mortenj
mortenj

ASKER

I have tried dumpbin /exports adding.dll it gave the following result:

Dump of file adding.dll

File Type: DLL

  Section contains the following exports for Adding.dll

           0 characteristics
           0 time date stamp Thu Jan 01 01:00:00 1970
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00003B4C Add

  Summary

        1000 .edata
        1000 .idata
        1000 .reloc
        1000 .rsrc
        1000 BSS
        3000 CODE
        1000 DATA

As far as I can see it only exports "Add" (it looks very much like the result you get by using dumpbin on a DLL that comes with Windows).
To continue that thought, if the dll exports a function called "add" not "_add@8" this suggests that the function is not using the standard call calling convention, and might be using the C-decl calling conbnetion.  so you will need to make sure that you call the function with the right calling conbention.  (Although I would have thought that delphi does use standard call by default, but I'm not sure.)

>> How do I make the LIB-file know that the decorated name "_Add@8"
>> should link to the undecorated name "Add" in the DLL?
Changing to the cdecl calling convetion will remove the standard call decoration you see.  Howver it is possible that you still want the standard call calling conbention, just not the deocration  
In that case try

nt __cdecl Add(int X, int Y);

That should link.  But it might crash when you call it.  Just try it and see.
>>When I compile my project everything works fine, but the
>>linker complains that it can't find a function
>>called "_Add@8".

Hmm, the underscore sort of says that the compiler uses the 'C' naming convention - see a related MSJ article at http://www.microsoft.com/msj/defaulttop.asp?page=/msj/archive/s330.htm

Try to alter your .der file:

LIBRARY
 Adding
EXPORTS
 _Add=Add
Avatar of mortenj

ASKER

1) The dll is using stdcall calling convention. It's produced by Delphi, and Delphi doesn't add any name decoration to stdcall functions (it produces DLL's that looks like the Win32 API DLL's)

2) If I did use cdecl calling convention, then everything works fine using the sceme I described - I get no linker errors. But to make the DLL look as much as possible as a Win32 API DLL I prefer the stdcall calling convention!

I guess I can formulate my question another way:
"Suppose you have a Win32 API DLL and a piece of paper describing the exported functions. Lets say you've lost the according LIB-file that comes with Visual C++. Is there a way you can use that DLL from Visual C++? (i.e. you have to create the LIB-file yourself)"

The article jkr gave a link to, sort of indicates that you can't - this means that if you want to create a DLL that people can use from any programming language (like a Win32 API dll) you get stuck using Visual C++...

But again how does Microsoft do it? Are the Win32 API DLL's created using Visual C++ (in which case the LIB-files are generated automatically)?

Btw. My current solution is to export two functions from the Delphi DLL: one named "Add" and one named "Add@8" and they both point to the same internal function in the DLL. My DEF-file then looks like:
LIBRARY Adding
EXPORTS
  Add
  Add@8
Note that "lib /DEF:Adding.def" automatically adds the underscore in front of the names.
It works but it's not elegant!!

Thanks for all your comments/answers - I'm still hoping for a nifty workaround!

Morten
>>  If I did use cdecl calling convention, then everything works fine
>> using the sceme I described - I get no linker errors.
But if you are right that the function uses stdcall as the calling convention then everything shoudl liknf fine, but should not run fine.  It should crash when you call the function.   Does it?  if it does not then the function is not stdcall.

>> Is there a way you can use that DLL from Visual C++?
>> (i.e. you have to create the LIB-file yourself)"
You can create an import library from a DLL.  but you alredy have the import library, right?  Otherwise you couldn't have gotten this to link.

Avatar of mortenj

ASKER

>>But if you are right that the function uses stdcall as
>>the calling convention then everything shoudl
>>liknf fine, but should not run fine.  It should crash
>>when you call the function.   Does it?  if it
>>does not then the function is not stdcall.

That's excatly the point!! It doesn't link!! When you compile a DLL with Delphi using stdcall then the DLL exports the exact name (i.e. "Add") and you will get no LIB-file you can use with Visual C++ (I create the DLL in Delphi myself, so I _know_ that it uses stdcall).

When you compile a DLL with Visual C++ using stdcall it exports "_Add@8" (try it yourself). But you can make the DLL export only "Add" by using a DEF file - but when you create a DLL in Visual C++ you automatically create a LIB-file, and this LIB-file will in any case contain "_Add@8" so you can allways call the DLL from Visual C++ programs without any problems.

I only have the Delphi DLL and no LIB file!!! And if I create a LIB-file using the lib-commandline-tool then this LIB-file will only contain reference to "_Add" (underscore added automatically), but the Visual C++ linker requires that the LIB-file contains reference to "_Add@8".

>>You can create an import library from a DLL.  but you
>>alredy have the import library, right?  Otherwise
>>you couldn't have gotten this to link.
I can't link it!! What I'm asking is:

If I give you a DLL which exports a function called "Add" and I tell you that the function has the following header:

int __stdcall Add(int X, int Y);

Can you with only these two informations (no LIB-file or anything else), create a Visual C++ program that use this DLL?

I know I can create a program in Delphi, Borland C++ and others without any problems - but I can't in Visual C++!!

Morten



Did you try modifying the .def file?

LIBRARY
Adding
EXPORTS
_Add=Add

should give you the name mapping and allow you to stay with '__stdcall'...
Avatar of mortenj

ASKER

>>Did you try modifying the .def file?
>>LIBRARY
>>Adding
>>EXPORTS
>>_Add=Add
>>should give you the name mapping and allow you to stay
>>with '__stdcall'...

Yes I tried that, but the leading underscore is not the problem, it's the @8 in the end. If you think about it, it seems reasonable that lib cannot create a lib-file containing a reference to "_Add@8" when it from the DEF-file doesn't the number and type of parameters that Add takes...
>>  you will get no LIB-file you can use with Visual C++
Its not the lib file that is the problem.  its the DLL.  The lib file will just reflec the exported name that appears in the DLL's exports lits.   You coudl create a doctored LIB file that had the decorated name, but then when you ran your program it would fail to dynamci link with the DLL and windows would termiante it.

The "problem" is not in the lib, its in the DLL

>> Icreate the DLL in Delphi myself, so I _know_ that it uses stdcall).
A simple fix would be to use cdecl in the DLL then.

>> Can you with only these two informations (no LIB-file or anything
>> else), create a Visual C++ program that use this DLL?
You can always use explicit linking to make the link.  I.e. load the DLL with LoadLibrary() and then find the function using its undecorated name in GetProcAddress().

but jkr believes that you can use an alias in your program's module definition file (.DEF) to make this link implicitly.  i don't know if that is right or not, but knowing jkr I would certainly try it before giving up!!! Did you try it?
LIBRARY
Adding
EXPORTS
_Add@8=Add
The "_Add@8" you got is the Microsoft C++ mangling of your function symbol. Every C++ compiler mangles C++ symbols because C++ functions may have overloads which have the same name but with different parameters.
Well, you just delete the #ifdef - #endif pair and your code will get compiled. Just like this:

extern "C" {

int __stdcall Add(int X, int Y);

}

This references exactly the "Add" symbol, and is exactly an stdcall function with 2 32-bit int parameters.
Avatar of mortenj

ASKER

>>LIBRARY
>>Adding
>>EXPORTS
>>_Add@8=Add

First: the leading underscore is added automatically by lib-commandline-tool, so to make it link you have specify:
LIBRARY
Adding
EXPORTS
  Add@8=Add

And yes this will make the program link!! But an error will arise when you run the diagram: "The procedure entry point Add@8 could not be located in the dynamic link library Adding.dll"

You can actually test this problem using only Visual C++. If you create the Adding.dll in Visual C++ using the following code:

int __stdcall Add(int A,int B)
{
  return A+B;
};

and include the following DEF-file:

LIBRARY  Adding
EXPORTS
  Add

Delete the LIB-file created when you compiled the DLL, and thereafter try to use the DLL in a Visual C++ program.
Avatar of mortenj

ASKER

To westaf:

No not excatly, Visual C++ also adds what is known as "__stdcall name mangling" this means that

extern "C" {
  int __stdcall Add(int X, int Y);
}

is interpreted by the Visual C++ linker as "_Add@8" - even thoug you use extern "C"!!!


>> Every C++ compiler mangles
>> C++ symbols because C++ functions may have overloads
No, this is not the C++ decoration.  The extern "C" removes that.   This is the windows standard call decaration which is unrelated.  It expreses the size of the parameters in bytes.  This is an attempt to insure that the caller and called function agree on the parmaeter size since that is extremely important when using standard call.  its less of a problem--slightly--in c-decl.

Is there a reason why you have to use standard-call?

How impractical would it be to use explicit linking?
>>Is there a reason why you have to use standard-call?

It's a Delphi DLL, if I'm not mistaken...

I would think delphi would still have c-decl as an option.  wsprintf() is c-decl for instance, there might be others.  it can't use those OS features without the ability to make c-decl calls.
Avatar of mortenj

ASKER

Yes I could use cdecl calling convention (and everything would work fine) - but I just thought that if you create a DLL which people can use with their preferred compiler/language, then you should stick to the stdcall calling convention, because this is the calling convention used in the Windows API (so all compilers should be able to link to the DLL). It then turns out that you the only problem is Visual C++, which can't use stdcall DLL's except if they are created in Visual C++... Bummer...

To nietod: Yes I could use explicit linking, but it's very impractical...

I think I'll stick with the solution of making Delphi export both "Add" and "Add@8" - i.e. to use Visual C++ you need a twice as big export table in your DLL...
ASKER CERTIFIED SOLUTION
Avatar of Wolfie320
Wolfie320

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Wolfie320, this question is nearly a year old!
I know... but if someone have this kind of problem, like I did. They may wan't to have some sort of answer.
This is a common problem when using VC++ and extern "C" __stdcall
In that case post it is a comment not an answer.  The question has been abandoned.
Dear morteni

I think you forgot this question. I will ask Community Support to close it unless you finalize it within 7 days. You can always request to keep this question open. But remember, experts can only help you if you provide feedback to their questions.
Unless there is objection or further activity,  I will suggest to accept

     "wolfie320"

comment(s) as an answer.

If you think your question was not answered at all, you can post a request in Community support (please include this link) to refund your points. The link to the Community Support area is: https://www.experts-exchange.com/commspt/

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
======
Werner