【问题标题】:Marshall weird C++ structure in C#Marshall C# 中奇怪的 C++ 结构
【发布时间】:2017-03-01 14:43:22
【问题描述】:

我一直在尝试用 C# 编组这个结构,但我在其中的最后两行遇到了麻烦。

typedef struct _modenv_
{
  long lMajor;         /* major version of kernel */
  long lMinor;         /* minor version of kernel */
  long lRelease;       /* release version of kernel */

  long lResultSize;    /* sResult buffer size */

  long (__stdcall *lPGSM_ExecuteKernel) (struct _modenv_ *PGEnv, char *sCommand, char *sResult, long lLength);
  long (__stdcall *lPGSM_ExecuteCommand)(struct _modenv_ *PGEnv, char *sCommand, char *sResult, long lLength);

} PGMODENV;

而我所做的只是:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PGMODENV
{
    /* input data */
    public long lMajor;         /* major version of kernel */
    public long lMinor;         /* minor version of kernel */
    public long lRelease;       /* release version of kernel */

    /* updated data */
    public long lResultSize;    /* sResult buffer size */

}

如何在 C# 中实现它们?

【问题讨论】:

  • 我见过这样的东西。如果编组是不可能的,我不会感到惊讶,因为您无法在内存中移动结构,因为缓冲区紧跟在结构之后。线索是缓冲区大小很长,但根本没有缓冲区指针。
  • 它们是函数指针,在 C# 中完全等效的是委托对象。您必须小心,您传递的委托对象必须在某个地方有另一个引用,因此当本机代码进行函数调用时,GC 不会清理它们并使您的程序崩溃。也将它们存储在静态变量中或使用 GCHandle.Alloc()。
  • 这些结构在导出函数中作为参数传递,它们会是 GC 吗?或者我应该如何防止它们被收集?

标签: c# c++ marshalling


【解决方案1】:

尝试为它们使用IntPtr,因为它们是指向函数的指针。让它看起来像这样:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PGMODENV
{
    /* input data */
    public long lMajor;         /* major version of kernel */
    public long lMinor;         /* minor version of kernel */
    public long lRelease;       /* release version of kernel */

    /* updated data */
    public long lResultSize;    /* sResult buffer size */

    public IntPtr lPGSM_ExecuteKernel;
    public IntPtr lPGSM_ExecuteCommand;
}

【讨论】:

  • 论点呢?
  • 这只是为了编组结构,之后您可以使用 Marshal.GetDelegateForFunctionPointer 将 IntPtrs 转换为像@vivek nuna 建议的委托实例。
【解决方案2】:
public struct PGMODENV
{
    public int lMajor; // major version of kernel
    public int lMinor; // minor version of kernel
    public int lRelease; // release version of kernel

    public int lResultSize; // sResult buffer size

    //The original C++ function pointer contained an unconverted modifier:
    //ORIGINAL LINE: int(__stdcall *lPGSM_ExecuteKernel)(struct _modenv_ *PGEnv, sbyte *sCommand, sbyte *sResult, int lLength);
    public delegate int lPGSM_ExecuteKernelDelegate(PGMODENV PGEnv, ref string sCommand, ref string sResult, int lLength);
    public lPGSM_ExecuteKernelDelegate lPGSM_ExecuteKernel;
    //The original C++ function pointer contained an unconverted modifier:
    //ORIGINAL LINE: int(__stdcall *lPGSM_ExecuteCommand)(struct _modenv_ *PGEnv, sbyte *sCommand, sbyte *sResult, int lLength);
    public delegate int lPGSM_ExecuteCommandDelegate(PGMODENV PGEnv, ref string sCommand, ref string sResult, int lLength);
    public lPGSM_ExecuteCommandDelegate lPGSM_ExecuteCommand;

}

【讨论】:

  • 这应该是独立于 PGMODENV 的结构?
  • 同理,基本上我把它转成类了,你可以作为结构体使用,如果我认为你感兴趣的话,只有委托部分
  • 知道了,明天测试一下。谢谢:)
  • 在将 PGMODENV 传递给其代表时错过了您的 ref 关键字。
  • 正确,参考PGEnv
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-15
  • 1970-01-01
  • 2015-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多