How to know pointer to structure by it's array pointer? - c#

I have structure:
public struct MyStruct
{
public int a;
public int b;
public byte[] mass;
}
I need:
Pass poiner to "mass" array to C++ unmanaged function.
And after it done all work it will return me pointer to "mass".
So I have the list of MyStruct. And I need to know what the MyStruct in the list contains returned "mass"(wich pointer to I have).
If I know pointer to "mass" can I reduce pointer to 8 bytes and take pointer to MyStruct?
HOW TO :
1.Get IntPtr to "mass" array?
2.Get IntPtr to MyStruct structure?
3.Get MyStruct from IntPtr?
But, do not using any copy procedure, like Marshal.Copy...
Or is there a better way to do what I need ? Can I use pointers like in C++ or IntPtr is enought, and how can I do that?

Assuming that the memory for the array is allocated by the managed code:
When you pass an array to an unmanaged function via P/Invoke, then by default the array is generally pinned in memory by the marshaller so that the memory used by the array does not have to be copied.
You should not need to use an IntPtr at all - you just need to declare the P/Invoke so that it is accepting an array parameter.
However, things are different if the unmanaged code is allocating memory to be returned to the managed code; then things get MUCH more difficult.
Assuming that's not the case, then if you can show us the "C" function declaration we might be able to come up with a P/Invoke declaration.
(I do have a feeling that your situation may be a bit more complicated though...)
Some useful links for you:
http://msdn.microsoft.com/en-us/library/z6cfh6e6%28v=vs.80%29.aspx
http://msdn.microsoft.com/en-us/library/zah6xy75.aspx
How can I pass a pointer to an array using p/invoke in C#?
And some lower level information about the optimizations that the marshaller makes when calling unmanaged code and passing arrays. Essentially, if it can it doesn't make a copy of the data at all:
http://msdn.microsoft.com/en-us/library/23acw07k%28v=vs.80%29.aspx

Take care as the structure may have some specific memory alignment.
You may be interested by this link

Related

Storing data for unmanaged code when using P/Invoke

I have an array of arrays of this struct (shown here in C#, but existing in C++ as well):
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
IntPtr name; //pointer to string, char* on C++ side
long pValues;
long jValues;
long eValues;
long kValues;
int cost;
};
and an algorithm in a C++ DLL that does work on it, being called from managed C# code. It's CPU-heavy, which is what necessitates this as it runs much faster in C++ than C#. The managed (C#) side never has to know the contents of the struct data, as the algorithm only returns a single array of ints.
So, how would I go about storing this data in the most efficient way (ie with the least overhead), for the lifetime of the application? I think I have it narrowed down to two options:
Initialize structs and set values in C#, pin memory with GCHandle and pass reference to C++ whenever I want to do work (see this post on Unity forums)
Initialize structs and set values in C++, have structs persist in memory on unmanaged side
So my questions are very specific:
With 1, I'm confused as to how marshalling works. It looks like in MSDN: Copying and Pinning that you are able to pass arrays of structures by pinning and passing a reference to the pinned data, without having to copy or convert any of it (and as long as the struct looks the same on both sides). Am I reading that correctly, is that how it actually works? Referring to the Unity3d forum post, I see Marshal.PtrToStructure being called; I thought that performs copying operations? As the data would be stored on the managed side in this instance, having to copy and/or convert the data every time the C++ function is called would cause a lot of overhead, unless I'm thinking that those type of operations are a lot more expensive than they actually are.
With 2, I'm wondering if it's possible to have persistence between C++ calls. To the best of my knowledge, if you're P/Invoking from a DLL, you can't have persistent data on the unmanaged side, so I can't just define and store my struct arrays there, making the only data transferred between managed and unmanaged the int array resulting from the unmanaged algorithm. Is this correct?
Thank you very much for taking the time to read and help!
If the C# code does not need to know the internals of the array and the structure, don't expose it to the C# code. Do all the work on this type in the unmanaged code and avoid marshalling overhead.
Essentially, you want to follow this basic pattern. I'm sure the details will differ, but this should give you the basic concept.
C++
MyStruct* newArray(const int len)
{
return new MyStruct[len];
}
void workOnArray(MyStruct* array, const int len)
{
// do stuff with the array
}
void deleteArray(const MyStruct* array)
{
delete[] array;
}
C#
[DllImport(dllname)]
static extern IntPtr newArray(int len);
[DllImport(dllname)]
static extern void workOnArray(IntPtr array int len);
[DllImport(dllname)]
static extern void deleteArray(IntPtr array);

Exchange pinned array's pointer with an unmanaged memory pointer

