【问题标题】:Getting a complex struct from C++ to C#从 C++ 到 C# 获取复杂的结构
【发布时间】:2019-04-01 18:41:39
【问题描述】:

几天前我提出了这个问题:Passing a complex Struct (with inner array of struct) from C# to C++

幸运的是,它已得到回答,并且代码似乎可以正常工作。

现在我需要做相反的情况,我的意思是,我需要将结构从 C++ dll 获取到我的 C# 代码。

我在这个网站上研究,尝试使用 IntPtr 类型,但没有用。然后,由于正确定义了 C# 中的结构,我尝试使用 out 引用。

作为总结,将重新发布用两种语言定义的结构

typedef struct _ImParam
{
  UINT Format;
  UINT Resolution;
  UINT ColorDepth;
} IM_PARAM;

typedef struct _sValues
{
  UINT Xpos;
  UINT Ypos;
  UINT Width;
  UINT Height;
  BOOL Milli; 
} S_VALUES;

typedef struct _sProperties
{
  BOOL Enable;
  S_VALUES Properties;
} S_PROPERTIES;

typedef struct _DevParam
{
  BOOL Enable;
  UINT Font;
  char Symbol;
  IM_PARAM Image1;
  IM_PARAM Image2;
  S_PROPERTIES Properties[10];
  UINT FeedMode;
} DevParam;

// more code, comments, etc. etc.

// The function I want to use
BOOL GetParameters( DWORD ID, DevParam  *dParam );

这就是我在 C# 中构建结构的方式

[StructLayout(LayoutKind.Sequential)]
public struct ImParam
{
   public uint Format;
   public uint Resolution;
   public uint ColorDepth;

   public ImParam(uint n)
   {
       Format = n;
       Resolution = 300;
       ColorDepth = 256;
   }
};

[StructLayout(LayoutKind.Sequential)]
public struct sValues
{
   public uint Xpos;
   public uint Ypos;
   public uint Width;
   public uint Height;
   public bool Milli;

   public sValues(uint n)
   {
       Xpos = n;
       Ypos = n;
       Width = n;
       Height = n;
       Milli = false;
   }
};

[StructLayout(LayoutKind.Sequential)]
public struct sProperties
{
   public bool Enable;
   public sValues Properties;

   public sProperties(int n)
   {
       Enable = false;
       Properties = new sValues(n);
   }
};

[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
   public bool Enable;
   public uint Font;
   public char Symbol;
   public ImParam Image1;
   public ImParam Image2;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
   public sProperties[] Properties;
   public uint FeedMode;

   public DeviceParameters(int n)
   {
       Enable = true;
       Font = 0;
       Symbol = '?';
       Image1 = new ImParam(3);
       Image2 = new ImParam(3);
       Properties = new sProperties[10];
       for(int i = 0; i < 10; i++)
          Properties[i] = new sProperties(n);
       FeedMode = 1;
   }
};

// This is the method imported from the C++ dll
[DllImport(path, EntryPoint = "?GetParameters@@YGHKPAU_DevParam@@@Z")]
public static extern bool GetParameters(int ID, out DevParam dParam);

这是电话

// Already got ID from somewhere else
DevParam DP;
bool res = Class1.GetParameters(ID, out DP);
Console.WriteLine("Result: " + res);

代码似乎有效,因为我得到了一个“真实”的结果。问题是它在结构成员中得到错误的值,放置默认值(数字始终为 0,布尔值始终为 false),即使我之前使用过 SetParam(..) 方法(我知道一个有效,因为当我更改图像格式扫描仪会降低扫描速度)。

我错过了什么?

注意:我没有 .dll 的源代码


已编辑:

一直在尝试进行这些修改:

// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters@@YGHKPAU_DevParam@@@Z")]
public static extern bool GetParameters(int ID, ref IntPtr dParam);

// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, ref Ptr);
Console.WriteLine("Result: " + res);
var test = Marshal.PtrToStructure(Ptr, typeof(DevParam));
// No idea what I'll do here
Marshal.FreeHGlobal(Ptr);

如果我尝试打印“test”,它应该给出一个地址,因为它是一个指针,但它是空的。都不知道如何从结构中提取数据。

有什么想法吗?

【问题讨论】:

  • 要研究的关键字:编组、序列化、结构填充、C++ ABI。
  • 我一直在寻找那些。我提出这个问题是因为我发现的并不能说服我。不要觉得那是我正在寻找的(或尝试了这些解决方案但失败了)
  • AFAIK BOOL 应编组为 MarshalAs(UnmanagedType.Bool)
  • 谢谢。添加了元帅。仍然得到错误。我正在了解如何使用 IntPtr 来做到这一点(因为我相信答案就在那里)。添加了“ref”关键字,结果为真。好像也可以这样通过。然而,我被困住了,因为不知道还能做什么(是的,这是我第一次导入 DLL 和编组的东西,我的经验是...... 5%?)

标签: c# c++ struct interop marshalling


【解决方案1】:

解决了!

// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters@@YGHKPAU_DevParam@@@Z")]
public static extern bool GetParameters(int ID, IntPtr dParam);

// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, Ptr);
DevParam test = (DevParam)Marshal.PtrToStructure(Ptr, typeof(DevParam));

// For testing purpoises, previously changed the default values with another method
Console.WriteLine(test.Enable);

Marshal.FreeHGlobal(Ptr);

不得不删除 ref 关键字。

【讨论】:

    猜你喜欢
    • 2020-04-08
    • 1970-01-01
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多