What does GetFunctionPointerForDelegate convert a String^ parameter in a delegate into? - c#

I'm trying to convert a C# delegate to a C++ function pointer, using Managed C++. Here's the method we were previously using:
// Define a delegate
public delegate void ADelegate(Int32);
ADelegate^ delegateInstance;
// Define a function pointer
typedef void (__stdcall *AFuntionPointer)(int);
AFuntionPointer functionPointerInstance;
// Create an instance of a delegate, using GetFunctionPointerForDelegate
delegateInstance = gcnew ADelegate(this, &AClass::AFunction);
// Convert the delegate to a pointer
IntPtr anIntPtr = Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(delegateInstance);
// Cast the pointer into a function pointer
functionPointerInstance = static_cast<AFuntionPointer>(anIntPtr.ToPointer());
If I turn the ADelegate's parameter from an Int32 to a String^, to what type should I change the AFunctionPointer's parameter to? In another words, if I changed the first two lines in the above code to:
public delegate void ADelegate(String ^);
ADelegate^ delegateInstance;
How should I change the next two lines?
// To what type does GetFunctionPointerForDelegate translate String^ to?
typedef void (__stdcall *AFuntionPointer)( /* char*? std::string? */ );
AFuntionPointer functionPointerInstance;

Marshal::GetFunctionPointerForDelegate() on that delegate would generate a function pointer that's compatible with
typedef void (__stdcall *AFuntionPointer)( const char* );
String^ marshals to const char* unless a [MarshalAs] attribute is applied to the delegate argument. Marshaling directly to std::string is not possible, the pinvoke marshaller doesn't know anything about C++ object layout for classes that are declared in a header file.

Related

Calling a C++ function with void* parameter in a C# app

I have a c++ function that look like this :
int Compression::DecompressPacket(const void* inData, int inLength, void* outData, int outLength)
{
int headerLength = ComputeDataHeaderLength(inData);
return DecompressDataContent(static_cast<const unsigned char*>(inData) + headerLength, inLength - headerLength, outData, outLength);
}
The fonction is inside a class which is inside a c++ library.
In the other hand, I need to call this fonction on my c# application. The fonction ask me to enter parameters of types : "void*, int, void*, int".
When I try to make a void* in an unsafe function,
unsafe private void lstbox_packets_SelectedIndexChanged(object sender, EventArgs e)
{
[...]
byte[] value = byteValuePackets[lstbox_packets.SelectedIndices[0]];
void* pValue = &value;
[...]
}
I get the error :
Error 8 Cannot take the address of, get the size of, or declare a pointer to a managed type ('byte[]')
I'm not very familiar with c++ and pointer but how i am suppose to pass a void* type in c# ?
You shouldn't take the address of value, and also you have to use fixed statement:
fixed (void* pValue = value)
{
//...
}

Passing managed function to unmanaged function that uses std::function()

in my C++ code, a callback function is represented as a std::function() obj, not as the more common function pointer construct.
typedef std::function<void()> MYCALLBACK;
The callback function in C++ is set via:
MYCALLBACK myCBFunc; // some member variable
void SetCallbackFunction(MYCALLBACK cbFunc)
{
myCBFunc = cbFunc;
}
in C#:
delegate void MyCallbackFunc(); // delegate matching the c++ callback sig
// method matching the call back sig
void foo()
{ }
[DllImport("mydll.dll")]
static extern SetCallbackFunction(MyCallbackFunc cbfunc);
// set the callback
MyCallbackFunc cb = foo;
SetCallbackFunction(cb); // crash here
Compiles OK, but crashes with AccessViolationException when run.
I initially thought this is because MYCALLBACK obj is on the stack, and need to pass by reference and changed the signature to match but it still crashes i.e.
MYCALLBACK myCBFunc; // some member variable
void SetCallbackFunction(MYCALLBACK& cbFunc)
{
myCBFunc = cbFunc;
}
[DllImport("mydll.dll")]
static extern SetCallbackFunction(ref MyCallbackFunc cbfunc);
// set the callback
MyCallbackFunc cb = foo;
SetCallbackFunction(ref cb); // crash here
how do i get this to work with std::function()? No problems using plain old function pointers.
std::function<void()> is a class template. It looks like a function because the class overloads operator(). So, std::function<void()> being a class means that it is simply not binary compatible with an unmanaged function pointer.
You'll need to use:
typedef void (*MYCALLBACK)();
Note that this function is cdecl. Either switch it to stdcall in your C++, or declare your C# delegate as being cdecl. I expect you know how to do the former. Here's an example of the latter:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void MyCallbackFunc();
Your pinvoke is also wrong in that it should not pass the callback as a ref parameter. It should be:
[DllImport("mydll.dll")]
static extern SetCallbackFunction(MyCallbackFunc cbfunc);

