C# 使用带结构和指针的pinvoke

C# 使用带结构和指针的pinvoke,c#,c,pinvoke,C#,C,Pinvoke,我试图在我的c代码中输入一个c函数。它接受一个struct和一个double作为输入,并返回一个相同类型的struct。我在c和c代码中定义了相同的结构。当PInvoke调用c函数时,我得到一个异常“方法类型签名与PInvoke不兼容”。有人能看出我做错了什么吗?谢谢 C: C#: 我知道这可能不是世界上最好的解决方案,但它在我的测试中对我有效,所以我将让你推断出你个人可能需要做的关于记忆释放的事情,并让你自己判断 我个人讨厌使用Marshal.Copy和Buffer.BlockCopy。我在这

我试图在我的c代码中输入一个c函数。它接受一个struct和一个double作为输入,并返回一个相同类型的struct。我在c和c代码中定义了相同的结构。当PInvoke调用c函数时,我得到一个异常“方法类型签名与PInvoke不兼容”。有人能看出我做错了什么吗?谢谢

C:

C#:


我知道这可能不是世界上最好的解决方案,但它在我的测试中对我有效,所以我将让你推断出你个人可能需要做的关于记忆释放的事情,并让你自己判断

我个人讨厌使用Marshal.Copy和Buffer.BlockCopy。我在这里为此编写了自己的函数行:(特别是DTCSMemory项目->MemPtr结构),但为了便于移植,我使用标准函数对其进行了编程。我必须承认,我可能正在用字节做一些古怪的事情,但我只是在双重肯定(不是双关语)

如果结构物采用正常包装,则必须使用IntPtr.尺寸。通常情况下,一个简单的结构互操作可以解决这个问题,但我们这里不使用简单的结构互操作。如果结构是字节压缩的,那么您需要将其显示“IntPtr.Size”的位置改回“4”

也就是说,如果我们在C中有:

typedef struct myStruct_struct
{
    int length;
    double array[1];
}
myStruct;

