Returning a struct from PInvoke - c#

Im trying to return a struct from a call to a c++ dll from c#, and I get some complicated and bad behaviour that I dont understand. If my struct contains a constructor I get a memory access violation when returning it, if it is less than 12 bytes. If it is larger there is no problem. If I remove the constructor it works for all sizes. I suppose this could have something to do with my calls being c-style but I cannot find information about this. So it would be much appreciated if someone could explain or point my in a good direction of what is going on. Below are examples of code that does and does not work:
Code that works
C++ side header:
#define DLL_API __declspec(dllexport)
struct Struct4Byte
{
int x1;
};
struct Struct12Byte
{
int x1;
int x2;
int x3;
Struct12Byte() { x1 = 0; x2 = 1; x3 = 2; }
};
#ifdef __cplusplus
extern "C" {
#endif
DLL_API Struct4Byte Function4Byte(int x);
DLL_API Struct12Byte Function12Byte(int x);
#ifdef __cplusplus
}
#endif
C++ file:
Struct4Byte Function4Byte(int x)
{
Struct4Byte output;
output.x1 = 1 + x;
return output;
}
Struct12Byte Function12Byte(int x)
{
Struct12Byte output;
output.x1 = 1 + x;
output.x2 = 2 + x;
output.x3 = 3 + x;
return output;
}
On the calling side (C#) I do:
[StructLayout(LayoutKind.Sequential)]
internal struct Struct4Byte
{
public int x1;
}
[StructLayout(LayoutKind.Sequential)]
internal struct Struct12Byte
{
public int x1;
public int x2;
public int x3;
}
class Program
{
static void Main(string[] args)
{
Struct4Byte result1 = Function4Byte(3);
Struct12Byte result2 = Function12Byte(3);
}
[DllImport(#"PInvokeCheck.dll")]
internal static extern Struct4Byte Function4Byte(int x);
[DllImport(#"PInvokeCheck.dll")]
internal static extern Struct12Byte Function12Byte(int x);
}
Code that does not work
If I now change in the header file the definition of the Struct4Byte to:
struct Struct4Byte
{
int x1;
Struct4Byte(){ x1 = 0; }
};
then I get Memory Access violation.
I've noted something that might be of interest. The problem is already when calling Function4Byte. Putting a brakpoint and viewing x in the function (I put the function again below) shows that x get some random value.
Struct4Byte Function4Byte(int x)
{
Struct4Byte output;
output.x1 = 1 + x;
return output;
}

I might have found the issue. Their was a warning that I had missed that: warning C4190: 'Function4Byte' has C-linkage specified, but returns UDT 'Struct4Byte' which is incompatible with C. From this discussion it is clear that it can lead to some undefined behaviour and that the layout of the struct may change: Error in C++ code linkage: warning C4190: type has C-linkage specified, but returns UDT which is incompatible with C
So that seems explain the problem I've had.

Yea returning structs like that isn't supported and the none of Microsoft's mainline P/Invoke articles represent an example of returning structs like that. None that I read anyways.
Here's a git hub example of your project doing it the correct way.
https://github.com/ditchcode/PInvokeTesting
I found this article most helpful on the marshaling of Structs and Classes
https://learn.microsoft.com/en-us/dotnet/framework/interop/passing-structures

I think the reason is explained in the calling conventions.
x64 calling convention
User-defined types can be returned by value from global functions and static member functions. To return a user-defined type by value in RAX, it must have a length of 1, 2, 4, 8, 16, 32, or 64 bits. It must also have no user-defined constructor, destructor, or copy assignment operator. It can have no private or protected non-static data members, and no non-static data members of reference type. It can't have base classes or virtual functions. And, it can only have data members that also meet these requirements. (This definition is essentially the same as a C++03 POD type. Because the definition has changed in the C++11 standard, we don't recommend using std::is_pod for this test.) Otherwise, the caller must allocate memory for the return value and pass a pointer to it as the first argument. The remaining arguments are then shifted one argument to the right. The same pointer must be returned by the callee in RAX.
x86 calling convention
On x86 platforms, all arguments are widened to 32 bits when they are passed. Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register as pointers to hidden return structures. Parameters are pushed onto the stack from right to left. Structures that are not PODs will not be returned in registers.
Doing what is says for x64 is a good alternative solution.
the caller must allocate memory for the return value and pass a pointer to it as the first argument
So your code would look like this
Struct4Byte Function4Byte(Struct4Byte& output, int x)
{
output.x1 = 1 + x;
}
Struct12Byte Function12Byte(Struct12Byte& output, int x)
{
output.x1 = 1 + x;
output.x2 = 2 + x;
output.x3 = 3 + x;
}
class Program
{
static void Main(string[] args)
{
Struct4Byte = Function4Byte(out var result1, 3);
Function12Byte(out var result2, 3);
}
[DllImport(#"PInvokeCheck.dll")]
internal static extern void Function4Byte(out Struct4Byte result, int x);
[DllImport(#"PInvokeCheck.dll")]
internal static extern void Function12Byte(out Struct12Byte result, intx);
}

Related

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);

Read Write C++ Dynamic Arrays in C# (InteropServices)

I have a C++ class which has a header(matrixheader.h) such that :
#pragma once
class M
{
public:
M(int m,int n);
void MSet(int m,int n,double d);
double MGet(int m,int n);
~M();
private:
double** mat;
};
Class is defined as follows in (matrixbody.cpp):It is built in Win32 Platform.
#pragma once
#include "matrixhead.h"
M::M(int m,int n)
{
mat = new double*[m];
for (int i = 0; i < m; i++)
{
mat[i] = new double[n];
}
}
void M::MSet(int m,int n,double d)
{
mat[m][n] = d;
}
double M::MGet(int m,int n)
{
double d = mat[m][n];
return d;
}
M::~M()
{
delete[] mat;
}
I have made a wrapper for the Class like so(matrixwrapper.cpp):The wrapper is also built in Win32 platform.
#include "matrixhead.h"
#include "matrixbody.cpp"
extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M o(m,n);
return &o;
}
extern "C" __declspec(dllexport) void setData(void* mp,int m,int n,double d)
{
M* ap = (M*)mp;
M a = *ap;
a.MSet(m,n,d);
}
extern "C" __declspec(dllexport) double getData(void* mp,int m,int n)
{
M* bp = (M*)mp;
M b = *bp;
double d = b.MGet(m,n);
return d;
}
I import the class to C# and try to call the C++ dl methods from C#:
using System;
using System.Runtime.InteropServices;
namespace wrappertest
{
class Program
{
[DllImport("matrixwrapper.dll")]
unsafe public static extern void* Make(int m,int n);
[DllImport("matrixwrapper.dll")]
unsafe public static extern void setData(void* mp,int m, int n,double d);
[DllImport("matrixwrapper.dll")]
unsafe public static extern double getData(void* mp,int m, int n);
static unsafe void Main(string[] args)
{
void* p = Make(10, 10);
setData(p,10,1,10);
Console.WriteLine(getData(p,10,1));
}
}
}
But when i try to run the C++ dll methods from C# i get the following error
1//Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.
2//An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.
Questions:
1//What is wrong in the above code ?
2//Considering that my final objective is to make a 2d dynamic array in C++ and read/write data in the array such as the one double**mat in the matrixheader.h file above from C#?is there any other way to implement it ?
Let's get the easy thing first:
An attempt was made to load a program with incorrect format when runnning in x86 Active/x86 or in AnyCPU platform.
This simply means you have a platform mismatch. You're either trying to load an x86 C++ dll in an x64 .NET runtime, or the reverse.
The following error is the real problem:
Attempted to read or write protected memory.This is often an indication that other memory is corrupt when running C# code in x64.
That's to be expected, because your Make function creates an object on the stack, then returns a pointer to it. By the time you read back this object, the contents on the stack has changed (the stack is being reused), and the mat pointer points somewhere else, most probably into unallocated memory.
Please see this answer where I go into deeper detail about this issue (it's C# but it's the same issue).
You have to allocate some dynamic memory to solve your problem. You may try:
extern "C" __declspec(dllexport) void* Make(int m,int n)
{
M* o = new M(m,n);
return o;
}
And of course, you'll have to create one more method to perform the matching delete if you don't want to leak memory.
Also, like Mgetz points out in the comments, you have a memory leak in the M class itself. The delete[] mat; call in the destructor won't free every allocated chunk of memory. You're calling new in the constructor m + 1 times, this means you have to call delete[] m + 1 times also in the destructor, once for each new. You probably should keep m and n as fields in your class (at least m is mandatory to know how many calls to delete[] you have to do).
A much better solution would be to use a single array instead of jagged arrays. You calculate the index i, j in that array as i * m + j. You may also use a std::vector or just do it in C# altogether:
public class M
{
private double[] _items;
private int _m;
private int _n;
public M(int m, int n)
{
_items = new double[m * n];
_m = m;
_n = n;
}
public this[int i, int j]
{
// Here, you should perform a bounds check on i and j against _m and _n
get { return _items[i * _m + j]; }
set { _items[i * _m + j] = value; }
}
}

Return list of points (x,y,z) from C to C# using PInvoke

I need to return a list of points i have from a C dll to a C# application using PInvoke. These are points in 3 dimensions [x,y,z]. The number of points varies by what kind of model it is. In C i handle this a linked list of structs. But I don't see how i can pass this on to C#.
The way I see it, I have to return a flexible two dimensional array, probably in a struct.
Any suggestions to how this can be done? Both ideas on how to return it in C and how to access it in C# are highly appreciated.
A linked list of structs could be passed back, but it would be quite a hassle to deal with, as you would have to write code to loop through the pointers, reading and copying the data from native memory into managed memory space. I would recommend a simple array of structs instead.
If you have a C struct like the following (assuming 32-bit ints)...
struct Point
{
int x;
int y;
int z;
}
... then you'd represent it nearly the same way in C#:
[StructLayout(LayoutKind.Sequential]
struct Point
{
public int x;
public int y;
public int z;
}
Now to pass an array back, it would be easiest to have your native code allocate the array and pass it back as a pointer, along with another pointer specifying the size in elements.
Your C prototype might look like this:
// Return value would represent an error code
// (in case something goes wrong or the caller
// passes some invalid pointer, e.g. a NULL).
// Caller must pass in a valid pointer-to-pointer to
// capture the array and a pointer to capture the size
// in elements.
int GetPoints(Point ** array, int * arraySizeInElements);
The P/Invoke declaration would then be this:
[DllImport("YourLib.dll")]
static extern int GetPoints(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out Point[] array,
out int arraySizeInElements);
The MarshalAs attribute specifies that the array should be marshaled using the size specified in the second parameter (you can read more about this at MSDN, "Default Marshaling for Arrays").
If you use this approach, note that you must use CoTaskMemAlloc to allocate the native buffer as this is what the .NET marshaler expects. Otherwise, you will get memory leaks and/or other errors in your application.
Here is a snippet from the simple example I compiled while verifying my answer:
struct Point
{
int x;
int y;
int z;
};
extern "C"
int GetPoints(Point ** array, int * arraySizeInElements)
{
// Always return 3 items for this simple example.
*arraySizeInElements = 3;
// MUST use CoTaskMemAlloc to allocate (from ole32.dll)
int bytesToAlloc = sizeof(Point) * (*arraySizeInElements);
Point * a = static_cast<Point *>(CoTaskMemAlloc(bytesToAlloc));
*array = a;
Point p1 = { 1, 2, 3 };
a[0] = p1;
Point p2 = { 4, 5, 6 };
a[1] = p2;
Point p3 = { 7, 8, 9 };
a[2] = p3;
return 0;
}
The managed caller can then deal with the data very simply (in this example, I put all the interop code inside a static class called NativeMethods):
NativeMethods.Point[] points;
int size;
int result = NativeMethods.GetPoints(out points, out size);
if (result == 0)
{
Console.WriteLine("{0} points returned.", size);
foreach (NativeMethods.Point point in points)
{
Console.WriteLine("({0}, {1}, {2})", point.x, point.y, point.z);
}
}

Calling FORTRAN dll from C# and assigning values to array of structures

I can pass a C# struct into FORTRAN just fine. I can even pass an array of a C# struct as an array of TYPE() in FORTRAN. Where I run into trouble is when I tried to return values back into C#. Here is an example:
The fortran dll is:
MODULE TESTING
TYPE VALUEREF
INTEGER*4 :: A
ENDTYPE VALUEREF
CONTAINS
SUBROUTINE TEST_REF(T,N)
!DEC$ ATTRIBUTES DLLEXPORT :: TEST_REF
!DEC$ ATTRIBUTES ALIAS:'TEST_REF' :: TEST_REF
!DEC$ ATTRIBUTES VALUE :: N
IMPLICIT NONE
INTEGER*4 :: A,I,N
TYPE(VALUEREF) :: T(N)
A = 100
DO I=1,N
T(I)%A = A + I
END DO
END SUBROUTINE
END MODULE
and the C# calling function that expects results is:
[StructLayout(LayoutKind.Sequential)]
public struct ValueRef
{
public int a;
}
[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef[] t, int n);
void Main()
{
ValueRef[] T = new ValueRef[4];
for (int i = 0; i < T.Length; i++)
{
T[i].a = i;
}
Console.WriteLine("Initialize");
for (int i = 0; i < T.Length; i++)
{
Console.WriteLine(" A={0}", T[i].a);
}
Console.WriteLine("Call Fortran");
TEST_REF(T, T.Length);
for (int i = 0; i < T.Length; i++)
{
Console.WriteLine(" A={0}", T[i].a);
}
}
With results:
Initialize
A=0
A=1
A=2
A=3
Call Fortran
A=0
A=1
A=2
A=3
Debugging through the FORTRAN code, I see the initial values pass from C# to FORTRAN just fine. The the values get overridden with new values and control is passed back into C# where the old values are still contained within the ValueRef instances.
Why is it that I can pass and return an array of float, or int in a similar fashion, just fine. and I can pass and return singular structures with ref keyword, and I can pass but not return and array of struct?
PS. I am using Compaq Visual Fortran 6.5 & .NET 3.5
PS2. I appreciate any comments/ideas on this. I am 95% done with my project, and now I run into this issue. The whole point of this project is to use structures as much as possible to reduce the #of arguments passed to functions and retain certain aspects of OOP design.
I have done this in the past using a pointer, not an array. I think that your structures are being copied for the P/Invoke call:
[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef* t, int n);
You will need to pin your array before calling the method.
fixed (ValueRef* pointer = t)
{
TEST_REF(pointer, n);
}
Edit:
Based on the comments the solution is to declare the external as
[DllImport("mathlib.dll")]
static extern void TEST_REF([Out] ValueRef[] t, int n);
Here is a MSDN reference on Marshaling of arrays, and how they default to [In].

Marshalling an array of structures from C++ to C#?

In my C# code I'm trying to fetch an array of structures from a legacy C++ DLL (the code I cannot change).
In that C++ code, the structure is defined like this:
struct MyStruct
{
char* id;
char* description;
};
The method that I'm calling (get_my_structures) returns a pointer to an array of MyStruct structures:
MyStruct* get_my_structures()
{
...
}
There is another method that returns the number of stuctures so I do know how many structures get returned.
In my C# code, I have defined MyStruct like this:
[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{
[MarshalAsAttribute(UnmanagedType.LPStr)] // <-- also tried without this
private string _id;
[MarshalAsAttribute(UnmanagedType.LPStr)]
private string _description;
}
The interop signature looks like this:
[DllImport("legacy.dll", EntryPoint="get_my_structures")]
public static extern IntPtr GetMyStructures();
Finally, the code that fetches the array of MyStruct structures looks like this:
int structuresCount = ...;
IntPtr myStructs = GetMyStructures();
int structSize = Marshal.SizeOf(typeof(MyStruct)); // <- returns 8 in my case
for (int i = 0; i < structuresCount; i++)
{
IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i);
MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct));
...
}
The trouble is, only the very first structure (one at the offset zero) gets marshaled correctly. Subsequent ones have bogus values in _id and _description members. The values are not completely trashed, or so it seems: they are strings from some other memory locations. The code itself does not crash.
I have verified that the C++ code in get_my_structures() does return correct data. The data is not accidentally deleted or modified during or after the call.
Viewed in a debugger, C++ memory layout of the returned data looks like this:
0: id (char*) <---- [MyStruct 1]
4: description (char*)
8: id (char*) <---- [MyStruct 2]
12: description (char*)
16: id (char*) <---- [MyStruct 3]
...
[Update 18/11/2009]
Here is how the C++ code prepares these structures (the actual code is much uglier, but this is a close enough approximation):
static char buffer[12345] = {0};
MyStruct* myStructs = (MyStruct*) &buffer;
for (int i = 0; i < structuresCount; i++)
{
MyStruct* ms = <some other permanent address where the struct is>;
myStructs[i].id = (char*) ms->id;
myStructs[i].description = (char*) ms->description;
}
return myStructs;
Admittedly, the code above does some ugly casting and copies raw pointers around, but it still does seem to do that correctly. At least that's what I see in the debugger: the above (static) buffer does contain all these naked char* pointers stored one after another, and they point to valid (non-local) locations in memory.
Pavel's example shows that this is really the only place where things can go wrong. I will try to analyze what happens with those 'end' locations where the strings really are, not the locations where the pointers get stored.
I cannot reproduce your problem, which leads me to suspect that it's really on C++ side of things. Here's the complete source code for my attempt.
dll.cpp - compile with cl.exe /LD:
extern "C" {
struct MyStruct
{
char* id;
char* description;
};
__declspec(dllexport)
MyStruct* __stdcall get_my_structures()
{
static MyStruct a[] =
{
{ "id1", "desc1" },
{ "id2", "desc2" },
{ "id3", "desc3" }
};
return a;
}
}
test.cs - compile with csc.exe /platform:x86:
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{
[MarshalAsAttribute(UnmanagedType.LPStr)]
public string _id;
[MarshalAsAttribute(UnmanagedType.LPStr)]
public string _description;
}
class Program
{
[DllImport("dll")]
static extern IntPtr get_my_structures();
static void Main()
{
int structSize = Marshal.SizeOf(typeof(MyStruct));
Console.WriteLine(structSize);
IntPtr myStructs = get_my_structures();
for (int i = 0; i < 3; ++i)
{
IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i);
MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct));
Console.WriteLine();
Console.WriteLine(ms._id);
Console.WriteLine(ms._description);
}
}
}
This correctly prints out all 3 structs.
Can you show your C++ code that fills the structs? The fact that you can call it from C++ directly and get correct results does not necessarily mean it's correct. For example, you could be returning a pointer to a stack-allocated struct. When doing a direct call, then, you'd get a technically invalid pointer, but the data would likely remain preserved. When doing P/Invoke marshalling, the stack could be overwritten by P/Invoke data structures by the point it tries to read values from there.
I would change the structure. Instead of strings etc. , use IntPtr:
[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{
private IntPtr _id;
private IntPtr _description;
}
Then each value of the C# array could be manually marshalled to string using Marshal.PtrToString taking into account charset etc.
I usually end up working these things out by trial and error. Make sure you have the CharSet property set on your StructLayout, and I would try UnmanagedType.LPTStr, seems to work better for char *, even though I am not sure why.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class MyStruct
{
[MarshalAsAttribute(UnmanagedType.LPTStr)]
private string _id;
[MarshalAsAttribute(UnmanagedType.LPTStr)]
private string _description;
}
I think, also, in addition to the answers given, that you need to supply the length as well, ie
[MarshalAsAttribute(UnmanagedType.LPTStr), SizeConst = , ArraySubType = System.Runtime.InteropServices.UnmanagedType.AnsiBStr)]
This is a trial and error to get this right, also, another thing to consider, in some WinAPI calls that expect a string parameter, usually a ref parameter, it might be worth your while to try the StringBuilder class also...Nothing else comes to mind on this other than the points I have mentioned here... Hope this helps, Tom
You have to use UnmanagedType.LPTStr for char*. Also a StringBuilder is recommended for a non const char*:
And a CharSet specification:
[StructLayout(LayoutKind.Sequential, Charset = CharSet.Auto)]
public class MyStruct
{
[MarshalAsAttribute(UnmanagedType.LPTStr)]
private StringBuilder _id;
[MarshalAsAttribute(UnmanagedType.LPTStr)]
private StringBuilder _description;
}
As for the DllImport declaration, have you tried
[DllImport("legacy.dll", EntryPoint="get_my_structures")]
public static extern MarshalAs(UnmanagedType.LPArray) MyStruct[] GetMyStructures();
?
Also, if the previous doesn't work, leave it at IntPtr and try to Mashal the returned structs like this:
for (int i = 0; i < structuresCount; i++)
{
MyStruct ms = (MyStruct) Marshal.PtrToStructure(myStructs, typeof(MyStruct));
...
myStructs += Marshal.SizeOf(ms);
}

Categories