P/invoke System.ExecutionEngineException when passing array as ref/out - c#

Im using an P/invoke on an unmanaged dll function swe_calc_ut.
int swe_calc_ut(double tjd_et, int ipl, int iflag, double *xx, char *serr)
Parameter xx is meant to be an "array of 6 doubles for storing the result", and parameter serr a "character string to return error messages"
my c# code is as follows.
[DllImport("swedll32.dll")]
private static extern int swe_calc_ut(double tjd_ut, int ipl, int iflag, out double[] xx, out char[] serr);
double jul_day_UT=22000;
int p=3;
int iflag=64 * 1024;
double[] arr;
char[] serr;
int x = swe_calc_ut(jul_day_UT, p, iflag , out arr, out serr);
Now when i execute the function swe_calc_ut function i get the error "Exception of type 'System.ExecutionEngineException' was thrown.". I'm new to P/invoke so i'm probably making a stupid mistake. I thought it must be the arrays since earlier when i passed them by value accidentally i did not get an error. I'd really appreciate your help.

You don't have to use out or ref here. In fact, lose both of them. And preallocate both arrays to the desired size in C#.

It is a convention of the C language, you pass an array by passing a pointer to the first element of the array. So a double[] is already marshaled as a double*. When you use the out or ref keyword, you tell the marshaller that the function returns a pointer to a new array, a double**.
The function does not create a new array, it requires the client to pass an array that's large enough to receive the result. Therefore, neither the out nor the ref annotation is correct. The serr argument should be declared as StringBuilder btw.
The function is very dangerous since there is no way for the client to say how large an array it created. Particularly a problem with the serr argument. A detailed error message is prone to overrun the end of the array and that will destroy the garbage collected heap. Nothing you can do but pass a very large array (i.e. StringBuilder with a large Capacity) and keep your fingers crossed. Buffer overruns are the preferred attack vector for malware authors. Not likely to be abused in a managed program, it will just crash the app with FEEE.

Related

c# dllimport with pointers

