I need to set a callback function in a C library equal to a C# function, and can't figure out a way to do it without either dlopen or kernel32, which seems windows/unix specific. Does anyone know of a way to do this?
The problem: C shared library exposes function pointers, whose values should be set by over-writing them. E.g.
//C Code
extern void (*ptr_R_ShowMessage) (const char *)
The current c# code creates a delegate to a function that matches this signature, uses the marshal class to get a pointer to that delegate, and then overwrites the C pointer with this value.
//call to libdl or kernel32.dll
IntPtr showPointer = GetFunctionAddress(hndl,"ptr_R_ShowMessage");
IntPtr newShowPointer = Marshal.GetFunctionPointerForDelegate(matchingDelegate);
Marshal.WriteIntPtr(showPointer, newShowPointer);
The requirement on libdl and kernel32.dll causes all kinds of problems... and ideally would be avoided.
Does anyone know how I can make the C libraries pointer point to the C# code, without modifying the C code or using the GetFunctionAddress dynamic loading? I think this might be impossible, but it seems like it could be.
I'm not 100% sure if this is what you're looking for.
In our case, we have a third party C Sdk that provides several hooks for callback messages. The callback call is initiated in C code and expects to invoke a C function, but we are able to hook it to a C# method using the following steps. (This code is kind of old and probably there are more succint and modern methods to accomplish the same in newer iterations of C#).
First we declare inside a C# class a Callback delegate, compatible with the signature of the C function pointer the SDK is expecting.
For example, if the C code is expecting to call back a function having the following signature:
void DecCallBack(int nPort, void* pBuf, int nSize, FRAME_INFO *pInfo, int nReserved1, int reserved 2);
Here's the matching C# delegate definition. Note that the "magic" happens thanks to the UnmanagedFunctionPointer attribute:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void DecCallBack(int nPort, IntPtr pBuf, int nSize, ref FRAME_INFO frameInfo, int nReserved1, int nReserved2);
Once we have this, we declare a class member of type DecCallBack that will hold a delegate instance in our class.
static DecCallBack _decodeCallBack = null;
Next we code a handler method compatible with the delegate signature. In this case we name it HandleDecData()
private static void HandleDecData(int nPort, IntPtr pBuf, int nSize, ref FRAME_INFO frameInfo, int nReserved1, int nReserved2) {
// Here we handle the callback, this code is being called from an external C library
}
Next, somewhere in the C# class, we need to initialize the delegate member and hook our callback Handler (In this case it is the static method HandleDecData()
_decodeCallBack += new DecCallBack(HandleDecData);
Finally, we pass the delegate member as if it were a function pointer to C.
In our case, the third party SDK has a C PlayM4_SetDecCallBack() function that expects the function pointer to call when the callback is invoked - we can safely pass the delegate member of our class instead.
if( !PlayM4_SetDecCallBack(channel, _decodeCallBack) )
throw new InvalidOperationException("Error setting DecCallBack");
I hope this is helpful.
C shared library DO NOT exposes function pointers in that way, extern means that this function is defined in another C file and linker during creation of binary object will use actual code from the function in final executable
to fix this you need to include C# file somehow in C project in way the C compiler will link both into binary object, but it is impossible
what current code is trying to do is called "hack", if you want to achieve similar functionality without hacks you need:
In C code provide function which will accept pointer to function to execute
In C code where ptr_R_ShowMessage is called use pointer from p1
In C# code call function from P1 and provide method to call as argument
Here is sample I've found which executes function from external library and provide it C# function as callback: http://tutorials.csharp-online.net/CSharp_Delegates_and_Events%E2%80%94Win32_callbacks
I confirmed that this is not possible in C# directly, so interfacing with the libary load function is required. Thanks to both for answers though, definitely useful.
Related
I'm trying to get a C# class (not struct!) from a C++ function back (using out parameter). This is the C# side:
[StructLayout(LayoutKind.Sequential)]
public class OutClass
{
public int X;
}
// This interface function will be mapped to the C++ function
void MarshalOutClass(out OutClass outClass);
The C++ part looks like this
struct OutClass
{
int x = 0;
};
extern "C" MARSHAL_TESTS_API void MarshalOutClass(OutClass** out);
The function mapping works via a custom mechanism and is not part of this question. All marshaling attributes are treated normally.
In C#, we usually declare out arguments inline, like:
MarshalOutClass(out var outClass);
DoSomething(outClass);
Since C# reference types are marshaled by pointer, I figured I would have to add another pointer for ref or out parameters. So I use OutClass** on the C++ side.
I assume that C# translates the
MarshalOutClass(out var outClass);
part to roughly
OutClass outClass = default(OutClass);
MarshalOutClass(ref outClass);
which is a reference to null, or on C++ side: a pointer to a nullptr. This wouldn't be a problem for C# value types (aka struct) because their default is a default constructed instance.
This means, I'd have to manually create an instance of my object on the C++ side and marshal it back to C#.
void MarshalOutClass(OutClass** out)
{
auto ptr = static_cast<OutClass*>(CoTaskMemAlloc(sizeof(OutClass)));
*ptr = OutClass{};
*out = ptr;
}
The code seems to work, but I'm not sure if I'm leaking memory with this or if the marshaler is going to to take care of it properly. I don't do any cleanup on the C# side.
This brings me to the following questions:
is my assumption on how ref and out are translated to C++ correct?
is CoTaskMemAlloc the correct function here?
do I have to perform any additional memory management related tasks (on either side)?
is the overall approach correct here? What should I do differently?
I know that static_cast<OutClass*>(CoTaskMemAlloc(sizeof(OutClass))) is a bit sketchy here but lets assume OutClass is always a trivial type.
I have such layers: C# main application -- CLI/C++ wrapper for C++ library -- C++ library.
CLI middle layer was written because of the limitations of C#-C++ interoperability. I used it also to polish some rough edges from C# point of view -- in other words, the middle layer allows to hide C/C++ types (like char*) and do all necessary conversions.
One conversion I fail to make is passing a callback. I tried to do it as in Pass a c++ lambda to old c function pointer but I cannot pass a lambda as a callback.
C++ callback definition:
typedef void (*CppOnEngineCloseCallback)
(void * customParam, const wchar_t * errorMessage);
I know customParam is not used, so I define such callback for middle layer (CLI/C++):
typedef void (*CLIOnEngineCloseCallback)
( String ^ errorMessage);
In the wrapper I create such lambda:
// lambda signature should resemble CppOnEngineCloseCallback
auto lambda = [&] (void * customParam, const wchar_t * errorMessage) {
cli_callback(Marshal::PtrToStringUni( IntPtr(static_cast<void*>(
const_cast<wchar_t*>(errorMessage)))));
};
My concern is if cli_callback will be properly kept in CLI environment (this is my first project) -- after all, I pass it in time A, and use it in time B.
Compiler has even stronger concern, because when I try to use the lambda:
InitEngine( // C++ function that requires callback
&lambda);
it says it cannot convert lambda into CppOnEngineCloseCallback.
Is it doable in the first place? How?
You're using auto, hence you're hiding the actual type, and making it harder on yourself to manage the C++ strongly typed type safety.
Probably the lambda function isn't the right type, or at least not the type you're expecting.
CppOnEngineCloseCallback is probably a function pointer type (or std::funciton type).
So, to help yourself, try changing the lambda's type to the expected type, and see what the compiler says.
CppOnEngineCloseCallback lambda = [&] (void * customParam, const wchar_t * errorMessage) {
cli_callback(Marshal::PtrToStringUni( IntPtr(static_cast<void*>(
const_cast<wchar_t*>(errorMessage)))));
};
The InitEngine() method expects a CppOnEngineCloseCallback, so you must make sure it gets it.
Besides that, you can only assign a lambda with empty brackets [] to a function pointer. In your case you're not using anything from the local scope, hence you don't really need [&].
Lambda functions : operator ret(*)(params)()
This user-defined conversion function is only defined if the capture
list of the lambda-expression is empty.
If you do want to use this kind of lambda expression, you'll have to use std::function instead of a function pointer:
typedef std::function<void(void *, const wchar_t *)> CppOnEngineCloseCallback;
In general, it is not possible, to cast a lambda to a function pointer.
As you know, a lambda is an object of a compiler generated class, that only behaves like a function.
For your actual problem: you mentioned that customParam is not used.
A typical pattern is, that customParam is provided by the caller of the library and used in the callback function to identify some object handling the callback. Inside the callback, you then map to the function you actually want to call:
void MyNativeCallback(void * customParam, const wchar_t * errorMessage)
{
static_cast<MyClass*>(customParam)->Callback(errorMessage);
}
So you could pass a pointer to your lambda as customParam to the library, and provide a helper function as above as callback. Anyways, getting the pointer types correctly will not be a simple task. I would prefer a small helper class instead.
I have written a C# application that injects a DLL into a third-party executable (which happens to have been built using the Qt framework). This DLL uses EasyHook to intercept calls to a number of specific functions. When my injected code is called, I then try to inspect some of the objects that are parameters to these functions.
For example, I have intercepted a call made to parse some XML:
virtual bool __thiscall QXmlSimpleReader::parse(class QXmlInputSource const &)
In my C# code, I have a PInvoke signature to match this:
static extern bool XmlParse(IntPtr Reader, IntPtr Source)
I would like to call the "data()" function which is a member of the "Source" class. That is, the QXmlSimpleReader parses the raw XML from the QXmlInputSource, but before it does so, I am trying to inspect the raw XML via this "data()" function.
On the advice of one of the experts here, I have tried to use C++/CLI to access the object natively (see Calling methods in third-party DLLs ). I have constructed a wrapper object in C++ that accepts the IntPtr from the C# code:
Header:
public ref class QXmlInputSource
{
public:
// Constructor must be called with C# IntPtr
QXmlInputSource(IntPtr Ptr);
bool LoadQt(void);
bool UnloadQt(void);
String^ Data();
private:
// Pointer to the native Qt object
void * Native;
HINSTANCE DllHandle;
// SIGNATURE: virtual QString QXmlInputSource::data() const
typedef void * (__thiscall *QXmlInputSource_Data)(void *);
QXmlInputSource_Data fpData;
};
CPP file:
QXmlInputSource::QXmlInputSource(IntPtr Ptr)
{
LoadQt();
Native = Ptr.ToPointer();
}
bool QXmlInputSource::LoadQt(void)
{
FARPROC Addr;
/* get handle to dll */
std::wstring LibName = QtPath + QtXml;
DllHandle = LoadLibrary(LibName.c_str());
/* get pointer to the function in the dll*/
Addr = GetProcAddress(HMODULE (DllHandle), "?data#QXmlInputSource##UBE?AVQString##XZ");
fpData = QXmlInputSource_Data(Addr);
return true;
}
bool QXmlInputSource::UnloadQt()
{
/* Release the Dll */
FreeLibrary(DllHandle);
return true;
}
String^ QXmlInputSource::Data()
{
void* Ptr = fpData(Native);
return "EPIC FAIL";
}
The Qt-based application crashes when I try to call the fpData() function pointer. Help :P
Some additional information which may or may not help:
I have successfully called functions on "simpler" objects, such as QString.count() and QString.data() using the same methodology. (QString seems to be just a lightweight wrapper for a standard unicode string).
In the QtXml4.dll file that contains the XML functions I am interested in, there are actually TWO parse() methods; one where the Source is a const &, and in the other, Source is a const *. I have no idea if I should be using one or the other. I don't think my signatures will change in any event.
While I was trying to play around, I tried dereferencing the IntPtr in the C# code and passing it to C++:
IntPtr DerefSrc = (IntPtr)Marshal.PtrToStructure(Source, typeof(IntPtr));
If I print out the values of these two IntPtrs, Source has a value of around 3.5Mb, while the DerefSrc has a value of 1.6Gb - which roughly matches the address of the QtXml4.dll in memory. My guess is that the 3.5Mb is a relative offset, while the DerefSrc is clearly an absolute reference. Is it worth a shot converting the DerefSrc to a relative address and passing that to C++ instead ... ?
I see several problems:
1.: You don't check the return value of LoadLibrary and GetProcAddress. Is QXmlInputSource::data even a DLL-exported method? If not then GetProcAddress will obviously fail.
2.: How do you instantiate the QXmlInputSource class? I ask because it seems you are trying to do it in the C# code, which is hard to do right (you need to know the size required for the class, allocate a properly aligned chunk of memory of that size, and call the constructor on it).
3.: The way you're invoking the function pointer is wrong. You need to declare a method pointer of the appropriate type:
FARPROC fp = ::GetProcAddress(...);
typedef QString (QXmlInputSource::*DataMethod)();
DataMethod mpData = reinterpret_cast<DataMethod>(fp);
QXmlInputSource source;
QString data = (source.*mpData)();
4.: Looking at the documentation for QXmlInputSource::data, I see that it returns a QString, which is woefully different from a pointer (as you're currently treating it). To convert it to a System.String, you need code like this:
QString s1 = (QChar*)L"example string";
String^ s2 = gcnew String((wchar_t*)s1.data()); // calls the String::String(wchar_t*) constructor overload
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 have created COM server in C++ that is used from C# application. Now I have to add one more method to my COM object and one of its parameter must be function pointer to callback function. C++ original function looks like this:
typedef int (__stdcall *tCallBackFunc)(int Param);
void MyFunc(void* CallBackFunc)
{
int Param;
//some code
((tCallBackFunc)(CallBackFunc))(Param); //call callback function
}
I need to add MyFunc as COM object method. VS VC++ "Add Method" dialog offers some predefined types for COM method parameter like "int*" or "bstr", I tried to define "CallBackFunc" parameter as "int*" type, but I was not able to make it work in C#:
public delegate int tCallBackFunc(int Param);
...
tCallBackFunc cb; //I will initialize it when it is compiled
MyCOMObject.MyFunc(cb); //cannot find any way to cast cb to "ref int"
It seems I use wrong approach, is there a fast way to declare function pointer as parameter of COM object method in C++ and then use it in C#?
The COM way is to make the parameter an interface pointer, and have the interface declare the callback function.
+1 for Frederik's answer.
#Michael: It will prove a lot easier than your imagined solution.
Especially with
object lifetimes
process boundaries
thread safety (apartment boundaries, IOW)
standards conformance (casting function pointers quickly enters the domain of Undefined Behaviour). Why should you worry? Standards conformance must concern you in case a compiler update introduces another optimization that makes your old (non-conformant) code break