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.
Related
I have been tasked with creating a Wrapper for a C-library to be used in C#. I have no control over the C-library's source code and I only have access to its header file and to the static library file (.lib).
I have followed several tutorials and got this working when creating an unmanaged C++ class which is wrapped using CLI/C++ and used in C#. No problem. The problem I am facing know though, is as C does not use namespaces, I have trouble figuring out how to tell the compiler when I want to call the function from the .lib file itself, rather than my identically named wrapper function. If it helps understanding, my header file only consists of function definitions, typedefs (structs, enums), but no classes (not even sure if C headers usually do?).
What I have done:
Created a VS C++ CLR Class Library (.NET Framework) project
Linked my .lib file to all configurations in linker->inputs as an additional dependency.
Created two files: Wrapper.h and Wrapper.cpp.
#included the header file corresponding to my .lib in the Wrapper.h file
This is where I get a bit confused, mostly due to the tutorials all covering how to link a C++ library rather than a C library. The difference there being the lack of namespace in C, and (in my case) the lack of class.
Uncertainties:
I do not know if I need a ref class Analytics{} in my Wrapper.h or not. I assume I do if I want to use all the functions statically, but as there is no corresponding class in the C library, can I just name this whatever I want?
In order to properly link the C library in my header file (Wrapper.h), I need to use the same function definition as in the original header file. Do I repeat the use of "extern" and such keywords? Can I freely add static and accessibility modifiers?
At this point I want to "implement" the function in the Wrapper.cpp file. Here my problem about identical function names comes in. The function I want to implement has the same name in the original header file as it does in the Wrapper header file (obviously, as it would not work otherwise, right?). The wrapper header file contains a namespace and a class (for now class name is Analytics) so I can declare the function as Analytics::void SanSetApplicationContext(){...}, but as the original C library header file does not contain classes or namespaces, there is no way for me to call that function and distinguishing between them. The C++ compiler always prefers the local definition and I am stuck with a function calling itself for all eternity. I hope you understand my point.
I am probably doing something wrong and/or misunderstanding something, but how would you guys suggest I approach this issue? I will append my files contents below. In the files I have so far only tried implementing a single function. Code should be fixed and hopefully working
Wrapper.h
#pragma once
using namespace System;
namespace Wrapper {
public ref class Analytics
{
public:
static void SanSetApplicationContext(String^ ctx);
};
}
Wrapper.cpp
#include "pch.h"
#include "Wrapper.h"
#include "../SWA_lib/Analytics.h"
namespace Wrapper {
void Analytics::SanSetApplicationContext(String^ ctx) {
//Convert String^ to const char*
msclr::interop::marshal_context mCtx;
const char* convertedStr = mCtx.marshal_as<const char*>(ctx);
::SanSetApplicationContext(convertedStr);
}
}
Analytics.h
...
extern void SanSetApplicationContext(const char *ctx);
...
Update
Updated the code to reflect my changes made based on your comments. Thanks!
Update 2
#Bodo asked me to explain another issue of mine, which is how I would handle wrapping functions that return opaque handles. The example used is the following: typedef struct SanEvent_s *SanEvent; which is found in my C header file. So basically, this library provides an API. The API execution always starts with a call to an Initialize(); function, and ends with a call to the Terminate(); function. I have no previous experience of using this API, but from the documentation, I assume that all objects, references and what not are freed/destroyed when Terminate() is called, as none of their examples show destroying objects.
Now, creating a SanEvent is done like this (according to documentation):
SanEvent event;
event = SanNewEvent("The Main Event");
This opaque handle is considered protected on the C# side, so there does not seem to be a way for me of returning it all the way there. My idea is to keep the events in some kind of Collection, in the C++/CLI wrapper where the type can be used, and only return the index of the Event to C# (The index the even would have in a List or something). I am not sure this is a good idea, but this is as far as I have come with my plan. Something that represents a SanEvent needs to be returned to C# as I need to be able to reference the event in the future, in order to add additional information to the event via other functions. This idea would of course need tailored "helper functions" on the C++ side which mediate between C# and C. I am sorry if the information is vague, but I don't really have a lot to go on myself as of now.
Adding "::" to the beginning of a function call tells the compiler to use the function found in global namespace rather than local namespace/class. So:
namespace Wrapper {
void Analytics::SanSetApplicationContext(const char *ctx) {
::SanSetApplicationContext(ctx);
}
}
Should call the c version correctly
I'm calling a C++ external library from C#. Return works, however printf() does not print data in the console window. Why does it happen? Am I doing something wrong?
Even when I call DisplayHelloFromDLL without assigning its return to variable x, printed text does not show on the screen.
C++:
#include <stdio.h>
extern "C"
{
__declspec(dllexport) char * DisplayHelloFromDLL()
{
printf ("Hello from DLL !\n");
return "Something";
}
}
C#:
using System;
using System.Runtime.InteropServices;
class HelloWorld
{
[DllImport("Hello.dll", EntryPoint = "DisplayHelloFromDLL")]
public static extern string DisplayHelloFromDLL();
static void Main()
{
Console.WriteLine("This is C# program");
string x = DisplayHelloFromDLL();
Console.WriteLine(x);
Console.ReadKey();
}
}
According to this thread (https://social.msdn.microsoft.com/Forums/en-US/5da6cdb2-bc2b-4fff-8adf-752b32143dae/printf-from-dll-in-console-app-in-visual-studio-c-2010-express-does-not-output-to-console-window?forum=Vsexpressvcs) the Visual Studio hosting process that exists when debugging is the reason why the console output from the DLL does not make its way to your console.
A simple way to check this is to run the executable directly rather than via the IDE's debugger. If that does confirm that this is the case then you can disable the hosting process if you wish, as described in the linked thread.
Your code has another couple of problems:
[DllImport("Hello.dll", EntryPoint = "DisplayHelloFromDLL")]
public static extern string DisplayHelloFromDLL();
The default p/invoke calling convention is stdcall but the default C++ calling convention is cdecl. Your C# p/invoke therefore uses the wrong calling convention. You will need to change one of the declarations to resolve this.
And declaring the return type as string means that the marshaller will attempt to deallocate the returned pointer by calling CoTaskMemFree. The C string was not allocated with CoTaskMemAlloc so this is undefined behaviour. You should declare the return type as IntPtr and use Marshal.PtrToStringAnsi to obtain the string, remembering that the C++ code returns a literal which should not (indeed cannot) be deallocated. Alternatively, use one of the various other ways to return a string that are perhaps a little clearer in the way memory ownership is determined.
I think, your Problem is that the DLL has no console assigned to it - it should not know the C#-Console. Maybe, you can try to pass a reference to your C#-Console-Object to your "DisplayHelloFromDLL"-Function.
But I never tried it - I do not know, how to Access/use the C#-Console-Object from a C/C++ DLL.
Your C external library might not have access to the any output console. You can use following functions for writing in to an output console.
AllocConsole
GetSTDHandle
WriteConsole
I created a DLL inside of MV C++ 2012 and when I used
Dumpbin /Exports filename
The name of the function inside of the DLL file has an equal sign inside of it. I had to use Common Language Runtime Support (/crl) because I used a DLL from C#. Is this why the name of the function would show up with an equals sign? My header file:
#ifdef ColorDLL_EXPORTS
#define ColorDLL_API __declspec(dllexport)
#else
#define ColorDLL_API __declspec(dllexport)
#endif
extern "C"{
ColorDLL_API int ColorSelect(int i);
}
ColorDLL.cpp
#include "stdafx.h"
#include "ColorDLL.h"
#using <ColorDiologeClass.dll>
extern "C"{
ColorDLL_API int ColorSelect(){
ColorDiologeClass::Class1::ColorReturn(1);
return 1;
}
}
When I used Dumpbin the name showed up as this:
Name
ColorSelect = _ColorSelect
Why is this? I am expecting it to show up as ColorSelect, not ColorSelect = _ColorSelect. And if I were to leave it this way, how would I call this function from a program like JMP where it needs the exact function name? Would it be ColorSelect? Or would it be ColorSelect = _ColorSelect?
The name is "mangled" - the return type and the parameters are enchoded into the name of the function. Should you wish to NOT have that, you would use extern "C" before the function name (or around a block of functions).
That would be name mangling, which is the under-the-covers feature of c++ that allows it to support function overloading (since it incorporates the argument types of the function into its name).
Here's another question that goes into greater detail.
Microsoft calls this "decorating" instead of mangling. They include a command line tool named "undname" that will produce the original name from the decorated name:
C:\>undname ?ColorSelect##YAHXZ
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?ColorSelect##YAHXZ"
is :- "int __cdecl ColorSelect(void)"
If you want to do the same in your own code, you can do that too, using UnDecorateSymbolName.
For what it's worth, decorating/mangling supports not only overloading, but typesafe linking. Typesafe linking stems from function overloading though it isn't really function overloading in itself.
Specifically, typesafe linking deals with (for example) how to deal with C++ code that has overloads of, say, sqrt for float, double, long double, and probably complex as well, but links to a C library that provides a double sqrt(double), but not the other overloads. In this case, we typically want that to be used when the right arguments were/are used, but not otherwise.
This can (or could) arise even without function overloading being involved. For example, in pure C you could do something like this:
#include <stdio.h>
extern int sqrt(int);
// ...
printf("%d", sqrt(100));
Now, we've told the compiler we're using a version of sqrt that takes (and returns) an int. Unfortunately, the linker doesn't realize that, so it still links with the sqrt in the standard library that takes and returns double. As a result, the code above will print some thoroughly useless result (typically 0, not that it matters a lot).
Typesafe linkage prevents that -- even though it isn't exactly function overloading, we still have two functions with the same name, but different types by the time we're linking. By encoding the parameter type(s) into the name, the linker can keep this sorted out just as well as the compiler can.
The same can (and frequently does) arise in C when we have name collisions between different libraries. With a traditional C compiler, straightening out this sort of mess can be extremely difficult (at best). With a C++ compiler, unless the two libraries use not only the same names, but identical number and types of parameters, it's never a problem at all.
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.
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.