I am looking for the correct method to create a DLL in C++ and call it in Delphi. I use CodeBlocks for the DLL and Delphi RAD Studio 10.2.
My C++ header and source code for building the DLL as described in How to create dll in C++ for using in C# is as follows:
Main.h:
#ifndef MATH_HPP
#define MATH_HPP
extern "C"
{
__declspec(dllexport) int __stdcall math_add(int a, int b);
}
#endif
Main.Cpp :
#include "main.h"
int __declspec(dllexport) __stdcall math_add(int a, int b)
{
return a + b;
}
This code in CodeBlocks builds math_dll.dll without any error.
Calling the DLL in Delphi:
function math_add(X, Y: Integer): Integer; stdcall; external 'math_dll.dll' name 'math_add';
But when I run Delphi and call this function, I have the following error:
"the procedure entry point math_add could not be located in the dynamic link library math_dll.dll"
Which part of my code is wrong?
The default name mangling for the __stdcall calling convention is _<name>#<bytes_in_arguments>. So your DLL function is most likely being exported as '_math_add#8' instead of as 'math_add' like you are expecting. Use a tool like PEDUMP to verify that.
You can use a .DEF file when compiling the DLL to change the exported name, or you can update your Delphi function declaration to use the correct exported name for the name attribute.
I am totally new in C++ and starting with creating a simple dll and console app that tests the dll. The dll plugin afterwards should work on x86 machines (diag tools, ECU or PLC). The samples given to me that I fallow the same structure exports dll function as __sdcall. so my helloWorld project looks like:
plugin.dll
-----------
plugin.h
#pragma once
#include "types.h"
#define EXPORT extern "C" __declspec (dllexport)
EXPORT S32 WINAPI Greetings(string *str);
plugin.cpp
#include "plugin.h"
#include "types.h"
S32 __stdcall Greetings(string *str){*str = "Hello From Plugin!"; return -1;}
and the console app looks like: (both are in same solution, project/properties/cc++/adnvances/callingConvention = __cdecl (/Gd))
VS settings - Solution configuration=debug, Solution Platforms=x86
main.cpp
HMODULE DllHandler = ::LoadLibrary(L"plugin.dll");
string greetingText;
typedef U32(*Type)(string*);
Type greetings = reinterpret_cast<Type>(GetProcAddress(DllHandler, "Greetings"));
greetings(&greetingText);
cout << greetingText << endl;
Now, without plugin.def the GetProcAddress(DllHandler, "Greetings") returns null (0x000000) with the plugin.def (alongside with EXPORT) I get the Greetings with decoration plugin.dll!Greetings#4 the call will succeed but get
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
also no casting with naming convention is allowed.
I red many posts about __cdecl __stdcall but mostly explaining the assembly level that who cleans the stack, or using either .def or extern "C" with export.
I totally got lost in naming convention and mangling in C++. is related to local project setting or the dll will run on all environments? specially in this sample project how should I handle it?
I have some code which is working on Unix (Linux and Solaris) and Windows (7 to be exact) but doesn't work on Windows CE. This code implements a plug-in framework and requires exporting symbols from the executable into the loaded plug-ins. I am unable to get the loaded plug-ins (DLLs) to resolve symbols from the main executable.
I have reduced the interface to a single function in the main executable which is defined as such:
extern "C" __declspec( dllexport )
const char * translate_name( const char *key ) {
...
}
If I run Dumpbin /EXPORTS on the executable I see this as one of the exported symbols:
81 50 00001474 translate_name = #ILT+1135(_translate_name)
The plug-ins are required to export two functions xxxLoadPlugin and xxxUnloadPlugin which the main executable will call after loading to allow them to interconnect. The xxx is replaced with an agreed upon name prefix (usually the dll or .so name). I have a test project which creates:
extern "C" __declspec( dllexport ) int testRegisterLibrary( ) {
return 0;
}
extern "C" __declspec( dllexport ) int testUnregisterLibrary( ) {
return 0;
}
If I compile and run this module everything will work as expected. I can load the dll, and walk through the functions in my debugger.
If I add code which references translate_name, such as:
extern "C" __declspec( dllimport ) const char * translate_name( const char *key );
extern "C" __declspec( dllexport ) int testRegisterLibrary( ) {
translate_name("test");
return 0;
}
extern "C" __declspec( dllexport ) int testUnregisterLibrary( ) {
return 0;
}
the DLL will now fail to load. Checking the created DLL with dumpbin /IMPORTS I see:
50 translate_name
translate_name is the only symbol imported from my main executable. If I try using GetProcAddress instead of relying on the linker, like this:
extern "C" __declspec( dllexport ) int testRegisterLibrary( ) {
HMODULE mainModule = GetModuleHandle(NULL); //handle for main executable
void *ptr = (void *)GetProcAddress(L"translate_name");
return 0;
}
extern "C" __declspec( dllexport ) int testUnregisterLibrary( ) {
return 0;
}
The DLL loads, but the value of 'ptr' is NULL (checked inside a debugger). I've also tried GetProcAddressA("translate_name"), and using "_translate_name" with the same results.
Given this it seems that the symbols that were exported by the executable are not retained after the initial loader pass in windows CE. Again, this works in any normal windows environment. Is there some setting I'm missing for windows CE? Why can GetProcAddress not find a symbol in the executable which dumpbin says is exported? Are the symbols being hidden or dropped by the windows CE loader?
Just to confirm your findings, this doesn't work. It is difficult to find hard evidence in the MSDN docs that this is not supported, other than that GetProcAddress() is adamant that the symbol must be exported by a DLL. You can't get the DLL loaded, it will fail with ERROR_BAD_EXE_FORMAT when it contains the import from the EXE. GetProcAddress() will always fail with ERROR_INVALID_HANDLE, even if you force the module handle to the EXE load address.
There's no strong evidence that the loader intentionally strips the export table of the EXE, it is resident in memory when you look with the debugger. It just categorically refuses to look at it.
You'll need to punt this problem and tackle this a different way. Beyond spinning off the helper functions in a separate DLL, an obvious workaround is that you provide the xxxLoadPlugin() entrypoint with an argument, a pointer to table of function pointers to the helper functions. The common IServiceProvider interface used in COM is a good approach.
I have been trying to call a DLL function in my VBA project but I keep getting this error message:
Run-time error '453': Can't find DLL entry point "CheckStatus" in "Power.dll"
Here is the definition for the DLL in the C++ file:
#define CLASS_DECLSPEC extern "C" __declspec(dllexport)
CLASS_DECLSPEC int __stdcall CheckStatus();
And here is how I'm trying to declare it and call it in VBA:
Public Declare Function CheckStatus Lib "Power.DLL" () As Long
Dim test As Long
test = CheckStatus
And then when I run it received the aforementioned error message.
Does anyone know how to fix this? Thanks.
This has to do with name mangling (even with extern "C").
Look at what export is really in the DLL, a guess would be either _CheckStatus or _CheckStatus#0.
To force the name to be as-is, make a .def file in your project with the content:
EXPORTS
CheckStatus=CheckStatus
using this MSDN article, I would try this method of declaring the function:
Public Declare Function CheckStatus Lib "Power.DLL" Alias "_CheckStatus#0" () As Long
I want to make a simple, simple DLL which exports one or two functions, then try to call it from another program... Everywhere I've looked so far, is for complicated matters, different ways of linking things together, weird problems that I haven't even begun to realize exist yet... I just want to get started, by doing something like so:
Make a DLL which exports some functions, like,
int add2(int num){
return num + 2;
}
int mult(int num1, int num2){
int product;
product = num1 * num2;
return product;
}
I'm compiling with MinGW, I'd like to do this in C, but if there's any real differences doing it in C++, I'd like to know those also. I want to know how to load that DLL into another C (and C++) program, and then call those functions from it.
My goal here, after playing around with DLLs for a bit, is to make a VB front-end for C(++) code, by loading DLLs into visual basic (I have visual studio 6, I just want to make some forms and events for the objects on those forms, which call the DLL).
I need to know how to call gcc (/g++) to make it create a DLL, but also how to write (/generate) an exports file... and what I can/cannot do in a DLL (like, can I take arguments by pointer/reference from the VB front-end? Can the DLL call a theoretical function in the front-end? Or have a function take a "function pointer" (I don't even know if that's possible) from VB and call it?) I'm fairly certain I can't pass a variant to the DLL...but that's all I know really.
update again
Okay, I figured out how to compile it with gcc, to make the dll I ran
gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--out-implib,libmessage.a
and then I had another program load it and test the functions, and it worked great,
thanks so much for the advice,
but I tried loading it with VB6, like this
Public Declare Function add2 Lib "C:\c\dll\mydll.dll" (num As Integer) As Integer
then I just called add2(text1.text) from a form, but it gave me a runtime error:
"Can't find DLL entry point add2 in C:\c\dll\mydll.dll"
this is the code I compiled for the DLL:
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
EXPORT int __stdcall add2(int num){
return num + 2;
}
EXPORT int __stdcall mul(int num1, int num2){
return num1 * num2;
}
calling it from the C program like this worked, though:
#include<stdio.h>
#include<windows.h>
int main(){
HANDLE ldll;
int (*add2)(int);
int (*mul)(int,int);
ldll = LoadLibrary("mydll.dll");
if(ldll>(void*)HINSTANCE_ERROR){
add2 = GetProcAddress(ldll, "add2");
mul = GetProcAddress(ldll, "mul");
printf("add2(3): %d\nmul(4,5): %d", add2(3), mul(4,5));
} else {
printf("ERROR.");
}
}
any ideas?
solved it
To solve the previous problem, I just had to compile it like so:
gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--add-stdcall-alias
and use this API call in VB6
Public Declare Function add2 Lib "C:\c\dll\mydll" _
(ByVal num As Integer) As Integer
I learned not to forget to specify ByVal or ByRef explicitly--I was just getting back the address of the argument I passed, it looked like, -3048.
Regarding building a DLL using MinGW, here are some very brief instructions.
First, you need to mark your functions for export, so they can be used by callers of the DLL. To do this, modify them so they look like (for example)
__declspec( dllexport ) int add2(int num){
return num + 2;
}
then, assuming your functions are in a file called funcs.c, you can compile them:
gcc -shared -o mylib.dll funcs.c
The -shared flag tells gcc to create a DLL.
To check if the DLL has actually exported the functions, get hold of the free Dependency Walker tool and use it to examine the DLL.
For a free IDE which will automate all the flags etc. needed to build DLLs, take a look at the excellent Code::Blocks, which works very well with MinGW.
Edit: For more details on this subject, see the article Creating a MinGW DLL for Use with Visual Basic on the MinGW Wiki.
Here is how you do it:
In .h
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
extern "C" // Only if you are using C++ rather than C
{
EXPORT int __stdcall add2(int num);
EXPORT int __stdcall mult(int num1, int num2);
}
in .cpp
extern "C" // Only if you are using C++ rather than C
{
EXPORT int __stdcall add2(int num)
{
return num + 2;
}
EXPORT int __stdcall mult(int num1, int num2)
{
int product;
product = num1 * num2;
return product;
}
}
The macro tells your module (i.e your .cpp files) that they are providing the dll stuff to the outside world. People who incude your .h file want to import the same functions, so they sell EXPORT as telling the linker to import. You need to add BUILD_DLL to the project compile options, and you might want to rename it to something obviously specific to your project (in case a dll uses your dll).
You might also need to create a .def file to rename the functions and de-obfuscate the names (C/C++ mangles those names). This blog entry might be an interesting launching off point about that.
Loading your own custom dlls is just like loading system dlls. Just ensure that the DLL is on your system path. C:\windows\ or the working dir of your application are an easy place to put your dll.
There is but one difference. You have to take care or name mangling win C++. But on windows you have to take care about
1) decrating the functions to be exported from the DLL
2) write a so called .def file which lists all the exported symbols.
In Windows while compiling a DLL have have to use
__declspec(dllexport)
but while using it you have to write
__declspec(dllimport)
So the usual way of doing that is something like
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
The naming is a bit confusing, because it is often named EXPORT.. But that's what you'll find in most of the headers somwhere. So in your case you'd write (with the above #define)
int DLL_EXPORT add....
int DLL_EXPORT mult...
Remember that you have to add the Preprocessor directive BUILD_DLL during building the shared library.
Regards
Friedrich
The thing to watch out for when writing C++ dlls is name mangling. If you want interoperability between C and C++, you'd be better off by exporting non-mangled C-style functions from within the dll.
You have two options to use a dll
Either use a lib file to link the symbols -- compile time dynamic linking
Use LoadLibrary() or some suitable function to load the library, retrieve a function pointer (GetProcAddress) and call it -- runtime dynamic linking
Exporting classes will not work if you follow the second method though.
For VB6:
You need to declare your C functions as __stdcall, otherwise you get "invalid calling convention" type errors. About other your questions:
can I take arguments by pointer/reference from the VB front-end?
Yes, use ByRef/ByVal modifiers.
Can the DLL call a theoretical function in the front-end?
Yes, use AddressOf statement. You need to pass function pointer to dll before.
Or have a function take a "function pointer" (I don't even know if that's possible) from VB and call it?)
Yes, use AddressOf statement.
update (more questions appeared :)):
to load it into VB, do I just do the usual method (what I would do to load winsock.ocx or some other runtime, but find my DLL instead) or do I put an API call into a module?
You need to decaler API function in VB6 code, like next:
Private Declare Function SHGetSpecialFolderLocation Lib "shell32" _
(ByVal hwndOwner As Long, _
ByVal nFolder As Long, _
ByRef pidl As Long) As Long