How to marshal arbitrary structures and unions between C# and C? - c#

I have a C program compiled to a DLL which I load into C# (using kernel32.dll LoadLibrary and FreeLibrary). Using GetProcAddress I can get a pointer to some data in memory, and I want to convert this data to an equivalent structure in C#.
My first idea was to create structs in C# that mapped directly to the C structs (using the StructLayout and MarshalAs attributes), and then just use the Marshal class (in System.Runtime.InteropServices). This works well for "simpler" structs, but does not work for multi-dimensional arrays and unions of arrays.
The data structures in C looks like the following (for example):
struct MyStruct
{
union MyUnion my_data[16][16];
}
union MyUnion
{
uint32_t ints[2];
uint8_t bytes[8];
}
I.e, it contains arbitrarily nested structs and unions, and multidimensional arrays of these.
Is there a built in way in C# to handle marshalling of these types of data structures?
Edit:
My requirements are:
The C# unions must work the same way as the C ones, i.e writing to the bytes field should also change the ints field (afaik, using explicit struct layout you can only make unions of built in value types in C#). (This is more a C# issue than a marshalling issue)
The C# structures must be marshallable to and from C/C++
As Selvin noted in the comments it's possible to flatten multi-dimensional arrays into a single dimension, and then access by [x + y*16]. However I prefer if the original dimensions were preserved, and the method of accessing is the same as in C.
My answer below does what I want, but since marshalling between C# and C++ is so common it feels like there should be a simpler way to achieve that result.

My current solution is to create a wrapper class around the raw data byte[], with accessors that imitate the structure of the underlying data.
For example, for a simple structure in C:
struct MySimpleStruct
{
uint32_t my_ints[16];
}
I create a wrapper:
public class MySimpleStruct
{
private byte[] _underlying;
public UintAccessor[] MyInts { get; }
public MySimpleStruct(byte[] data)
{
_underlying = data;
MyInts = new UintAccessor[16];
// for-loop to initialize each accessor with the right index
}
}
public class UintAccessor
{
public uint Value
{
get => BitConverter.ToUint32(_underlying, _idx);
set => BitConverter.GetBytes(value).CopyTo(_underlying, _idx);
}
public UintAccessor(byte[] data, int index) { /* ... */ }
}
and the wrapper can be used like so
var myStruct = new MySimpleStruct(theData);
myStruct.MyInts[5].Value = 123;
These wrapper classes can become quite complex, however we automatically generate the C structures and we will generate these C# wrappers at the same time, so the complexity is only an issue when generating the code.

Related

How to return `uint []` from `unsigned int *` using swig

