DllImport how to get single values by reference - c#

What's the appropiate signature/marshall attribute to be able to get output params using pointers params? So far I tried this:
// Function to calculate the norm of vector. !0 on error.
// int err_NormVec(int size, double * vector, double * norm)
[DllImport("vectors.dll")]
int err_NormVec(int size, double[] vector, ref double norm)
The previous approach doesn't pop back the value to .NET from C. I also tried to use pinned GCHandle, with the IntPtr signature.
[DllImport("vectors.dll")]
int err_NormVec(int size, double[] vector, IntPtr norm)
public void doSomething()
{
double norm = 0;
// ...
GCHandle handle = GCHandle.Alloc(norm, GCHandleType.Pinned);
int status = err_NormVec(vector.Lenght, vector, handle.AddrOfPinnedObject());
// ... clean gchandle, check status and so on
}
In this case I got the value back but on the GCHandle.Target, not on the original norm. Which is annoying. I would like to be able to pin the intptr of the norm it self not just a copy.
What is the appropiate signature to return a value using a pointer? Is there a supported way to get a IntPtr to an int value?

This works for me (as it should):
//C++ DLL (__stdcall calling convention)
extern "C" __declspec(dllexport) void Foo(double *result) {
*result = 1.2;
}
//C#
class Program
{
[DllImport( "Snadbox.dll", CallingConvention=CallingConvention.StdCall )]
static extern void Foo( ref double output );
static void Main( string[] args )
{
double d = 0;
Foo( ref d );
Console.WriteLine( d ); // prints "1.2"
}
}
Passing the double using the ref keyword is sufficient. So, I am led to believe that there is something wrong (or misunderstood) in the implementation. Can you post the implementation for us?
Also, perhaps you are building the C++ version using the default calling convention (cdecl), but .NET is using StdCall. Have you made sure that these line up? You may crash if they are mixed, but there is no guarantee. For instance, in my example, if I change the C++ side to cdecl then the out parameter is read back as 0.

Related

How to pass array as parameter to function call from C++ to C# [duplicate]