__declspec(dllexport) myStruct *doSomething(const myStruct *inStruct, double val)
{
    int i = sizeof(double);

    //doSomething ...
    myStruct *outStruct = (myStruct*)GlobalAlloc(0, sizeof(void*) + (8 * 256));
    ZeroMemory(outStruct, sizeof(void*) + (8 * 256));
    outStruct->length = 256;
    outStruct->array[0] = inStruct->array[0] + val;

    return outStruct;
}
那么C#中的代码就可以工作了:

  public class Program
    {

        /// <summary>
        /// myStruct is not marshaled, directly.
        /// </summary>
        public struct myStruct
        {

            public int Length;
            public double[] Array;


            private IntPtr _ptr;

            /// <summary>
            /// Custom marshal a structure in from interop (and optionally free the original pointer).
            /// </summary>
            /// <param name="ptr"></param>
            /// <param name="freeOrig"></param>
            /// <returns></returns>
            public static myStruct MarshalIn(IntPtr ptr, bool freeOrig = true)
            {
                byte[] by = new byte[4];
                myStruct ns = new myStruct();

                Marshal.Copy(ptr, by, 0, 4);
                ns.Length = BitConverter.ToInt32(by, 0);

                ns.Array = new double[ns.Length];
                by = new byte[ns.Length * 8];

                Marshal.Copy(ptr + IntPtr.Size, by, 0, by.Length);
                Buffer.BlockCopy(by, 0, ns.Array, 0, by.Length);
                if (freeOrig) Marshal.FreeHGlobal(ptr);

                return ns;
            }

            /// <summary>
            /// Custom marshal a structure for calling interop.
            /// </summary>
            /// <returns></returns>
            public IntPtr MarshalOut()
            {
                IntPtr ptr;
                int l = IntPtr.Size + (8 * Array.Length);
                ptr = Marshal.AllocHGlobal(l);

                byte[] by = BitConverter.GetBytes(Length);

                Marshal.Copy(by, 0, ptr, 4);

                by = new byte[Length * 8];
                Buffer.BlockCopy(Array, 0, by, 0, by.Length);
                Marshal.Copy(by, 0, ptr + IntPtr.Size, by.Length);

                _ptr = ptr;
                return ptr;
            }

            /// <summary>
            /// Free any associated pointer with this structure created with MarshalOut().
            /// </summary>
            public void Free()
            {
                if (_ptr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(_ptr);
                    _ptr = IntPtr.Zero;
                }
            }
        }

        [DllImport("mylib.dll", SetLastError = true, CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr doSomething(IntPtr inStruct, double val);


        static void Main()
        {

            // let's do some math.

            myStruct ms = new myStruct(), ms2;
            ms.Array = new double[1];

            ms.Length = 1;
            ms.Array[0] = 424.444;

            ms2 = myStruct.MarshalIn(doSomething(ms.MarshalOut(), 524.444));

            // Free this after the call.
            ms.Free();

        }


    }
公共类程序
{
/// 
///myStruct不是直接编组的。
/// 
公共结构myStruct
{
公共整数长度;
公共双[]数组;
私人IntPtr_ptr;
/// 
///从互操作中自定义封送结构(并可以选择释放原始指针)。
/// 
/// 
/// 
/// 
公共静态myStruct MarshalIn(IntPtr ptr,bool freeOrig=true)
{
byte[]by=新字节[4];
myStruct ns=新的myStruct();
封送员副本(ptr,by,0,4);
ns.Length=BitConverter.ToInt32(by,0);
ns.数组=新的双精度[ns.长度];
by=新字节[ns.Length*8];
封送处理副本(ptr+IntPtr.Size,by,0,by.Length);
块复制(按,0,ns.数组,0,按.长度);
if(自由党)自由党元帅(ptr);
返回ns;
}
/// 
///自定义封送处理用于调用互操作的结构。
/// 
/// 
公共IntPtr封送处理()
{
IntPtr-ptr;
intl=IntPtr.Size+(8*Array.Length);
ptr=编组分配全局(l);
byte[]by=BitConverter.GetBytes(长度);
封送员副本(由,0,ptr,4);
by=新字节[长度*8];
块复制(数组,0,by,0,by.Length);
封送处理副本(按,0,ptr+IntPtr.Size,按.长度);
_ptr=ptr;
返回ptr;
}
/// 
///释放与使用MarshalOut()创建的此结构关联的任何指针。
/// 
公众免费
{
如果(ptr!=IntPtr.Zero)
{
自由全球元帅(_ptr);
_ptr=IntPtr.Zero;
}
}
}
[DllImport(“mylib.dll”,SetLastError=true,CharSet=CharSet.None,CallingConvention=CallingConvention.Cdecl)]
公共静态外部IntPtr剂量测量(IntPtr指令,双val);
静态void Main()
{
//让我们做一些数学题。
myStruct ms=newmystruct(),ms2;
ms.数组=新的双精度[1];
ms.长度=1;
ms.Array[0]=424.444;
ms2=myStruct.MarshalIn(doSomething(ms.marshallout(),524.444));
//通话结束后,请将此免费。
弗里女士();
}
}

LPStruct和Struct是易变的生物。通常,封送拆收器会返回一个错误,但是这次没有发生,但是如果你到达那个点,可能会发生,因为那不是ref或out结构,它只是一个结构(即使它是通过指针传递的,我也不认为它符合LPStruct的条件。最好是在参数行的末尾添加一个true ref struct变量来接收输出结构,并简单地返回void或bool作为函数的返回值。)不幸的是,我无法更改c代码签名。它在其他地方使用。[Marshallas(UnmanagedType.ByValArray)]数组声明中缺少。请删除UnmanagedType.LPStruct。您必须对参数使用ref来匹配本机代码中的myStruct*。如果函数返回数组中的数据,则需要使用IntPtr手动封送处理。然后您需要用C编写一个可调用的包装器。我刚刚注意到…它看起来像数组占位符对于可变长度数组,如果我没有弄错的话。可变长度数组必须手动封送。封送它们并不容易。如果您需要的话,我实际上已经在代码中找到了这个问题的解决方案,但是根据我所说的,应该足以让您计算出来。结构的内存分配到了某个地方?您自己的最好的解决方案是在托管代码中分配内存,并让封送处理程序完成所有工作。这需要将动态大小的数组排除在任何结构之外。这很容易做到。而且它消除了对所有这些代码的需要。然后他已经被套住了。使用共享堆进行分配的几率非常接近于零。修复接口就是解决方案。@ben这些天都是一样的SMSDN说:@Davidheffernanw他应该做的可能是用C或C++/CLI编写一个包装器,如果这是一个选项的话。。。
typedef struct myStruct_struct
{
    int length;
    double array[1];
}
myStruct;

__declspec(dllexport) myStruct *doSomething(const myStruct *inStruct, double val)
{
    int i = sizeof(double);

    //doSomething ...
    myStruct *outStruct = (myStruct*)GlobalAlloc(0, sizeof(void*) + (8 * 256));
    ZeroMemory(outStruct, sizeof(void*) + (8 * 256));
    outStruct->length = 256;
    outStruct->array[0] = inStruct->array[0] + val;

    return outStruct;
}
  public class Program
    {

        /// <summary>
        /// myStruct is not marshaled, directly.
        /// </summary>
        public struct myStruct
        {

            public int Length;
            public double[] Array;


            private IntPtr _ptr;

            /// <summary>
            /// Custom marshal a structure in from interop (and optionally free the original pointer).
            /// </summary>
            /// <param name="ptr"></param>
            /// <param name="freeOrig"></param>
            /// <returns></returns>
            public static myStruct MarshalIn(IntPtr ptr, bool freeOrig = true)
            {
                byte[] by = new byte[4];
                myStruct ns = new myStruct();

                Marshal.Copy(ptr, by, 0, 4);
                ns.Length = BitConverter.ToInt32(by, 0);

                ns.Array = new double[ns.Length];
                by = new byte[ns.Length * 8];

                Marshal.Copy(ptr + IntPtr.Size, by, 0, by.Length);
                Buffer.BlockCopy(by, 0, ns.Array, 0, by.Length);
                if (freeOrig) Marshal.FreeHGlobal(ptr);

                return ns;
            }

            /// <summary>
            /// Custom marshal a structure for calling interop.
            /// </summary>
            /// <returns></returns>
            public IntPtr MarshalOut()
            {
                IntPtr ptr;
                int l = IntPtr.Size + (8 * Array.Length);
                ptr = Marshal.AllocHGlobal(l);

                byte[] by = BitConverter.GetBytes(Length);

                Marshal.Copy(by, 0, ptr, 4);

                by = new byte[Length * 8];
                Buffer.BlockCopy(Array, 0, by, 0, by.Length);
                Marshal.Copy(by, 0, ptr + IntPtr.Size, by.Length);

                _ptr = ptr;
                return ptr;
            }

            /// <summary>
            /// Free any associated pointer with this structure created with MarshalOut().
            /// </summary>
            public void Free()
            {
                if (_ptr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(_ptr);
                    _ptr = IntPtr.Zero;
                }
            }
        }

        [DllImport("mylib.dll", SetLastError = true, CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr doSomething(IntPtr inStruct, double val);


        static void Main()
        {

            // let's do some math.

            myStruct ms = new myStruct(), ms2;
            ms.Array = new double[1];

            ms.Length = 1;
            ms.Array[0] = 424.444;

            ms2 = myStruct.MarshalIn(doSomething(ms.MarshalOut(), 524.444));

            // Free this after the call.
            ms.Free();

        }


    }