I have to wrap the following c++ function:
class Foo {
unsigned int *getVector3();
};
The member function getVector3, returns a (fixed) 3D array, eg [1,2,3]. How should I use arrays_csharp.i for a return type ? The documentation only describes for input parameters:
22.4 C# Arrays
In my case the return type is always a fixed size array (of 3 elements).
I have an answer, although it's not entirely satisfactory in my view. That's mostly limited by my knowledge of C# though, so you can probably make it work better than I can.
I don't think arrays_csharp is what you're looking for here. It seems to be about pinning memory so it can be used as input to a function, but in your scenario you've got memory already allocated that you'd like to work with.
That's fairly easy (and for a 3D vector pretty cheap), using System.InteropServices.Marshal normally. So I put together a few typemaps using that which does what you want:
%module test
%typemap(csout,excode=SWIGEXCODE) unsigned *getVector {
global::System.IntPtr cPtr = $imcall;$excode
int[] tmp = new int[3];
// I have no idea why Marshal.Copy does not seem to have any support for unsigned types...
global::System.Runtime.InteropServices.Marshal.Copy(cPtr, tmp, 0, 3);
// There is probably a better way to go from int[3] -> uint[3], but it is not obvious to me
return new $typemap(cstype, $*1_type)[3]{($typemap(cstype, $*1_type))tmp[0],($typemap(cstype, $*1_type))tmp[1],($typemap(cstype, $*1_type))tmp[2]};
}
%typemap(cstype) unsigned *getVector "$typemap(cstype, $*1_type)[]"
%inline %{
unsigned *getVector() {
static unsigned arr[3] = {1,2,3};
return arr;
}
%}
A few notes though:
$typemap(cstype, $*1_type) is a fancy way of saying find me the C# type corresponding to my C element type. I tend to try and avoid explicitly writing types in typemaps as it makes things more generic.
Having said that Marshal.Copy only seems to work with signed rather than unsigned array types, for reasons I can't quite figure out. And I can't see an automatic way to find the corresponding signed type for an unsigned one, so I did have to explicitly write int[]
I'm not sure that signed -> unsigned casting is actually well defined behaviour in C#. Maybe this won't work properly for values where the last bit is set. You can work around that by increasing the size of the int type for tmp. (E.g. use int64 instead of int32, but that's not pretty)
There ought to be a better way to cast a whole array than what I've done, but I don't know the C# language all that well.
That said this is sufficient that I can run the following program (with Mono) and get the output expected
public class runme {
static void Main(string[] args) {
uint[] arr = test.getVector();
System.Console.WriteLine(arr[0]);
System.Console.WriteLine(arr[1]);
System.Console.WriteLine(arr[2]);
}
}
We could do a bunch more work to make this generic (i.e. other size vectors, other datatypes int16[4], etc.) if that was useful.

User Defined Types (UDT) in C#?

I know in VB you can define a UDT like:
Public Type Buffer1
ProductCode As String
SerialNumber As String
Date As Date
End Type
Is it possible to create a User Defined Type in C#? I know that they are used to implement data structures. I have researched and cannot seem to find anything.
The .NET equivalent of the VB6 Type is a struct with public fields. If what you need is the equivalent of the VB6 type, you should the ignore people who are telling you not to use a mutable struct.
Some people believe all data types should behave like class objects, and since structs with exposed fields behave in ways that class objects cannot they are evil.
In reality, there are times when the equivalent of a VB6 Type can be very useful, and any attempt to achieve such functionality with anything other than an exposed-field or otherwise "mutable" struct will be more cumbersome and yield less performant code than would using a type whose natural semantics precisely match what one is trying to achieve. Note that struct fields should generally be exposed as fields rather than properties, since the whole purpose of a VB6 Type is to serve as an aggregation of data types, rather than an ecapsulation of protected state.
There is, alas, one problem with .NET structure types, which is that unless you declare a structure as an unsafe type, only usable within unsafe code (and not usable in contexts which require being able to run in a Partial Trust environment), arrays within structures cannot achieve the semantics of arrays nor fixed-length strings in a VB6 Type. C# will allow one to declare fixed-sized arrays within a struct using the fixed keyword, but as noted only in conjunction with unsafe. Any other array declarations within a struct will cause a struct to hold an array reference rather than an array. Thus:
struct MyStruct {int n; int[] Arr; }
MyStruct a,b;
a.Arr = new int[4];
a.Arr[0] = 3;
a.n = 1;
b=a; // Copies the value of n, and the array reference in Arr, but not the array contents
b.n = 2;
b.Arr[1] = 2;
After the above code runs, b has its own copy of variable n, so the write to b.n will not affect a.n. Field b.Arr, however, holds a reference to the same array as a.Arr. An assignment directly to field Arr of b could make it point to a different array from a.Arr, but the assignment to b.Arr[1] doesn't actually write to field Arr but instead writes to the array object identified by that field, which is the same object identified by field a.Arr.
In some cases, you can replace what in VB6 would be a fixed-sized array with a simple list of discrete variables. Icky, but workable. Alternatively, if the restrictions associated with fixed arrays aren't a problem, you could use those. Beyond that, there isn't any good way to include arrays within a structure.
C# have classes and structs:
public class Buffer1
{
string ProductCode;
string SerialNumber;
DateTime Date;
}
But if you don't know classes, you must previously read some articles or books about C# (e.g. CLR via C#)
A "User Defined Data Type" from Visual Basic is called a Structure in VB.Net, and a struct in C#.
public struct Buffer1
{
public string ProductCode;
public string SerialNumber;
public DateTime Date;
}
Note that unlike the VB6 Type, which always makes all fields public, fields in all .NET types, including structures, default to private.

VARIANT datatype of C++ into C#

What is equivalent of the VARIANT datatype of C++ in C#?
I have code in C++ which uses the VARIANT datatype. How can I convert that code in C#?
Well, there are actually two variant's in C++: boost::variant and COM variant. The solution follows more or less the same idea, but the former is more complex. I expect you mean to use the latter.
Let me first start by telling that this is something you just shouldn't use if possible. That said, this is how you do it :-)
Variants and interop
Variants are sometimes used in interop of if you need the byte representation to be the same.
If you're dealing with interop, make sure to check out the VariantWrapper class on MSDN and make it work like that.
Variants and porting considerations
Variants are mostly used in APIs, and usually like this:
void Foo(SomeEnum operation, Variant data);
The reason it's done like this in C++ is because there is no base object class and you therefore need something like this. The easiest way to port this is to change the signature to:
void Foo(SomeEnum operation, object data);
However, if you're porting anyway, you also seriously want to consider these two, since they are resolved at compile-time and can save you the big 'switch' that usually follows in method Foo:
void SomeOperation(int data);
void SomeOperation(float data);
// etc
Variants and byte consistency
In rare cases you need to manipulate the bytes themselves.
Essentially the variant is just a big union of value types wrapped in a single value type (struct). In C++, you can allocate a value type on the heap because a struct is the same as a class (well sort-of). How the value type is being used is just a bit important but more on that later.
Union simply means you are going to overlap all the data in memory. Notice how I explicitly noted value type above; for variant's this is basically what it's all about. This also gives us a way to test it - namely by checking another value in the struct.
The way to do this in C# is to use the StructLayout attribute in a value type, which basically works as follows:
[StructLayout(LayoutKind.Explicit)]
public struct Variant
{
[FieldOffset(0)]
public int Integer;
[FieldOffset(0)]
public float Float;
[FieldOffset(0)]
public double Double;
[FieldOffset(0)]
public byte Byte;
// etc
}
// Check if it works - shouldn't print 0.
public class VariantTest
{
static void Main(string[] args)
{
Variant v = new Variant() { Integer = 2 };
Console.WriteLine("{0}", v.Float);
Console.ReadLine();
}
}
C++ variant's can also be stored on the heap as I noted earlier. If you do this, you probably still want the memory signature to be the same. The way to do this is to box the Variant struct we build earlier by simply casing it to object.
This is a tricky question.
From C# 4, you can use dynamic to indicate that the type is known at run-time.
By my personal understanding, however, c++ requires the type known at compile time. Thus you might consider to use object, but object in C# is an existent type.
For the concept of multi-type, single value (AKA polymorphism) of VARIANT, you would not need to find a corresponding type in C#, just define your classes and interfaces. You can always reference an object as its interface which the class implements.
If you are porting the code, and to figure out a syntax that you can simply use in LHS and for the considering of the type is known at compile time, then use var.
When .NET implements a COM interface, just use VARIANT* instead.
Then bypass marshalling on the .NET receiving side by using a IntPtr type to receive the pointer.
public class ComVariant
{
[StructLayout(LayoutKind.Sequential)]
public struct Variant
{
public ushort vt;
public ushort wReserved1;
public ushort wReserved2;
public ushort wReserved3;
public Int32 data01;
public Int32 data02;
}
private Variant _variant;
private IntPtr _variantPtr;
public ComVariant(int variantPtr) : this(new IntPtr(variantPtr))
{
}
public ComVariant(IntPtr variantPtr)
{
_variant = (Variant)Marshal.PtrToStructure(variantPtr, typeof(Variant));
_variantPtr = variantPtr;
}
public VarEnum Vt
{
get
{
return (VarEnum)_variant.vt;
}
set
{
_variant.vt = (ushort)value;
}
}
public object Object
{
get
{
return Marshal.GetObjectForNativeVariant(_variantPtr);
}
}
}
then if you are accessing a VT_UNKNOWN pointing to a COM interface object instance, just
var variant = new ComVariant(variantPtr);
var stream = variant.Object as IStream; // will not be null if type is correct
var obj = variant.Object as IObj; // in general...
will do the trick, but pay attention not to use a newly allocated VARIANT and giving its ownership to the .NET implementation without deallocating it somewhere...
For more complex code you might read this article which also talks about memory management.
Let's take a step back. Sooner or later, we want the actual data in the VARIANT. A VARIANT is just a holder for meaningful data. Suppose we converted the VARIANT to some sort of Object in C# that had the variant type and some raw buffer under the .NET hood (e.g. .NET strings can expose the raw buffer). At that point, the VARIANT type would need to be determined from the object and the raw data converted or cast to the data type specified by the variant, and then create a new Object e.g. string/int/etc. from the raw data.
So, rather than worry about passing the VARIANT to C#, look at the variant data type and convert it in C++ to the actual data type and pass that to C#.
For example, if the VARIANT type is VT_INT, then get the int from the variant and can use something like:
VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);
returnInt can be returned as an Out parameter from a C++ function in a C++ dll that can be called from C#. The C++ dll needs to use /clr option.
Function would look like:-
void ThisFunctionReturnsAnInt(Runtime::InteropServices::OutAttribute Int^ % returnIntValue)
{
VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);
}
Can use similar approach for other data types. It's only natural, a VARIANT of VT_INT is really just like an int, it's not as if there's some major conversion going on, you're just taking the actual value out of the VARIANT at the time when you're interested in it as you would if you were passing a straight integer value from C++ to C#. You would still need to do the gcnew anyway.