I am seeing a pretty bizarre issue while trying to pass an array from C++ to C#. I am using Marshal.Copy (specifically: https://msdn.microsoft.com/en-us/library/a53bd6cz(v=vs.110).aspx).
Problem: float array from C++ to C# is yielding a few NaN's in the resulting array.
(Note: I am working in the context of the Unity game engine)
Code
Example C++ code:
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API getSomeFloats(float** points, int* count) {
std::vector<float> results;
std::vector<SOME_TYPE> key_points = <SOME_POINTS>
for (auto iter = key_points.begin(); iter < key_points.end(); iter++) {
results.push_back(static_cast<float>(iter->pt.x));
results.push_back(static_cast<float>(iter->pt.y));
}
*points = results.data();
*count = results.size();
//<Print results to csv here>
return true;
}
Example C# code:
[DllImport("NativePlugin")]
private static extern bool getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);
private static float[] getFloatArrayFromNative() {
IntPtr ptrResultItems = IntPtr.Zero;
int resultItemsLength = 0;
bool success = getSomeFloats (ref ptrResultItems, ref resultItemsLength);
float[] resultItems = null;
if (success) {
// Load the results into a managed array.
resultItems = new float[resultItemsLength];
Marshal.Copy (ptrResultItems
, resultItems
, 0
, resultItemsLength);
// <PRINT out resultItems to csv here>
return resultItems;
} else {
Debug.Log ("Something went wrong getting some floats");
return new float[] { -1, -2 };
}
}
Example Ouput:
Take the following example:
C++ output (print_out.csv):
123, 456, 789
C# output (print_out_cs.csv):
123, NaN, 789
I'm completely stumped on this one. I just don't understand why only some (roughly 7/100) floats are returning NaN. Does anyone have any advice/insight that might help?
Thanks!
Found few problems in your code:
1. std::vector<float> results; is declared on the stack. It will be gone by the time the function has returned. Declare it as a pointer
std::vector<float> *results = new std::vector<float>(10);
but make sure to also declare a function that will free it on the C++ side.
2.The function parameter do not match.
Your C++:
getSomeFloats(float** points, int* count, CameraPose* pose)
Your C#:
getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);
You either have to remove CameraPose* pose from the C++ side or add IntPtr pose to the C# side.
3. The use of UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API.
You don't need that. This is used when you want to use Unity's built in functions such as GL.IssuePluginEvent. You are not using it in this case.
This should do it:
#define DLLExport __declspec(dllexport)
extern "C"
{
DLLExport void fillArrayNative(float* data, int count, int* outValue)
{
}
}
4.C# has a garbage collector that moves variables around in the memory. You must pin C# array if you want to modify it from C++ side. You only need to pin C# array. Another option is to allocate the array on C++ side, return it to C# copy it to a temporary variable on the C# side then delete it on the C++ side.
5.Copy the result back to the array instead of assigning it.
Recommended method:
There are just many ways to do this and some of them are extremely slow. If you want to use Marshal.Copy, you have to allocate the array on the C++ side or else you will run into some undefined behavior.
The fastest and the most efficient way to do this is to allocate the array on the C# side as a global variable. Pass the array and its length to the native side. Also pass a third parameter which C++ can use to tell C# the amount of index that has been updated or written to.
This is much more better than creating new array, copying it to C# variable then destroying it each time the function is called.
This is what you should be using:
C++:
#define DLLExport __declspec(dllexport)
extern "C"
{
DLLExport void fillArrayNative(float* data, int count, int* outValue)
{
std::vector<float> results;
for (int i = 0; i < count; i++)
{
//Fill the array
data[i] = results[i];
}
*outValue = results.size();
}
}
You can also use: std::copy ( data, data+count, results.begin() ); instead of loop to copy the data too.
C#:
[DllImport("NativePlugin", CallingConvention = CallingConvention.Cdecl)]
private static extern void fillArrayNative(IntPtr data, int count, out int outValue);
public unsafe void getFillArrayNative(float[] outArray, int count, out int outValue)
{
//Pin Memory
fixed (float* p = outArray)
{
fillArrayNative((IntPtr)p, count, out outValue);
}
}
Usage:
const int arraySize = 44500;
float[] arrayToFill = new float[arraySize];
void Start()
{
int length = arrayToFill.Length;
int filledAmount = 0;
getFillArrayNative(arrayToFill, length, out filledAmount);
//You can then loop through it with with the returned filledAmount
for (int i = 0; i < filledAmount; i++)
{
//Do something with arrayToFill[i]
}
}
This is just an example and it is faster than all other methods I've used before. Avoid doing it the way you are currently doing it with Marshal.Copy. If you still want to do it your way or use Marshal.Copy then here is the appropriate way to do it which requires allocation, copying data and de-allocating memory in each call.
The pointer you return in getSomeFloats is owned by results. Before getSomeFloats returns, the vector destructor for results will free that memory. When the C# code tries to use the pointer, you are accessing unallocated memory, which results in Undefined Behavior. In your case most of the data hasn't been changed yet, but some of it has. Potentially any or all of the data could have been changed (if the memory has been reused), or even a program crash (if the freed memory has been returned to the OS).

C++ DLL from C# returns -858993460

