C#中的PInvoke DLL

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

当我运行它时,第一个函数Foo1正在工作,然后函数Foo获得exception。 你能帮我理解问题是什么吗?…

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;iSize;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); } } } 

对于downvoters :这个答案解决了两个问题:调用约定/ MarhsalAs属性的即时问题,以及他很快就会发现他的TTest参数无法工作的问题,如果他接受我将TTest转换为结构的建议。

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

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

第三,你应该使用fixed关键字fixed TTest并将其指针传递给Foo 。 如果您正在使用类,则可以使用Marhsal.StructureToPtr从您的TTest获取IntPtr

这在两端都提供了相同的function,其中可以传入指向任何类型的指针。您还可以使用要使用的所有类类型编写重载,因为它们都等同于本机端的void* 。 使用结构,您的参数将以ref为前缀。

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

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

你会把这个函数称为Program.Foo(ref Test);

如果您正在使用该类,则不需要引用,因为类是引用类型。