Conversion of unmanaged type structure pointer into managed type structure pointer

Consider the following stucture in c++, I need to wrap this using CLI to make it usable for C#
typedef struct A
{
int b[5];
A* next;
};
How can I do so? Please help.
non-op edit:
What I've tried is the following:
public ref struct ANET
{
array<int>^ b;
ANET^ next;
ANET()
{ b = gcnew array<int>(5) }
};
now let's say we have an pointer of object of A is a, pointer of object ofANET is aNET
nSize = sizeof(a->b)/sizeof(a->b[0]);
Marshal::Copy( IntPtr( ( void * ) a->b ), aNET->b, 0, nSize);
so far I am able get the values of a->b in aNET->b but I am stuck with marshaling the pointer of a->next to aNET->next.
Thanks
That's a linked list. So one option is to write C++/CLI code to adapt the native linked list to a .net LinkedList<T>. Going down this route will mean that you need to make copies of the list whenever it is modified in the native code and needs to be returned to the managed code. And vice versa.
If making copies is not an option then you should wrap the native linked list in a managed class. So you don't try to convert the struct definition at all. Instead you write a C++/CLI managed class that encapsulates the functionality that you need to expose. I can't say much more than that because you haven't given any information on the operations that you need to perform on this list. Now have you explained what the data flow is.