Invoke a C DLL function to marshal a string from a type defined char

This is my first attempt at creating a C# wrapper to a C lib. The SDK is 3rd party and outside my control:
sdk_defines.h
#ifndef SDK_CHAR_T
#define SDK_CHAR_T
typedef char sdk_char_t;
#endif /* SDK_CHAR_T */
#ifndef SDK_CSTR_T
#define SDK_CSTR_T
typedef const sdk_char_t* sdk_cstr_t;
#endif /* SDK_CSTR_T */
sdk.h
sdk_cstr_t SDK_API
sdk_get_version(void);
My C# wrapper:
[DllImport("sdk.dll", CharSet = CharSet.Ansi)]
private static extern string sdk_get_version();
Any call to sdk_get_version causes a crash, no exception. I have a feeling it's the return type, but how do I properly marshal it in C#?
If you return as string, then the marshaller will call CoTaskMemFree on the pointer that is returned. I expect that's what's happening to you and is why your code fails. Looking at that API it seems most likely that the pointer that is returned points to a string literal in the DLL, certainly not something allocated with CoTaskMemAlloc.
So, you are going to need to return that as an IntPtr and then convert to string using Marshal.PtrToStringAnsi.
So you need it like this:
[DllImport("sdk.dll")]
private static extern IntPtr sdk_get_version();
....
IntPtr ptr = sdk_get_version();
string version = Marshal.PtrToStringAnsi(ptr);
Before you go much further you need to work out what SDK_API is. Is it stdcall or is it cdecl? It makes no difference for this no-parameter function, but before long you'll be passing parameters, and you'll need to know.

How to Marshal a void* function return type and parameter in C#?

I have a C function with prototype,
void* VoidPointer(void*);
Now I need to marshal it in C#(using DllImport). But I do not know how to mention the parameters in C# code.
static public extern WHAT_RETURN_TYPE VoidPointer( WHAT_PARAMETER_TYPE );
How to make a call with the proper parameters in the C# code (SAMPLE USE)
I am new to C# and need to solve this asap ( in several attempts have got errors like this cannot convert from 'int' to 'System.IntPtr')
Thanks.
c# supports void pointers. Just declare the function as
[DllImport("test.dll")]
public static extern unsafe void* VoidPointer(void* AValue);
public unsafe void Test()
{
int* a;
int b = 0;
a = (int*)VoidPointer(&b);
}
(this only works if the void pointers are referencing integers ofcourse)

How do I call a function defined in a C++ DLL that has a parameter of type int *, from inside C# code?

I have a native regular C++ Dll which I want to call from C# code, so i created C++/CLI class (as described here and here) which will include managed C++ code and which can be called by any C# code directly and which can make calls inturn to native unmanaged C++.
One of function in native C++ dll has parameter of type int *. How do I declare in wrapper function and how can i convert it into int *?
It is the C/C++ way of passing a value by reference. You should use the ref or out keyword:
[DllImport("something.dll")]
private static extern void Foo(ref int arg);
In C++/CLI that would look roughly like this:
public ref class Wrapper {
private:
Unmanaged* impl;
public:
void Foo(int% arg) { impl->Foo(&arg); }
// etc..
};
[DllImport("some.dll")]
static extern void SomeCPlusPlusFunction(IntPtr arg);
IntPtr is a type that is roughly equivalent to void *.
From your comment, you'd be best off doing something like this (C#):
int size = 3;
fixed (int *p = &size) {
IntPtr data = Marshal.AllocHGlobal(new IntPtr(p));
// do some work with data
Marshal.FreeHGlobal(data); // have to free it
}
but since AllocHGlobal can take an int, I don't know why you wouldn't do this:
IntPtr data = Marshal.AllocHGlobal(size);

Categories