Problems with wrapping a C++ DLL from C# - c#

I'm using System.Runtime.InteropServices to call several functions written in C++ from my C# app. I'm just having problems with a particular function that returns an array.
I've seen that my function shouldn't return anything, and a pointer to the "returning variable" should be en entry. But I'm not managing to do it properly.
For instance if I have a function in c++
void func(double *y, double *x){...}
that manipulates an array x and returns an array y.
I'm doing:
-in my .h:
extern "C" __declspec(dllexport) void func(double *y,double *x);
-in my .cpp:
__declspec(dllexport) void func(double *y,double *x){...}
-in my c# code:
static class AnyClass
{
[DllImport(dllPath)]
public extern static void func(out double[] y, double[] x);
int otherfunc
{
double[] x = new double[5];
double[] y = new double[5];
...
func(out y, x);
}
}
but it gives me a System.EntryPointNotFoundException.
Any clue?

EntryPointNotFoundException means that nothing called 'function' was found in your DLL.
In your .h file you call it 'func'. But in your .cpp file you call it 'function'. And since your .h file is the only place which is declaring extern "C", what is effectively happening is that the function is being exported by your DLL c++-style-name-mangled, instead of plain-c-style. So, when C# looks for plain-c-style 'function', it cannot find it.

I think, you also have to specify extern "C" in your .cpp file. If not, you might end up with two different functions func, the one with the correct linkage only be declared and not defined.
Note: Afair the extern "C" linkage also specify how the functions are named in the DLL file. For C++ functions some pre- resp. postfixes are added to the name relating to the signature (i.e. the parameters and the return type). This is necessary because you can overload functions in C++. Therefore, if you don't specify extern "C", the functions are named differently in the DLL and thus cannot be found by the managed code.

An EntryPointNotFoundException means that the runtime failed to find the specified function name in your DLL.
Possible reasons are
You misspelled the function name in your DLL or your program
The you did not deactivate name mangling (extern "C")
The first reason is easy to find, just double-check all names and make sure they are really equal. If for some reason you can not change the DLL, but like a different name from C#, you can use the DllImportAttribute.EntryPoint property to point to a function of a different name.
The second one is more difficult to come by. To diagnose the problem, I suggest you use Dependency Walker to see what really is going on inside your compiled DLL. Using that tool, you can see the function names, and whether they are C++'ified or not.
You already tried to use extern "C" to make sure the function name is not afflicted by name mangling. Maybe you did not include the .h file from your .cpp file, so that the compiler did not see the extern "C" at all.

Related

C#/Fortran: Unable to find an entry point

