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);
如果您正在使用该类,则不需要引用,因为类是引用类型。