Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
167 views
in Technique[技术] by (71.8m points)

c# - PInvoke Pointer to struct including float array

I'm attempting to P Invoke a C library for use on a Xamarin android app.

Consider the following C structure:

typedef struct
{
    bool myBool;
    myOtherStruct sOtherStruct;
    int myInt;
    float myFloat;
    float myFloatArray[1024];
    float myFloatArray2[1024];
    float myFloatArray3[20];
    float myFloatArray4[30];
} sMyStruct;

This is called using the following function:

unsigned int initialise(sMyStruct* a_pMyStruct)

I've put this into a C# structure:

[StructLayout(LayoutKind.Sequential)]
public unsafe struct SMyStruct
{
    bool myBool;
    myOtherStruct sOtherStruct;
    int myInt;
    float myFloat;
    public fixed float myFloatArray[1024];
    public fixed float myFloatArray2[1024];
    public fixed float myFloatArray3[20];
    public fixed float myFloatArray4[30];

    public unsafe float[] MyFloatArray
    {
        get
        {
            fixed (float* ptr = myFloatArray)
            {
                float[] array = new float[1024];
                Marshal.Copy((IntPtr)ptr, array, 0, 1024 * sizeof(float));
                return array;
            }
        }
    }

    public SMyStruct (bool MyBool, myOtherStruct otherStruct, int MyInt, float MyFloat)
{
    myBool = MyBool;
    sOtherStruct = myOtherStruct;
    myInt = MyInt;
    myFloat = MyFloat;
}

Here's my function in C# to invoke this:

[DllImport("libMylib")]
private static extern unsafe uint initialise(SMyStruct* a_pMyStruct);

I then call this function with:

public unsafe void init ()
{
    SMyStruct initStruct;
    uint result = initialise(&initStruct);
}

So what happens is the C function will return my structure with A LOT of data. I then pass the structure again into another C routine which uses these parameters for the rest of the program.

My issue is how do I get the float array data back into the correct structure variable so that I can pass it again? At current my code has been based on these questions: Marshalling float Array to c# and Marshalling complex struct to c#

But I've not managed to code this so I can pass the float array back to my struct without even seeing a compiler error (let alone failing when I test it!)

How do I get the float array data into my structure?

EDIT After a couple of answers and comments, I'm adding what I was doing initially to try and add some clarity.

I get a compiler error when rather than using the "public unsafe float[]..." routine above I do this (within the struct):

public SMyStruct (bool MyBool, myOtherStruct otherStruct, int MyInt, float MyFloat, float* MyFloatArray, float* MyFloatArray2, float* MyFloatArray3, float* MyFloatArray4)
{
    myBool = MyBool;
    sOtherStruct = myOtherStruct;
    myInt = MyInt;
    myFloat = MyFloat;
    myFloatArray = MyFloatArray;
    myFloatArray2 = MyFloatArray2;
    myFloatArray3 = MyFloatArray3;
    myFloatArray4 = MyFloatArray4;
}

With this code I get the error "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement" At this point I attempted to use the copy routine instead.

What I want is to ensure the fields myFloatArray, myFloatArray2 etc. to be populated with whatever the initialise function returns. FYI myBool, sOtherStruct etc. are populated as I expect.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you don't need to access the data you can leave it as a pointer. Although it looks like you're responsible for the memory, so you'll need to alloc and later free the unmanaged memory you are using. Something like...

[DllImport("libMylib")]
private static extern uint initialise(IntPtr a_pMyStruct);

[DllImport("libMylib")]
private static extern uint anotherNativeMethod(IntPtr a_pMyStruct);

//...

//How big is myOtherStruct??
int size = 1 + ?? + 4 + 4 + (1024*4) + (1024*4) + (20*4) + (30*4);
//int size = Marhsal.SizeOf(SMyStruct);
IntPtr pMyStruct = Marshal.AllocHGlobal(size);
initialise(pMyStruct);
anotherNativeMethod(pMyStruct);
Marshal.FreeHGlobal(pMyStruct);

Note that you can still use the get the Marshaller to copy the pointer to your structure using Marshal.PtrToStructure but you no longer need to depend on it for your code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...