I have a C++ (MSVS 2010) DLL from the samples MS give as:
namespace MathLibrary
{
double Functions::Add(double a, double b)
{
return a + b;
}
double Functions::Multiply(double a, double b)
{
return a * b;
}
double Functions::AddMultiply(double a, double b)
{
return a + (a * b);
}
}
dumpbin for the compiled DLL exports the following info:
1 0 00011078 ?Add#Functions#MathLibrary##SANNN#Z = #ILT+115(?Add#Functions#MathLibrary##SANNN#Z)
2 1 000110B9 ?AddMultiply#Functions#MathLibrary##SANNN#Z = #ILT+180(?AddMultiply#Functions#MathLibrary##SANNN#Z)
3 2 00011005 ?Multiply#Functions#MathLibrary##SANNN#Z = #ILT+0(?Multiply#Functions#MathLibrary##SANNN#Z)
So I've written C# code (.NET framework 4.5.2) to call the Add function as:
namespace ConsoleApplication5
{
class Program
{
[DllImport(#"MathLib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "#1")]
public static extern int Add(Int32 a, Int32 b);
public unsafe static void Main()
{
int i = Add( 1,3 );
Console.WriteLine(i);
Console.ReadLine();
}
}
}
When I run this console application, it always outputs
-858993460
regardless of the arguments passed to the Add function.
Can anyone suggest what this output represents, and how to fix my calling code?
-858993460 expressed in hexadecimal is 0xCCCCCCCC. This is the value that Microsoft C/C++ compiler uses for uninitialized variables in a Debug build. My initial suspicion is that the value returned from your DLL is a variable that never actually got assigned.
Also, the fact that your C# code is declaring the function to be using and returning integers, but the actual C++ code implementation is using doubles could also be the problem. MSVC Functions returning integers typically stuff the result into the EAX register, but I suspect that's not the case for functions that return a floating point value. That might explain it. But at best, this is "undefined behavior".
I suspect what you really need in the C# code is this declaration for Add:
[DllImport(#"MathLib.dll", CharSet = CharSet.Ansi, CallingConvention =
CallingConvention.Cdecl, EntryPoint = "#1")]
public static extern double Add(double a, double b);

Update float array from C++ native plugin

I am seeing a pretty bizarre issue while trying to pass an array from C++ to C#. I am using Marshal.Copy (specifically: https://msdn.microsoft.com/en-us/library/a53bd6cz(v=vs.110).aspx).
Problem: float array from C++ to C# is yielding a few NaN's in the resulting array.
(Note: I am working in the context of the Unity game engine)
Code
Example C++ code:
extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API getSomeFloats(float** points, int* count) {
std::vector<float> results;
std::vector<SOME_TYPE> key_points = <SOME_POINTS>
for (auto iter = key_points.begin(); iter < key_points.end(); iter++) {
results.push_back(static_cast<float>(iter->pt.x));
results.push_back(static_cast<float>(iter->pt.y));
}
*points = results.data();
*count = results.size();
//<Print results to csv here>
return true;
}
Example C# code:
[DllImport("NativePlugin")]
private static extern bool getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);
private static float[] getFloatArrayFromNative() {
IntPtr ptrResultItems = IntPtr.Zero;
int resultItemsLength = 0;
bool success = getSomeFloats (ref ptrResultItems, ref resultItemsLength);
float[] resultItems = null;
if (success) {
// Load the results into a managed array.
resultItems = new float[resultItemsLength];
Marshal.Copy (ptrResultItems
, resultItems
, 0
, resultItemsLength);
// <PRINT out resultItems to csv here>
return resultItems;
} else {
Debug.Log ("Something went wrong getting some floats");
return new float[] { -1, -2 };
}
}
Example Ouput:
Take the following example:
C++ output (print_out.csv):
123, 456, 789
C# output (print_out_cs.csv):
123, NaN, 789
I'm completely stumped on this one. I just don't understand why only some (roughly 7/100) floats are returning NaN. Does anyone have any advice/insight that might help?
Thanks!
Found few problems in your code:
1. std::vector<float> results; is declared on the stack. It will be gone by the time the function has returned. Declare it as a pointer
std::vector<float> *results = new std::vector<float>(10);
but make sure to also declare a function that will free it on the C++ side.
2.The function parameter do not match.
Your C++:
getSomeFloats(float** points, int* count, CameraPose* pose)
Your C#:
getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);
You either have to remove CameraPose* pose from the C++ side or add IntPtr pose to the C# side.
3. The use of UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API.
You don't need that. This is used when you want to use Unity's built in functions such as GL.IssuePluginEvent. You are not using it in this case.
This should do it:
#define DLLExport __declspec(dllexport)
extern "C"
{
DLLExport void fillArrayNative(float* data, int count, int* outValue)
{
}
}
4.C# has a garbage collector that moves variables around in the memory. You must pin C# array if you want to modify it from C++ side. You only need to pin C# array. Another option is to allocate the array on C++ side, return it to C# copy it to a temporary variable on the C# side then delete it on the C++ side.
5.Copy the result back to the array instead of assigning it.
Recommended method:
There are just many ways to do this and some of them are extremely slow. If you want to use Marshal.Copy, you have to allocate the array on the C++ side or else you will run into some undefined behavior.
The fastest and the most efficient way to do this is to allocate the array on the C# side as a global variable. Pass the array and its length to the native side. Also pass a third parameter which C++ can use to tell C# the amount of index that has been updated or written to.
This is much more better than creating new array, copying it to C# variable then destroying it each time the function is called.
This is what you should be using:
C++:
#define DLLExport __declspec(dllexport)
extern "C"
{
DLLExport void fillArrayNative(float* data, int count, int* outValue)
{
std::vector<float> results;
for (int i = 0; i < count; i++)
{
//Fill the array
data[i] = results[i];
}
*outValue = results.size();
}
}
You can also use: std::copy ( data, data+count, results.begin() ); instead of loop to copy the data too.
C#:
[DllImport("NativePlugin", CallingConvention = CallingConvention.Cdecl)]
private static extern void fillArrayNative(IntPtr data, int count, out int outValue);
public unsafe void getFillArrayNative(float[] outArray, int count, out int outValue)
{
//Pin Memory
fixed (float* p = outArray)
{
fillArrayNative((IntPtr)p, count, out outValue);
}
}
Usage:
const int arraySize = 44500;
float[] arrayToFill = new float[arraySize];
void Start()
{
int length = arrayToFill.Length;
int filledAmount = 0;
getFillArrayNative(arrayToFill, length, out filledAmount);
//You can then loop through it with with the returned filledAmount
for (int i = 0; i < filledAmount; i++)
{
//Do something with arrayToFill[i]
}
}
This is just an example and it is faster than all other methods I've used before. Avoid doing it the way you are currently doing it with Marshal.Copy. If you still want to do it your way or use Marshal.Copy then here is the appropriate way to do it which requires allocation, copying data and de-allocating memory in each call.
The pointer you return in getSomeFloats is owned by results. Before getSomeFloats returns, the vector destructor for results will free that memory. When the C# code tries to use the pointer, you are accessing unallocated memory, which results in Undefined Behavior. In your case most of the data hasn't been changed yet, but some of it has. Potentially any or all of the data could have been changed (if the memory has been reused), or even a program crash (if the freed memory has been returned to the OS).

