I have a working DLL written in C++ with Visual Studio 2015. It contains many functions of the form:
BECALIBRARY_API int Functions::GetVersion(char* ptrVersionString)
{
char * Version;
Version = "Test 123456";
strcpy_s(ptrVersionString, strlen(Version) + 1, Version);
return strlen(Version);
}
The Delphi function to retrieve this is:
unit uBecaLibrary;
interface
function getVersion(Str1: pAnsichar): integer; stdCall;
implementation
function getVersion; external 'BecaLibrary.dll' index 1;
//function getVersion; external 'BecaLibrary.dll' name 'getVersion';
end.
This works fine except that I have to maintain the Delphi code using the index numbers of the DLL.
What do I need to do to both the C++ side and the Delphi Seattle Windows 10 side to use function names rather than indexes.
You can use dumpbin utility to view exported names as
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\dumpbin.exe" /EXPORTS BecaLibrary.dll
Names will probably be mangled but it should not be a problem.
If you can change DLL, you can add following inside function body to export unmangled name
#pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
You can just use the function name on the last like this
var
function getVersion(Str1: pAnsichar): integer; stdCall; external 'BecaLibrary.dll' name 'GetVersion';
implementation
For the DLL
To export an undecorated name, you can link by using a Module Definition (.def) file that defines the undecorated name in an EXPORTS section. For more information, see EXPORTS. Another way to export an undecorated name is to use a #pragma comment(linker, "/export:alias=decorated_name") directive in the source code.
When you declare dllexport or dllimport, you must use extended attribute syntax and the __declspec keyword.
Source: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx
Related
I'm trying to use an external dll in my c++ builder application. The dll (let.s call it X.dll) was created with Qt Creator (using MingW 32 bit compiler, tried gcc as well )
and consists of a single functon to keep things simple (besides X.dll, an import library X.a is also created).
The dll header (Dll_lib.h) is basically just
__declspec(dllexport) Dll_method(float *p, int n);
If I create a simple Qt application, add the dll header to it and link it to the dll import library X.a, everythink works as expected.
However, when I try to use the dll in my c++ builder application, I get an "unresolved external _Dll_method referenced from ..." error.
The part of my c++ builder app that references the dll looks like
#include "lib\Dll_lib.h"
#pragma comment(lib, "X.lib")
__declspec(dllimport) Dll_method(float *p, int n);
.....
X.lib was created directly from the dll using the implib tool that comes bundled with c++ builder. I also tried to create X.lib from X.a using coff2omf tool but nothing worked and I always get the same error message.
C++ environments have a habit of name mangling to support overloads, different arguments with the same name, like:
int use(int x, char y); // mangles to something like use__Int__Chr.
int use(double x); // mangles to something like use__Dbl.
This allows the correct one to be linked depending on the arguments.
You may need to wrap it inside extern "C" to get it to not mangle the name, something like:
extern "C" {
__declspec(dllimport) Dll_method(float *p, int n);
}
That's assuming you're creating it without name mangling and using it from something that assumes it is mangled. If it's mangled on both sides, you'll probably have to create and use it with extern "C" since there's no guarantee different compilers will mangle with the same rules.
As an aside, you should be able to examine the object files or DLLs created by your toolchain, to ascertain what the function is called where it's defined and also what it's expected to be by the caller. Under Linux, I'd use something like nm, I'm not sure what the equivalent is for Windows.
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've got 2 Question concerning exported function names.
I walked through the MSDN Example:
Creating and Using a Dynamic Link Library (C++)
Why can I access the dll function with their undecorated name? There is no .defFile. As MSDN states :
"dllexport of a C++ function will expose the function with C++ name mangling" I am wondering about why this works.
If I remove the __declspec(dllexport) resp. the macro and use instead a
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
within the function body e.g.:
double __stdcall ExternalAdd(double arg1, double arg2)
{
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
return arg1 + arg2;
}
I get a linker error. Why?
dumpbin /Exports on the dll shows:
ExternalAdd = #ILT+720(?ExternalAdd##YGNNN#Z)
dumpbin /Headers on the lib shows:
Symbol name : ExternalAdd
...
Name : ExternalAdd
Many thanks for your help.
I am new to using PInvoke with Classic C++ and I asked this question yesterday: Using Windows API functions in .NET
I have now created a very simple C++ program as follows:
#include <iostream>
#include <stdio.h>
#include <string>
extern "C" __declspec(dllexport) int hello()
{
//printf ("Hello World!\n");
return 1;
}
I then compiled the DLL using the following command: g++ -c mydll.cpp
Then created the shared library using the following command: g++ -shared -o mydll.dll mydll.o, then copied mydll.dll to C:\Windows\syswow64.
I then created a new VB.NET project and created the following code:
Imports System.Runtime.InteropServices
Public Class TestPlatformInvoke
<DllImport("mydll.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Function hello() As Integer
End Function
Public Sub New()
Try
Dim test As Integer = hello() 'Line 6 ex As Exception
'I don't swallow exceptions
MsgBox("test")
Catch ex As Exception
End Try
End Sub
End Class
The application exits after calling hello(). It does not throw an exception.
I am trying to get to grips with how this works. I don't have any commercial experience with c++; only academic experience at university.
Here is an image of Dependancy Walker for mydll.dll.
Declare is VB6 legacy. You should use p/invoke and the DllImport attribute.
<DllImport("mydll.dll", CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Function hello() As Integer
End Function
There are lots of ways that this could fail. Perhaps the DLL is not loading because there's a 32/64 bit mismatch. Also, your calling conventions do not match. Your DLL will be using cdecl but your VB code uses stdcall. The pinvoke above fixes that.
Most seriously your function does not appear to have been exported from the DLL. That's going to make it fail for sure. Use Dependency Walker to determined whether or not your function has been exported. I'm not so familiar with g++ so you'll have to work out how to export your function using the GNU toolchain. But watch out for name decoration and name mangling. You may need to take care with how you export your function so that it is exported with the desired name.
If you use Visual Studio to debug programs and include the DLL in your project (Visual Studio 2012 Express Edition allows including projects of different types in the solution), you may set the "Allow native code debugging" option to automatically switch the debugger from the VB.NET to C++, when you P/Invoke function from the DLL.
Here's a working Proof-of-concept. Simply unzip, open in Visual Studio, build and run. You may compare this program with your project and find the differences, which makes your code failing.
I guess, that you haven't actually exported the function from the DLL. Simply including it in the DLL's code may not be enough: check, which functions are exported from the DLL using the Dependency Walker (other link) program. For example, I had to add folowing declaration:
__declspec(dllexport) int __stdcall Test() { ... }
And additionally create the .def file for the names for exported functions not to be decorated.
Try to modify your DLL source code and change the function declaration to:
extern "C" __declspec(dllexport) int hello()
{
return 1;
}