0

I have an IntPtr which is a pointer to an array of structs, and I'm trying to convert it to the array.

I tried

Marshal.Copy(srcIntPtr, destIntPtrArray, 0, destIntPtrArray.Length);

but after doing the copy, I'm not able to convert the IntPtr's inside of the destination array to the desired structure, while I can convert the srcIntPtr to the structure, which of course only gives me the data of the first index. It looks like after doing the copy, the destination array contains a bunch of broken IntPtr's

I also tried

    var size = Marshal.SizeOf(Marshal.ReadIntPtr(myIntPtr));

    for (int i = 0; i < length; i++)
    {
        IntPtr iP = new IntPtr(myIntPtr.ToInt64() + i * size);
    
        MyStruct ms =
            (MyStruct ) Marshal.PtrToStructure(iP, typeof(MyStruct ));
    }

which doesn't throw any error, but the data of the array of structs that I get out of my source IntPtr are not accurate.

This is the struct that I'm trying to convert to

struct MyStruct
{
    public Categories categories;  
    public Dimensions dimensions;
}



public struct Categories {
    public double d;
    public double c;
    public double b;
    public double a;
}



struct Dimensions {
    public double v;
    public double e;
}

I have [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] on top of the structs, but removing that doesn't break my code.

Thanks in advance

6
  • Can you show the declaration of the struct. Commented Dec 30, 2021 at 14:23
  • Dear @Sean I just edited my question. the declaration of the structs in the c++ library is identical to the ones in c#. conversion of an IntPtr to one single struct can be done without any problem Commented Dec 30, 2021 at 14:39
  • To clarify: you've tried Marshall.Copy to an IntPtr[] array and then looped through to Marshal.Copy each item in that IntPtr[] and the structs are broken/incomplete? Commented Dec 30, 2021 at 14:48
  • @JacobShanley no, I copied the IntPtr into IntPtr[] and then looped through that IntPtr[] and tried to Marshal.PtrToStructure each of them. but it throws an exception at the beginning of the loop and says Object reference is not set to an object (unknown wrapper) a null exception basically. shall I update the question? Commented Dec 30, 2021 at 14:53
  • 1
    Marshal.ReadIntPtr(myIntPtr) to read the array size is very unlikely to be correct. There is no hint whatsoever in the question to tell us how to obtain the array size. Never not a problem with a C array declaration, we can't see any sample C code that reads that same array. Commented Dec 30, 2021 at 17:36

1 Answer 1

1

This...

Marshal.ReadIntPtr(myIntPtr)

...returns an IntPtr, as the name implies. When passed to Marshal.SizeOf()...

var size = Marshal.SizeOf(Marshal.ReadIntPtr(myIntPtr));

...it does not return the size of the MyStruct to which it points but the size of IntPtr for the current process (either 4 or 8 bytes). To get the unmanaged size of MyStruct you need to call SizeOf() like this...

var size = Marshal.SizeOf<MyStruct>();

...or this...

var size = Marshal.SizeOf(typeof(MyStruct));

Also, the whole point of IntPtr is that it is address width-agnostic, yet you are explicitly retrieving it as a long...

IntPtr iP = new IntPtr(myIntPtr.ToInt64() + i * size);

I don't think that will have a negative effect on anything (as opposed to if you called ToInt32() in a 64-bit process, which could throw an OverflowException), but it would be better to let IntPtr handle calculating the pointer to each MyStruct element, which you can do like this...

IntPtr iP = IntPtr.Add(myIntPtr, i * size);

...or simply this...

IntPtr iP = myIntPtr + i * size;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much dear lance. I really appreciate this answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.