C# 将浮点[]编组为浮点** 让我说,我有一个C++函数,原型 int someFunction(const float ** raws)

C# 将浮点[]编组为浮点** 让我说,我有一个C++函数,原型 int someFunction(const float ** raws),c#,c++,pinvoke,marshalling,C#,C++,Pinvoke,Marshalling,如何使用C#中的float[][参数调用此函数?可能不使用不安全的代码。据我所知,大部分工作您必须自己完成。Interop将帮助您编组顶级数组,但您的工作是固定所有嵌套数组,然后在完成后取消固定它们。此代码显示了一种方法: using System; using System.Runtime.InteropServices; namespace ManagedClient { class Program { [DllImport("UnmanagedDll.dl

如何使用C#中的
float[][
参数调用此函数?可能不使用不安全的代码。

据我所知,大部分工作您必须自己完成。Interop将帮助您编组顶级数组,但您的工作是固定所有嵌套数组,然后在完成后取消固定它们。此代码显示了一种方法:

using System;
using System.Runtime.InteropServices;

namespace ManagedClient
{
    class Program
    {
        [DllImport("UnmanagedDll.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int UseFloats([MarshalAs(UnmanagedType.LPArray)] IntPtr[] raws);

        static void Main(string[] args)
        {
            float[][] data =
            {
                new[] { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f },
                new[] { 1.0f, 1.1f, 1.2f, 1.3f },
                new[] { 2.0f },
                new[] { 3.0f, 3.1f }
            };

            var handles = new GCHandle[data.Length];
            var pointers = new IntPtr[data.Length];

            try
            {
                for (int i = 0; i < data.Length; ++i)
                {
                    var h = GCHandle.Alloc(data[i], GCHandleType.Pinned);
                    handles[i] = h;
                    pointers[i] = h.AddrOfPinnedObject();
                }

                UseFloats(pointers);
            }
            finally
            {
                for (int i = 0; i < handles.Length; ++i)
                {
                    if (handles[i].IsAllocated)
                    {
                        handles[i].Free();
                    }
                }
            }
        }
    }
}

实际上,您可能需要做一些事情来告诉非托管代码每个子数组的长度-您选择的非托管函数签名不会让被调用的代码知道每个子数组的长度。(大概你使用浮点**的原因是因为你想要锯齿状数组。如果不是,而且如果每个子数组的长度都完全相同,那么在这里使用矩形数组而不是指针数组会更有效率,而且这也会使编组更容易。)

据我所知,你必须自己完成大部分工作。Interop将帮助您编组顶级数组,但您的工作是固定所有嵌套数组,然后在完成后取消固定它们。此代码显示了一种方法:

using System;
using System.Runtime.InteropServices;

namespace ManagedClient
{
    class Program
    {
        [DllImport("UnmanagedDll.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern int UseFloats([MarshalAs(UnmanagedType.LPArray)] IntPtr[] raws);

        static void Main(string[] args)
        {
            float[][] data =
            {
                new[] { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f },
                new[] { 1.0f, 1.1f, 1.2f, 1.3f },
                new[] { 2.0f },
                new[] { 3.0f, 3.1f }
            };

            var handles = new GCHandle[data.Length];
            var pointers = new IntPtr[data.Length];

            try
            {
                for (int i = 0; i < data.Length; ++i)
                {
                    var h = GCHandle.Alloc(data[i], GCHandleType.Pinned);
                    handles[i] = h;
                    pointers[i] = h.AddrOfPinnedObject();
                }

                UseFloats(pointers);
            }
            finally
            {
                for (int i = 0; i < handles.Length; ++i)
                {
                    if (handles[i].IsAllocated)
                    {
                        handles[i].Free();
                    }
                }
            }
        }
    }
}

实际上,您可能需要做一些事情来告诉非托管代码每个子数组的长度-您选择的非托管函数签名不会让被调用的代码知道每个子数组的长度。(大概你使用浮点**的原因是因为你想要锯齿状数组。如果不是,而且如果每个子数组的长度完全相同,那么在这里使用矩形数组而不是指针数组会更有效,这也会使编组更容易。)

Ian已经回答了你的问题,我只想建议在C++方面使用SAFEAREL。< /P> SAFEARRAY是解决C/C++中数组定义不明确问题的COM解决方案,它们是包含底层元素数量和大小的结构,更适合.Net数组。使用它们将允许从C#自动封送数组


在C++中使用SAFEAREX是很痛苦的,但是ATL有一些很好的包装使事情变得更容易。如果可能的话,改变C++函数来使用它,或者考虑编写一个C++包,用于使用.NET的互操作,并使用C++编写封送处理代码。

< p>伊恩已经回答了你的问题,我只想在C++方面使用SAFEAREX。 SAFEARRAY是解决C/C++中数组定义不明确问题的COM解决方案,它们是包含底层元素数量和大小的结构,更适合.Net数组。使用它们将允许从C#自动封送数组



在C++中使用SAFEAREX是很痛苦的,但是ATL有一些很好的包装使事情变得更容易。如果可能的话,改变C++函数来使用它,或者考虑编写一个C++包,用于使用.NET的互操作,并使用C++编写封送处理代码。<<代码>浮点[][]/C> >与<代码>浮点**/COD>基本不同,所以可能不是。我肯定有办法。这就是为什么我称之为“编组”。我的意思是,一种很有技巧的方法是将float[][]放入类/结构中,然后将其传递。具体地说,通过引用传递它,这样就不会在每次传递到函数时都在堆栈上复制整个float[][],只要在类/structA
float[][]
中的数据上添加正确的包装,它就与
float**
有根本的不同,所以可能不是。这应该不是不可能的。我肯定有办法。这就是为什么我称之为“编组”。我的意思是,一种很有技巧的方法是将float[][]放入类/结构中,然后将其传递。具体地说,通过引用传递它,这样就不会在每次传递到函数时都在堆栈上复制整个float[][],只要在类/结构中的数据上添加正确的包装,这就是一个很好的答案。您的意思可能是“大概是您使用float[][]的原因”,而不是“float**”,应该加下划线或粗体,因为如果是这种情况,二维数组(float[,])可以自动封送。谢谢!但我的意思是:我指责“float**”,因为这是他试图调用的非托管函数的签名。这就是问题的根本原因。(如果非托管签名仍然是float**,那么在C#中切换到float[,]对您没有多大帮助-非托管签名需要一个指针数组,这是问题的核心。从float[,]开始意味着您只需要锁定一个对象,但仍然需要构建一个IntPtr[])我认为最好的解决方案是更改非托管签名,如果可能的话。@Ian为什么要使用
[MarshalAs(UnmanagedType.LPArray)]
?另外,如果不使用该属性,默认的封送是什么?我使用它是因为我知道非托管端要求以C样式传递数组,即作为指向第一个元素的指针。我记不起默认值是什么,当我使用P/Invoke时,我更喜欢显式地确保我理解了我的意思,而不是依赖默认值。回答得好。您的意思可能是“大概是您使用float[][]的原因”,而不是“float**”,应该加下划线或粗体,因为如果是这种情况,二维数组(float[,])可以自动封送。谢谢!但我的意思是:我指责“float**”,因为这是他试图调用的非托管函数的签名。这就是问题的根本原因。(如果非托管签名仍然是float**,那么在C#中切换到float[,]对您没有多大帮助-该非托管签名需要一个