C# 将byval C结构封送为C中的返回值#
我有非托管代码:C# 将byval C结构封送为C中的返回值#,c#,marshalling,unmanaged,managed,C#,Marshalling,Unmanaged,Managed,我有非托管代码: ... typedef struct foo { int a; bool b int c; } FOO,*LPFOO; .... __declspec(dllexport) FOO __stdcall GetFoo() { FOO f; <some work> return f; } .... 但当我从C代码调用GetFoo时,我总是有MarshalDirectiveException——方法的
...
typedef struct foo
{
int a;
bool b
int c;
} FOO,*LPFOO;
....
__declspec(dllexport) FOO __stdcall GetFoo()
{
FOO f;
<some work>
return f;
}
....
但当我从C代码调用GetFoo时,我总是有MarshalDirectiveException——方法的类型签名与PInvoke不兼容。如何声明C#prototype?是的,返回结构的函数往往很难进行互操作。这样的结构必须是可Blitttable的,这样pinvoke封送器就可以传递一个指向函数的指针,为函数编写返回值做好准备。“blittable”意味着托管代码中的结构布局需要与结构的非托管布局相同。如果不是,则需要进行复制,pinvoke封送员不希望在返回值的特定情况下进行该复制
bool
类型是一个互操作问题,不同的运行时做出了不同的选择。在C中,它往往是4字节(与Windows BoL类型相比,也是PINKEK的默认值),COM互操作中的2字节(Aka ValueIn BooL),C++中的1字节,CLR中的1字节。由于目标运行时未知,CLR无法猜测哪个选项是正确的。BOOL是默认值,4个字节
即使使用[marshallas(UnmanagedType.U1)]
强制进行精确匹配,也不会使其成为可快速删除的。这很奇怪,我认为这是CLR错误。一个很好的解决方法是将其替换为字节
,您可以使用属性将其包装回bool。请注意,在发布的代码片段中有很多错误,我使这个版本正常工作:
using System;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
Foo value = GetFoo();
}
[StructLayout(LayoutKind.Sequential)]
private struct Foo {
public int a;
private byte _b;
public bool b {
get { return _b != 0; }
}
public int c;
};
[DllImport(@"c:\projects\consoleapplication3\debug\cpptemp10.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "_GetFoo@0")]
private static extern Foo GetFoo(/*int CoreIndex*/);
}
您的非托管
GetFoo
函数似乎不接受任何参数,而其托管定义接受整数参数。也许那是个打字错误?另外,您打算如何释放由GetFoo
函数分配的非托管内存?对不起,我在帖子中弄错了。因为它没有任何参数。非托管GetFoo不分配任何内存对象我也在'b'变量上尝试过[Marshallas(UnmanagedType.I4)],[Marshallas(UnmanagedType.I1)],[Marshallas(UnmanagedType.Bool)],但没有帮助。这不就是Bool
不可blittable吗?
using System;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
Foo value = GetFoo();
}
[StructLayout(LayoutKind.Sequential)]
private struct Foo {
public int a;
private byte _b;
public bool b {
get { return _b != 0; }
}
public int c;
};
[DllImport(@"c:\projects\consoleapplication3\debug\cpptemp10.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "_GetFoo@0")]
private static extern Foo GetFoo(/*int CoreIndex*/);
}
typedef struct foo
{
int a;
bool b;
int c;
} FOO,*LPFOO;
extern "C" __declspec(dllexport)
FOO __stdcall GetFoo()
{
FOO f;
f.a = 42;
f.b = true;
f.c = 101;
return f;
}