I have a dll that I cannot import in my vs2012 c# project. I have used dllImport before but I have never had to use Marshal or pointers before. Lucky me I guess.
This is the code that I currently have.
The function being called is fnLDA_GetDevInfo(DEVID *ActiveDevices)
DEVID is a normal unsigned integer (#define DEVID unsigned integer)
//Allocate an array big enough to hold the device ids for the number of devices present.
//Call fnLDA_GetDevInfo(DEVID *ActiveDevices), which will fill in the array with the device ids for each connected attenuator
//The function returns an integer, which is the number of devices present on the machine.
[DllImport(DLLLOCATION,CallingConvention = CallingConvention.Cdecl)]
private static extern int fnLDA_GetDevInfo([MarshalAs(UnmanagedType.LPArray)] ref uint[] ActiveDevices);
I call the function in my code this way
uint[] MyDevices;
fnLDA_GetDevInfo(ref MyDevices);
At this point I get an error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Now I'm pretty sure the error occurs because I don't call the pointer right or something.
Any help would be appreciated.
You have an extra level of indirection. An array is marshalled as a pointer to the array. When you declare the parameter as ref, again a pointer is passed. Thus your C# code matches uint**. Even so, you cannot use ref with an array type because you cannot expect the unmanaged code to produce a managed array.
Your p/invoke should be:
[DllImport(DLLLOCATION,CallingConvention = CallingConvention.Cdecl)]
private static extern int fnLDA_GetDevInfo([Out] uint[] ActiveDevices);
Note that this function is pretty hard to call. Since the function is not passed the length of the array, it is impossible for the function to avoid running off the end of the array if the array is not long enough. I really hope that you have some way to work out how large the array needs to be ahead of calling this function.
So perhaps you are expected to call it like this:
uint[] MyDevices = new uint[SomeLargeNumberThatYouPresumablyCanProvide];
int len = fnLDA_GetDevInfo(MyDevices);
Or perhaps like this:
int len = fnLDA_GetDevInfo(null);
uint[] MyDevices = new uint[len];
fnLDA_GetDevInfo(MyDevices);
I trust that you'll be able to work the rest out from the documentation for the DLL and/or the example C++ programs that call the DLL.

Does .NET interop copy array data back and forth, or does it pin the array?

I have this COM method signature, declared in C#:
void Next(ref int pcch,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
char[] pchText);
I call it like this:
int cch = 100;
var buff = new char[cch];
com.Next(ref cch, buff);
Does the .NET interop layer first copy the whole array to a temporary unmanaged memory buffer, then copy it back? Or does the array get automatically pinned and passed by reference?
For the sake of trying, I did this in the COM object (C++):
*pcch = 1;
pchText[0] = L'A';
pchText[1] = L'\x38F'; // 'Ώ'
I do get 'Ώ' back when I check buff[1] in C# upon return. But I don't think this is a strong proof that the array gets pinned, rather than copied back and forth.
It isn't always easy to tell, particularly if you use an invalid declaration of course. A char[] can't be marshaled as LPWStr, it has to be LPArray. Now the CharSet attribute plays a role, since you did not specify it, the char[] will be marshaled as an 8-bit char[], not a 16-bit wchar_t[]. The marshaled array element is not the same size (it is not "blittable") so the marshaller must copy the array.
Pretty undesirable, particularly given that your C++ code expects wchar_t. A very easy way to tell in this specific case is not getting anything back in the array. If the array is marshaled by copying then you have to tell the marshaller explicitly that the array needs to be copied back after the call. You'd have to apply the [In, Out] attribute on the argument. You'll get Chinese.
The normal way to tell if the array gets marshaled by copying is by using the debugger. Enable unmanaged debugging in your C# program. Set a breakpoint on the call as well as a breakpoint in the first statement in the native function. When the 1st breakpoint hits, use Debug + Windows + Memory + Memory 1. Put buff in the Address box and switch the display to "4-byte Integer". You'll see the address of the array object, the 4-byte type handle, the 4-byte array length and the array content itself. So you know that if the array isn't copied that the passed addressed is the displayed address plus 8.
Press F5 to continue, the breakpoint in the native function hits. Look at the pchText argument, the debugger tells you its address. If it matches then the marshaller simply passed a pointer. If not then you got a copy of the array.
Let's do a small experiment. First, let's change your COM method to look like this (in C++):
STDMETHODIMP CComObject::Next(ULONG* pcch, int* addr, OLECHAR* pbuff)
{
pbuff[0] = L'A';
pbuff[1] = L'\x38F';
*addr = (int)pbuff;
*pcch = 1;
return S_OK;
}
Then, change the C# method signature:
void Next(ref uint pcch, out IntPtr addr,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
char[] pbuff);
Finally, test it like this:
uint cch = 10;
var buff = new char[cch];
IntPtr addr1;
unsafe
{
fixed (char* p = &buff[0])
{
addr1 = (IntPtr)p;
}
}
IntPtr addr2;
com.Next(ref cch, out addr2, buff);
Console.WriteLine(addr1 == addr2);
As expected, addr1 == addr2 is true. Thus, apparently the array does get pinned rather than copied when passed to COM.
That said, I couldn't find any documentation which would feature this as a hard requirement for a CLR implementation. E.g., this may or may not be true for Mono.

How to convert ref byte into byte[]?

Have anyone had an experience in converting ref byte into byte[]?
If the function takes an argument like
void foo(ref byte buffer);
then it is possible to call foo using
void call_func()
{
byte arr[] = new byte[10];
foo(ref arr[0]);
}
The question is how can one re-convert the buffer argument into byte[] array in the foo.
You don't.
In order to avoid pinning the entire array, the runtime might just make a copy of the single element you selected (and then copy back after the call). In that case your function will get the address of a temporary copy, which is unrelated to the address of the other array elements. (Well, there could be some aliasing considerations, this optimization is much more likely for pinvoke and/or remote calls, where aliasing analysis is more feasible)
If you need an array, pass the array.
If you don't care that it might not work right, you can use unsafe code to get to the other elements.
pinned( byte* p = &buffer ) {
buffer[4] = 0;
}

How to map and marshal a C array into a C# code

I am writing C# code that call a C library and something it is not quite clear in my mind.
The C function has this signature:
double* DoSomeStuff(double* input,int numberOfElements);
I have mapped the function as:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(ref double input, int numberOfElements) ;
The input value is an array, so the C function will expect a contiguous memory layout. I am more familiar with C++ than C#. In C++ I'd used a std::vector to store the data and then I would use the data() method to get the pointer and exchange the information with C code. std::vector guarantees a contiguous layout memory.
Which data structure can I used in C#? Is there anything like std::vector in C#?
I have faced before the same problem for a string (In C++ std::string is just a std::vector with some make up). And I have solve the problem using:
System.IntPtr stringExample = Marshal.StringToHGlobalAnsi("StringExample");
The static function does the job for me. There is anything like this function for other types?
I have asked already too many questions, I think the most important one is: what is the best practise to solve this kind of problem?
Thanks
1)
Define the input as IntPtr:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(IntPtr input, int numberOfElements) ;
2)
Create an array in a fixed block, then create an IntPtr from the Pointer and then pass it to DoSomeStuff.
double[] input = new double[20];
IntPtr result = IntPtr.Zero;
fixed(double* d = &input[0])
{
result = DoSomeStuff(new InptPtr(d), 20);
}
...
Reason for the fixed block is so that GC does not move the array while unmanaged code is populating it.
To make your example work you should define the siganture of the extern function as follows:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)], int numberOfElements);
The second (named) parameter of MarshalAs attaribute tells to the marshaller where the size of the array stored.
Regarding the second question, C# has List<Type> class that behaves similary to std:vector<Type>. However, I don't think you can directly provide it to the marshaller. What you can do is to use ToArray() methor of the List class, to get an array.