Structs with FieldOffsetValueAttribute

I am currently doing some reading on structs and came across an example of structs being used with attributes. In the example the struct attribute being used is [FieldOffset(0)] which it says makes sure the fields are stored in the same piece of memory.
What is the advantage(s) or disadvantage(s) of this?
Also why would one want to use FieldOffsetAttribute to put the fields in different parts of memory?
This is used to control the exact offset in memory of the members of the struct. It's sometimes used in C# when you want to represent a native (C++) struct in the context of a P/Invoke call.
In C# there is no things such as structs unions, so you have to use FieldOffsetValueAttribute.
I recommend you to read the following article.
I've seen this trick used somewhere, which will change the underlying type of the array, from uint to int, without copying the elements of the array:
[StructLayout(LayoutKind.Explicit)]
struct ArrayTypeChanger
{
[FieldOffset(0)]
public int[] ArrayOfInts;
[FieldOffset(0)]
public uint[] ArrayOfUInts;
}
and somewhere a type-changing method:
public static int[] ChangeArayType(uint[] input)
{
return new ArrayTypeChanger { ArrayOfUInts = input }.ArrayOfInts;
}
No memory is copied, which should make it very fast. Of course, it only works if the types have the same size (sizeof(uint) == sizeof(int)).
Not sure MS recommends this...
Other methods of changing the type of such an array (like Marshal.Copy()) envolve some sort of memory copy and that can be a problem with large arrays.

Categories