【问题标题】:Marshaling byval C-structure as return value in C#在 C# 中将 byval C 结构编组为返回值
【发布时间】:2011-01-30 19:56:59
【问题描述】:

我有非托管代码:

...
typedef struct foo  
{  
 int  a;  
 bool b
 int  c;  
} FOO,*LPFOO;
....
__declspec(dllexport) FOO __stdcall GetFoo()  
{  
   FOO f;  
   <some work>  
   return f;   
}  
....

我已经为 GetFoo 函数声明了 C# 原型:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    private struct Foo
    {
      public int  a;  
      public bool b
      public int  c; 
    };

    [DllImport("foo.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    [return:MarshalAs( UnmanagedType.Struct)]        
    private static extern Foo GetFoo();

但是当我从 C# 代码调用 GetFoo 时,我总是遇到 MarshalDirectiveException - 方法的类型签名与 PInvoke 不兼容。我应该如何声明 C# 原型?

【问题讨论】:

  • 您的非托管 GetFoo 函数似乎没有采用任何参数,而其托管定义采用整数参数。也许那是一个错字?另外你打算如何释放GetFoo函数分配的非托管内存?
  • 对不起,我发错了。场外它没有任何参数。非托管 GetFoo 不分配任何内存对象

标签: c# marshalling unmanaged managed


【解决方案1】:

是的,返回结构的函数往往难以互操作。这样的结构必须是 blittable 以便 pinvoke marshaller 可以将指针传递给函数,准备好写入返回值。 “blittable”意味着托管代码中的结构布局需要与结构的非托管布局相同。如果不是,则需要制作副本,pinvoke marshaller 不希望在返回值的特定情况下制作该副本。

bool 类型是互操作问题,不同的运行时做出不同的选择。它往往是 C 中的 4 个字节(与 Windows BOOL 类型相比,也是 pinvoke 的默认值),COM 互操作中的 2 个字节(又名 VARIANT_BOOL),C++ 中的 1 个字节,CLR 中的 1 个字节。由于目标运行时未知,CLR 无法猜测哪个选择是正确的。 BOOL 是默认值,4 个字节。

即使使用[MarshalAs(UnmanagedType.U1)] 强制完全匹配也不会使其成为 blittable。这很奇怪,我认为这是一个 CLR 错误。一个好的解决方法是将其替换为byte,您可以使用属性将其包装回布尔值。注意发布的sn-p有很多错误,我做了这个版本:

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

【讨论】:

  • 我也试过 [MarshalAs(UnmanagedType.I4)], [MarshalAs(UnmanagedType.I1)], [MarshalAs(UnmanagedType.Bool)] 对 'b' 变量,但它没有帮助.
  • 这不就是bool不可blittable吗?
猜你喜欢
  • 2014-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-02
相关资源
最近更新 更多