I'm pinning and unpinning with:
GCHandle pinArray(object a)
{
return GCHandle.Alloc(a, GCHandleType.Pinned);
}
void unpinArray(GCHandle h)
{
h.Free();
}
before and after an opencl method so array does not move while computing on it. Now I need to exchange backing array pointer with an aligned unmanaged array pointer to have faster read/write operations on it.
But I couldn't find anything like "change value of gchandle backing array pointer" info.
I need something like an "exchange" method:
GCHandle h=pinArray(array);
// how to?
IntPtr oldBackingArray=exchange(h,alignedMallocCSpace(10000000,4096));
// unmanaged operations
copyValues(h,oldBackingArray);
compute(array,...); // only passing with "array" for simplicity everywhere
array[3]=5;
l=array.toList();
compute(array,....);
Console.WriteLine(array[3]);
copyValues(oldBackingArray,h);
freeCSpace(exchange(h,oldBackingArray));
unpinArray(h);
does this need reflection to access and change that variable? There are also many C# methods using those arrays inside compute method so will it give more speed even on C# space too? So I'm tring to let C# to use alignedAlloc space for everything using "array" object until I unpin it.
You don't need to. The GCHandle relates to managed memory; unmanaged memory does not require any kind of GCHandle. Nor is it possible to talk to that memory as though it is a managed array. Instead, you need to accept that the unmanaged data is a pointer and only a pointer. You can abstract over the top of that to hide these details, but it doesn't change the reality. Fortunately, to the casual observer, talking to a SomeType[] is very similar to talking to a SomeType* - as long as you pass the lengths around yourself.
In the future, the upcoming Span<T> does a great job of unifying pointers and arrays, but that is only experimental at the moment.

How to cast an allocated memory block to an array addressable data type.

I am trying to Marshal some data from c# to a c library. The struct that I need to pass is just a collection of pointers... something like:
struct sometype {
type1* element1;
type2** element2;
type3** element3;
type4* element4;
}
Now... I've opted to forgo the attempt to copy all of these types into c# and marshal them as structures and decided to just fill a IntPtr array with the correct data in the correct order and pass it as a pointer. As you can see, in this setup I am passing a 4 position array of pointers with positions 1 and 2 being arrays of pointers themselves. It was simple enough and indeed does work when I marshal by fixing the IntPtr array...
fixed(IntPtr* ptr = structArray){
InteropCall(ptr);
}
However, I soon realized that the c library is actually keeping a reference to the struct and after sometime, expectedly breaks when the array is moved or collected. So my solution was to allocate a block of memory using Marshal.AllocHGlobal and hold on to the reference throughout the time the c library needs that data.
So I run this:
IntPtr* pointerArray = (IntPtr*)Marshal.AllocHGlobal (IntPtr.Size * 4);
However, pointerArray always comes out as IntPtr.Zero... or i guess... just zero.
What am I doing wrong? Can I not cast a memory block into a pointer datatype? What if I wanted a byte* or int* so that I can operate on the memory block like an array?

Marshaling a struct that has a variable array with zero elements

.NET 4 with 64bit. I have a C# structure that I intend to marshal to C
[StructLayout(LayoutKind.Sequential)]
public struct ParentStruct
{
public float[] FArray;
public int FArrayLength;
}
To
struct ParentStruct
{
float* FArray;
int FArrayLength;
};
The special circumstances here is the array I need to copy float[] FArray is always pinned and has 0 elements and I am only interested in copying its pointer across to native and not interested in the actual elements it has (which are none!) nor in allocating memory on the native side on the free store (heap), it will be pointing to a garbage location, this is fine.
The technical reason for doing this is that float[] FArray is pointing to an address on the GPU memory and once it is marshaled to the GPU, it will be pointing to the right data.
I want to be able to marshal this struct to C, but I am not sure what is the proper marshal way
I tried marshaling it in the current structure, I got Object contains non-primitive or non-blittable data.
I tried adding [MarshalAs(UnmanagedType.LPArray)] and I was getting Type 'Test.ParentStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
By the way, I do understand why I am getting these errors, what I really want is a way to marshal given that my array is not a variable array (but it looks like one to the interop libraries) and you can think of my struct as a fixed size.
N.B. I have to use a float[] rather than a uint or something like that because of intellisense and other constraints.

How to pass Object array to unmanaged code?

I'm trying to pass an array of objects from C# to unmanaged C++, and nothing seems to work.
The compiler won't let me pretend the array is an IntPtr. Casting the array to an IntPtr doesn't work. I've tried to pass the address of pinned data, but this didn't work either.
I just need to pass a pointer to the beginning of the array, and this is turning out to be incredibly difficult.
Any suggestions or links? Thanx!
What finally worked:
Passing an array of structs instead of an array of objects (references).
Putting "[StructLayout(LayoutKind.Sequential, Pack = 1)]" just before the struct definition.
Putting "[MarshalAs(UnmanagedType.LPWStr)]" before the string (in the struct definition) to cause the string to appear as a wide-character string on the C++ side.
Declaring an array of structs for the argument in the DllImport declaration: "VariableObject[] varObj".
Declaring a pointer to the class as the parameter on the C++ side. (The C++ class mirrors the C# struct.): "VariableObject* varObj".
Can you cast to a void pointer? Be sure the array of objects is pinned.
In your C#/Managed method signature, mark the input parameter with [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]...
[DllImport(...)]
public void DoTask
(
...,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] results,
...
);
Then call it as you did always. Also, inside the unmanaged code, you can modify this array. I suggest that you send in an extra int telling the unmanaged code what the size of the array is to prevent “array out of bound” modification.

Categories

Resources