Keep getting the following error when trying to call a subroutine stored in a Fortran DLL from a C# console application: "An unhandled exception of type 'System.EntryPointNotFoundException' occurred in name.exe Additional information: Unable to find an entry point named 'Fortran_Subroutine' in DLL 'Fortran.dll'" Nearly all of the posts related to this error message pertain to C#/C++. The Fortran project has a post-build event that copies the DLL over to the C# project (CSharp_proj\bin\debug).
The Fortran code uses two calls to !DEC$, do they look OK?:
C
MODULE MF_DLL
C
CONTAINS
C
SUBROUTINE MFNWT_INIT()
C
!DEC$ ATTRIBUTES DLLEXPORT :: MFNWT_INIT
!DEC$ ATTRIBUTES DECORATE, ALIAS: "MFNWT_INIT"
C
USE GLOBAL
...(do stuff)
RETURN
END SUBROUTINE MFNWT_INIT
The C# code that calls the fortran, does the DLLImport call look OK?:
using System.Runtime.InteropServices;
public static class CustomMODSIM
{
public static Model myModel = new Model();
private static SortedList myStreamNodes;
public static void Main(string[] CmdArgs)
{
string FileName = CmdArgs[0];
myModel.Init += OnInitialize;
...(do more stuff)...
//Function call that will invoke "OnInitialize" below
myProgram.RunSolver(myModel);
}
private static void OnInitialize()
{
//call Fortran function
MFNWT_INIT();
//Initialize list of stream nodes
myStreamNodes = new SortedList();
Node m_Node = myModel.FindNode("NonStorage1");
...(do more stuff)
}
//Fortran DLL interface
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern void MFNWT_INIT();
}
Your second compiler directive (the second !DEC$ line) is incorrect - it is missing the :: MFNWT_INIT part that designates which Fortran thing has the nominated attributes (DECORATE and ALIAS). I would expect the compiler to issue a warning about the syntax problem.
For what its worth (assuming you are using a version of ifort >= 11 or so and not one of its ancestors): given you want to use the C calling convention, you are better off getting rid of that second directive completely, and just using the suffix BIND(C,NAME="MFNWT_INIT") on the SUBROUTINE statement.
Most likely the DLL is exporting the function with a decorated name. Find out what that name is and use it on the C# side.
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="DecoratedNameGoesHere")]
public static extern void MFNWT_INIT();
To find the exported name use a tool like dumpbin or Dependency Walker.
Are you quite sure that your DLL uses the cdecl calling convention?
In the IVF Help, have a look at Building Applications/Programming with Mixed Languages/Adjusting calling conventions in Mixed Languages/Attributes properties and calling conventions. That is where it is on Version 11. It may have moved in the version you are using. The confusing bit in the help is whether the exported symbol is upper or lowercase. It is only slightly different from the one written for the old MS Fortran 77 compiler (circa 1986). If you are unsure the exported symbols, use depends to find out what they are.
1) If you are not using an alias, then it should look like this on the Fortran side
MODULE MF_DLL
CONTAINS
SUBROUTINE MFNWT_INIT()
!DEC$ ATTRIBUTES STDCALL, DLLEXPORT :: MFNWT_INIT
If STDCALL is used, there will be two exported symbols: MF_DLL_mp_MFNWT_INIT and _MF_DLL_mp_MFNWT_INIT#0. If STDCALL is not specified, it defaults to C. In that case you will only MF_DLL_mp_MFNWT_INIT. The number after the # sign is the number of bytes on the stack that the routine needs to remove before returning to the caller. You will not get this in C decl because it is the responsibility of the caller.
2) On the C# side using stdcall
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.StdCall,
EntryPoint="_MF_DLL_mp_MFNWT_INIT#0")]
public static extern void MFNWT_INIT();
3) On the C# side using Cdecl
[DllImport("MF_DLL.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="MF_DLL_mp_MFNWT_INIT")]
public static extern void MFNWT_INIT();
The difference is that in C, it does not need to know the number of parameters whereas in stdcall it does. This affects the stacking/unstacking of parameters. If this goes wrong, it will make the call, run the Fortran routine and then crash on exit. In your case, it doesn't really matter because there are no parameters but it is nice to get it right.
4) If an alias is used, the name changes but not the calling convention. In your case, you should have specified
! ,-- This is the name in DLL export
!DEC$ ATTRIBUTES DECORATE, ALIAS: "MFNWT_INIT"::MFNWT_INIT
With C decl, you will get MFNWT_INIT.
With STDCALL, you will get MFNWT_INIT and _MFNWT_INIT#0
On the C# side the entry point is not needed when C Decl is used. It is only needed when STDCALL is used.
5) If the routine is used in both Fortran and C# then it would be better to stick to stdcall.

How to natively call this function from a DLL?

