none
Array returned from native DLL call only has 1 element RRS feed

  • Question

  • Hi again,

     

    I'm starting to feel like a right pain, always begging for help on these boards but as you've all been so helpful, I've got one more issue...

     

    I'm passing an array from a c# app to a native unmanaged c++ dll.

     

    C++ exported method:

     

    __declspec(dllexport) bool SearchTest(MY_STRUCT *structArray[], int iMaxRes, int &size)

     

    C# extern method declaration

     

    [DllImport("C:\\....dll")]

    public static extern bool SearchTest([MarshalAs(UnmanagedType.LPArray)]

    ref MY_STRUCT[] data, int maxRes, ref int returnedData);

     

    Array declaration

     

    [MarshalAs(UnmanagedType.ByValArray)]

    MY_STRUCT[] searchResultArray = new MY_STRUCT[MAX_RESULTS];

     

    C# Call

     

    SearchTest(ref searchResultArray, MAX_RESULTS, ref iResults);

     

    This all appears at first glance to work fine.  However, no matter how many elements I set in the DLL, searchResultsArray[0] is fine, but searchResultsArray[1] and upwards I get Out of bounds array index errors on. 

     

    The structure itself is defined as:

     

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

    public struct MY_STRUCT

    {

        public uint ulFieldID;

        public ushort usFieldLength;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=FIELD_LENGTH)]

        public string strFieldData;

    };

     

    The wierd bit is before the C# call, I can see all 10 empty elements in the debug inspector.  After the call, it acts as if only 1 element was defined.

     

    Any ideas?  Please if you can, it's driving me nutty as I know it's going to be something simple I'm missing!

     

    Lee.

     

    Edit:

     

    Ok, I now know that this will never work.  You can't populate an array passed like this, it apparently needs marshalling to an IntPtr, and then back again after the DLL call.

     

    I've modified the C++ code to account for this, and I believe I've got the marshalling code done.  However, I'm having trouble with getting the IntPtr back to and array of structs:

     

    int len = MAX_RESULTS;

    for (int i = 0; i < len; i++)

    {

       int sizeArr = Marshal.SizeOf(searchResultArrayIdea);

       MY_STRUCT pD = new MY_STRUCT();

       Marshal.PtrToStructure(((IntPtr)(buf.ToInt32() + (i * sizeArr))), pD);

    }

     

    To explain, I am trying to create a new struct, and then marshall the IntPtr data into it, incrementing the IntPtr each time using pointer arithmetic.  This gives me an error as apparently the struct is a value class.

     

    Any clues?

     

     

    Wednesday, May 2, 2007 8:29 AM

Answers

  • No worries people, done it.

     

    For anyone that comes after:

     

    Get the IntPtr for the struct

     

    private IntPtr MarshalArray(RESULT_DATA[] MyArray)

    {

        int iStructSize = Marshal.SizeOf(MyArray[0]);

         IntPtr Buf = Marshal.AllocCoTaskMem(MyArray.Length * iStructSize);

     

        int iCurOffset = 0;

        foreach (RESULT_DATA item in MyArray)

        {

            Marshal.StructureToPtr(item, (IntPtr)(Buf.ToInt32() + iCurOffset), false);

            iCurOffset += iStructSize;

        }

    return Buf;

    }

     

    Get the structs out of the IntPtr after the native call

     

    // How big is one single structure (for the pointer arithmetic in a minute)

    int sizeOfStruct = Marshal.SizeOf(searchResultArray[0]);

    // loop through the amount of structs sent back, and retrieve them.

    int iCounter = 0;

    for (int i = 0; i < results; i++)

    {

        RESULT_DATA pD;

        pD = (RESULT_DATA)Marshal.PtrToStructure(((IntPtr)(buf.ToInt32() + iCounter)), typeof(RESULT_DATA));

        searchResultArrayIdea = pD;

        iCounter += sizeOfStruct;

    }

     

    Set the native method to take a ref IntPtr and the size,  have the C++ side take a RESULT_DATA** structArray parameter to access the IntPtr.

     

    Job done, works a treat.

     

    Lee.

    Wednesday, May 2, 2007 10:53 AM

All replies

  • No worries people, done it.

     

    For anyone that comes after:

     

    Get the IntPtr for the struct

     

    private IntPtr MarshalArray(RESULT_DATA[] MyArray)

    {

        int iStructSize = Marshal.SizeOf(MyArray[0]);

         IntPtr Buf = Marshal.AllocCoTaskMem(MyArray.Length * iStructSize);

     

        int iCurOffset = 0;

        foreach (RESULT_DATA item in MyArray)

        {

            Marshal.StructureToPtr(item, (IntPtr)(Buf.ToInt32() + iCurOffset), false);

            iCurOffset += iStructSize;

        }

    return Buf;

    }

     

    Get the structs out of the IntPtr after the native call

     

    // How big is one single structure (for the pointer arithmetic in a minute)

    int sizeOfStruct = Marshal.SizeOf(searchResultArray[0]);

    // loop through the amount of structs sent back, and retrieve them.

    int iCounter = 0;

    for (int i = 0; i < results; i++)

    {

        RESULT_DATA pD;

        pD = (RESULT_DATA)Marshal.PtrToStructure(((IntPtr)(buf.ToInt32() + iCounter)), typeof(RESULT_DATA));

        searchResultArrayIdea = pD;

        iCounter += sizeOfStruct;

    }

     

    Set the native method to take a ref IntPtr and the size,  have the C++ side take a RESULT_DATA** structArray parameter to access the IntPtr.

     

    Job done, works a treat.

     

    Lee.

    Wednesday, May 2, 2007 10:53 AM
  •  

     Hi Lee. I am trying to do the exact same things as you. I want to pass my struct array to a dll file written in C. But when i am trying to get the answers my array has only one element. I dont fully understand your solution to the problem. This is quite new for me. One of the things are i cant see where do you make the call to the Dll and where do you call private IntPtr MarshalArray(RESULT_DATA[] MyArray)? how does your C function look now?
    I would be so thankfull if you could help me to understand these things. maybe you can show me some more source code.

    Best regards
    /Rob

    Thursday, August 28, 2008 8:37 AM