【问题标题】:Marshalling type which references itself引用自身的编组类型
【发布时间】:2014-07-31 06:36:07
【问题描述】:

我的 c++ 代码中有以下(缩短的)函数定义:

EXPORT_API Table* OpenTableExport();

其中 Table 是以下形式的结构:

typedef struct Table
{
  int fCurrKey;
  int fTableNo;
  int fRecSize;
  char fCreating;
  Table* fNextTable;
  Table* fPrevTable;
  MyFileType fFile;
} Table;

所以,为了从托管代码中 PInvoke 这个函数,我自然地尝试了以下操作:

[DllImport("Export.dll", EntryPoint = "OpenTableExport", CharSet = CharSet.Auto,   CallingConvention = CallingConvention.Cdecl)]
public static extern Table OpenTable();

有下表类:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class Table
{
    public KeyDescription fCurrKey;
    public int fTableNo;
    public uint fRecSize;
    public byte fCreating;
    public Table fNextTable;
    public Table fPrevTable;
    public FileDescription fFile;

}

现在使用该方法时,我得到以下异常(从德语翻译):

“Table”类型的字段“fNextTable”无法编组,该类型不存在编组支持。

为什么 .NET 在任何情况下都不能编组它编组的同一类型的 fNextTable 和 fPrevTable 成员?

我也可以用 IntPtr 替换托管类定义中的引用...但这真的有必要吗? (然后编组或多或少会起作用)。

【问题讨论】:

  • 您需要将 Table* 字段定义为 IntPtr。
  • 好吧,好吧,我确实看到了这种可能性,我只是不明白为什么这是必要的(包含这些字段的对象被正确编组)
  • 当您将字段定义为 Table 时,您要求编组另一个 Table 结构,这会产生无休止的递归。 IntPtr 只是指针,你得到它然后传递给另一个期望 Table* 的 API,或者使用 Marshal 方法来处理非托管内存,比如 PtrToStructure。
  • 啊,好吧,我明白你的意思了,在某种程度上是有道理的(尽管递归不一定是无止境的,我想这取决于编组的实现方式)。我将其放入答案中,我很乐意接受,非常感谢。

标签: c# c pinvoke marshalling


【解决方案1】:

通过以下方式定义结构:

public class Table
{
    public KeyDescription fCurrKey;
    public int fTableNo;
    public uint fRecSize;
    public byte fCreating;
    public IntPtr fNextTable;
    public IntPtr fPrevTable;
    public FileDescription fFile;
}

测试 IntPtr 成员是否为 NULL (IntPtr.Zero) 并处理它们。可能非托管 API 包含另一个期望 Table* 的函数。另请参阅 Marshal.PtrToStructure 方法和另一个用于托管-非托管内存交换的低级 Marshal 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    相关资源
    最近更新 更多