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