Are double* and double** blittable types? C#

I have a question regarding marshalling of C++ arrays to C#.
Does the double* automatically convert to double[]?
I know double is a blittable type, so double from C++ is the same as double from C#.
And what about double**, does it convert to double[,] ?
I have the following unmanaged function:
int get_values(double** param,int sz)
where param is a pointer to array of doubles and sz it's size.
How can I DLLImport this function to C#?
Thanks in advance
The declaration makes no sense. It would make sense if the function takes a pointer to an array of doubles, but then the declaration would be
int get_values(double* array, int size);
Where size would give the size of the array allocated by the client and the function's return value indicates how many doubles were actually copied into the array. The equivalent P/Invoke declaration would be:
[DllImport("blah.dll")]
private static extern int get_values(double[] array, int size);
You have to allocate the array with new to the size you promised before calling the function.
But the double** argument is a hangup. It could mean that the function returns a pointer to an array of doubles but then the size argument makes little sense. Since it is the function that owns the array and controls its size. Or it could mean that the client passes a two-dimensional array, but then having only one size argument makes no sense.
Please update your question with the correct interpretation of what the function does.
This article says the following:
The following complex types are also
blittable types:
One-dimensional arrays of blittable
types, such as an array of integers.
However, a type that contains a
variable array of blittable types is
not itself blittable.
In the context of a function's parameter type, double* and double[] are identical:
void f(double* p);
void g(double p[]);
void h(double p[10]); // even if you supply a size! (it's ignored)
void i(double (&a)[10]); // now this is different
In other contexts they aren't:
void j() {
double a[10]; // sizeof a == sizeof(double) * 10
double* p; // sizeof p == sizeof(void*)
}
This holds similarly for double** vs double*[], but note double[][] (without sizes) is different, and with sizes means a pointer-to-array (you have to specify all but one dimension).
It does sound like you're using a double** when it's not needed. Does just passing the array as a double* work for you?
int get_values(double* array, int size);
void func() {
double a[10];
get_values(a, 10);
}
(I know I didn't answer your DLLImport question, I don't know the answer.)

Categories