Marshaling an array of IntPtrs in C#

From safe, managed code in C#, I would like to call a function in a C API that receives an array of pointers (void**).
I have the corresponding managed array of IntPtr objects, but the Marshal methods advertised in the documentation at MSDN do not seem sufficient to provide an IntPtr to an unmanaged block of memory with the correct content.
I had hoped to obtain an IntPtr with 'Marshal.AllocHGlobal' and then assign the correct content using 'Marshal.Copy', but it seems the function has not been overloaded for an array of IntPtr.
Any thoughts on the best way to do this?
Thanks in advance.
The P/Invoke marshaller already does this, you don't have to help. Just declare the function argument as an array:
[DllImport("blah.dll")]
private static extern void SomeFunction(IntPtr[] array);
Just in case: although you don't have to use the unsafe keyword here, there isn't anything safe about it. The C code can easily corrupt the heap when it writes past the end of the block you allocated.
Pass the array as an IntPtr[], IntPtr are by default marshaled as void*. No
need for unsafe.
[DllImport("containingFoo.dll")]
public static extern void foo( IntPtr[] ptr);
...
// some floats
float[] fpa = {7.2F, 2.3F, 3.3F, 4.5F, 6.5F};
// allocate unmanaged for float[] fpa and int (length of array)
IntPtr fptr = Marshal.AllocHGlobal(fpa.Length *
Marshal.SizeOf(typeof(float)));
IntPtr iptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)));
// set length of array
Marshal.WriteInt32(iptr, fpa.Length);
// copy the array
Marshal.Copy(fpa, 0, fptr, fpa.Length);
// strore both pointers in IntPtr[]
IntPtr[] pptr = {fptr, iptr};
// call foo passing the IntPtr[] to C
foo(pptr);
//C/C++
// note that stdcall is the default calling convention when using
PInvoke!!!!
void __stdcall foo(void** data)
{
float * fa = (float*)*data; // first element points to float array
int *ip = (int*)data + 1; // pointer to next element in void array
int *pp = (int*)*ip; // get pointer to int
for (int i = 0; i < *pp ; i++)
{
printf("\t: %f\n", *fa++);
}
}

Returning a variable sized array of doubles from C++ to C# - a simpler way?

I have the following C++ method :
__declspec(dllexport) void __stdcall getDoubles(int *count, double **values);
the method allocates and fills an array of double and sets *count to the size of the array.
The only way i managed to get this to work via pinvoke is :
[System.Runtime.InteropServices.DllImportAttribute("xx.dll")]
public static extern void getDoubles(ref int count, ref System.IntPtr values);
and usage is :
int count = 0;
IntPtr doubles = new IntPtr();
Nappy.getDoubles(ref count, ref doubles);
double[] dvs = new double[count];
for(int i = 0;i < count;++{
dvs[i] = (double)Marshal.PtrToStructure(doubles, typeof(System.Double));
doubles = new IntPtr(doubles.ToInt64()+Marshal.SizeOf(typeof(System.Double)));
}
the values end up in the dvs array.
Is there a better way ti do this not invloving pointer arithmetic in a managed language...
I think you can use
Marshal.Copy( source, destination, 0, size );
You'll need to change the unmanaged method signature so it reads like this:
__declspec(dllexport) void __stdcall getDoubles(SAFEARRAY *array);
Then you should be able to use the following managed version of the function:
[System.Runtime.InteropServices.DllImportAttribute("xx.dll")]
public static extern void getDoubles(
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_R8)]
double[] array
);
Of course that you'll also have to rewrite your unmanaged code to work with SAFEARRAYs.
More about this topic can be found at MSDN.
One question though, I recall working with ZLib in C# which is able, without any wrapper, to work with byte[] while the unmanaged counterpart is BYTE*, have you tried working directly with double* / double[] ?

Categories