我想将结构传递给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
。如果使用的是类,则可以使用fixed
从Foo
中获取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*
是不必要的,因为类是引用类型。