I have used DLL Export viewer to try and find the functions that are in this DLL, I have found a list of functions and here it is:
public: int __thiscall CSTVdsDisk::GetPartitionCount(void);
the question is within in C# I am not able to call the function using either:
[DllImport("Some.dll",
ExactSpelling = true,
EntryPoint = "GetPartitionCount",
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
or:
[DllImport("Some.dll",
ExactSpelling = true,
EntryPoint = "CSTVdsDisk::GetPartitionCount",
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
private static extern int GetPartitionSize();
They all fail. Is there something that I am doing wrong? Can anyone help? Thanks!
You can't call that function using P/Invoke. The __thiscall calling reference means that this function is a class member function. It is a member function of the CSTVdsDisk class.
To be able to call the function you will have to create an instance of the CSTVdsDisk class and call GetPartitionCount from that instance.
You'll have to do that in C++ or C++/CLR as you can't create a C++ class in C#. See also Create unmanaged c++ object in c#.
Based on the name, that appears to be a C++ class method. That is going to make it very difficult to call that method directly from P/Invoke for two reasons:
You need to find the "real" name; the Export Viewer is apparently showing up the unmangled name, but the actual C++ function name will look much uglier, like #0GetPartitionCount#CSTVdsDisk##QPBAEXA or similar. You may need to use a lower-level tool like dumpbin to find that name.
You need to fake the "thiscall" style call; this means you need to pass an instance of a C++ class as the first parameter. This is only going to work if the C++ class constructor is also exposed from the DLL; in which case, you can call the class constructor, store the result in an IntPtr, and pass it to every subsequent call. (If the constructor is exposed as a DLL export its mangled name will start with ??, like `??0CSTVdsDisk##QAE#ABV0##Z
This CodeProject article shows you how to do most of that, but it's pretty fragile, so expect problems. I'd strongly suggest you look for a non-C++ library that does something similar, or at least one that's designed to be usable from C code.
In your native code, make sure you're exporting the function. By default you function wont be listed in the Exports table so you need to mark it so that the compiler knows to export it. You also need to mark the function as
extern "C"
so that the compiler doesn't mangle the name.
Typically I define the following macro:
#define DLLEXPORT extern "C" __declspec(dllexport)
to handle all of this, and then simply declare exported functions like:
DLLEXPORT __cdecl int Example(int x, int y)
If you find you're still having troubles with the name, try using a free PE explorer program on the dll and checking the exported function table for the correct name.

can't call C++ function from C#

I have a DLL with a set of functions. The DLL was used with "themidia" to make it safe.
When I try to call the functions, C# spits out errors due to the functions names.
[DllImport("safety.dll", CallingConvention=CallingConvention.StdCall, ExactSpelling=true)]
private static extern IntPtr _encryptLogin#8(string string_0, string string_1);
If I remove the #8 and remove ExactSpelling=true, it just returns an exception saying no entry point.
What exactly am I doing wrong?
Remove the "#", and in your attribute add EntryPoint="_encryptLogin#8"
As an alternative to specifying EntryPoint as rfmodulator suggested, you can use extern "C" in your C++ source, which will make the exported function names the same as their names in your C++ source.
C++ compiler normally mangles the names of functions, so that you can have overloaded functions (functions with the same name bu different parameters).

Call a C# method/function from a C++ DLL (which is loaded from C# with "Dllimport")

It's a little hard to resume it in a single title, so here my situation.
I'm building a C# application that loads a C++ library.
I call functions from that C++ DLL.
But I'd also like my C++ DLL to call functions from the C# application (that is importing/running it)...
Here a piece of code to make it a little more comprehensive :
// I'm importing functions from my native code
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern int returnIntValue(int value);
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern int returnIntArrValueAt(int[] values, int index);
// Here is the kind of code it should be
// [DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
// public static extern void callCSharpFunction( FunctionPointer fctPointer );
main
{
// I run the function
int intValue1 =
MyAddIn.returnIntValue(147852369);
int intValue2 =
MyAddIn.returnIntArrValueAt( new int[] { 9, 4, 3, 2, 1, 0 }, 5);
// Here is an example function I use to call my C# func from C++
// MyAddIn.returnIntValue( &myCSharpFunction );
}
// This is the method I'd like to call from my C++ imported library
static public void myCSharpFunction()
{
MessageBox.Show("Called from C++ code !!");
}
So, to resume :
C# code import my C++ DLL
C# runs functions from C++ DLL
C++ DLL method calls a C# method which displays a MessageBox (ie)
Here's my answer to this question, which was similar. My example doesn't use arguments for the callback. Since your arguments are integers, though, you shouldn't have any problems.
Basically, the Marshal.GetFunctionPointerForDelegate method creates an IntPtr from a delegate. That delegate should have the same signature as the function pointer used in your C++ library.
// This is the delegate type that we use to marshal
// a function pointer for C to use. You usually need
// to specify the calling convention so it matches the
// convention of your C library. The signature of this
// delegate must match the signature of the C function
// pointer we want to use.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FunctionPointer();
// This is the function we import from the C library.
[DllImport(dllFilePath)]
static extern void callCSharpFunction(IntPtr fctPointer);
// This is the placeholder for the function pointer
// we create using Marshal.GetFunctionPointerForDelegate
IntPtr FctPtr;
// This is the instance of the delegate to which our function
// pointer will point.
FunctionPointer MyFunctionPointer;
// This calls the specified delegate using the C library.
void CallFunctionPointer(FunctionPointer cb)
{
// make sure the delegate isn't null
if (null == cb) throw new ArgumentNullException("cb");
// set our delegate place holder equal to the specified delegate
MyFunctionPointer = cb;
// Get a pointer to the delegate that can be passed to the C library
FctPtr = Marshal.GetFunctionPointerForDelegate(MyFunctionPointer );
// call the imported function with that function pointer.
callCSharpFunction(FctPtr);
}
This can be done, and overall not that big of a deal. However there are several points of consideration.
Since you said C++ and not C, note that besides static class, instance methods, friend functions, etc, there are still some functions that are not loadable via DllImport due to name mangling. Avoiding COM, wrapping C++ in C is occasionally used as a more portable strategy to allows libraries to be wrapped by other languages .Net or otherwise. Similarly some of these same considerations apply to callbacks from the wrapped library as in your case. Although the prototypes from your DLL don't seem to likely be a problem, if it really was built with a C++ compiler it might be worth looking at the exported symbol names to make sure.
Tell help with your searching, you need to know the vocabulary. Generally when a function takes as a parameter another function to be called either during the function invocation or later on, that is refereed to as a callback. In the world of C and C++ this is based around a language feature known as function pointers (which also serve purposes other than callbacks). Often in MS documentation the overall process of letting different functions be dynamically bound to different callers at runtime is called delegation. The C# equivalent of a function pointer are objects known as delegates created with the C# keyword delegate. I would recommend first creating some experiment programs in just C# using this feature to first understand how that works.
Also DllImport is part of the implementation, the actual .Net facility you are using is pinvoke. That should also when looking for more info. What you then want to do is to export your delegate with pinvoke by marshaling it as a function pointer. That is, .Net will create a shim function for the native code to run. Two big problem areas that often take several tries are 1) making sure this shim function / marshaled delegate itself has the correct calling convention, and 2) that the object lifetime of this behind-the-scenes shim function is such that it still exists when the native DLL is going to use it. This curve ball can sometimes require manually overriding the garbage collection behavior, but usually this means just keeping a reference to it.
I actually think that the Mono Documentation is way better than MSDN in this area also.
So ok, after a few test on starting back to zero, I finally managed to get this callback running !
So here is the test project I created to use the callback.
On C++ side
export.def
LIBRARY TestCallBack
EXPORTS
callCSharpFunction
TestCallBack.cpp
__declspec(dllexport) void callCSharpFunction ( void *fctPointer(int) )
{
fctPointer(123456);
}
This C++ project is being built as a "DLL" file and put within a "lib" project in the C#'s project folder.
On C# side
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
// Set the library path
const string dllFilePath =
"C:\\PathToProject\\TestCallBack\\ConsoleApp\\lib\\TestCallBack.dll";
// This is the delegate type that we use to marshal
// a function pointer for C to use. You usually need
// to specify the calling convention so it matches the
// convention of your C library. The signature of this
// delegate must match the signature of the C function
// pointer we want to use.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FunctionPointer( int nb);
// This is the function we import from the C library.
//[DllImport(dllFilePath)]
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern void callCSharpFunction(IntPtr fctPointer);
// This is the placeholder for the function pointer
// we create using Marshal.GetFunctionPointerForDelegate
static IntPtr FctPtr;
// This is the instance of the delegate to which our function
// pointer will point.
FunctionPointer MyFunctionPointer;
// This calls the specified delegate using the C library.
void CallFunctionPointer(FunctionPointer cb)
{
// make sure the delegate isn't null
if (null == cb) throw new ArgumentNullException("cb");
// set our delegate place holder equal to the specified delegate
MyFunctionPointer = cb;
// Get a pointer to the delegate that can be passed to the C lib
FctPtr = Marshal.GetFunctionPointerForDelegate(MyFunctionPointer);
// call the imported function with that function pointer.
callCSharpFunction(FctPtr);
}
static void Main(string[] args)
{
// This is the instance of the delegate to which our function
// pointer will point.
FunctionPointer printInConsoleDelegate;
// Create the delegate object "MyFunctionPointer" that references
printInConsoleDelegate = new FunctionPointer(printInConsole);
// Get a pointer to the delegate that can be passed to the C lib
IntPtr printInConsolePtr =
Marshal.GetFunctionPointerForDelegate(printInConsoleDelegate);
Console.WriteLine(
"Call C++ which's calling back C# func \"printInConsole\"");
// Call C++ which calls C#
callCSharpFunction(printInConsolePtr);
// Stop the console until user's pressing Enter
Console.ReadLine();
}
public static void printInConsole(int nb)
{
// Write the parameter in the console
Console.WriteLine("value = " + nb + "; ");
}
}
}
The Unmanaged Exports project might help you with this:
https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports
Basically it allows you to export Functions from your assembly using the DllExport Attribute. Those functions can then be used like normal native Dll exports. It's something like the missing counterpart of the DllImport attribute.
You would then declare your method like this:
[DllExport("myCSharpFunction")]
static public void myCSharpFunction()
{
MessageBox.Show("Called from C++ code !!");
}
But also such a two-way dependency would usually look suspicious to me. Maybe it is also possible in your case to use callbacks, like ken suggested.

Strings in c++?

My problem is , i have some functions in a DLL some of these functions are for example :
#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
return s;
}
Whenever i try to call this function from C# , here is the code im using :
[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);
i get an error :
A call to PInvoke function 'Packer' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
im guessing i get this error because i dont have the right declarations for the function
can anyone guide me how to fix that , thanks in advance
std::string can not be used with PInvoke, because C++ does not have an ABI for its objects which is required to properly clean stack, copy objects, etc. This is one of the greatest pains of C++.
You have to use char* pointers and plain C APIs. Simply put, PInvoke does not work with C++.
As I'm sure you already know, the C++ std::string is actually a template. Only when the template is instantiated (as std::basic_string<char> in this case), the exact layout of the objects of that type and signatures of the methods are determined by the C++ compiler.
Unfortunately, only the C++ compiler in question has the access to all the relevant information (such as template source code) to make these kinds of decisions. That's why non-C features such as templates are generally not "transferable" even between different C++ compilers, let alone C++ and C#.
Also, C++ names are typically "mangled" in a C++ compiler-specific manner.
You'll have to change the signature of your native method, so it is becomes a "pure" C function:
Ensure there is no C++ name mangling by declaring the function as extern "C" (you are already doing that).
Use char* parameter instead of std::string.
Return char* result instead of std::string, but be very careful how you do it.
Ensure your DllImportAttribute.CallingConvention matches the __cdecl, __stdcall or __fastcall in your C.
The problem here is, you're using the STL string class which C# doesn't know how to marshal. You have two options here:
refactor your C++ code to work with char * buffers. Or write a wrapper or an overload or something that uses char * instead of string.
Write a C++/CLI wrapper around your C++ functions that uses System::String and calls the STL string versions internally.
If memory serves, if you don't specify otherwise P/Invoke assumes the calling convention is __stdcall. If so, changing your __cdecl to __stdcall should fix the first problem.
As #Adam Rosenfield points out, you probably also need to pass and return a char const *, not a string. C# and C++ almost certainly have somewhat different ideas of what constitutes a string.

Categories