PInvoke指向struct的指针,包括float数组

时间:2015-06-02 09:39:58

标签: c# arrays pointers struct pinvoke

我正在尝试P调用C库以在Xamarin安卓应用程序上使用。

考虑以下C结构:

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

使用以下函数调用:

unsigned int initialise(sMyStruct* a_pMyStruct)

我把它放到C#结构中:

[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;
}

这是我在C#中的函数来调用它:

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

然后我用以下方法调用此函数:

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

所以会发生什么是C函数将使用大量数据返回我的结构。然后我再次将结构传递给另一个C程序,该程序将这些参数用于程序的其余部分。

我的问题是如何将float数组数据恢复到正确的结构变量中,以便我可以再次传递它?目前,我的代码基于以下问题: Marshalling float Array to c#Marshalling complex struct to c#

但我没有成功编写代码,因此我可以将float数组传递回我的结构,甚至没有看到编译器错误(更不用说在测试时失败了!)

如何将float数组数据放入我的结构中?

修改 经过几个答案和评论后,我正在添加我最初做的事情,试图增加一些清晰度。

我遇到编译器错误,而不是使用上面的“public unsafe float [] ...”例程,我这样做(在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;
}

使用此代码,我收到错误“您不能使用未固定表达式中包含的固定大小缓冲区。请尝试使用fixed语句” 此时我尝试使用复制例程。

我想要的是确保填充初始化函数返回的字段myFloatArray,myFloatArray2等。 FYI myBool,sOtherStruct等就像我期望的那样填充。

2 个答案:

答案 0 :(得分:0)

如果您不需要访问数据,可以将其保留为指针。虽然您看起来对内存负责,但您需要分配并稍后释放您正在使用的非托管内存。有点像...

[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);

请注意,您仍然可以使用获取Marshaller使用Marshal.PtrToStructure将指针复制到您的结构,但您不再需要依赖它来代码。

答案 1 :(得分:0)

我怀疑你的许多问题是由于你在行走之前试图跑步造成的。您试图使用许多成员创建复杂的结构。在一个地方犯一个错误,任何地方都无济于事。

那么,我们如何简化呢?那么,你问的问题与固定缓冲区有关。用你要问的问题来解释:

  

如何将数组复制到固定缓冲区和从固定缓冲区复制?

让我们通过使用仅包含固定缓冲区的简化类型来处理它,并证明我们可以复制到该缓冲区和从该缓冲区复制。

你的财产获取者是在正确的方向。最大的问题是你传递的长度不正确。您调用的MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init]; mc.mailComposeDelegate = self; [mc.navigationBar setTintColor:[UIColor whiteColor]]; [mc setSubject:[NSString stringWithFormat:@"V%@ Support", version]]; [mc setMessageBody:supportText isHTML:NO]; [mc setToRecipients:@[@"ring@ringid.com"]]; [self presentViewController:mc animated:YES completion:NULL]; 重载的最后一个参数是元素的数量。您错误地传递了字节数。二传手的性质与吸气剂非常相似。这一切看起来像这样:

mc.navigationBar.translucent = NO;
[mc.navigationBar setTintColor:[UIColor myColor]];
mc.navigationBar.backgroundColor = [UIColor myColor];
UIImage *image = [UIImage imageNamed:@"nav-bar_6_plus.png"];
[mc.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];

该计划的输出是:

0 0 0 0
1 2 3 4
5 6 0 0

此building block向您展示如何处理固定缓冲区。您可以使用此程序中的代码,并确保正确处理固定缓冲区。当您转移到更复杂的结构时,如果您遇到任何问题,您可以确信它们与固定缓冲区代码无关。