我想将结构传递给C函数,然后编写以下代码。

当我运行它时,第一个功能-Foo1正在工作,然后功能Foo出现异常。您能帮助我了解问题所在吗?...

C代码:

typedef struct
{
    int Size;
    //char *Array;
}TTest;

__declspec(dllexport) void Foo(void  *Test);
__declspec(dllexport) int  Foo1();

void Foo(void  *Test)
{
    TTest *X = (TTest *)Test;
    int i = X->Size;
    /*for(int i=0;i<Test->Size;Test++)
    {
        Test->Array[i] = 127;
    }*/
}

int Foo1()
{
    return 10;
}


C#代码:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    [StructLayout(LayoutKind.Sequential)]
    public class TTest
    {
        public int Size;
    }

    class Program
    {
        [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
        public static extern void Foo(
            [MarshalAs(UnmanagedType.LPStruct)]
            TTest lplf   // characteristics
        );

        [DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
        public static extern int Foo1();

        static void Main(string[] args)
        {
            TTest Test = new TTest();
            Test.Size = 25;

            int XX = Program.Foo1();
            Program.Foo(Test);
        }
    }
}

最佳答案

致下降投票者:这个答案解决了两个问题:调用约定/ MarhsalAs属性的直接问题,以及如果他接受我建议将进入结构。

您的本机代码要求输入TTest,在C#中为TTest。首先,您应该将void*定义为结构而不是类。其次,您应该将IntPtr的声明更改为:

[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo(IntPtr lplf);


第三,您应该使用TTest关键字固定Foo并将其指针传递给TTest。如果使用的是类,则可以使用fixedFoo中获取Marhsal.StructureToPtr

这在两侧都提供了相同的功能,可以传递指向任何类型的指针。您还可以为所有要使用的类类型编写重载,因为它们在本机端都等同于IntPtr。使用结构时,您的参数将以TTest开头。

我很好奇的是,当您将非托管代码中执行的第一件事强制转换为void*时,为什么您的本机代码需要ref而不是void*。如果将参数切换为TTest*,则提供相同的功能将变得更加简单。您的声明将变为:

[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo(ref TTest lplf);


然后您将函数称为TTest*

如果您使用的是类,则TTest*是不必要的,因为类是引用类型。

10-04 13:47